Deformat a bit.
This commit is contained in:
parent
a9cc30ff6e
commit
9c394320d4
@ -6,10 +6,10 @@ GTE.TXT by doomed@c64.org / psx.rules.org<br/>
|
||||
SPU.TXT by doomed@c64.org / psx.rules.org<br/>
|
||||
CDINFO.TXT by doomed with big thanks to Barubary, who rewrote a large part<br/>
|
||||
SYSTEM.TXT by doomed with thanx to Herozero for breakpoint info<br/>
|
||||
PS_ENG.TXT PlayStation PAD/Memory Interface Protocol by HFB03536<br/>
|
||||
PS\_ENG.TXT PlayStation PAD/Memory Interface Protocol by HFB03536<br/>
|
||||
IDT79R3041 Hardware User's Manual by Integrated Device Technology, Inc.<br/>
|
||||
IDTR3051, R3052 RISController User's Manual by Integrated Device Technology<br/>
|
||||
PSX.* by Joshua Walker (additional details in various distorted file formats)<br/>
|
||||
PSX.\* by Joshua Walker (additional details in various distorted file formats)<br/>
|
||||
LIBMIRAGE by Rok; info/source code for various cdrom-image formats<br/>
|
||||
psxdev.ru; cdrom sub-cpu decapping<br/>
|
||||
|
||||
|
@ -360,9 +360,9 @@ E = Error 80h appears on some commands (02h..09h, 0Bh..0Dh, 10h..16h, 1Ah,
|
||||
1Bh?, and 1Dh) when the disk is missing, or when the drive unit is disconnected
|
||||
from the mainboard.<br/>
|
||||
|
||||
#### sub_function numbers (for command 19h)
|
||||
Test commands are invoked with command number 19h, followed by a sub_function
|
||||
number as first parameter byte. The Kernel seems to be using only sub_function
|
||||
#### sub\_function numbers (for command 19h)
|
||||
Test commands are invoked with command number 19h, followed by a sub\_function
|
||||
number as first parameter byte. The Kernel seems to be using only sub\_function
|
||||
20h (to detect the CDROM Controller version).<br/>
|
||||
```
|
||||
sub params response ;Effect
|
||||
@ -412,9 +412,9 @@ number as first parameter byte. The Kernel seems to be using only sub_function
|
||||
76h *** a,b,c,d INT3(stat) ;Decoder Prepare Transfer to/from SRAM
|
||||
77h..FFh - INT5(11h,10h) ;N/A
|
||||
```
|
||||
* sub_functions 06h..08h, 30h..31h, and 4xh are supported only in vC0 and vC1.<br/>
|
||||
** sub_function 51h is supported only in BIOS version vC2 and up.<br/>
|
||||
*** sub_functions 22h..25h, 71h..76h supported only in BIOS version vC1 and up.<br/>
|
||||
\* sub\_functions 06h..08h, 30h..31h, and 4xh are supported only in vC0 and vC1.<br/>
|
||||
\*\* sub\_function 51h is supported only in BIOS version vC2 and up.<br/>
|
||||
\*\*\* sub\_functions 22h..25h, 71h..76h supported only in BIOS version vC1 and up.<br/>
|
||||
|
||||
#### Unsupported GetQ,VCD,SecretUnlock (command 1Dh,1Fh,5xh)
|
||||
INT5 will be returned if the command is unsupported. That, WITHOUT removing the
|
||||
@ -830,7 +830,7 @@ boundaries (eg. if track=N Index=0 starts at 12:34:56, and Track=N Index=1
|
||||
starts at 12:36:56, then GetTD(N) will return 12:36, ie. the sector number is
|
||||
truncated, and the Index=0 region is skipped).<br/>
|
||||
|
||||
#### GetQ - Command 1Dh,adr,point --\> INT3(stat) --\> INT2(10bytesSubQ,peak_lo)
|
||||
#### GetQ - Command 1Dh,adr,point --\> INT3(stat) --\> INT2(10bytesSubQ,peak\_lo)
|
||||
```
|
||||
Caution: Supported only in BIOS version vC1 and up. Not supported in vC0.
|
||||
Caution: When unsupported, Parameter Fifo isn't cleared after the command.
|
||||
@ -1120,8 +1120,8 @@ match). Typically, the values are "01h,01h" for Licensed PSX Data CDs, or
|
||||
"00h,00h" for disk missing, unlicensed data CDs, Audio CDs.<br/>
|
||||
The counters are reset to zero, and SCEx receive mode is active for a few
|
||||
seconds after booting a new disk (on power up, on closing the drive door, on
|
||||
sending a Reset command, and on sub_function 04h). The disk is unlocked if the
|
||||
"success" counter is nonzero, the only exception is sub_function 04h which does
|
||||
sending a Reset command, and on sub\_function 04h). The disk is unlocked if the
|
||||
"success" counter is nonzero, the only exception is sub\_function 04h which does
|
||||
update the counters, but does not lock/unlock the disk.<br/>
|
||||
|
||||
|
||||
@ -1314,14 +1314,14 @@ That two bytes are 0Ch,08h after Read commands.<br/>
|
||||
changes to [1F1h] which may occur after read command (eg. may be 20h)
|
||||
```
|
||||
|
||||
#### 19h,76h,len_lo,len_hi,addr_lo,addr_hi --\> INT3(stat) ;Prepare SRAM Transfer
|
||||
#### 19h,76h,len\_lo,len\_hi,addr\_lo,addr\_hi --\> INT3(stat) ;Prepare SRAM Transfer
|
||||
Prepare Transfer to/from 32K SRAM.<br/>
|
||||
After INT3, data can be read (same way as sector data after INT1).<br/>
|
||||
|
||||
|
||||
|
||||
## CDROM - Test Commands - Read HC05 SUB-CPU RAM and I/O Ports
|
||||
#### 19h,60h,addr_lo,addr_hi --\> INT3(data) ;Read one byte from Drive RAM or I/O
|
||||
#### 19h,60h,addr\_lo,addr\_hi --\> INT3(data) ;Read one byte from Drive RAM or I/O
|
||||
Reads one byte from the controller's RAM or I/O area, see the memory map below
|
||||
for more info. Among others, the command allows to read Subchannel Q data, eg.
|
||||
at [200h..209h], including ADR=2/UPC/EAN and ADR=3/ISRC values (which are
|
||||
@ -1792,7 +1792,7 @@ error).<br/>
|
||||
Read (double speed) 0036cd2h 00322dfh..003ab2bh
|
||||
```
|
||||
The INT1 rate needs to be precise for CD-DA and CD-XA Audio streaming, exact
|
||||
clock cycle values should be: SystemClock*930h/4/44100Hz for Single Speed (and
|
||||
clock cycle values should be: SystemClock\*930h/4/44100Hz for Single Speed (and
|
||||
half as much for Double Speed) (the "Average" values are AVERAGE values, not
|
||||
exact values).<br/>
|
||||
|
||||
@ -2487,7 +2487,7 @@ Character Set values (for ID1=8Fh, ID2=00h, DATA[0]=charset):<br/>
|
||||
09h (or 0909h for 16bit charset) may be used to indicate the same as previous
|
||||
track. It shall not used for the first track."<br/>
|
||||
|
||||
#### adjust_crc_16_ccitt(addr_len) ;for CD-TEXT and Subchannel Q
|
||||
#### adjust\_crc\_16\_ccitt(addr\_len) ;for CD-TEXT and Subchannel Q
|
||||
```
|
||||
lsb=00h, msb=00h ;-initial value (zero for both CD-TEXT and Sub-Q)
|
||||
for i=0 to len-1 ;-len (10h for CD-TEXT, 0Ah for Sub-Q)
|
||||
@ -2541,7 +2541,7 @@ track. It shall not used for the first track."<br/>
|
||||
92Ch 4 EDC (checksum accross [010h..92Bh]) (or 00000000h if no EDC)
|
||||
```
|
||||
|
||||
#### encode_sector
|
||||
#### encode\_sector
|
||||
```
|
||||
sector[000h]=00h,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,00h
|
||||
sector[00ch]=bcd(adr/75/60) ;0..7x
|
||||
@ -2570,7 +2570,7 @@ track. It shall not used for the first track."<br/>
|
||||
adjust_edc(sector+10h,914h+8) ;edc is optional for form2
|
||||
```
|
||||
|
||||
#### calc_parity(sector,offs,len,j0,step1,step2)
|
||||
#### calc\_parity(sector,offs,len,j0,step1,step2)
|
||||
```
|
||||
src=00ch, dst=81ch+offs, srcmax=dst
|
||||
for i=0 to len-1
|
||||
@ -2583,10 +2583,10 @@ track. It shall not used for the first track."<br/>
|
||||
sector[dst+2*len+1]=y AND 0FFh, [dst+1]=y SHR 8
|
||||
dst=dst+2, src=base+step2
|
||||
```
|
||||
calc_p_parity(sector) = calc_parity(sector,0,43,19,2*43,2)<br/>
|
||||
calc_q_parity(sector) = calc_parity(sector,43*4,26,0,2*44,2*43)<br/>
|
||||
calc\_p\_parity(sector) = calc\_parity(sector,0,43,19,2\*43,2)<br/>
|
||||
calc\_q\_parity(sector) = calc\_parity(sector,43\*4,26,0,2\*44,2\*43)<br/>
|
||||
|
||||
#### adjust_edc(addr,len)
|
||||
#### adjust\_edc(addr,len)
|
||||
```
|
||||
x=00000000h
|
||||
for i=0 to len-1
|
||||
@ -2594,7 +2594,7 @@ calc_q_parity(sector) = calc_parity(sector,43*4,26,0,2*44,2*43)<br/>
|
||||
word[addr+len]=x ;append EDC value (little endian)
|
||||
```
|
||||
|
||||
#### init_tables
|
||||
#### init\_tables
|
||||
```
|
||||
for i=0 to FFh
|
||||
x=i, for j=0 to 7, x=x shr 1, if carry then x=x xor D8018001h
|
||||
@ -2700,7 +2700,7 @@ various ways to arrange multiple files or channels, for example,<br/>
|
||||
eight different files with one 1/8 audio channel each
|
||||
etc.
|
||||
```
|
||||
(*) If the Audio and Video data belongs together then both should use the SAME
|
||||
(\*) If the Audio and Video data belongs together then both should use the SAME
|
||||
channel.<br/>
|
||||
Note: Above interleave values are assuming that PSX Game Disks are always
|
||||
running at double speed (that's fastest for normal data files, and ADPCM files
|
||||
@ -2796,7 +2796,7 @@ or, for 8bit ADPCM format:<br/>
|
||||
24-31 Byte for 4th Block/Mono, or 2nd Block/Right (-80h..+7Fh)
|
||||
```
|
||||
|
||||
#### decode_sector(src)
|
||||
#### decode\_sector(src)
|
||||
```
|
||||
src=src+12+4+8 ;skip sync,header,subheader
|
||||
for i=0 to 11h
|
||||
@ -2814,7 +2814,7 @@ or, for 8bit ADPCM format:<br/>
|
||||
src=src+14h+4 ;skip padding,edc
|
||||
```
|
||||
|
||||
#### decode_28_nibbles(src,blk,nibble,dst,old,older)
|
||||
#### decode\_28\_nibbles(src,blk,nibble,dst,old,older)
|
||||
```
|
||||
shift = 12 - (src[4+blk*2+nibble] AND 0Fh)
|
||||
filter = (src[4+blk*2+nibble] AND 30h) SHR 4
|
||||
@ -2840,7 +2840,7 @@ supports five filters (0..4).<br/>
|
||||
The incoming old/older values are usually that from the previous part, or
|
||||
garbage (in case of decoding errors in the previous part), or whatever (in case
|
||||
there was no previous part) (ie. maybe zero on power-up?) (and maybe there's
|
||||
also a way to reset the values to zero at the begin of a new file, or *maybe*
|
||||
also a way to reset the values to zero at the begin of a new file, or \*maybe\*
|
||||
it's silently done automatically when issuing seek commands?).<br/>
|
||||
|
||||
#### 25-point Zigzag Interpolation
|
||||
@ -3110,8 +3110,8 @@ Playstation disks usually have only two Volume Descriptors,<br/>
|
||||
## CDROM ISO File and Directory Descriptors
|
||||
The location of the Root Directory is described by a 34-byte Directory Record
|
||||
being located in Primary Volume Descriptor entries 09Ch..0BDh. The data therein
|
||||
is: Block Number (usually 22 on PSX disks), LEN_FI=01h, Name=00h, and,
|
||||
LEN_SU=00h (due to the 34-byte limit).<br/>
|
||||
is: Block Number (usually 22 on PSX disks), LEN\_FI=01h, Name=00h, and,
|
||||
LEN\_SU=00h (due to the 34-byte limit).<br/>
|
||||
|
||||
#### Format of a Directory Record
|
||||
```
|
||||
@ -3129,8 +3129,8 @@ LEN_SU=00h (due to the 34-byte limit).<br/>
|
||||
xxh 0..1 Padding Field (00h) (only if LEN_FI is even)
|
||||
xxh LEN_SU System Use (LEN_SU bytes) (see below for CD-XA disks)
|
||||
```
|
||||
LEN_SU can be calculated as "LEN_DR-(33+LEN_FI+Padding)". For CD-XA disks (as
|
||||
used in the PSX), LEN_SU is 14 bytes:<br/>
|
||||
LEN\_SU can be calculated as "LEN\_DR-(33+LEN\_FI+Padding)". For CD-XA disks (as
|
||||
used in the PSX), LEN\_SU is 14 bytes:<br/>
|
||||
```
|
||||
00h 2 Owner ID Group (whatever, usually 0000h, big endian)
|
||||
02h 2 Owner ID User (whatever, usually 0000h, big endian)
|
||||
@ -3185,7 +3185,7 @@ size and location of the tables is stored in Volume Descriptor entries
|
||||
```
|
||||
The first entry (directory number 0001h) is the root directory, the root
|
||||
doesn't have a name, nor a parent (the name field contains a 00h byte, rather
|
||||
than ASCII text, LEN_DI is 01h, and parent is 0001h, making the root it's own
|
||||
than ASCII text, LEN\_DI is 01h, and parent is 0001h, making the root it's own
|
||||
parent; ignoring the fact that incest is forbidden in many countries).<br/>
|
||||
The next entries (directory number 0002h and up) (if any) are sub-directories
|
||||
within the root (sorted in alphabetical order, and all having parent=0001h).
|
||||
@ -3340,8 +3340,8 @@ AUTOEXEC.BAT files for MSDOS. A typical SYSTEM.CNF would look like so:<br/>
|
||||
STACK = 801FFF00 ;HEX (=memtop-256)
|
||||
```
|
||||
The first line specifies the executable to load, from the "cdrom:" drive, "\"
|
||||
root directory, filename "abcd_123.45" (case-insensitive, the real name in the
|
||||
disk directory would be uppercase, ie. "ABCD_123.45"), and, finally ";1" is the
|
||||
root directory, filename "abcd\_123.45" (case-insensitive, the real name in the
|
||||
disk directory would be uppercase, ie. "ABCD\_123.45"), and, finally ";1" is the
|
||||
file's version number (a rather strange ISO-filesystem specific feature) (the
|
||||
version number should be usually/always 1). Additionally, "arg" may contain an
|
||||
optional 128-byte command line argument string, which is copied to address
|
||||
@ -3350,17 +3350,17 @@ don't use that feature).<br/>
|
||||
Each line in the file should be terminated by 0Dh,0Ah characters... not sure if
|
||||
it's also working with only 0Dh, or only 0Ah...?<br/>
|
||||
|
||||
A note on the "ABCD_123.45" file:<br/>
|
||||
A note on the "ABCD\_123.45" file:<br/>
|
||||
This is a normal executable (exactly as for the .EXE files, described below),
|
||||
however, the filename/extension is taken from the game code (the "ABCD-12345"
|
||||
text that is printed on the CD cover), but, with the minus replaced by an
|
||||
underscore, and due to the 8-letter filename limit, the last two characters are
|
||||
stored in the extension region.<br/>
|
||||
That "XXXX_NNN.NN" naming convention seems to apply for all official licensed
|
||||
That "XXXX\_NNN.NN" naming convention seems to apply for all official licensed
|
||||
PSX games, not sure if it's possible to specify something like "FILENAME.EXE"
|
||||
as boot-file.<br/>
|
||||
|
||||
#### XXXX_NNN.NN (Boot-Executable) (filename specified in SYSTEM.CNF)
|
||||
#### XXXX\_NNN.NN (Boot-Executable) (filename specified in SYSTEM.CNF)
|
||||
#### FILENAME.EXE (General-Purpose Executable)
|
||||
PSX executables are having an 800h-byte header, followed by the code/data.<br/>
|
||||
```
|
||||
@ -3465,7 +3465,7 @@ color of the disks, and works also with normal silver disks.<br/>
|
||||
|
||||
#### Disk-Swap-Trick
|
||||
Once when the PSX has recognized a disk with the "SCEx" signal, it'll be
|
||||
satisfied until a new disk is inserted, which is sensed by the SHELL_OPEN
|
||||
satisfied until a new disk is inserted, which is sensed by the SHELL\_OPEN
|
||||
switch. When having that switch blocked, it is possible to insert a CDR without
|
||||
the PSX noticing that the disk was changed.<br/>
|
||||
Additionally, the trick requires some boot software that stops the drive motor
|
||||
@ -3598,7 +3598,7 @@ protection, ie. games that refuse to run if they detect a modchip. The
|
||||
detection relies on the fact that the SCEx signal is normally received only
|
||||
when booting the disk, whilst older modchips were sending that signal
|
||||
permanently. Stealth modchips are sending the signal only on power-up (and when
|
||||
inserting a new disk, which can be sensed via SHELL_OPEN signal).<br/>
|
||||
inserting a new disk, which can be sensed via SHELL\_OPEN signal).<br/>
|
||||
Modchip detection reportedly works like so (not too sure if all commands are
|
||||
required, some seem to be rather offtopic):<br/>
|
||||
```
|
||||
@ -3897,7 +3897,7 @@ usually TOC info for Track 1 and up.<br/>
|
||||
The .CCD file doesn't define the "PreGapSize" (the number of missing sectors at
|
||||
begin of first track). It seems to be simply constant " PreGapSize=150". Unless
|
||||
one is supposed to calculate it as
|
||||
"PreGapSize=((PMin*60+PSec)*75+PFrame)-PLBA".<br/>
|
||||
"PreGapSize=((PMin\*60+PSec)\*75+PFrame)-PLBA".<br/>
|
||||
The SectorSize seems to be also constant, "SectorSize=930h".<br/>
|
||||
|
||||
#### Non-BCD Caution
|
||||
@ -4274,7 +4274,7 @@ the tracks could use separate filename blocks; with different filenames).<br/>
|
||||
```
|
||||
00h 6 Filename, terminated by zero (usually "*.mdf",00h)
|
||||
```
|
||||
Contains the filename of the of the sector data (usually "*.mdf", indicating to
|
||||
Contains the filename of the of the sector data (usually "\*.mdf", indicating to
|
||||
use the same name as for the .mds file, but with .mdf extension).<br/>
|
||||
|
||||
#### Missing
|
||||
@ -4624,7 +4624,7 @@ checksums.<br/>
|
||||
M3S files are containing Subchannel Q data for all sectors on Minute=03 (the
|
||||
region where PSX libcrypt data is located) (there is no support for storing the
|
||||
(unused) libcrypt backup copy on Minute=09). The .M3S filesize is 72000 bytes
|
||||
(60 seconds * 75 sectors * 16 bytes). The 16 bytes per sector are:<br/>
|
||||
(60 seconds \* 75 sectors \* 16 bytes). The 16 bytes per sector are:<br/>
|
||||
```
|
||||
Q0..Q9 Subchannel Q data (normally position data)
|
||||
Q10..Q11 Subchannel Q checksum
|
||||
|
@ -48,7 +48,7 @@ Later version is CXD1817R (Servo/Signal/Decoder Combo).<br/>
|
||||
Even later PSX mainboards have it integrated in the Sound Chip: CXD2938Q
|
||||
(SPU+CDROM) with some changed bits and New SCEx transfer:<br/>
|
||||
[CDROM Internal Commands CX(0x..Ex) - CXD2938Q Servo/Signal/SPU Combo](cdrominternalinfoonpsxcdromcontroller.md#cdrom-internal-commands-cx0xex---cxd2938q-servosignalspu-combo)<br/>
|
||||
Finally, PM-41(2) boards are using a CXD2941R chip (SPU+CDROM+SPU_RAM), unknown
|
||||
Finally, PM-41(2) boards are using a CXD2941R chip (SPU+CDROM+SPU\_RAM), unknown
|
||||
if/how far the CDROM part of that chip differs from CXD2938Q.<br/>
|
||||
Some general notes:<br/>
|
||||
[CDROM Internal Commands CX(xx) - Notes](cdrominternalinfoonpsxcdromcontroller.md#cdrom-internal-commands-cxxx---notes)<br/>
|
||||
@ -1746,7 +1746,7 @@ XXX<br/>
|
||||
$EX OV64 OV64 -
|
||||
$7X-9X,DX,FX Z 0 -
|
||||
```
|
||||
*1 $38 outputs AGOK during AGT and AGF command settings, and XAVEBSY during
|
||||
\*1 $38 outputs AGOK during AGT and AGF command settings, and XAVEBSY during
|
||||
AVRG measurement.<br/>
|
||||
SSTP is output in all other cases.<br/>
|
||||
|
||||
@ -2030,7 +2030,7 @@ commands:<br/>
|
||||
- CX(Xxxxxx) CX(Xxxxxx) SerialSense, CX(Xxxx) with extra 8bit junk
|
||||
```
|
||||
Note: for vC2, some CX(38xxxx) values may differ depending on
|
||||
"set_mid_lsb_to_140Eh".<br/>
|
||||
"set\_mid\_lsb\_to\_140Eh".<br/>
|
||||
For vC2, CX(Dx) and CX(Ex) should be officially zero-padded to CX(Dx00) and
|
||||
CX(Ex00), but the vC2 BIOS doesn't do that, it still uses short 8bit form.<br/>
|
||||
For vC2, CX(Dx) and CX(Ex) should be apparently zero-padded to CX(Dx0000) and
|
||||
|
@ -87,7 +87,7 @@ InfoStatusFlags at [02Bh] describes certain characteristics of the disc:<br/>
|
||||
Note: Bit5/6 are used only if the next disc has the same Album ID (eg. the
|
||||
feature allows to skip copyright messages if the same message was already shown
|
||||
on another disc).<br/>
|
||||
First_segment_addr: The location of the first sector of the Segment Play Item
|
||||
First\_segment\_addr: The location of the first sector of the Segment Play Item
|
||||
Area [that is... the first ITEMnnnn.DAT file?], in the form mm:ss:00. Must be
|
||||
00:00:00 if PSD size is zero. If PSD size is nonzero, but no segments used:
|
||||
Usually set to 00:02:00.<br/>
|
||||
@ -106,7 +106,7 @@ Version;<br/>
|
||||
0x02 --- VCD2.0
|
||||
0x01 --- SVCD, should be same as version in INFO.SVD
|
||||
```
|
||||
Sys_prof_tag;<br/>
|
||||
Sys\_prof\_tag;<br/>
|
||||
```
|
||||
0x01 if VCD1.1
|
||||
0x00 else
|
||||
@ -239,14 +239,14 @@ one picture frame, or eventually with a few frames for short animations,
|
||||
including audio in some cases). Still images are said to be allowed to use
|
||||
twice the resolution of MPEG videos.<br/>
|
||||
|
||||
#### EXT\PSD_X.VCD or EXT\PSD_X.SVD (extended version of PSD.VCD)
|
||||
#### EXT\LOT_X.VCD or EXT\LOT_X.SVD (extended version of LOT.VCD)
|
||||
#### EXT\PSD\_X.VCD or EXT\PSD\_X.SVD (extended version of PSD.VCD)
|
||||
#### EXT\LOT\_X.VCD or EXT\LOT\_X.SVD (extended version of LOT.VCD)
|
||||
The "extended" files are often identical to the normal PSD/LOT files. The
|
||||
difference is that, if disc uses SelectionLists, then PSD should use the normal
|
||||
descriptor (18h), and PSD_X should use the extended descriptor (1Ah), the
|
||||
descriptor (18h), and PSD\_X should use the extended descriptor (1Ah), the
|
||||
latter one seems to be intended to allow to highlight the current menu
|
||||
selection (particulary useful when using +/- buttons instead of Numeric Keypad
|
||||
input). Note: Nethertheless, Muppets from Space uses descriptor 18h in PSD_X.<br/>
|
||||
input). Note: Nethertheless, Muppets from Space uses descriptor 18h in PSD\_X.<br/>
|
||||
Unknown if SVCDs do really have "extended" files, too (theoretically the VCD
|
||||
extension should be a default feature for SVCDs).<br/>
|
||||
|
||||
@ -254,7 +254,7 @@ extension should be a default feature for SVCDs).<br/>
|
||||
Although PBC was intended as "nice extra feature", many VCDs are containing
|
||||
faulty PSD files. In general, VCD players should either leave PBC unsupported
|
||||
(or provide an option for disabling it).<br/>
|
||||
Red Dragon from 2003 uses extended selection lists, but crops PSD_X.VCD to the
|
||||
Red Dragon from 2003 uses extended selection lists, but crops PSD\_X.VCD to the
|
||||
same filesize as PSD.VCD.<br/>
|
||||
Muppets from Space from 1999 assigns weird functions to Prev/Next buttons (Next
|
||||
wraps from Last Track to First Track, but Prev doesn't wrap from First to Last;
|
||||
@ -285,7 +285,7 @@ If that's correct, then the files would overlap with PSD.SVD (when PSD.SVD is
|
||||
bigger than one sector), that would be weird, but possible (ie. the "PsdOffset"
|
||||
in PSD.SVD would need to "skip" the region used by those two files).<br/>
|
||||
|
||||
#### EXT\SCANDATA.DAT (12+3*N bytes for VCD 2.0) (or 16+3*N+2*X+3*Y+3*Z for SVCD)
|
||||
#### EXT\SCANDATA.DAT (12+3\*N bytes for VCD 2.0) (or 16+3\*N+2\*X+3\*Y+3\*Z for SVCD)
|
||||
This file fulfills much the same purpose of the SEARCH.DAT file except that
|
||||
this file is mandatory only if the System Profile Tag of the INFO.SVD file is
|
||||
0x01 (HQ-VCD) and also that it contains sector addresses also for each video
|
||||
@ -316,7 +316,7 @@ Segment Play Items in addition to the regular MPEG tracks.<br/>
|
||||
xxxh 3*Z msf_t scandata_table[Z] ;MM:SS:FF
|
||||
```
|
||||
|
||||
#### SVCD\SEARCH.DAT (13+3*N bytes)
|
||||
#### SVCD\SEARCH.DAT (13+3\*N bytes)
|
||||
This file defines where the scan points are. It covers all mpeg tracks
|
||||
together. A scan point at time T is the nearest I-picture in the MPEG stream to
|
||||
the given time T. Scan points are given at every half-second for the entire
|
||||
@ -333,7 +333,7 @@ Note: This SVCD file is about same as the old EXT\SCANDATA.DAT file on VCDs
|
||||
(with one extra entry for Time Interval). Whilst, SVCDs are storing some
|
||||
different stuff in EXT\SCANDATA.DAT (despite of the identical filename).<br/>
|
||||
|
||||
#### SVCD\TRACKS.SVD (11+4*N bytes) (or rarely:11+5*N bytes)
|
||||
#### SVCD\TRACKS.SVD (11+4\*N bytes) (or rarely:11+5\*N bytes)
|
||||
The TRACKS.SVD file contains a series of structures, one for each track, which
|
||||
indicates the track's playing time (in sectors, not actually real time) and
|
||||
contents.<br/>
|
||||
@ -409,8 +409,8 @@ the picture frames (ie. in the MPEG macroblocks, rather than using the Closed
|
||||
Caption feature).<br/>
|
||||
These CAPTnn.DAT files are intended for Closed Captions (eg. subtitles in
|
||||
different languages and/or for deaf people).<br/>
|
||||
Alternately, the "user_data_cc" flag in INFO.VCD?/INFO.SVD can indicate to
|
||||
store Closed Captions in MPEG User Data (with START_CODE=000001B2h=User Data)
|
||||
Alternately, the "user\_data\_cc" flag in INFO.VCD?/INFO.SVD can indicate to
|
||||
store Closed Captions in MPEG User Data (with START\_CODE=000001B2h=User Data)
|
||||
instead of in EXT\CAPTnn.DAT. Either way, the format of those Closed Captions
|
||||
is unknown.<br/>
|
||||
Moreover, Content can be flagged to have Overlay Graphics/Text (OGT), whatever
|
||||
@ -434,17 +434,17 @@ of that files is unknown.<br/>
|
||||
Reportedly there are Midi VCDs (MVCDs) for karaoke, maybe those discs have
|
||||
"KARINFO.xxx" files(?)<br/>
|
||||
|
||||
#### PICTURES\*.* (whatever)
|
||||
#### PICTURES\\*.\* (whatever)
|
||||
Unknown purpose. The PICTURES folder has been spotted on one VCD (Wallace and
|
||||
Gromit), but the folder was just empty.<br/>
|
||||
|
||||
#### CDI\*.* (some kind of GUI/driver for Philips CDI Players)
|
||||
#### CDI\\*.\* (some kind of GUI/driver for Philips CDI Players)
|
||||
The CDI folder is some relict for Philips CDI Players, it isn't used by normal
|
||||
VCD players, however, the CDI folder & files are included on most or all
|
||||
VCDs.<br/>
|
||||
The path/name for the CDI executable is stored at offset 23Eh in the ISO
|
||||
Primary Volume Descriptor (usually "CDI/CDI_APPL.VCD;1" or "CDI/CDI_VCD.APP;1")
|
||||
(or accidentally "CDI_CDI_VCD.APP;1" on homebrew Nero discs).<br/>
|
||||
Primary Volume Descriptor (usually "CDI/CDI\_APPL.VCD;1" or "CDI/CDI\_VCD.APP;1")
|
||||
(or accidentally "CDI\_CDI\_VCD.APP;1" on homebrew Nero discs).<br/>
|
||||
The files in the CDI folder are usually just some standard files (without any
|
||||
customizations), however, there are some different revisions of these files:<br/>
|
||||
```
|
||||
@ -463,20 +463,20 @@ customizations), however, there are some different revisions of these files:<br/
|
||||
CDI_TEXT.FNT 13616 bytes, 00-Nul-0000 CRC32=BDC55E86h ;font?
|
||||
CDI_IMAG.RTF 1510028 bytes, 00-Nul-0000 CRC32=(RIFF) ;realtimefile?
|
||||
```
|
||||
CDI_VCD.CFG is some ASCII text file (with uncommon 0Dh,0Dh,0Ah line breaks),
|
||||
CDI\_VCD.CFG is some ASCII text file (with uncommon 0Dh,0Dh,0Ah line breaks),
|
||||
the file could be customized to change things like GUI colors, but most or all
|
||||
discs seem to contain the same file with CRC32=D1C6F7ADh. Note: The CFG file is
|
||||
missing on the homebrew DemoVCD.<br/>
|
||||
CDI_IMAG.RTF is seen as 1510028 byte file under windows (that is, with a
|
||||
CDI\_IMAG.RTF is seen as 1510028 byte file under windows (that is, with a
|
||||
windows RIFF header, and with data area containing the whole 930h bytes from
|
||||
each sector; this includes the MM:SS:FF values from the sector header, so the
|
||||
RTF file may look slightly different depending on which sectors it has been
|
||||
stored on, although the files are usually exactly same apart from those
|
||||
MM:SS:FF values). Note: The RTF file is cropped to 1324220 bytes (instead of
|
||||
1510028) on the homebrew DemoVCD (apart from that, the file is same as normal).<br/>
|
||||
CDI_ALL.RTF and CDI_BUM.RTF cannot be read/copied under Windows 7 (which is
|
||||
CDI\_ALL.RTF and CDI\_BUM.RTF cannot be read/copied under Windows 7 (which is
|
||||
weirdly reporting them to use an "invalid MS-DOS function"; some people also
|
||||
reported having CDI_IMAG.RTF files with similar problems). The reason is
|
||||
reported having CDI\_IMAG.RTF files with similar problems). The reason is
|
||||
unknown, maybe windows doesn't fully support the CD filesystem, or some VCDs
|
||||
are violating the filesystem specs, or whatever... maybe windows is
|
||||
mis-identifying certain RTF files as Rich Text Format files and tries to
|
||||
@ -521,7 +521,7 @@ determine the position/bitrate, so the Pack is kinda useless).<br/>
|
||||
1bit Marker (1) ;/
|
||||
```
|
||||
|
||||
#### MPEG-1 Multiplex System Header (12+N*3 bytes)(optionally)(at start of stream)
|
||||
#### MPEG-1 Multiplex System Header (12+N\*3 bytes)(optionally)(at start of stream)
|
||||
The System Header is usally found after the first Pack at the begin of the
|
||||
stream.<br/>
|
||||
```
|
||||
@ -539,7 +539,7 @@ stream.<br/>
|
||||
5bit Video Bound (max number of video streams in this ISO stream) ;/
|
||||
8bit Reserved (FFh) ;-1byte
|
||||
```
|
||||
Followed by N*3 bytes for the streams (each with first bit=set):<br/>
|
||||
Followed by N\*3 bytes for the streams (each with first bit=set):<br/>
|
||||
```
|
||||
8bit Stream ID (C0h..DFh=Audio, E0h..EFh=Video) ;\
|
||||
2bit Fixed (11b) ; 3byte
|
||||
@ -626,7 +626,7 @@ packets preceeded (and interrupted) by Multiplex headers. Ie. before processing
|
||||
the Video packets, one must first extract the video snippets from the Multiplex
|
||||
stream (see previous chapter).<br/>
|
||||
|
||||
#### MPEG-1 Video Sequence Header (12, 76, or 140 bytes, ie. 12+N*64)
|
||||
#### MPEG-1 Video Sequence Header (12, 76, or 140 bytes, ie. 12+N\*64)
|
||||
```
|
||||
32bit SEQUENCE_HEADER_CODE (000001B3h) ;-4byte
|
||||
12bit Width in pixels (1..4095) ;\3byte
|
||||
@ -899,7 +899,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
|
||||
|
||||
## Inflate - Core Functions
|
||||
#### tinf_uncompress(dst,src)
|
||||
#### tinf\_uncompress(dst,src)
|
||||
```
|
||||
tinf_init() ;init constants (needed to be done only once)
|
||||
tinf_align_src_to_byte_boundary()
|
||||
@ -915,7 +915,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
ret
|
||||
```
|
||||
|
||||
#### tinf_inflate_uncompressed_block()
|
||||
#### tinf\_inflate\_uncompressed\_block()
|
||||
```
|
||||
tinf_align_src_to_byte_boundary()
|
||||
len=LittleEndian16bit[src+0] ;get len
|
||||
@ -925,7 +925,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
ret
|
||||
```
|
||||
|
||||
#### tinf_inflate_compressed_block()
|
||||
#### tinf\_inflate\_compressed\_block()
|
||||
```
|
||||
repeat
|
||||
sym1=tinf_decode_symbol(tinf_len_tree)
|
||||
@ -940,7 +940,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
ret
|
||||
```
|
||||
|
||||
#### tinf_decode_symbol(tree)
|
||||
#### tinf\_decode\_symbol(tree)
|
||||
```
|
||||
sum=0, cur=0, len=0
|
||||
repeat ;get more bits while code value is above sum
|
||||
@ -952,21 +952,21 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
return tree.trans[sum+cur]
|
||||
```
|
||||
|
||||
#### tinf_read_bits(num) ;get N bits from source stream
|
||||
#### tinf\_read\_bits(num) ;get N bits from source stream
|
||||
```
|
||||
val=0
|
||||
for i=0 to num-1, val=val+(tinf_getbit() shl i), next i
|
||||
return val
|
||||
```
|
||||
|
||||
#### tinf_getbit() ;get one bit from source stream
|
||||
#### tinf\_getbit() ;get one bit from source stream
|
||||
```
|
||||
bit=tag AND 01h, tag=tag/2
|
||||
if tag=00h then tag=[src], src=src+1, bit=tag AND 01h, tag=tag/2+80h
|
||||
return bit
|
||||
```
|
||||
|
||||
#### tinf_align_src_to_byte_boundary()
|
||||
#### tinf\_align\_src\_to\_byte\_boundary()
|
||||
```
|
||||
tag=01h ;empty/end-bit (discard any bits, align src to byte-boundary)
|
||||
ret
|
||||
@ -975,7 +975,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
|
||||
|
||||
## Inflate - Initialization & Tree Creation
|
||||
#### tinf_init()
|
||||
#### tinf\_init()
|
||||
```
|
||||
tinf_build_bits_base(length_bits, length_base, 4, 3)
|
||||
length_bits[28]=0, length_base[28]=258
|
||||
@ -983,7 +983,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
ret
|
||||
```
|
||||
|
||||
#### tinf_build_bits_base(bits,base,delta,base_val)
|
||||
#### tinf\_build\_bits\_base(bits,base,delta,base\_val)
|
||||
```
|
||||
for i=0 to 29
|
||||
bits[i]=min(0,i-delta)/delta
|
||||
@ -992,7 +992,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
ret
|
||||
```
|
||||
|
||||
#### tinf_build_fixed_trees()
|
||||
#### tinf\_build\_fixed\_trees()
|
||||
```
|
||||
for i=0 to 6, tinf_len_tree.table[i]=0, next i ;[0..6]=0 ;len tree...
|
||||
tinf_len_tree.table[7,8,9]=24,152,112 ;[7..9]=24,152,112
|
||||
@ -1006,7 +1006,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
ret
|
||||
```
|
||||
|
||||
#### tinf_decode_dynamic_trees()
|
||||
#### tinf\_decode\_dynamic\_trees()
|
||||
```
|
||||
hlit = tinf_read_bits(5)+257 ;get 5 bits HLIT (257-286)
|
||||
hdist = tinf_read_bits(5)+1 ;get 5 bits HDIST (1-32)
|
||||
@ -1027,7 +1027,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
ret
|
||||
```
|
||||
|
||||
#### tinf_build_tree(tree, first, num)
|
||||
#### tinf\_build\_tree(tree, first, num)
|
||||
```
|
||||
for i=0 to 15, tree.table[i]=0, next i ;clear code length count table
|
||||
;scan symbol lengths, and sum code length counts...
|
||||
@ -1041,7 +1041,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
ret
|
||||
```
|
||||
|
||||
#### tinf_data
|
||||
#### tinf\_data
|
||||
```
|
||||
clcidx[0..18] = 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 ;constants
|
||||
```
|
||||
@ -1070,7 +1070,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
|
||||
|
||||
## Inflate - Headers and Checksums
|
||||
#### tinf_gzip_uncompress(void *dest, *destLen, *source, sourceLen)
|
||||
#### tinf\_gzip\_uncompress(void \*dest, \*destLen, \*source, sourceLen)
|
||||
```
|
||||
src_start=src, dst_start=dst ;memorize start addresses
|
||||
if (src[0]<>1fh or src[1]<>8Bh) then ERROR ;check id bytes
|
||||
@ -1092,7 +1092,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
ret
|
||||
```
|
||||
|
||||
#### tinf_zlib_uncompress(dst, destLen, src, sourceLen)
|
||||
#### tinf\_zlib\_uncompress(dst, destLen, src, sourceLen)
|
||||
```
|
||||
src_start=src, dst_start=dst ;memorize start addresses
|
||||
hdr=BigEndian16bit[src], src=src+2 ;get header
|
||||
@ -1108,7 +1108,7 @@ used by the .CDZ cdrom-image format.<br/>
|
||||
ret
|
||||
```
|
||||
|
||||
#### tinf_adler32(src, length)
|
||||
#### tinf\_adler32(src, length)
|
||||
```
|
||||
s1=1, s2=0
|
||||
while (length>0)
|
||||
|
@ -27,7 +27,7 @@ DB25 connector can be directly connected to a PC parallel port.<br/>
|
||||
[Cheat Devices - FLASH/EEPROMs](cheatdevices.md#cheat-devices---flasheeproms)<br/>
|
||||
|
||||
http://gamehacking.org/faqs/hackv500c.html - cheat code formats<br/>
|
||||
http://doc.kodewerx.org/hacking_psx.html - cheat code formats<br/>
|
||||
http://doc.kodewerx.org/hacking\_psx.html - cheat code formats<br/>
|
||||
http://xianaix.net/museum.htm - around 64 bios versions<br/>
|
||||
http://www.murraymoffatt.com/playstation-xplorer.html - xplorer bioses<br/>
|
||||
|
||||
@ -624,7 +624,7 @@ The filedata is split into fragments, Len should be max 2000h per fragment.<br/>
|
||||
```
|
||||
Memcard ReadFile does transfer N fragments of Len=2000h (depending on
|
||||
filesize). The GetWhatever function transfers one fragment with Len=80h,
|
||||
followed by N*6 fragments with Len=40Ah.<br/>
|
||||
followed by N\*6 fragments with Len=40Ah.<br/>
|
||||
|
||||
#### RxTurbo for Memcard (bu) GetDirectory/GetFileHeader functions
|
||||
```
|
||||
@ -857,7 +857,7 @@ on/off" flag (bit3: 0=on, 1=off; whatever that means, it does probably require
|
||||
WHATEVER actions to enable codes that are "off"; maybe via the Ftaaaaaa dddd
|
||||
code).<br/>
|
||||
|
||||
#### break_type (cccc) (aka MSBs of cop0r7 DCIC register)
|
||||
#### break\_type (cccc) (aka MSBs of cop0r7 DCIC register)
|
||||
```
|
||||
E180 (instruction gotton by CPU but not yet implemented) (uh, gotton what?)
|
||||
EE80 (data to be read or written) ;<--looks okay
|
||||
@ -868,7 +868,7 @@ code).<br/>
|
||||
The CPU supports one data breakpoint and one instruction breakpoint (though
|
||||
unknown if the Xplorer does support to use both simultaneously, or if it does
|
||||
allow only one of them to be used).<br/>
|
||||
If the break_type/address/mask to match up with CPU's memory access actions...
|
||||
If the break\_type/address/mask to match up with CPU's memory access actions...
|
||||
then "something" does probably happen (maybe executing a sub-function that
|
||||
consists of the d0,d1,d2,etc-bytes, if so, maybe at a fixed/unknown memory
|
||||
address, or maybe at some random address; which would require relocatable
|
||||
@ -881,7 +881,7 @@ The "Slide" code shall be used only with even addresses, unknown if other
|
||||
|
||||
|
||||
## Cheat Devices - Xplorer Cheat Code and ROM-Image Decryption
|
||||
#### decrypt_xplorer_cheat_code:
|
||||
#### decrypt\_xplorer\_cheat\_code:
|
||||
```
|
||||
key = x[0] and 07h ;'''''''' AABBCCDD EEFF '''''''';
|
||||
x[0] = x[0] xor key ; / / / \ \ \ ;
|
||||
@ -916,7 +916,7 @@ The "Slide" code shall be used only with even addresses, unknown if other
|
||||
endif
|
||||
```
|
||||
|
||||
#### decrypt_xplorer_fcd_rom_image:
|
||||
#### decrypt\_xplorer\_fcd\_rom\_image:
|
||||
```
|
||||
for i=0 to romsize-1
|
||||
x=45h
|
||||
|
@ -33,33 +33,33 @@
|
||||
|
||||
|
||||
## Controller and Memory Card I/O Ports
|
||||
#### 1F801040h JOY_TX_DATA (W)
|
||||
#### 1F801040h JOY\_TX\_DATA (W)
|
||||
```
|
||||
0-7 Data to be sent
|
||||
8-31 Not used
|
||||
```
|
||||
Writing to this register starts the transfer (if, or as soon as TXEN=1 and
|
||||
JOY_STAT.2=Ready), the written value is sent to the controller or memory card,
|
||||
and, simultaneously, a byte is received (and stored in RX FIFO if JOY_CTRL.1 or
|
||||
JOY_CTRL.2 is set).<br/>
|
||||
The "TXEN=1" condition is a bit more complex: Writing to SIO_TX_DATA latches
|
||||
JOY\_STAT.2=Ready), the written value is sent to the controller or memory card,
|
||||
and, simultaneously, a byte is received (and stored in RX FIFO if JOY\_CTRL.1 or
|
||||
JOY\_CTRL.2 is set).<br/>
|
||||
The "TXEN=1" condition is a bit more complex: Writing to SIO\_TX\_DATA latches
|
||||
the current TXEN value, and the transfer DOES start if the current TXEN value
|
||||
OR the latched TXEN value is set (ie. if TXEN gets cleared after writing to
|
||||
SIO_TX_DATA, then the transfer may STILL start if the old latched TXEN value
|
||||
SIO\_TX\_DATA, then the transfer may STILL start if the old latched TXEN value
|
||||
was set).<br/>
|
||||
|
||||
#### 1F801040h JOY_RX_DATA (R)
|
||||
#### 1F801040h JOY\_RX\_DATA (R)
|
||||
```
|
||||
0-7 Received Data (1st RX FIFO entry) (oldest entry)
|
||||
8-15 Preview (2nd RX FIFO entry)
|
||||
16-23 Preview (3rd RX FIFO entry)
|
||||
24-31 Preview (4th RX FIFO entry) (5th..8th cannot be previewed)
|
||||
```
|
||||
A data byte can be read when JOY_STAT.1=1. Data should be read only via 8bit
|
||||
A data byte can be read when JOY\_STAT.1=1. Data should be read only via 8bit
|
||||
memory access (the 16bit/32bit "preview" feature is rather unusable, and
|
||||
usually there shouldn't be more than 1 byte in the FIFO anyways).<br/>
|
||||
|
||||
#### 1F801044h JOY_STAT (R)
|
||||
#### 1F801044h JOY\_STAT (R)
|
||||
```
|
||||
0 TX Ready Flag 1 (1=Ready/Started)
|
||||
1 RX FIFO Not Empty (0=Empty, 1=Not Empty)
|
||||
@ -75,7 +75,7 @@ usually there shouldn't be more than 1 byte in the FIFO anyways).<br/>
|
||||
11-31 Baudrate Timer (21bit timer, decrementing at 33MHz)
|
||||
```
|
||||
|
||||
#### 1F801048h JOY_MODE (R/W) (usually 000Dh, ie. 8bit, no parity, MUL1)
|
||||
#### 1F801048h JOY\_MODE (R/W) (usually 000Dh, ie. 8bit, no parity, MUL1)
|
||||
```
|
||||
0-1 Baudrate Reload Factor (1=MUL1, 2=MUL16, 3=MUL64) (or 0=MUL1, too)
|
||||
2-3 Character Length (0=5bits, 1=6bits, 2=7bits, 3=8bits)
|
||||
@ -86,7 +86,7 @@ usually there shouldn't be more than 1 byte in the FIFO anyways).<br/>
|
||||
9-15 Unknown (always zero)
|
||||
```
|
||||
|
||||
#### 1F80104Ah JOY_CTRL (R/W) (usually 1003h,3003h,0000h)
|
||||
#### 1F80104Ah JOY\_CTRL (R/W) (usually 1003h,3003h,0000h)
|
||||
```
|
||||
0 TX Enable (TXEN) (0=Disable, 1=Enable)
|
||||
1 /JOYn Output (0=High, 1=Low/Select) (/JOYn as defined in Bit13)
|
||||
@ -109,7 +109,7 @@ Dualshock and Mouse require at least some small delay, and older Analog Joypads
|
||||
require a huge delay (around 500 clock cycles for SCPH-1150), official kernel
|
||||
waits more than 2000 cycles (which is much more than needed).<br/>
|
||||
|
||||
#### 1F80104Eh JOY_BAUD (R/W) (usually 0088h, ie. circa 250kHz, when Factor=MUL1)
|
||||
#### 1F80104Eh JOY\_BAUD (R/W) (usually 0088h, ie. circa 250kHz, when Factor=MUL1)
|
||||
```
|
||||
0-15 Baudrate Reload value for decrementing Baudrate Timer
|
||||
```
|
||||
@ -136,16 +136,16 @@ an /ACK, or if there's no peripheral connected at all).<br/>
|
||||
Actually, /IRQ7 means "more-data-request",
|
||||
accordingly, it does NOT get triggered after receiving the LAST byte.
|
||||
```
|
||||
I_STAT.7 is edge triggered (that means it can be acknowledge before or after
|
||||
acknowledging JOY_STAT.9). However, JOY_STAT.9 is NOT edge triggered (that
|
||||
I\_STAT.7 is edge triggered (that means it can be acknowledge before or after
|
||||
acknowledging JOY\_STAT.9). However, JOY\_STAT.9 is NOT edge triggered (that
|
||||
means it CANNOT be acknowledged while the external /IRQ input is still low; ie.
|
||||
one must first wait until JOY_STAT.7=0, and then set JOY_CTRL.4=1) (this is
|
||||
one must first wait until JOY\_STAT.7=0, and then set JOY\_CTRL.4=1) (this is
|
||||
apparently a hardware glitch; note: the LOW duration is circa 100 clock
|
||||
cycles).<br/>
|
||||
|
||||
#### /IRQ10 (/IRQ) Controller - Lightpen Interrupt
|
||||
Pin8 on Controller Port. Routed directly to the Interrupt Controller (at
|
||||
1F80107xh). There are no status/enable bits in the JOY_registers (at
|
||||
1F80107xh). There are no status/enable bits in the JOY\_registers (at
|
||||
1F80104xh).<br/>
|
||||
|
||||
#### RX FIFO / TX FIFO Notes
|
||||
@ -191,7 +191,7 @@ Controllers can be probably accessed via InitPad and StartPad functions,<br/>
|
||||
[BIOS Joypad Functions](kernelbios.md#bios-joypad-functions)<br/>
|
||||
Memory cards can be accessed by the filesystem (with device names "bu00:"
|
||||
(slot1) and "bu10:" (slot2) or so). Before using that device names, it seems to
|
||||
be required to call InitCard, StartCard, and _bu_init (?).<br/>
|
||||
be required to call InitCard, StartCard, and \_bu\_init (?).<br/>
|
||||
|
||||
#### Connectors
|
||||
The PlayStation has four connectors (two controllers, two memory cards),<br/>
|
||||
@ -261,15 +261,15 @@ usually 00h) to receive the response bytes.<br/>
|
||||
|
||||
X = none, - = Hi-Z<br/>
|
||||
|
||||
* 0x81 is memory-card, 0x01 is standard-pad at top command.<br/>
|
||||
* serial data transfer is LSB-First format.<br/>
|
||||
* data is down edged output, PSX is read at up edge in shift clock.<br/>
|
||||
* PSX expects No-connection if not returned Acknowledge less than 100 usec.<br/>
|
||||
* clock pulse is 250KHz.<br/>
|
||||
* no need Acknowledge at last data.<br/>
|
||||
* Acknowledge signal width is more than 2 usec.<br/>
|
||||
* time is 16msec between SEL from previous SEL.<br/>
|
||||
* SEL- for memory card in PAD access.<br/>
|
||||
\* 0x81 is memory-card, 0x01 is standard-pad at top command.<br/>
|
||||
\* serial data transfer is LSB-First format.<br/>
|
||||
\* data is down edged output, PSX is read at up edge in shift clock.<br/>
|
||||
\* PSX expects No-connection if not returned Acknowledge less than 100 usec.<br/>
|
||||
\* clock pulse is 250KHz.<br/>
|
||||
\* no need Acknowledge at last data.<br/>
|
||||
\* Acknowledge signal width is more than 2 usec.<br/>
|
||||
\* time is 16msec between SEL from previous SEL.<br/>
|
||||
\* SEL- for memory card in PAD access.<br/>
|
||||
|
||||
|
||||
|
||||
@ -1065,7 +1065,7 @@ screen; ie. on the game's GP1(06h) and GP1(07h) settings.<br/>
|
||||
Vertical coordinates are counted in scanlines (ie. equal to pixels). Horizontal
|
||||
coordinates are counted in 8MHz units (which would equal a resolution of 385
|
||||
pixels; which can be, for example, converted to 320 pixel resolution as
|
||||
X=X*320/385).<br/>
|
||||
X=X\*320/385).<br/>
|
||||
|
||||
#### Misinformation (from bugged homebrew source code)
|
||||
```
|
||||
@ -1184,7 +1184,7 @@ different if IRQs are disabled (eg. while another IRQ is processed).<br/>
|
||||
However, IRQ10 does also get triggered in the next some scanlines, so the first
|
||||
IRQ10 is used only as a notification that the CPU should watch out for further
|
||||
IRQ10's. Ie. the IRQ10 handler should disable all DMAs, acknowledge IRQ10, and
|
||||
then enter a waitloop that waits for the IRQ10 bit in I_STAT to become set
|
||||
then enter a waitloop that waits for the IRQ10 bit in I\_STAT to become set
|
||||
again (or abort if a timeout occurs) and then read the timers, reportedly like
|
||||
so:<br/>
|
||||
```
|
||||
@ -1824,7 +1824,7 @@ port).<br/>
|
||||
|
||||
#### TTY Debug Terminal
|
||||
If present, the external DUART can be used for external keyboard input, at the
|
||||
BIOS side, this is supported as "std_in".<br/>
|
||||
BIOS side, this is supported as "std\_in".<br/>
|
||||
|
||||
|
||||
|
||||
@ -2056,7 +2056,7 @@ Sony), followed by up to 8 characters,<br/>
|
||||
```
|
||||
(which may identify the file if the game uses multiple files; this part often
|
||||
contains a random string which seems to be allowed to contain any chars in
|
||||
range of 20h..7Fh, of course it shouldn't contain "?" and "*" wildcards).<br/>
|
||||
range of 20h..7Fh, of course it shouldn't contain "?" and "\*" wildcards).<br/>
|
||||
|
||||
#### Broken Sector List (Block 0, Frame 16..35)
|
||||
```
|
||||
|
@ -6,7 +6,7 @@ function trim(s) { return rtrim(ltrim(s)); }
|
||||
# Escape slashes and amps in a string for building links
|
||||
function linkescape(s) {
|
||||
gsub(/\//, "\\/", s);
|
||||
gsub(/\&/, "\\\\&", s);
|
||||
gsub(/&/, "\\\\&", s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -68,6 +68,9 @@ WAIT_FOR_START { next; }
|
||||
# outside of <PRE> blocks, we want to escape these for the md format.
|
||||
gsub(/</, "\\<");
|
||||
gsub(/>/, "\\>");
|
||||
gsub(/*/, "\\*");
|
||||
gsub(/_/, "\\_");
|
||||
gsub(/~/, "\\~");
|
||||
}
|
||||
gsub(/&/, "\\&");
|
||||
|
||||
|
@ -52,7 +52,7 @@ for most CPUs) - Full means that SP points to the first ALLOCATED word on the
|
||||
stack, so the allocated memory is at SP+0 and above, free memory at SP-1 and
|
||||
below, Wasted means that when calling a sub-function with N parameters, then
|
||||
the caller must pre-allocate N works on stack, and the sub-function may freely
|
||||
use and destroy these words; at [SP+0..N*4-1].<br/>
|
||||
use and destroy these words; at [SP+0..N\*4-1].<br/>
|
||||
|
||||
For example, "push ra,r16,r17" would be implemented as:<br/>
|
||||
```
|
||||
@ -294,7 +294,7 @@ The mul/div opcodes are starting the multiply/divide operation, starting takes
|
||||
only a single clock cycle, however, trying to read the result from the hi/lo
|
||||
registers while the mul/div operation is busy will halt the CPU until the
|
||||
mul/div has completed. For multiply, the execution time depends on rs (ie.
|
||||
"small*large" can be much faster than "large*small").<br/>
|
||||
"small\*large" can be much faster than "large\*small").<br/>
|
||||
```
|
||||
__umul_execution_time_____________________________________________________
|
||||
Fast (6 cycles) rs = 00000000h..000007FFh
|
||||
|
@ -15,7 +15,7 @@ These ports control DMA at the CPU-side. In most cases, you'll additionally
|
||||
need to initialize an address (and transfer direction, transfer enabled, etc.)
|
||||
at the remote-side (eg. at the GPU-side for DMA2).<br/>
|
||||
|
||||
#### 1F801080h+N*10h - D#_MADR - DMA base address (Channel 0..6) (R/W)
|
||||
#### 1F801080h+N\*10h - D#\_MADR - DMA base address (Channel 0..6) (R/W)
|
||||
```
|
||||
0-23 Memory Address where the DMA will start reading from/writing to
|
||||
24-31 Not used (always zero)
|
||||
@ -30,7 +30,7 @@ hold the end-address in SyncMode=1, or the 00FFFFFFh end-code in SyncMode=2)<br/
|
||||
Note: Address bit0-1 are writeable, but any updated current/end addresses are
|
||||
word-aligned with bit0-1 forced to zero.<br/>
|
||||
|
||||
#### 1F801084h+N*10h - D#_BCR - DMA Block Control (Channel 0..6) (R/W)
|
||||
#### 1F801084h+N\*10h - D#\_BCR - DMA Block Control (Channel 0..6) (R/W)
|
||||
For SyncMode=0 (ie. for OTC and CDROM):<br/>
|
||||
```
|
||||
0-15 BC Number of words (0001h..FFFFh) (or 0=10000h words)
|
||||
@ -50,10 +50,10 @@ set the blocksize larger than the buffer of the corresponding unit can hold.
|
||||
(GPU and SPU both have a 16-word buffer). A larger blocksize means faster
|
||||
transfer.<br/>
|
||||
SyncMode=1 decrements BA to zero, SyncMode=0 with chopping enabled decrements
|
||||
BC to zero (aside from that two cases, D#_BCR isn't changed during/after
|
||||
BC to zero (aside from that two cases, D#\_BCR isn't changed during/after
|
||||
transfer).<br/>
|
||||
|
||||
#### 1F801088h+N*10h - D#_CHCR - DMA Channel Control (Channel 0..6) (R/W)
|
||||
#### 1F801088h+N\*10h - D#\_CHCR - DMA Channel Control (Channel 0..6) (R/W)
|
||||
```
|
||||
0 Transfer Direction (0=To Main RAM, 1=From Main RAM)
|
||||
1 Memory Address Step (0=Forward;+4, 1=Backward;-4)
|
||||
@ -82,7 +82,7 @@ force the first block to be transferred instantly without DRQ, which isn't
|
||||
desired).<br/>
|
||||
The Start/Busy bit is automatically cleared upon COMPLETION of the transfer,
|
||||
this bit must be always set for all SyncModes when starting a transfer.<br/>
|
||||
For DMA6/OTC there are some restrictions, D6_CHCR has only three
|
||||
For DMA6/OTC there are some restrictions, D6\_CHCR has only three
|
||||
read/write-able bits: Bit24,28,30. All other bits are read-only: Bit1 is always
|
||||
1 (step=backward), and the other bits are always 0.<br/>
|
||||
|
||||
|
@ -298,8 +298,8 @@ Additionally, the OP0 and OP1 outputs are controlled via MR2A.5 and MR2B.5.<br/>
|
||||
BGR Test switches between Baud Rate Set1/Set2 and Set3/Set4.<br/>
|
||||
1X/16X Test switches between whatever...?<br/>
|
||||
|
||||
#### 1F80202Eh/Read - CT_START - DUART Start Counter Command (Read=Strobe)
|
||||
#### 1F80202Fh/Read - CT_STOP - DUART Stop Counter Command (Read=Strobe)
|
||||
#### 1F80202Eh/Read - CT\_START - DUART Start Counter Command (Read=Strobe)
|
||||
#### 1F80202Fh/Read - CT\_STOP - DUART Stop Counter Command (Read=Strobe)
|
||||
```
|
||||
7-0 Not used (just issue a dummy-read to strobe start/stop command)
|
||||
```
|
||||
@ -333,7 +333,7 @@ Note: The Motorola 68681 should be the same as the Philips/Signetics 2681.<br/>
|
||||
Unknown if the Interrupt signal is connected to the PSX... there seems to be no
|
||||
spare IRQ for it, though it \<might\> share an IRQ with whatever other
|
||||
hardware...?<br/>
|
||||
The BIOS seems to use only one of the two channels; for the std_io functions:<br/>
|
||||
The BIOS seems to use only one of the two channels; for the std\_io functions:<br/>
|
||||
[BIOS TTY Console (std_io)](kernelbios.md#bios-tty-console-stdio)<br/>
|
||||
Aside from the external DUART, the PSX additionally contains an internal UART,<br/>
|
||||
[Serial Port (SIO)](serialportsio.md)<br/>
|
||||
|
@ -414,7 +414,7 @@ set.<br/>
|
||||
MAC0=(((H*20000h/SZ3)+1)/2)*IR2+OFY, SY2=MAC0/10000h ;ScrY FIFO -400h..+3FFh
|
||||
MAC0=(((H*20000h/SZ3)+1)/2)*DQA+DQB, IR0=MAC0/1000h ;Depth cueing 0..+1000h
|
||||
```
|
||||
If the result of the "(((H*20000h/SZ3)+1)/2)" division is greater than 1FFFFh,
|
||||
If the result of the "(((H\*20000h/SZ3)+1)/2)" division is greater than 1FFFFh,
|
||||
then the division result is saturated to +1FFFFh, and the divide overflow bit
|
||||
in the FLAG register gets set; that happens if the vertex is exceeding the
|
||||
"near clip plane", ie. if it is very close to the camera (SZ3\<=H/2), exactly
|
||||
@ -475,12 +475,12 @@ Multiplies a vector with either the rotation matrix, the light matrix or the
|
||||
color matrix and then adds the translation vector or background color vector.<br/>
|
||||
The GTE also allows selection of the far color vector (FC), but this vector is
|
||||
not added correctly by the hardware: The return values are reduced to the last
|
||||
portion of the formula, ie. MAC1=(Mx13*Vx3) SAR (sf*12), and similar for MAC2
|
||||
portion of the formula, ie. MAC1=(Mx13\*Vx3) SAR (sf\*12), and similar for MAC2
|
||||
and MAC3, nethertheless, some bits in the FLAG register seem to be adjusted as
|
||||
if the full operation would have been executed. Setting Mx=3 selects a garbage
|
||||
matrix (with elements -60h, +60h, IR0, RT13, RT13, RT13, RT22, RT22, RT22).<br/>
|
||||
|
||||
#### COP2 0A00428h+sf*80000h - 5 Cycles - SQR(sf) - Square vector
|
||||
#### COP2 0A00428h+sf\*80000h - 5 Cycles - SQR(sf) - Square vector
|
||||
```
|
||||
[MAC1,MAC2,MAC3] = [IR1*IR1,IR2*IR2,IR3*IR3] SHR (sf*12)
|
||||
[IR1,IR2,IR3] = [MAC1,MAC2,MAC3] ;IR1,IR2,IR3 saturated to max 7FFFh
|
||||
@ -488,7 +488,7 @@ matrix (with elements -60h, +60h, IR0, RT13, RT13, RT13, RT22, RT22, RT22).<br/>
|
||||
Calculates the square of a vector. The result is, of course, always positive,
|
||||
so the "lm" flag for negative saturation has no effect.<br/>
|
||||
|
||||
#### COP2 170000Ch+sf*80000h - 6 Cycles - OP(sf,lm) - Outer product of 2 vectors
|
||||
#### COP2 170000Ch+sf\*80000h - 6 Cycles - OP(sf,lm) - Outer product of 2 vectors
|
||||
```
|
||||
[MAC1,MAC2,MAC3] = [IR3*D2-IR2*D3, IR1*D3-IR3*D1, IR2*D1-IR1*D2] SAR (sf*12)
|
||||
[IR1,IR2,IR3] = [MAC1,MAC2,MAC3] ;copy result
|
||||
@ -563,7 +563,7 @@ Fifo entries are modified.<br/>
|
||||
Note: Although the SHL in GPL is theoretically undone by the SAR, 44bit
|
||||
overflows can occur internally when sf=1.<br/>
|
||||
|
||||
#### Details on "MAC+(FC-MAC)*IR0"
|
||||
#### Details on "MAC+(FC-MAC)\*IR0"
|
||||
```
|
||||
[IR1,IR2,IR3] = (([RFC,GFC,BFC] SHL 12) - [MAC1,MAC2,MAC3]) SAR (sf*12)
|
||||
[MAC1,MAC2,MAC3] = (([IR1,IR2,IR3] * IR0) + [MAC1,MAC2,MAC3])
|
||||
@ -572,7 +572,7 @@ Note: Above "[IR1,IR2,IR3]=(FC-MAC)" is saturated to -8000h..+7FFFh (ie. as if
|
||||
lm=0), anyways, further writes to [IR1,IR2,IR3] (within the same command) are
|
||||
saturated as usually (ie. depening on lm setting).<br/>
|
||||
|
||||
#### Details on "(LLM*V0) SAR (sf*12)" and "(BK*1000h + LCM*IR) SAR (sf*12)"
|
||||
#### Details on "(LLM\*V0) SAR (sf\*12)" and "(BK\*1000h + LCM\*IR) SAR (sf\*12)"
|
||||
Works like MVMVA command (see there), but with fixed Tx/Vx/Mx parameters, the
|
||||
sf/lm bits can be changed and do affect the results (although normally both
|
||||
bits should be set for use with color matrices).<br/>
|
||||
@ -621,7 +621,7 @@ mechanism (based on Unsigned Newton-Raphson (UNR) algorithm):<br/>
|
||||
n = min(1FFFFh, (((n*d) + 8000h) SHR 16)) ;n=0..1FFFFh
|
||||
else n = 1FFFFh, FLAG.Bit17=1, FLAG.Bit31=1 ;n=1FFFFh plus overflow flag
|
||||
```
|
||||
the GTE's unr_table[000h..100h] consists of following values:<br/>
|
||||
the GTE's unr\_table[000h..100h] consists of following values:<br/>
|
||||
```
|
||||
FFh,FDh,FBh,F9h,F7h,F5h,F3h,F1h,EFh,EEh,ECh,EAh,E8h,E6h,E4h,E3h ;\
|
||||
E1h,DFh,DDh,DCh,DAh,D8h,D6h,D5h,D3h,D1h,D0h,CEh,CDh,CBh,C9h,C8h ; 00h..3Fh
|
||||
@ -641,9 +641,9 @@ the GTE's unr_table[000h..100h] consists of following values:<br/>
|
||||
07h,07h,06h,06h,05h,05h,04h,04h,03h,03h,02h,02h,01h,01h,00h,00h ;/
|
||||
00h ;<-- one extra table entry (for "(d-7FC0h)/80h"=100h) ;-100h
|
||||
```
|
||||
Above can be generated as "unr_table[i]=min(0,(40000h/(i+100h)+1)/2-101h)".<br/>
|
||||
Above can be generated as "unr\_table[i]=min(0,(40000h/(i+100h)+1)/2-101h)".<br/>
|
||||
Some special cases: NNNNh/0001h uses a big multiplier (d=20000h), in practice,
|
||||
this can occur only for 0000h/0001h and 0001h/0001h (due to the H\<SZ3*2
|
||||
this can occur only for 0000h/0001h and 0001h/0001h (due to the H\<SZ3\*2
|
||||
overflow check).<br/>
|
||||
The min(1FFFFh) limit is needed for cases like FE3Fh/7F20h, F015h/780Bh, etc.
|
||||
(these do produce UNR result 20000h, and are saturated to 1FFFFh, but without
|
||||
|
@ -645,7 +645,7 @@ edge, which can be utilised by setting the start of the screen earlier and the
|
||||
end later. The size of the pixels is NOT changed with these settings, the GPU
|
||||
simply sends more data to the screen. Some monitors/TVs have a smaller display
|
||||
area and the extended size might not be visible on those sets. "(Mine is
|
||||
capable of about 330 pixels horizontal, and 272 vertical in 320*240 mode)"<br/>
|
||||
capable of about 330 pixels horizontal, and 272 vertical in 320\*240 mode)"<br/>
|
||||
|
||||
#### GP1(05h) - Start of Display area (in VRAM)
|
||||
```
|
||||
@ -655,7 +655,7 @@ capable of about 330 pixels horizontal, and 272 vertical in 320*240 mode)"<br/>
|
||||
```
|
||||
Upper/left Display source address in VRAM. The size and target position on
|
||||
screen is set via Display Range registers; target=X1,Y2;
|
||||
size=(X2-X1/cycles_per_pix), (Y2-Y1).<br/>
|
||||
size=(X2-X1/cycles\_per\_pix), (Y2-Y1).<br/>
|
||||
|
||||
#### GP1(06h) - Horizontal Display range (on Screen)
|
||||
```
|
||||
@ -664,8 +664,8 @@ size=(X2-X1/cycles_per_pix), (Y2-Y1).<br/>
|
||||
```
|
||||
Specifies the horizontal range within which the display area is displayed. For
|
||||
resolutions other than 320 pixels it may be necessary to fine adjust the value
|
||||
to obtain an exact match (eg. X2=X1+pixels*cycles_per_pix).<br/>
|
||||
The number of displayed pixels per line is "(((X2-X1)/cycles_per_pix)+2) AND
|
||||
to obtain an exact match (eg. X2=X1+pixels\*cycles\_per\_pix).<br/>
|
||||
The number of displayed pixels per line is "(((X2-X1)/cycles\_per\_pix)+2) AND
|
||||
NOT 3" (ie. the hardware is rounding the width up/down to a multiple of 4
|
||||
pixels).<br/>
|
||||
Most games are using a width equal to the horizontal resolution (ie. 256, 320,
|
||||
|
@ -1,9 +1,9 @@
|
||||
# Interrupts
|
||||
#### 1F801070h I_STAT - Interrupt status register (R=Status, W=Acknowledge)
|
||||
#### 1F801074h I_MASK - Interrupt mask register (R/W)
|
||||
Status: Read I_STAT (0=No IRQ, 1=IRQ)<br/>
|
||||
Acknowledge: Write I_STAT (0=Clear Bit, 1=No change)<br/>
|
||||
Mask: Read/Write I_MASK (0=Disabled, 1=Enabled)<br/>
|
||||
#### 1F801070h I\_STAT - Interrupt status register (R=Status, W=Acknowledge)
|
||||
#### 1F801074h I\_MASK - Interrupt mask register (R/W)
|
||||
Status: Read I\_STAT (0=No IRQ, 1=IRQ)<br/>
|
||||
Acknowledge: Write I\_STAT (0=Clear Bit, 1=No change)<br/>
|
||||
Mask: Read/Write I\_MASK (0=Disabled, 1=Enabled)<br/>
|
||||
```
|
||||
0 IRQ0 VBLANK (PAL=50Hz, NTSC=60Hz)
|
||||
1 IRQ1 GPU Can be requested via GP0(1Fh) command (rarely used)
|
||||
@ -24,26 +24,26 @@ Mask: Read/Write I_MASK (0=Disabled, 1=Enabled)<br/>
|
||||
[EXP2 DTL-H2000 I/O Ports](expansionportpio.md#exp2-dtl-h2000-io-ports)<br/>
|
||||
|
||||
#### Interrupt Request / Execution
|
||||
The interrupt request bits in I_STAT are edge-triggered, ie. the get set ONLY
|
||||
The interrupt request bits in I\_STAT are edge-triggered, ie. the get set ONLY
|
||||
if the corresponding interrupt source changes from "false to true".<br/>
|
||||
If one or more interrupts are requested and enabled, ie. if "(I_STAT AND
|
||||
I_MASK)=nonzero", then cop0r13.bit10 gets set, and when cop0r12.bit10 and
|
||||
If one or more interrupts are requested and enabled, ie. if "(I\_STAT AND
|
||||
I\_MASK)=nonzero", then cop0r13.bit10 gets set, and when cop0r12.bit10 and
|
||||
cop0r12.bit0 are set, too, then the interrupt gets executed.<br/>
|
||||
|
||||
#### Interrupt Acknowledge
|
||||
To acknowledge an interrupt, write a "0" to the corresponding bit in I_STAT.
|
||||
To acknowledge an interrupt, write a "0" to the corresponding bit in I\_STAT.
|
||||
Most interrupts (except IRQ0,4,5,6) must be additionally acknowledged at the
|
||||
I/O port that has caused them (eg. JOY_CTRL.bit4).<br/>
|
||||
Observe that the I_STAT bits are edge-triggered (they get set only on
|
||||
I/O port that has caused them (eg. JOY\_CTRL.bit4).<br/>
|
||||
Observe that the I\_STAT bits are edge-triggered (they get set only on
|
||||
High-to-Low, or False-to-True edges). The correct acknowledge order is:<br/>
|
||||
```
|
||||
First, acknowledge I_STAT (eg. I_STAT.bit7=0)
|
||||
Then, acknowledge corresponding I/O port (eg. JOY_CTRL.bit4=1)
|
||||
```
|
||||
When doing it vice-versa, the hardware may miss further IRQs (eg. when first
|
||||
setting JOY_CTRL.4=1, then a new IRQ may occur in JOY_STAT.4 within a single
|
||||
clock cycle, thereafter, setting I_STAT.7=0 would successfully reset I_STAT.7,
|
||||
but, since JOY_STAT.4 is already set, there'll be no further edge, so I_STAT.7
|
||||
setting JOY\_CTRL.4=1, then a new IRQ may occur in JOY\_STAT.4 within a single
|
||||
clock cycle, thereafter, setting I\_STAT.7=0 would successfully reset I\_STAT.7,
|
||||
but, since JOY\_STAT.4 is already set, there'll be no further edge, so I\_STAT.7
|
||||
won't be ever set in future).<br/>
|
||||
|
||||
#### COP0 Interrupt Handling
|
||||
@ -55,7 +55,7 @@ opcode) is used to prepare the return from interrupts. For more info, see<br/>
|
||||
#### PSX specific COP0 Notes
|
||||
COP0 has six hardware interrupt bits, of which, the PSX uses only cop0r13.bit10
|
||||
(the other ones, cop0r13.bit11-15 are always zero). cop0r13.bit10 is NOT a
|
||||
latch, ie. it gets automatically cleared as soon as "(I_STAT AND I_MASK)=zero",
|
||||
latch, ie. it gets automatically cleared as soon as "(I\_STAT AND I\_MASK)=zero",
|
||||
so there's no need to do an acknowledge at the cop0 side. COP0 additionally has
|
||||
two software interrupt bits, cop0r13.bit8-9, which do exist in the PSX, too,
|
||||
these bits are read/write-able latches which can be set/cleared manually to
|
||||
|
316
kernelbios.md
316
kernelbios.md
@ -131,8 +131,8 @@ total size (in bytes) of the corresponding control blocks.<br/>
|
||||
00000148h - Unused/reserved
|
||||
00000150h DCB Device Control Blocks (addr=fixed, size=0Ah*50h)
|
||||
```
|
||||
File handles (fd=00h..0Fh) can be simply converted as fcb=[140h]+fd*2Ch.<br/>
|
||||
Event handles (event=F10000xxh) as evcb=[120h]+(event AND FFFFh)*1Ch.<br/>
|
||||
File handles (fd=00h..0Fh) can be simply converted as fcb=[140h]+fd\*2Ch.<br/>
|
||||
Event handles (event=F10000xxh) as evcb=[120h]+(event AND FFFFh)\*1Ch.<br/>
|
||||
|
||||
#### Garbage Area at Address 00000000h
|
||||
The first some bytes of memory address 00000000h aren't actually used by the
|
||||
@ -163,7 +163,7 @@ Argument(s) are passed in R4,R5,R6,R7,[SP+10h],[SP+14h],etc.<br/>
|
||||
Caution: When calling a sub-function with N parameters, the caller MUST always
|
||||
allocate N words on the stack, and, although the first four parameters are
|
||||
passed in registers rather than on stack, the sub-function is allowed to
|
||||
use/destroy these words at [SP+0..N*4-1].<br/>
|
||||
use/destroy these words at [SP+0..N\*4-1].<br/>
|
||||
BIOS Functions (and custom callback functions) are allowed to destroy registers
|
||||
R1-R15, R24-R25, R31 (RA), and HI/LO. Registers R16-R23, R29 (SP), and R30 (FP)
|
||||
must be left unchanged (if the function uses that registers, then it must
|
||||
@ -513,7 +513,7 @@ The 20bit immediate in the "syscall imm" opcode is unused (should be zero).<br/>
|
||||
|
||||
#### BREAK-Functions (Break opcode with function number in opcode's immediate)
|
||||
BRK opcodes may be used within devkits, however, the standard BIOS simply calls
|
||||
DeliverEvent(F0000010h,1000h) and SystemError_A_40h upon any BRK opcodes (as
|
||||
DeliverEvent(F0000010h,1000h) and SystemError\_A\_40h upon any BRK opcodes (as
|
||||
well as on any other unresolved exceptions).<br/>
|
||||
```
|
||||
BRK(1C00h) Division by zero (commonly checked/invoked by software)
|
||||
@ -554,7 +554,7 @@ Opens a file on the target device for io. Accessmode is set like this:<br/>
|
||||
bit16-31 Number of memory card blocks for a new file on the memory card
|
||||
```
|
||||
The PSX can have a maximum of 16 files open at any time, of which, 2 handles
|
||||
are always reserved for std_io, so only 14 handles are available for actual
|
||||
are always reserved for std\_io, so only 14 handles are available for actual
|
||||
files. Some functions (chdir, testdevice, FileDelete, FileUndelete,
|
||||
FormatDevice, firstfile, FileRename) are temporarily allocating 1 filehandle
|
||||
(FileRename tries to use 2 filehandles, but, it does accidently use only 1
|
||||
@ -621,10 +621,10 @@ stored in RAM, so chdir is causing useless SLOW read/seek delays).<br/>
|
||||
#### B(42h) - firstfile(filename,direntry) - Find first file to match the name
|
||||
Returns r2=direntry (or r2=0 if no matching files).<br/>
|
||||
Searches for the first file to match the specified filename; the filename may
|
||||
contain "?" and "*" wildcards. "*" means to ignore ALL following characters;
|
||||
accordingly one cannot specify any further characters after the "*" (eg.
|
||||
"DATA*" would work, but "*.DAT" won't work). "?" is meant to ignore a single
|
||||
character cell. Note: The "?" wildcards (but not "*") can be used also in all
|
||||
contain "?" and "\*" wildcards. "\*" means to ignore ALL following characters;
|
||||
accordingly one cannot specify any further characters after the "\*" (eg.
|
||||
"DATA\*" would work, but "\*.DAT" won't work). "?" is meant to ignore a single
|
||||
character cell. Note: The "?" wildcards (but not "\*") can be used also in all
|
||||
other file functions; causing the function to use the first matching name (eg.
|
||||
FileDelete "????" would erase the first matching file, not all matching files).<br/>
|
||||
Start the name with the device you want to address. (ie. pcdrv:) Different
|
||||
@ -659,7 +659,7 @@ operations.<br/>
|
||||
Returns r2=direntry (or r2=0 if no more matching files).<br/>
|
||||
Uses the settings of a previous firstfile/nextfile command.<br/>
|
||||
|
||||
#### B(44h) - FileRename(old_filename, new_filename)
|
||||
#### B(44h) - FileRename(old\_filename, new\_filename)
|
||||
Returns 1=okay, or 0=failed.<br/>
|
||||
|
||||
#### B(45h) - FileDelete(filename) - Delete a file on target device
|
||||
@ -778,18 +778,18 @@ BUG: Part3 accidently treats the first 4 characters of the exename as memory
|
||||
address (causing an invalid memory address exception on address 6F726463h, for
|
||||
"cdrom:filename.exe").<br/>
|
||||
|
||||
#### A(9Ch) - SetConf(num_EvCB, num_TCB, stacktop)
|
||||
#### A(9Ch) - SetConf(num\_EvCB, num\_TCB, stacktop)
|
||||
Changes the number of EvCBs and TCBs, and the stacktop. That values are usually
|
||||
initialized from the settings in the SYSTEM.CNF file, so using this function
|
||||
usually shouldn't ever be required.<br/>
|
||||
The function deallocates all old ExCBs, EvCBs, TCBs (so all Exception handlers,
|
||||
Events, and Threads (except the current one) are lost, and all other memory
|
||||
that may have been allocated via alloc_kernel_memory(size) is deallocated, too.
|
||||
that may have been allocated via alloc\_kernel\_memory(size) is deallocated, too.
|
||||
It does then allocate the new control blocks, and enqueue the default handlers.
|
||||
Despite of the changed stacktop, the current stack pointer is kept intact, and
|
||||
the function returns to the caller.<br/>
|
||||
|
||||
#### A(9Dh) - GetConf(num_EvCB_dst, num_TCB_dst, stacktop_dst)
|
||||
#### A(9Dh) - GetConf(num\_EvCB\_dst, num\_TCB\_dst, stacktop\_dst)
|
||||
Returns the number of EvCBs, TCBs, and the initial stacktop. There's no return
|
||||
value in the R2 register, instead, the three 32bit return values are stored at
|
||||
the specified "dst" addresses.<br/>
|
||||
@ -822,7 +822,7 @@ to:<br/>
|
||||
init_card B(4Ah)
|
||||
and by intro/boot code
|
||||
```
|
||||
for load_file/load_exec, IRQ2 (cdrom) and IRQ3 (dma) need to be enabled, so the
|
||||
for load\_file/load\_exec, IRQ2 (cdrom) and IRQ3 (dma) need to be enabled, so the
|
||||
"disable all IRQs" workaround cannot be used for that functions, however, one
|
||||
can/should disable as many IRQs as possible, ie. everything except IRQ2/IRQ3,
|
||||
and all DMA interrupts except DMA3 (cdrom).<br/>
|
||||
@ -942,7 +942,7 @@ Memory Cards aka Backup Units (bu) are basically accessed via normal file
|
||||
functions, with device names "bu00:" (Slot 1) and "bu10:" (Slot 2),<br/>
|
||||
[BIOS File Functions](kernelbios.md#bios-file-functions)<br/>
|
||||
Before using the file functions for memory cards, first call
|
||||
InitCard(pad_enable), then StartCard(), and then _bu_init().<br/>
|
||||
InitCard(pad\_enable), then StartCard(), and then \_bu\_init().<br/>
|
||||
|
||||
#### File Header, Filesize, and Sector Alignment
|
||||
The first 100h..200h bytes (2..4 sectors) of the file must contain the title
|
||||
@ -987,7 +987,7 @@ immediately after invoking the access (which does then continue on interrupt
|
||||
level, and does return an event when finished).<br/>
|
||||
The file "FileRead" and "FileWrite" functions act asynchronous when accessmode
|
||||
bit15 is set when opening the file. Additionally, the A(ACh)
|
||||
_card_async_load_directory(port) function can be used to tell the BIOS to load
|
||||
\_card\_async\_load\_directory(port) function can be used to tell the BIOS to load
|
||||
the directory entries and broken sector list to its internal RAM buffers (eg.
|
||||
during the games title screen, so the BIOS doesn't need to load that data once
|
||||
when the game enters its memory card menu). All other functions like FileDelete
|
||||
@ -1007,7 +1007,7 @@ cards (via Multitap adaptors). Device/port names "bu01:", "bu02:", "bu03:"
|
||||
allow to access extra memory carts in slot1 (and "bu11:", "bu12:", "bu13:" in
|
||||
slot2). Namely, those names will send values 82h, 83h, 84h to the memory card
|
||||
slot (instead of the normal 81h value).<br/>
|
||||
However, the BIOS directory_buffer and broken_sector_list do support only two
|
||||
However, the BIOS directory\_buffer and broken\_sector\_list do support only two
|
||||
memory cards (one in slot1 and one in slot2). So, trying to access more memory
|
||||
cards may cause great data corruption (though there might be a way to get the
|
||||
BIOS to reload those buffers before accessing a different memory card).<br/>
|
||||
@ -1016,52 +1016,52 @@ accessing only two memory cards. Trying to use the BIOS to access up to eight
|
||||
memory cards would be very-extremly-very slow, which would be more annoying
|
||||
than useful.<br/>
|
||||
|
||||
#### B(4Ah) - InitCard(pad_enable) ;uses/destroys k0/k1 !!!
|
||||
#### B(4Ah) - InitCard(pad\_enable) ;uses/destroys k0/k1 !!!
|
||||
#### B(4Bh) - StartCard()
|
||||
#### B(4Ch) - StopCard()
|
||||
#### A(55h) or A(70h) - _bu_init()
|
||||
#### A(55h) or A(70h) - \_bu\_init()
|
||||
|
||||
```
|
||||
--- Below are some lower level memory card functions ---
|
||||
```
|
||||
|
||||
#### A(ABh) - _card_info(port)
|
||||
#### B(4Dh) - _card_info_subfunc(port) ;subfunction for "_card_info"
|
||||
Can be used to check if the most recent call to write_card_sector has completed
|
||||
#### A(ABh) - \_card\_info(port)
|
||||
#### B(4Dh) - \_card\_info\_subfunc(port) ;subfunction for "\_card\_info"
|
||||
Can be used to check if the most recent call to write\_card\_sector has completed
|
||||
okay. Issues an incomplete dummy read command (similar to B(4Fh) -
|
||||
read_card_sector). The read command is aborted once when receiving the status
|
||||
read\_card\_sector). The read command is aborted once when receiving the status
|
||||
byte from the memory card (the actual data transfer is skipped).<br/>
|
||||
|
||||
#### A(AFh) - card_write_test(port) ;not supported by old CEX-1000 version
|
||||
#### A(AFh) - card\_write\_test(port) ;not supported by old CEX-1000 version
|
||||
Resets the card changed flag. For some strange reason, this flag isn't
|
||||
automatically reset after reading the flag, instead, the flag is reset upon
|
||||
sector writes. To do that, this function issues a dummy write to sector 3Fh.<br/>
|
||||
|
||||
#### B(50h) - allow_new_card()
|
||||
#### B(50h) - allow\_new\_card()
|
||||
Normally any memory card read/write functions fail if the BIOS senses the card
|
||||
change flag to be set. Calling this function tells the BIOS to ignore the card
|
||||
change flag on the next read/write operation (the function is internally used
|
||||
when loading the "MC" ID from sector 0, and when calling the card_write_test
|
||||
when loading the "MC" ID from sector 0, and when calling the card\_write\_test
|
||||
function to acknowledge the card change flag).<br/>
|
||||
|
||||
#### B(4Eh) - write_card_sector(port,sector,src)
|
||||
#### B(4Fh) - read_card_sector(port,sector,dst)
|
||||
#### B(4Eh) - write\_card\_sector(port,sector,src)
|
||||
#### B(4Fh) - read\_card\_sector(port,sector,dst)
|
||||
Invokes asynchronous reading/writing of a single sector. The function returns
|
||||
1=okay, or 0=failed (on invalid sector numbers). The actual I/O is done on IRQ
|
||||
level, completion of the I/O command transmission can be checked, among others,
|
||||
via get/wait_card_status(slot) functions (with slot=port/10h).<br/>
|
||||
via get/wait\_card\_status(slot) functions (with slot=port/10h).<br/>
|
||||
In case of the write function, completion of the \<transmission\> does NOT
|
||||
mean that the actual \<writing\> has completed, instead, write errors are
|
||||
indicated upon completion of the \<next sector\> read/write transmission
|
||||
(or, if there are no further sectors to be accessed; one can use _card_info to
|
||||
(or, if there are no further sectors to be accessed; one can use \_card\_info to
|
||||
verify completion of the last written sector).<br/>
|
||||
The sector number should be in range of 0..3FFh, for some strange reason,
|
||||
probably a BUG, the function also accepts sector 400h. The specified sector
|
||||
number is directly accessed (it is NOT parsed through the broken sector
|
||||
replacement list).<br/>
|
||||
|
||||
#### B(5Ch) - get_card_status(slot)
|
||||
#### B(5Dh) - wait_card_status(slot)
|
||||
#### B(5Ch) - get\_card\_status(slot)
|
||||
#### B(5Dh) - wait\_card\_status(slot)
|
||||
Returns the status of the most recent I/O command, possible values are:<br/>
|
||||
```
|
||||
01h=ready
|
||||
@ -1071,29 +1071,29 @@ Returns the status of the most recent I/O command, possible values are:<br/>
|
||||
11h=failed/timeout (eg. when no cartridge inserted)
|
||||
21h=failed/general error
|
||||
```
|
||||
get_card_status returns immediately, wait_card_status waits until a non-busy
|
||||
get\_card\_status returns immediately, wait\_card\_status waits until a non-busy
|
||||
state occurs.<br/>
|
||||
|
||||
#### A(A7h) - bu_callback_okay()
|
||||
#### A(A8h) - bu_callback_err_write()
|
||||
#### A(A9h) - bu_callback_err_busy()
|
||||
#### A(AAh) - bu_callback_err_eject()
|
||||
#### A(AEh) - bu_callback_err_prev_write()
|
||||
#### A(A7h) - bu\_callback\_okay()
|
||||
#### A(A8h) - bu\_callback\_err\_write()
|
||||
#### A(A9h) - bu\_callback\_err\_busy()
|
||||
#### A(AAh) - bu\_callback\_err\_eject()
|
||||
#### A(AEh) - bu\_callback\_err\_prev\_write()
|
||||
These five callback functions are internally used by the BIOS, notifying other
|
||||
BIOS functions about (un-)successful completion of memory card I/O commands.<br/>
|
||||
|
||||
#### B(58h) - get_bu_callback_port()
|
||||
This is a subfunction for the five bu_callback_xxx functions (indicating
|
||||
#### B(58h) - get\_bu\_callback\_port()
|
||||
This is a subfunction for the five bu\_callback\_xxx functions (indicating
|
||||
whether the callback occured for a slot1 or slot2 access).<br/>
|
||||
|
||||
#### A(ACh) - _card_async_load_directory(port)
|
||||
#### A(ACh) - \_card\_async\_load\_directory(port)
|
||||
Invokes asynchronous reading of the memory card directory. The function isn't
|
||||
too useful because the BIOS tends to read the directory automatically in
|
||||
various places in synchronous mode, so there isn't too much chance to replace
|
||||
the automatic synchronous reading by asynchronous reading.<br/>
|
||||
|
||||
#### A(ADh) - set_card_auto_format(flag)
|
||||
Can be used to enable/disable auto format (0=off, 1=on). The _bu_init function
|
||||
#### A(ADh) - set\_card\_auto\_format(flag)
|
||||
Can be used to enable/disable auto format (0=off, 1=on). The \_bu\_init function
|
||||
initializes auto format as disabled. If auto format is enabled, then the BIOS
|
||||
does automatically format memory cards if it has failed to read the "MC" ID
|
||||
bytes on sector 0. Although potentially useful, activating this feature is
|
||||
@ -1102,8 +1102,8 @@ due to improperly inserted cards with dirty contacts, so it'd be better to
|
||||
prompt the user whether or not to format the card, rather than doing that
|
||||
automatically).<br/>
|
||||
|
||||
#### C(1Ah) - set_card_find_mode(mode)
|
||||
#### C(1Dh) - get_card_find_mode()
|
||||
#### C(1Ah) - set\_card\_find\_mode(mode)
|
||||
#### C(1Dh) - get\_card\_find\_mode()
|
||||
Allows to get/set the card find mode (0=normal, 1=find deleted files), the mode
|
||||
setting affects only the firstfile/nextfile functions. All other file functions
|
||||
are used fixed mode settings (always mode=0 for FileOpen, FileRename,
|
||||
@ -1330,7 +1330,7 @@ This function is usually called by the kernel, undelivers all events that are
|
||||
enabled/ready, and that have mode=2000h, and that have the specified class and
|
||||
spec values. Undeliver means that the events are marked as enabled/busy.<br/>
|
||||
|
||||
#### C(04h) get_free_EvCB_slot()
|
||||
#### C(04h) get\_free\_EvCB\_slot()
|
||||
A subfunction for OpenEvent.<br/>
|
||||
|
||||
#### Event Classes
|
||||
@ -1482,7 +1482,7 @@ notifications from the BIOS).<br/>
|
||||
|
||||
|
||||
## BIOS Thread Functions
|
||||
#### B(0Eh) OpenThread(reg_PC,reg_SP_FP,reg_GP)
|
||||
#### B(0Eh) OpenThread(reg\_PC,reg\_SP\_FP,reg\_GP)
|
||||
Searches a free TCB, marks it as used, and stores the inital program counter
|
||||
(PC), global pointer (GP aka R28), stack pointer (SP aka R29), and frame
|
||||
pointer (FP aka R30) (using the same value for SP and FP). All other registers
|
||||
@ -1530,7 +1530,7 @@ back to that thread. Mind that other registers (I/O Ports or GTE registers
|
||||
aren't stored automatically, so, when needed, they need to be pushed/popped by
|
||||
software before/after ChangeThread).<br/>
|
||||
|
||||
#### C(05h) get_free_TCB_slot()
|
||||
#### C(05h) get\_free\_TCB\_slot()
|
||||
Subfunction for OpenThread, returns the number of the first free TCB (usually
|
||||
in range 0..3) or FFFFFFFFh if there's no free TCB.<br/>
|
||||
|
||||
@ -1558,33 +1558,33 @@ the two handlers).<br/>
|
||||
So, although Vblank IRQs are most important for games, the PSX BIOS doesn't
|
||||
actually allow to use them for purposes other than joypad access. A possible
|
||||
workaround is to examine the status byte in one of the joypad buffers (ie. the
|
||||
InitPad(buf1,22h,buf2,22h) buffers). Eg. a wait_for_vblank function could look
|
||||
InitPad(buf1,22h,buf2,22h) buffers). Eg. a wait\_for\_vblank function could look
|
||||
like so: set buf1[0]=55h, then wait until buf1[0]=00h or buf1[0]=FFh.<br/>
|
||||
|
||||
#### B(02h) init_timer(t,reload,flags)
|
||||
When t=0..2, resets the old timer mode by setting [1F801104h+t*16]=0000h,
|
||||
applies the reload value by [1F801108h+t*16]=reload, computes the new mode:<br/>
|
||||
#### B(02h) init\_timer(t,reload,flags)
|
||||
When t=0..2, resets the old timer mode by setting [1F801104h+t\*16]=0000h,
|
||||
applies the reload value by [1F801108h+t\*16]=reload, computes the new mode:<br/>
|
||||
```
|
||||
if flags.bit4=0 then mode=0048h else mode=0049h
|
||||
if flags.bit0=0 then mode=mode OR 100h
|
||||
if flags.bit12=1 then mode=mode OR 10h
|
||||
```
|
||||
and applies it by setting [1F801104h+t*16]=mode, and returns 1. Does nothing
|
||||
and applies it by setting [1F801104h+t\*16]=mode, and returns 1. Does nothing
|
||||
and returns zero for t\>2.<br/>
|
||||
|
||||
#### B(03h) get_timer(t)
|
||||
Reads the current timer value: Returns halfword[1F801100h+t*16] for t=0..2.
|
||||
#### B(03h) get\_timer(t)
|
||||
Reads the current timer value: Returns halfword[1F801100h+t\*16] for t=0..2.
|
||||
Does nothing and returns zero for t\>2.<br/>
|
||||
|
||||
#### B(04h) enable_timer_irq(t)
|
||||
#### B(05h) disable_timer_irq(t)
|
||||
#### B(04h) enable\_timer\_irq(t)
|
||||
#### B(05h) disable\_timer\_irq(t)
|
||||
Enables/disables timer or vblank interrupt enable bits in [1F801074h], bit4,5,6
|
||||
for t=0,1,2, or bit0 for t=3, or random/garbage bits for t\>3. The enable
|
||||
function returns 1 for t=0..2, and 0 for t=3. The disable function returns
|
||||
always 1.<br/>
|
||||
|
||||
#### B(06h) restart_timer(t)
|
||||
Sets the current timer value to zero: Sets [1F801100h+t*16]=0000h and returns 1
|
||||
#### B(06h) restart\_timer(t)
|
||||
Sets the current timer value to zero: Sets [1F801100h+t\*16]=0000h and returns 1
|
||||
for t=0..2. Does nothing and returns zero for t\>2.<br/>
|
||||
|
||||
#### C(0Ah) - ChangeClearRCnt(t,flag) ;root counter (aka timer)
|
||||
@ -1609,8 +1609,8 @@ pads (such like for controlling rumble motors).<br/>
|
||||
Memorizes the desired buf1/buf2 addresses, zerofills the buffers by using the
|
||||
siz1/siz2 buffer size values (which should be 22h bytes each). And does some
|
||||
initialization on the PadCardIrq element (but doesn't enqueue it, that must be
|
||||
done by a following call to StartPad), and does set the "pad_enable_flag", that
|
||||
flag can be also set/cleared via InitCard(pad_enable), where it selects if the
|
||||
done by a following call to StartPad), and does set the "pad\_enable\_flag", that
|
||||
flag can be also set/cleared via InitCard(pad\_enable), where it selects if the
|
||||
Pads are kept handled together with Memory Cards. buf1/buf2 are having the
|
||||
following format:<br/>
|
||||
```
|
||||
@ -1622,7 +1622,7 @@ Note: InitPad does initially zerofill the buffers, so, until the first IRQ is
|
||||
processed, the initial status is 00h=okay, with buttons=0000h (all buttons
|
||||
pressed), to fix that situation, change the two status bytes to FFh after
|
||||
calling InitPad (or alternately, reject ID1=00h).<br/>
|
||||
Once when the PadCardIrq is enqueued via StartPad, and while "pad_enable_flag"
|
||||
Once when the PadCardIrq is enqueued via StartPad, and while "pad\_enable\_flag"
|
||||
is set, the data for (both) Pad1 and Pad2 is read on Vblank interrupts, and
|
||||
stored in the buffers, the IRQ handler stores up to 22h bytes in the buffer
|
||||
(regardless of the siz1/siz2 values) (eg. a Multitap adaptor uses all 22h
|
||||
@ -1636,7 +1636,7 @@ additionally initialize some flags.<br/>
|
||||
Dequeues the PadCardIrq handler. Note that this handler is also used for memory
|
||||
cards, so it'll "stop" cards, too.<br/>
|
||||
|
||||
#### B(15h) - OutdatedPadInitAndStart(type, button_dest, unused, unused)
|
||||
#### B(15h) - OutdatedPadInitAndStart(type, button\_dest, unused, unused)
|
||||
This is an extremely bizarre and restrictive function - don't use! The function
|
||||
fails unless type is 20000000h or 20000001h (the type value has no other
|
||||
function). The function uses "buf1/buf2" addresses that are located somewhere
|
||||
@ -1645,7 +1645,7 @@ internal buffers is to use the ugly "OutdatedPadGetButtons()" function. For
|
||||
some strange reason it FFh-fills buf1/buf2, and does then call
|
||||
InitPad(buf1,22h,buf2,22) (which does immediately 00h-fill the previously
|
||||
FFh-filled buffers), and does then call StartPad().<br/>
|
||||
Finally, it does memorize the "button_dest" address (see
|
||||
Finally, it does memorize the "button\_dest" address (see
|
||||
OutdatedPadGetButtons() for details on that value). The two unused parameters
|
||||
have no function, however, they are internally written back to the stack
|
||||
locations reserved for parameter 2 and 3, ie. at [SP+08h] and [SP+0Ch] on the
|
||||
@ -1654,13 +1654,13 @@ allocated on stack. Return value is 2 (or 0 if type was disliked).<br/>
|
||||
|
||||
#### B(16h) - OutdatedPadGetButtons()
|
||||
This is a very ugly function, using the internal "buf1/buf2" values from
|
||||
"OutdatedPadInitAndStart" and the "button_dest" value that was passed to that
|
||||
"OutdatedPadInitAndStart" and the "button\_dest" value that was passed to that
|
||||
function.<br/>
|
||||
If "button_dest" is non-zero, then this function is automatically called by the
|
||||
PadCardIrq handler, and stores it's return value at [button_dest] (where it may
|
||||
be read by the main program). If "button_dest" is zero, then it isn't called
|
||||
If "button\_dest" is non-zero, then this function is automatically called by the
|
||||
PadCardIrq handler, and stores it's return value at [button\_dest] (where it may
|
||||
be read by the main program). If "button\_dest" is zero, then it isn't called
|
||||
automatically, and it \<can\> be called manually (with return value in R2),
|
||||
however, it does additionally write the return value to [button_dest], ie. to
|
||||
however, it does additionally write the return value to [button\_dest], ie. to
|
||||
[00000000h] in this case, destroying that memory location.<br/>
|
||||
The return value itself is useless garbage: The lower 16bit contain the pad1
|
||||
buttons, the upper 16bit the pad2 buttons, of which, both values have reversed
|
||||
@ -1678,23 +1678,23 @@ other ID values, or disconnected joypads, cause the halfword to be set to FFFFh
|
||||
#### A(48h) - SendGP1Command(gp1cmd)
|
||||
Writes [1F801814h]=gp1cmd. There's no return value (r2 is left unchanged).<br/>
|
||||
|
||||
#### A(49h) - GPU_cw(gp0cmd) ;send GP0 command word
|
||||
Calls gpu_sync(), and does then write [1F801810h]=gp0cmd. Returns the return
|
||||
value from the gpu_sync() call.<br/>
|
||||
#### A(49h) - GPU\_cw(gp0cmd) ;send GP0 command word
|
||||
Calls gpu\_sync(), and does then write [1F801810h]=gp0cmd. Returns the return
|
||||
value from the gpu\_sync() call.<br/>
|
||||
|
||||
#### A(4Ah) - GPU_cwp(src,num) ;send GP0 command word and parameter words
|
||||
Calls gpu_sync(), and does then copy "num" words from [src and up] to
|
||||
#### A(4Ah) - GPU\_cwp(src,num) ;send GP0 command word and parameter words
|
||||
Calls gpu\_sync(), and does then copy "num" words from [src and up] to
|
||||
[1F801810h], src should usually point to a command word, followed by num-1
|
||||
parameter words. Transfer is done by software (without DMA). Always returns 0.<br/>
|
||||
|
||||
#### A(4Bh) - send_gpu_linked_list(src)
|
||||
Transfer an OT via DMA. Calls gpu_sync(), and does then write
|
||||
#### A(4Bh) - send\_gpu\_linked\_list(src)
|
||||
Transfer an OT via DMA. Calls gpu\_sync(), and does then write
|
||||
[1F801814h]=4000002h, [1F8010F4h]=0, [1F8010F0h]=[1F8010F0h] OR 800h,
|
||||
[1F8010A0h]=src, [1F8010A4h]=0, [1F8010A8h]=1000401h. The function does
|
||||
additionally output a bunch of TTY status messages via printf. The function
|
||||
doesn't wait until the DMA is completed. There's no return value.<br/>
|
||||
|
||||
#### A(4Ch) - gpu_abort_dma()
|
||||
#### A(4Ch) - gpu\_abort\_dma()
|
||||
Writes [1F8010A8h]=401h, [1F801814h]=4000000h, [1F801814h]=2000000h,
|
||||
[1F801814h]=1000000h. Ie. stops GPU DMA, and issues GP1(4), GP1(2), GP1(1).
|
||||
Returns 1F801814h, ie. the I/O address.<br/>
|
||||
@ -1702,30 +1702,30 @@ Returns 1F801814h, ie. the I/O address.<br/>
|
||||
#### A(4Dh) - GetGPUStatus()
|
||||
Reads [1F801814h] and returns that value.<br/>
|
||||
|
||||
#### A(46h) - GPU_dw(Xdst,Ydst,Xsiz,Ysiz,src)
|
||||
Waits until GPUSTAT.Bit26 is set (unlike gpu_sync, which waits for Bit28), and
|
||||
#### A(46h) - GPU\_dw(Xdst,Ydst,Xsiz,Ysiz,src)
|
||||
Waits until GPUSTAT.Bit26 is set (unlike gpu\_sync, which waits for Bit28), and
|
||||
does then [1F801810h]=A0000000h, [1F801810h]=YdstXdst, [1F801810h]=YsizXsiz,
|
||||
and finally transfers "N" words from [src and up] to [1F801810h], where "N" is
|
||||
"Xsiz*Ysiz/2". The data is transferred by software (without DMA) (by code
|
||||
"Xsiz\*Ysiz/2". The data is transferred by software (without DMA) (by code
|
||||
executed in the uncached BIOS region with high waitstates, so the data transfer
|
||||
is very SLOW).<br/>
|
||||
Caution: If "Xsiz*Ysiz" is odd, then the last halfword is NOT transferred, so
|
||||
Caution: If "Xsiz\*Ysiz" is odd, then the last halfword is NOT transferred, so
|
||||
the GPU stays waiting for the last data value.<br/>
|
||||
Returns [SP+04h]=Ydst, [SP+08h]=Xsiz, [SP+0Ch]=Ysiz, [SP+10h]=src+N*4, and
|
||||
R2=src=N*4.<br/>
|
||||
Returns [SP+04h]=Ydst, [SP+08h]=Xsiz, [SP+0Ch]=Ysiz, [SP+10h]=src+N\*4, and
|
||||
R2=src=N\*4.<br/>
|
||||
|
||||
#### A(47h) - gpu_send_dma(Xdst,Ydst,Xsiz,Ysiz,src)
|
||||
Calls gpu_sync(), writes [1F801810h]=A0000000h, [1F801814h]=4000002h,
|
||||
[1F8010F0h]=[1F8010F0h] OR 800h, [1F8010A0h]=src, [1F8010A4h]=N*10000h+10h
|
||||
(where N="Xsiz*Ysiz/32"), [1F8010A8h]=1000201h.<br/>
|
||||
Caution: If "Xsiz*Ysiz" is not a multiple of 32, then the last halfword(s) are
|
||||
#### A(47h) - gpu\_send\_dma(Xdst,Ydst,Xsiz,Ysiz,src)
|
||||
Calls gpu\_sync(), writes [1F801810h]=A0000000h, [1F801814h]=4000002h,
|
||||
[1F8010F0h]=[1F8010F0h] OR 800h, [1F8010A0h]=src, [1F8010A4h]=N\*10000h+10h
|
||||
(where N="Xsiz\*Ysiz/32"), [1F8010A8h]=1000201h.<br/>
|
||||
Caution: If "Xsiz\*Ysiz" is not a multiple of 32, then the last halfword(s) are
|
||||
NOT transferred, so the GPU stays waiting for that values.<br/>
|
||||
Returns R2=1F801810h, and [SP+04h]=Ydst, [SP+08h]=Xsiz, [SP+0Ch]=Ysiz.<br/>
|
||||
|
||||
#### A(4Eh) - gpu_sync()
|
||||
#### A(4Eh) - gpu\_sync()
|
||||
If DMA is off (when GPUSTAT.Bit29-30 are zero): Waits until GPUSTAT.Bit28=1 (or
|
||||
until timeout).<br/>
|
||||
If DMA is on: Waits until D2_CHCR.Bit24=0 (or until timeout), and does then
|
||||
If DMA is on: Waits until D2\_CHCR.Bit24=0 (or until timeout), and does then
|
||||
wait until GPUSTAT.Bit28=1 (without timeout, ie. may hang forever), and does
|
||||
then turn off DMA via GP1(04h).<br/>
|
||||
Returns 0 (or -1 in case of timeout, however, the timeout values are very big,
|
||||
@ -1752,17 +1752,17 @@ handle it may destroy memory at [buf-4], or trigger a memory exception (for
|
||||
example, when buf=0).<br/>
|
||||
|
||||
#### A(37h) - calloc(sizx, sizy) ;SLOW!
|
||||
Allocates xsiz*ysiz bytes by calling malloc(xsiz*ysiz), and, unlike malloc, it
|
||||
Allocates xsiz\*ysiz bytes by calling malloc(xsiz\*ysiz), and, unlike malloc, it
|
||||
does additionally zerofill the memory via SLOW "bzero" function. Returns the
|
||||
address of the memory block (or zero if failed).<br/>
|
||||
|
||||
#### A(38h) - realloc(old_buf, new_size) ;SLOW!
|
||||
If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or
|
||||
0=failed). Else, if "new_size" is zero, executes free(old_buf), and returns
|
||||
r2=garbage. Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size),
|
||||
and free(old_buf), and returns r2=new_buf (or 0=failed).<br/>
|
||||
#### A(38h) - realloc(old\_buf, new\_size) ;SLOW!
|
||||
If "old\_buf" is zero, executes malloc(new\_size), and returns r2=new\_buf (or
|
||||
0=failed). Else, if "new\_size" is zero, executes free(old\_buf), and returns
|
||||
r2=garbage. Else, executes malloc(new\_size), bcopy(old\_buf,new\_buf,new\_size),
|
||||
and free(old\_buf), and returns r2=new\_buf (or 0=failed).<br/>
|
||||
Caution: The bcopy function is SLOW, and realloc does accidently copy
|
||||
"new_size" bytes from old_buf, so, if the old_size was smaller than new_size
|
||||
"new\_size" bytes from old\_buf, so, if the old\_size was smaller than new\_size
|
||||
then it'll copy whatever garbage data - in worst case, if it exceeds the top of
|
||||
the 2MB RAM region, it may crash with a locked memory exception, although
|
||||
that'd happen only if SetMemSize(2) was used to restrict RAM to 2MBs.<br/>
|
||||
@ -1777,11 +1777,11 @@ may use it to deallocate all old memory).<br/>
|
||||
The heap is used only by malloc/realloc/calloc/free, and by the "qsort"
|
||||
function.<br/>
|
||||
|
||||
#### B(00h) alloc_kernel_memory(size)
|
||||
#### B(01h) free_kernel_memory(buf)
|
||||
#### B(00h) alloc\_kernel\_memory(size)
|
||||
#### B(01h) free\_kernel\_memory(buf)
|
||||
Same as malloc/free, but, instead of the heap, manages the 8kbyte control block
|
||||
memory at A000E000h..A000FFFFh. This region is used by the kernel to allocate
|
||||
ExCBs (4x08h bytes), EvCBs (N*1Ch bytes), TCBs (N*0C0h bytes), and the process
|
||||
ExCBs (4x08h bytes), EvCBs (N\*1Ch bytes), TCBs (N\*0C0h bytes), and the process
|
||||
control block (1x04h bytes). Unlike the heap, the BIOS does automatically
|
||||
initialize this memory region via SysInitMemory(addr,size), and does
|
||||
autimatically allocate the above data (where the number of EvCBs and TCBs is as
|
||||
@ -1931,14 +1931,14 @@ Returns the index (relative to src) of that occurence. If there was no
|
||||
occurence, then it returns the length of src. That silly return values do not
|
||||
actually indicate if an occurence has been found or not (unless one checks for
|
||||
[src+index]=00h or so).<br/>
|
||||
***<br/>
|
||||
\*\*\*<br/>
|
||||
"The strcspn() function shall compute the length (in bytes) of the maximum
|
||||
initial segment of the string pointed to by s1 which consists entirely of bytes
|
||||
not from the string pointed to by s2."<br/>
|
||||
"The strspn() function shall compute the length (in bytes) of the maximum
|
||||
initial segment of the string pointed to by s1 which consists entirely of bytes
|
||||
from the string pointed to by s2."<br/>
|
||||
***<br/>
|
||||
\*\*\*<br/>
|
||||
Hmmmm, that'd be vice-versa?<br/>
|
||||
|
||||
#### A(23h) - strtok(src, list) ;first call
|
||||
@ -1994,7 +1994,7 @@ to uppercase/lowercase format accordingly. Works only for char 00h..7Fh (some
|
||||
characters in range 80h..FFh are left unchanged, others are randomly "adjusted"
|
||||
by adding/subtracting 20h, and by sign-expanding the result to 32bits).<br/>
|
||||
|
||||
#### A(0Dh) - strtol(src, src_end, base)
|
||||
#### A(0Dh) - strtol(src, src\_end, base)
|
||||
Converts a string to a number. The function skips any leading "blank"
|
||||
characters (that are, 09h..0Dh, and 20h) (ie. TAB, CR, LF, SPC, and some
|
||||
others) (some characters in range 80h..FFh are accidently treated as "blank",
|
||||
@ -2014,34 +2014,34 @@ string "o55" will be treated as 55 octal) (the only workaround would be to
|
||||
add/remove leading "0" characters, ie. "b11" or "00b11" or "0o55" would work
|
||||
okay).<br/>
|
||||
Finally, the function initializes result=0, and does then process the digits as
|
||||
"result=result*base+digit" (without any overflow checks) unless/until it
|
||||
"result=result\*base+digit" (without any overflow checks) unless/until it
|
||||
reaches an unknown digit (or when digit\>=base) (ie. the string may end with
|
||||
00h, or with any other unexpected characters).<br/>
|
||||
The function accepts both uppercase and lowercase characters (both as prefixes,
|
||||
and as numeric digits). The function returns R2=result, and
|
||||
[src_end]=end_address (ie. usually the address of the ending 00h byte; or of
|
||||
[src\_end]=end\_address (ie. usually the address of the ending 00h byte; or of
|
||||
any other unexpected end-byte). If src points to 00000000h, then the function
|
||||
returns r2=0, and leaves [src_end] unchanged.<br/>
|
||||
returns r2=0, and leaves [src\_end] unchanged.<br/>
|
||||
|
||||
#### A(0Ch) - strtoul(src, src_end, base)
|
||||
#### A(0Ch) - strtoul(src, src\_end, base)
|
||||
Same as "strtol" except that it doesn't recognize the "-" sign prefix (ie.
|
||||
works only for unsigned numbers).<br/>
|
||||
|
||||
#### A(10h) - atoi(src)
|
||||
#### A(11h) - atol(src) ;exactly same as "atoi" (but slightly slower)
|
||||
Same as "strtol", except that it doesn't return the string end address in
|
||||
[src_end], and except that it defaults to base=10, but still supports prefixes,
|
||||
[src\_end], and except that it defaults to base=10, but still supports prefixes,
|
||||
allowing to use base2,8,16. CAUTION: For some super bizarre reason, this
|
||||
function treats "0" (a leading ZERO digit) as OCTAL prefix (unlike strtol,
|
||||
which uses the "o" letter as octal prefix) (the "0x" and "0b" prefixes are
|
||||
working as usually).<br/>
|
||||
|
||||
#### A(12h) - atob(src, num_dst)
|
||||
Calls "strtol(str,src_end,10)", and does then exchange the two return values
|
||||
(ie. sets R2=[src_end], and [num_dst]=value_32bit).<br/>
|
||||
#### A(12h) - atob(src, num\_dst)
|
||||
Calls "strtol(str,src\_end,10)", and does then exchange the two return values
|
||||
(ie. sets R2=[src\_end], and [num\_dst]=value\_32bit).<br/>
|
||||
|
||||
#### A(0Bh) - atof(src) ;USES (ABSENT) COP1 FPU !!!
|
||||
#### A(32h) - strtod(src, src_end) ;USES (ABSENT) COP1 FPU !!!
|
||||
#### A(32h) - strtod(src, src\_end) ;USES (ABSENT) COP1 FPU !!!
|
||||
These functions are intended to convert strings to floating point numbers,
|
||||
however, the functions are accidently compiled for MIPS processors with COP1
|
||||
floating point unit (which is not installed in the PSX, nor does the BIOS
|
||||
@ -2058,7 +2058,7 @@ values.<br/>
|
||||
|
||||
## BIOS Misc Functions
|
||||
#### A(2Fh) - rand()
|
||||
Advances the random generator as "x=x*41C64E6Dh+3039h" (aka plus 12345
|
||||
Advances the random generator as "x=x\*41C64E6Dh+3039h" (aka plus 12345
|
||||
decimal), and returns a 15bit random value "R2=(x/10000h) AND 7FFFh".<br/>
|
||||
|
||||
#### A(30h) - srand(seed)
|
||||
@ -2122,9 +2122,9 @@ be, if it'd be in the array). Both functions return the address of the element
|
||||
#### C(19h) - ioabort(txt1,txt2)
|
||||
Displays the two strings on the TTY (in some cases the BIOS does accidently
|
||||
pass garbage instead of the 2nd string though). And does then execute
|
||||
ioabort_raw(1), see there for more details.<br/>
|
||||
ioabort\_raw(1), see there for more details.<br/>
|
||||
|
||||
#### A(B2h) - ioabort_raw(param) ;not supported by old CEX-1000 version
|
||||
#### A(B2h) - ioabort\_raw(param) ;not supported by old CEX-1000 version
|
||||
Executes "RestoreState(ioabortbuffer,param)". Internally used to recover from
|
||||
failed I/O operations, param should be nonzero to notify the SaveState caller
|
||||
that the abort has occurred.<br/>
|
||||
@ -2153,7 +2153,7 @@ code at RA, ie. usually to the caller of the original SaveState call) (since
|
||||
SaveState returns 0, "param" should be usually 1, or another non-zero value to
|
||||
inidicate that RestoreState has occurred). See SaveState for further details.<br/>
|
||||
|
||||
#### A(53h) - set_ioabort_handler(src) ;PS2 only ;PSX: SystemError
|
||||
#### A(53h) - set\_ioabort\_handler(src) ;PS2 only ;PSX: SystemError
|
||||
Normally the ioabort handler is changed only internally during booting, with
|
||||
this new function, games can install their own ioabort handler. src is pointer
|
||||
to a 30h-byte "savestate" structure, which will be copied to the actual ioabort
|
||||
@ -2215,7 +2215,7 @@ to SystemErrorUnresolvedException().<br/>
|
||||
|
||||
|
||||
## BIOS Internal Boot Functions
|
||||
#### A(45h) - init_a0_b0_c0_vectors
|
||||
#### A(45h) - init\_a0\_b0\_c0\_vectors
|
||||
Copies the three default four-opcode handlers for the A(NNh),B(NNh),C(NNh)
|
||||
functions to A00000A0h..A00000CFh.<br/>
|
||||
|
||||
@ -2349,7 +2349,7 @@ Attributes Bits (standard MSDOS-style):<br/>
|
||||
V1 0 = success, error code if V0 is negative
|
||||
```
|
||||
|
||||
#### BRK(105h) - PCRead(filehandle, length, memory_destination_address)
|
||||
#### BRK(105h) - PCRead(filehandle, length, memory\_destination\_address)
|
||||
```
|
||||
out: V0 0 = success, -1 = failure
|
||||
V1 number of read bytes or error code if V0 is negative.
|
||||
@ -2360,13 +2360,13 @@ filelength obtain the filelength by PClSeek (A2=0, A3=2, V1 will return the
|
||||
length of the file, don't forget to reset the file pointer to the start before
|
||||
calling PCread!)<br/>
|
||||
|
||||
#### BRK(106h) - PCWrite(filehandle, length, memory_source_address)
|
||||
#### BRK(106h) - PCWrite(filehandle, length, memory\_source\_address)
|
||||
```
|
||||
out: V0 0 = success, -1 = failure
|
||||
V1 number of written bytes or error code if V0 is negative.
|
||||
```
|
||||
|
||||
#### BRK(107h) - PClSeek(filehandle, file_offset, seekmode) - Change Filepos
|
||||
#### BRK(107h) - PClSeek(filehandle, file\_offset, seekmode) - Change Filepos
|
||||
seekmode may be from 0=Begin of file, 1=Current fpos, or 2=End of file.<br/>
|
||||
```
|
||||
out: V0 0 = success, -1 = failure
|
||||
@ -2375,14 +2375,14 @@ seekmode may be from 0=Begin of file, 1=Current fpos, or 2=End of file.<br/>
|
||||
|
||||
|
||||
|
||||
## BIOS TTY Console (std_io)
|
||||
## BIOS TTY Console (std\_io)
|
||||
#### A(3Fh) - Printf(txt,param1,param2,etc.) - Print string to console
|
||||
```
|
||||
in: A0 Pointer to 0 terminated string
|
||||
A1,A2,A3,[SP+10h..] Argument(s)
|
||||
```
|
||||
Prints the specified string to the TTY console. Printf does internally use
|
||||
"std_out_putchar" to output the separate characters (and expands char 09h and
|
||||
"std\_out\_putchar" to output the separate characters (and expands char 09h and
|
||||
0Ah accordingly).<br/>
|
||||
The string can contain C-style escape codes (prefixed by "%" each):<br/>
|
||||
```
|
||||
@ -2415,7 +2415,7 @@ doesn't work at all (accidently sign-expands 16bit to 32bit, and then displays
|
||||
that signed 32bit value as giant unsigned value). Printf supports only octal,
|
||||
decimal, and hex (but not binary).<br/>
|
||||
|
||||
#### A(3Eh) or B(3Fh) std_out_puts(src) - Write string to TTY
|
||||
#### A(3Eh) or B(3Fh) std\_out\_puts(src) - Write string to TTY
|
||||
```
|
||||
in: R4=address of string (terminated by 00h)
|
||||
```
|
||||
@ -2424,32 +2424,32 @@ in a special way: If R4 points to a 00h character then nothing is output (as
|
||||
one would expect it), but, if R4 is 00000000h then "\<NULL\>" is output
|
||||
(only that six letters; without appending any CR or LF).<br/>
|
||||
|
||||
#### A(3Dh) or B(3Eh) std_in_gets(dst) - Read string from TTY (keyboard input)
|
||||
#### A(3Dh) or B(3Eh) std\_in\_gets(dst) - Read string from TTY (keyboard input)
|
||||
```
|
||||
in: r4=dst (pointer to a 128-byte buffer) - out: r2=dst (same is incoming r4)
|
||||
```
|
||||
Internally uses "std_in_getchar" to receive the separate characters (which are
|
||||
Internally uses "std\_in\_getchar" to receive the separate characters (which are
|
||||
thus masked by 7Fh). The received characters are stored in the buffer, and are
|
||||
additionally sent back as echo to the TTY via std_out_putc.<br/>
|
||||
additionally sent back as echo to the TTY via std\_out\_putc.<br/>
|
||||
The following characters are handled in a special way: 09h (TAB) is replaced by
|
||||
a single SPC. 08h or 7FH (BS or DEL) are removing the last character from the
|
||||
buffer (unless it is empty) and send 08h,20h,08h (BS,SPC,BS) to the TTY. 0Dh or
|
||||
0Ah (CR or LF) do terminate the input (append 00h to the buffer, send 0Ah to
|
||||
the TTY, which is expanded to 0Dh,0Ah by the std_out_putc function, and do then
|
||||
return from the std_in_gets function).<br/>
|
||||
the TTY, which is expanded to 0Dh,0Ah by the std\_out\_putc function, and do then
|
||||
return from the std\_in\_gets function).<br/>
|
||||
The sequence 16h,NNh forces NNh to be stored in the buffer (even if NNh is a
|
||||
special character like 00h..1Fh or 7Fh). If the buffer is full (circa max 125
|
||||
chars, plus one extra byte for the ending 00h), or if an unknown control code
|
||||
in range of 00h..1Fh is received without the 16h prefix, then 07h (BELL) is
|
||||
sent to the TTY.<br/>
|
||||
|
||||
#### A(3Bh) or B(3Ch) std_in_getchar() - Read character from TTY
|
||||
#### A(3Bh) or B(3Ch) std\_in\_getchar() - Read character from TTY
|
||||
Reads one character from the TTY console, by internally redirecting to
|
||||
"FileRead(0,tempbuf,1)". The returned character is ANDed by 7Fh (so, to read a
|
||||
fully intact 8bit character, "FileRead(0,tempbuf,1)" must be used instead of
|
||||
this function).<br/>
|
||||
|
||||
#### A(3Ch) or B(3Dh) std_out_putchar(char) - Write character to TTY
|
||||
#### A(3Ch) or B(3Dh) std\_out\_putchar(char) - Write character to TTY
|
||||
Writes the character to the TTY console, by internally redirecting to
|
||||
"FileWrite(1,tempbuf,1)". Char 09h (TAB) is expanded to one or more SPC
|
||||
characters, until reaching the next tabulation boundary (every 8 characters).
|
||||
@ -2458,22 +2458,22 @@ should be handled at the remote terminal side) are 08h (BS, backspace, move
|
||||
cursor one position to the left), and 07h (BELL, produce a short beep sound).<br/>
|
||||
|
||||
#### C(13h) FlushStdInOutPut()
|
||||
Closes and re-opens the std_in (fd=0) and std_out (fd=1) file handles.<br/>
|
||||
Closes and re-opens the std\_in (fd=0) and std\_out (fd=1) file handles.<br/>
|
||||
|
||||
#### C(1Bh) KernelRedirect(ttyflag) ;PS2: ttyflag=1 causes SystemError
|
||||
Removes, re-mounts, and flushes the TTY device, the parameter selects whether
|
||||
to mount the real DUART-TTY device (r4=1), or a Dummy-TTY device (r4=0), the
|
||||
latter one sends any std_out to nowhere. Values other than r4=0 or r4=1 do
|
||||
latter one sends any std\_out to nowhere. Values other than r4=0 or r4=1 do
|
||||
remove the device, but do not re-mount it (which might result in problems).<br/>
|
||||
Caution: Trying to use r4=1 on a PSX that does not has the DUART hardware
|
||||
installed causes the BIOS to hang (so one should first detect the DUART
|
||||
hardware, eg. by writing two different bytes to Port 1F802020h.1st/2nd access,
|
||||
and the read and verify that two bytes).<br/>
|
||||
|
||||
#### Activating std_io
|
||||
The std_io functions can be enabled via C(1Bh) KernelRedirect(ttyflag), the
|
||||
#### Activating std\_io
|
||||
The std\_io functions can be enabled via C(1Bh) KernelRedirect(ttyflag), the
|
||||
BIOS is unable to detect the presence of the TTY hardware, by default the BIOS
|
||||
bootcode disables std_io by setting the initial KernelRedirect value at
|
||||
bootcode disables std\_io by setting the initial KernelRedirect value at
|
||||
[A000B9B0h] to zero, this is hardcoded shortly after the POST(E) output:<br/>
|
||||
```
|
||||
call output_post_r4 ;\output POST(E)
|
||||
@ -2507,19 +2507,19 @@ handles (fd=0 and fd=1) would cause such functions to work unstable.<br/>
|
||||
|
||||
|
||||
## BIOS Character Sets
|
||||
#### B(51h) Krom2RawAdd(shiftjis_code)
|
||||
#### B(51h) Krom2RawAdd(shiftjis\_code)
|
||||
```
|
||||
In: r4 = 16bit Shift-JIS character code
|
||||
Out: r2 = address in BIOS ROM of the desired character (or -1 = error)
|
||||
```
|
||||
r4 should be 8140h..84BEh (charset 2), or 889Fh..9872h (charset 3).<br/>
|
||||
|
||||
#### B(53h) Krom2Offset(shiftjis_code)
|
||||
#### B(53h) Krom2Offset(shiftjis\_code)
|
||||
```
|
||||
In: r4 = 16bit Shift-JIS character code
|
||||
Out: r2 = offset within charset (without charset base address)
|
||||
```
|
||||
This is a subfunction for B(51h) Krom2RawAdd(shiftjis_code).<br/>
|
||||
This is a subfunction for B(51h) Krom2RawAdd(shiftjis\_code).<br/>
|
||||
|
||||
#### Character Sets in ROM (112Kbytes)
|
||||
The character sets are located at BFC64000h and up, intermixed with some other
|
||||
@ -2543,7 +2543,7 @@ char(8FA6E0h..8FABF7h).<br/>
|
||||
Version (and Copyright) string is NOT included in SCPH1000 version (that BIOS
|
||||
includes further japanese 8x15 pix chars in that region).<br/>
|
||||
For charset 2 and 3 it may be recommended to use the B(51h)
|
||||
Krom2RawAdd(shiftjis_code) to obtain the character addresses. Not sure if that
|
||||
Krom2RawAdd(shiftjis\_code) to obtain the character addresses. Not sure if that
|
||||
BIOS function (or another BIOS function) allows to retrieve charset 1, 4, 5,
|
||||
and 6 addresses?<br/>
|
||||
|
||||
@ -2745,7 +2745,7 @@ care), so the nocash PSX bios (or other homebrewn BIOSes) can detect and
|
||||
reproduce them. Or alternately, don't use the BIOS, and access I/O ports
|
||||
directly, which is much better and faster anyways.<br/>
|
||||
|
||||
#### patch_missing_cop0r13_in_exception_handler:
|
||||
#### patch\_missing\_cop0r13\_in\_exception\_handler:
|
||||
In newer Kernel version, the exception handler reads cop0r13/cause to r2,
|
||||
examines the Excode value in r2, and if the exception was caused by an
|
||||
interrupt, and if the next opcode (at EPC) is a GTE/COP2 command, then it does
|
||||
@ -2792,7 +2792,7 @@ Racer at 80047B14h:<br/>
|
||||
175BFFFC jne k0,k1,@@copy_lop ; 40026800 mov r2,cop0r13
|
||||
AC43FFFC +mov [r2-4h],r3 ;/ 00000000 nop
|
||||
```
|
||||
Alternately, slightly different code used in metal_gear_solid at 80095CC0h, and
|
||||
Alternately, slightly different code used in metal\_gear\_solid at 80095CC0h, and
|
||||
in alone1 at 800A3ECCh:<br/>
|
||||
```
|
||||
24090056 mov r9,56h ;\
|
||||
@ -2864,7 +2864,7 @@ Alternately, a bugged/nonfunctional homebrew variant (used by Hitmen's
|
||||
@@verify_mismatch:
|
||||
```
|
||||
|
||||
#### early_card_irq_patch:
|
||||
#### early\_card\_irq\_patch:
|
||||
Because of a hardware glitch the card IRQ cannot be acknowledged while the
|
||||
external IRQ signal is still LOW, making it neccessary to insert a delay that
|
||||
waits until the signal gets HIGH before acknowledging the IRQ.<br/>
|
||||
@ -2938,13 +2938,13 @@ Alternately, elo2 uses slightly different code at 8003961Ch:<br/>
|
||||
AC22xxxx +mov [r1+xxxxh],r2 ;/ ;03E00008 ret
|
||||
... ;00000000 +nop
|
||||
```
|
||||
Note: The above @@wait_lop's should be more preferably done with timeouts (else
|
||||
Note: The above @@wait\_lop's should be more preferably done with timeouts (else
|
||||
they may hang endless if a Sony Mouse is newly connected; the mouse does have
|
||||
/ACK stuck LOW on power-up).<br/>
|
||||
|
||||
#### patch_uninstall_early_card_irq_handler:
|
||||
Used to uninstall the "early_card_irq_vector" (the BIOS installs that vector
|
||||
from inside of B(4Ah) InitCard(pad_enable), and, without patches, the BIOS
|
||||
#### patch\_uninstall\_early\_card\_irq\_handler:
|
||||
Used to uninstall the "early\_card\_irq\_vector" (the BIOS installs that vector
|
||||
from inside of B(4Ah) InitCard(pad\_enable), and, without patches, the BIOS
|
||||
doesn't allow to uninstall it thereafter).<br/>
|
||||
Used in Breath of Fire III (SLES-01304) at 8017E790, and also in Ace Combat 2
|
||||
(SLUS-00404) at 801D23F4:<br/>
|
||||
@ -2984,11 +2984,11 @@ Alternately, more inefficient, used in Blaster Master-Blasting Again
|
||||
1549FFFB jne r10,r9,@@copy_lop ; @@new_data_end:
|
||||
24420004 +add r2,4h ;dst ;/
|
||||
```
|
||||
Note: the above code is same as "patch_install_lightgun_irq_handler", except
|
||||
Note: the above code is same as "patch\_install\_lightgun\_irq\_handler", except
|
||||
that it writes to r2+70h, instead of r2+80h.<br/>
|
||||
|
||||
#### patch_card_specific_delay:
|
||||
Same purpose as the "early_card_irq_patch" (but for the command/status bytes
|
||||
#### patch\_card\_specific\_delay:
|
||||
Same purpose as the "early\_card\_irq\_patch" (but for the command/status bytes
|
||||
rather than for the data bytes). The patch looks buggy since it inserts the
|
||||
delay AFTER the acknowledge, but it DOES work (the BIOS accidently acknowledges
|
||||
the IRQ twice; and the delay occurs PRIOR to 2nd acknowledge).<br/>
|
||||
@ -3037,8 +3037,8 @@ Evil 2 at 800910E4h:<br/>
|
||||
AC4809C4 +mov [r2+9C4h],r8 ;
|
||||
```
|
||||
|
||||
#### patch_card_info_step4:
|
||||
The "card_info" function sends an incomplete read command to the card; in order
|
||||
#### patch\_card\_info\_step4:
|
||||
The "card\_info" function sends an incomplete read command to the card; in order
|
||||
to receive status information. After receiving the last byte, the function does
|
||||
accidently send a further byte to the card, so the card responds by another
|
||||
byte (and another IRQ7), which is not processed nor acknowledged by the BIOS.
|
||||
@ -3057,10 +3057,10 @@ Used in alone1 at 800AE214h:<br/>
|
||||
AC600000 +mov [r3],0 ;=nop ;/
|
||||
```
|
||||
|
||||
#### patch_pad_error_handling_and_get_pad_enable_functions:
|
||||
#### patch\_pad\_error\_handling\_and\_get\_pad\_enable\_functions:
|
||||
If a transmission error occurs (or if there's no controller connected), then
|
||||
the Pad handler handler does usually issue a strange chip select signal to the
|
||||
OTHER controller slot, and does then execute the bizarre_pad_delay function.
|
||||
OTHER controller slot, and does then execute the bizarre\_pad\_delay function.
|
||||
The patch below overwrites that behaviour by NOPs. Purpose of the original (and
|
||||
patched) behaviour is unknown.<br/>
|
||||
Used by Perfect Assassin at 800519D4h:<br/>
|
||||
@ -3119,7 +3119,7 @@ Pandemonium II (at 80083C94h and at 8010B77Ch):<br/>
|
||||
24420004 +add r2,4h ;/
|
||||
```
|
||||
|
||||
#### patch_optional_pad_output:
|
||||
#### patch\_optional\_pad\_output:
|
||||
The normal BIOS functions are only allowing to READ from the controllers, but
|
||||
not to SEND data to them (which would be required to control Rumble motors, and
|
||||
to auto-activate Analog mode without needing the user to press the Analog
|
||||
@ -3177,7 +3177,7 @@ Alternately, more inefficient (with NOPs), used in Lemmings at 80036618h:<br/>
|
||||
00000000 +nop ;/
|
||||
```
|
||||
|
||||
#### patch_no_pad_card_auto_ack:
|
||||
#### patch\_no\_pad\_card\_auto\_ack:
|
||||
This patch suppresses automatic IRQ0 (vblank) acknowleding in the Pad/Card IRQ
|
||||
handler, that, even if auto-ack is enabled. Obviously, one could as well
|
||||
disable auto-ack via B(5Bh) ChangeClearPad(int), so this patch is total
|
||||
@ -3220,7 +3220,7 @@ actually support the same IRQ to be processed by two different IRQ handlers,
|
||||
eg. the custom handler may acknowledge the IRQ even when the Pad/Card handler
|
||||
didn't process it, so pad input may become bumpy.<br/>
|
||||
|
||||
#### patch_install_lightgun_irq_handler:
|
||||
#### patch\_install\_lightgun\_irq\_handler:
|
||||
Used in Sporting Clays at 80027D68h (when Konami Lightgun connected):<br/>
|
||||
```
|
||||
240A00B0 mov r10,0B0h ;\
|
||||
@ -3265,11 +3265,11 @@ coordinate (timer0) to a variable in RAM, thus getting the timer0 value
|
||||
unpredictable timing offsets that could be caused by cache hits/misses during
|
||||
later IRQ handling (and may also eliminate a rather irrelevant 1-cycle
|
||||
inaccuracy depending on whether EPC was pointing to a GTE opcode, and also
|
||||
eliminates constant cycle offsets depending on whether early_card_irq_handler
|
||||
eliminates constant cycle offsets depending on whether early\_card\_irq\_handler
|
||||
was installed and enabled, and might eliminate timing differences for different
|
||||
BIOS versions).<br/>
|
||||
|
||||
#### set_conf_without_realloc:
|
||||
#### set\_conf\_without\_realloc:
|
||||
Used in Spec Ops Airborne Commando at 80070AE8h, and also in the homebrew game
|
||||
Roll Boss Rush at 80010B68h and 8001B85Ch. Purpose is unknown (maybe to
|
||||
override improperly defined .EXE headers).<br/>
|
||||
|
@ -120,7 +120,7 @@ These commands act identical as MDEC(0).<br/>
|
||||
|
||||
|
||||
## MDEC Decompression
|
||||
#### decode_colored_macroblock ;MDEC(1) command (at 15bpp or 24bpp depth)
|
||||
#### decode\_colored\_macroblock ;MDEC(1) command (at 15bpp or 24bpp depth)
|
||||
```
|
||||
rl_decode_block(Crblk,src,iq_uv) ;Cr (low resolution)
|
||||
rl_decode_block(Cbblk,src,iq_uv) ;Cb (low resolution)
|
||||
@ -130,12 +130,12 @@ These commands act identical as MDEC(0).<br/>
|
||||
rl_decode_block(Yblk,src,iq_y), yuv_to_rgb(8,8) ;Y4 (and lower-right Cr,Cb)
|
||||
```
|
||||
|
||||
#### decode_monochrome_macroblock ;MDEC(1) command (at 4bpp or 8bpp depth)
|
||||
#### decode\_monochrome\_macroblock ;MDEC(1) command (at 4bpp or 8bpp depth)
|
||||
```
|
||||
rl_decode_block(Yblk,src,iq_y), y_to_mono ;Y
|
||||
```
|
||||
|
||||
#### rl_decode_block(blk,src,qt)
|
||||
#### rl\_decode\_block(blk,src,qt)
|
||||
```
|
||||
for i=0 to 63, blk[i]=0, next i ;initially zerofill all entries (for skip)
|
||||
@@skip:
|
||||
@ -157,7 +157,7 @@ These commands act identical as MDEC(0).<br/>
|
||||
return (with "src" address advanced)
|
||||
```
|
||||
|
||||
#### fast_idct_core(blk) ;fast "idct_core" version
|
||||
#### fast\_idct\_core(blk) ;fast "idct\_core" version
|
||||
Fast code with only 80 multiplications, works only if the scaletable from
|
||||
MDEC(3) command contains standard values (which is the case for all known PSX
|
||||
games).<br/>
|
||||
@ -189,9 +189,9 @@ games).<br/>
|
||||
next pass
|
||||
```
|
||||
|
||||
#### real_idct_core(blk) ;low level "idct_core" version
|
||||
#### real\_idct\_core(blk) ;low level "idct\_core" version
|
||||
Low level code with 1024 multiplications, using the scaletable from the MDEC(3)
|
||||
command. Computes dst=src*scaletable (using normal matrix maths, but with "src"
|
||||
command. Computes dst=src\*scaletable (using normal matrix maths, but with "src"
|
||||
being diagonally mirrored, ie. the matrices are processed column by column,
|
||||
instead of row by column), repeated with src/dst exchanged.<br/>
|
||||
```
|
||||
@ -215,9 +215,9 @@ working roughly like that, still the results aren't perfect.<br/>
|
||||
Maybe the real hardware is doing further roundings in other places, possibly
|
||||
stripping some fractional bits before summing up "sum", possibly stripping
|
||||
different amounts of bits in the two "pass" cycles, and possibly keeping a
|
||||
final fraction passed on to the y_to_mono stage.<br/>
|
||||
final fraction passed on to the y\_to\_mono stage.<br/>
|
||||
|
||||
#### yuv_to_rgb(xx,yy)
|
||||
#### yuv\_to\_rgb(xx,yy)
|
||||
```
|
||||
for y=0 to 7
|
||||
for x=0 to 7
|
||||
@ -232,10 +232,10 @@ final fraction passed on to the y_to_mono stage.<br/>
|
||||
next x
|
||||
next y
|
||||
```
|
||||
Note: The exact fixed point resolution for "yuv_to_rgb" is unknown. And,
|
||||
there's probably also some 9bit limit (similar as in "y_to_mono").<br/>
|
||||
Note: The exact fixed point resolution for "yuv\_to\_rgb" is unknown. And,
|
||||
there's probably also some 9bit limit (similar as in "y\_to\_mono").<br/>
|
||||
|
||||
#### y_to_mono
|
||||
#### y\_to\_mono
|
||||
```
|
||||
for i=0 to 63
|
||||
Y=[Yblk+i]
|
||||
@ -246,7 +246,7 @@ there's probably also some 9bit limit (similar as in "y_to_mono").<br/>
|
||||
next i
|
||||
```
|
||||
|
||||
#### set_iqtab ;MDEC(2) command
|
||||
#### set\_iqtab ;MDEC(2) command
|
||||
```
|
||||
iqtab_core(iq_y,src), src=src+64 ;luminance quant table
|
||||
if command_word.bit0=1
|
||||
@ -254,15 +254,15 @@ there's probably also some 9bit limit (similar as in "y_to_mono").<br/>
|
||||
endif
|
||||
```
|
||||
|
||||
#### iqtab_core(iq,src) ;src = 64 unsigned paramter bytes
|
||||
#### iqtab\_core(iq,src) ;src = 64 unsigned paramter bytes
|
||||
```
|
||||
for i=0 to 63, iq[i]=src[i], next i
|
||||
```
|
||||
Note: For "fast_idct_core" one could precalc "iq[i]=src[i]*scalezag[i]", but
|
||||
Note: For "fast\_idct\_core" one could precalc "iq[i]=src[i]\*scalezag[i]", but
|
||||
that would conflict with the RLE saturation/rounding steps (though those steps
|
||||
aren't actually required, so a very-fast decoder could omit them).<br/>
|
||||
|
||||
#### scalefactor[0..7] = cos((0..7)*90'/8) ;for [1..7]: multiplied by sqrt(2)
|
||||
#### scalefactor[0..7] = cos((0..7)\*90'/8) ;for [1..7]: multiplied by sqrt(2)
|
||||
```
|
||||
1.000000000, 1.387039845, 1.306562965, 1.175875602,
|
||||
1.000000000, 0.785694958, 0.541196100, 0.275899379
|
||||
@ -280,7 +280,7 @@ aren't actually required, so a very-fast decoder could omit them).<br/>
|
||||
35,36,48,49,57,58,62,63
|
||||
```
|
||||
|
||||
#### scalezag[0..63] (precalulated factors, for "fast_idct_core")
|
||||
#### scalezag[0..63] (precalulated factors, for "fast\_idct\_core")
|
||||
```
|
||||
for y=0 to 7
|
||||
for x=0 to 7
|
||||
@ -294,7 +294,7 @@ aren't actually required, so a very-fast decoder could omit them).<br/>
|
||||
for i=0 to 63, zagzig[zigzag[i]]=i, next i
|
||||
```
|
||||
|
||||
#### set_scale_table: ;MDEC(3) command
|
||||
#### set\_scale\_table: ;MDEC(3) command
|
||||
This command defines the IDCT scale matrix, which should be usually/always:<br/>
|
||||
```
|
||||
5A82 5A82 5A82 5A82 5A82 5A82 5A82 5A82
|
||||
|
@ -47,7 +47,7 @@ the internal I/O ports, and crash the PSX. The Size bits seem to be ignored for
|
||||
SPU/CDROM. The SPU timings seem to be applied for both the 200h-byte SPU region
|
||||
at 1F801C00h and for the 200h-byte unknown region at 1F801E00h.<br/>
|
||||
|
||||
#### 1F801020h - COM_DELAY / COMMON_DELAY (00031125h or 0000132Ch or 00001325h)
|
||||
#### 1F801020h - COM\_DELAY / COMMON\_DELAY (00031125h or 0000132Ch or 00001325h)
|
||||
```
|
||||
0-3 COM0 - Offset A ;used for SPU/EXP2 (and for adjusted CDROM timings)
|
||||
4-7 COM1 - No effect? ;used for EXP2
|
||||
@ -76,7 +76,7 @@ values or so).<br/>
|
||||
And the purpose... probably allows to define the length of the chipselect
|
||||
signals, and of gaps between that signals...?<br/>
|
||||
|
||||
#### 1F801060h - RAM_SIZE (R/W) (usually 00000B88h) (or 00000888h)
|
||||
#### 1F801060h - RAM\_SIZE (R/W) (usually 00000B88h) (or 00000888h)
|
||||
```
|
||||
0-2 Unknown (no effect)
|
||||
3 Crashes when zero (except PU-7 and EARLY-PU-8, which <do> set bit3=0)
|
||||
@ -105,7 +105,7 @@ seems to be always Locked.<br/>
|
||||
The HighZ regions are FFh-filled, that even when grounding data lines on the
|
||||
system bus (ie. it is NOT a mirror of the PIO expansion region).<br/>
|
||||
Locked means that the CPU generates an exception when accessing that area.<br/>
|
||||
Note: Wipeout uses a BIOS function that changes RAM_SIZE to 00000888h (ie. with
|
||||
Note: Wipeout uses a BIOS function that changes RAM\_SIZE to 00000888h (ie. with
|
||||
corrected size of 2MB, and with the unknown Bit8 cleared). Gundam Battle
|
||||
Assault 2 does actually use the "8MB" space (with stacktop in mirrored RAM at
|
||||
807FFFxxh).<br/>
|
||||
|
@ -733,7 +733,7 @@ while power is on, better measure them at the CPU side.<br/>
|
||||
Pin 1..36 = MIPS-CPU bus. Pin 45..87 = SPU-RAM bus (A0,A10-A15,/WE1,OE1=NC).
|
||||
Pin 91..99 = Digital serial audio in/out (A=CDROM, B=EXP, O=OUT).<br/>
|
||||
|
||||
#### IC732 - SONY CXD2941R (SPU+CDROM+SPU_RAM) (on PM-41(2) boards)
|
||||
#### IC732 - SONY CXD2941R (SPU+CDROM+SPU\_RAM) (on PM-41(2) boards)
|
||||
```
|
||||
1-DA16 23-FILO 45-LOCK 67-FSTO 89-SCSY 111-XCS 133-HD9 155-VSS5
|
||||
2-DA15 24-FILI 46-SSTP 68-COUT 90-SCLK 112-XRD 134-HD8 156-HA1
|
||||
@ -824,7 +824,7 @@ SPU.Pin42 via capacitor to SPU.Pin41, and via resistor?/diode? to IC723.10<br/>
|
||||
SPU206 (*) circa 2.27MHz
|
||||
SPU70 (*) whatever clock (with SHORT low pulses)
|
||||
```
|
||||
(*) these frequencies are twice as fast in double speed mode.<br/>
|
||||
(\*) these frequencies are twice as fast in double speed mode.<br/>
|
||||
|
||||
#### CXD2938Q CDROM signals
|
||||
```
|
||||
@ -970,7 +970,7 @@ and even later boards have it integrated in the SPU.<br/>
|
||||
```
|
||||
Datasheet exists. The CXD2545Q combines the functionality of CXA1782BR+CXD2510Q
|
||||
from older boards (later boards have it integrated in the SPU). XTAI/XTAO input
|
||||
is 16.9344MHz (44.1kHz*180h), with XTSL=GND. Clock outputs are
|
||||
is 16.9344MHz (44.1kHz\*180h), with XTSL=GND. Clock outputs are
|
||||
FSTO=16.9344MHz/3, FSOF=16.9344MHz/4, C16M=16.9344MHz/1.<br/>
|
||||
|
||||
#### IC101 - SONY CXD2515Q - Signal Processor + Servo Amp (used on DTL-H2010)
|
||||
|
346
pocketstation.md
346
pocketstation.md
@ -153,7 +153,7 @@ BIOS and FLASH can be read only in 16bit and 32bit units (not 8bit).<br/>
|
||||
Upon reset, BIOS ROM is mirrored to address 00000000h (instead of RAM).<br/>
|
||||
For most I/O ports, it is unknown if they are (R), (W), or (R/W)...?<br/>
|
||||
I/O ports are usually accessed at 32bit width, occassionally some ports are
|
||||
(alternately) accessed at 16bit width. A special case are the F_SN registers
|
||||
(alternately) accessed at 16bit width. A special case are the F\_SN registers
|
||||
which seem to be required to be accessed at 16bit (not 32bit).<br/>
|
||||
|
||||
#### Memory Access Time
|
||||
@ -171,7 +171,7 @@ Memory Access Time for Data Read/Write:<br/>
|
||||
For data access, it doesn't matter if the access is 8bit/16bit/32bit (unlike as
|
||||
for opcode fetch, where 16bit/thumb can be faster than 32bit/arm). There seems
|
||||
to be no timing differences for sequential/non-sequential access.<br/>
|
||||
Additional memory waitstates can be added via F_WAIT2 (and F_WAIT1 maybe).<br/>
|
||||
Additional memory waitstates can be added via F\_WAIT2 (and F\_WAIT1 maybe).<br/>
|
||||
|
||||
#### Invalid/Unused Memory Locations
|
||||
```
|
||||
@ -221,8 +221,8 @@ Additional memory waitstates can be added via F_WAIT2 (and F_WAIT1 maybe).<br/>
|
||||
0B800002h-0BFFFFFEh RTC area, odd addresses (with A1=1) mirror to 0B80000Ah
|
||||
```
|
||||
|
||||
#### garbage_byte (for unsupported 8bit reads)
|
||||
The "garbage_byte" depends on the LSBs of the read address, prefetched opcodes,
|
||||
#### garbage\_byte (for unsupported 8bit reads)
|
||||
The "garbage\_byte" depends on the LSBs of the read address, prefetched opcodes,
|
||||
and recent data fetches:<br/>
|
||||
```
|
||||
garbage_word = (prefetch OR (ramdata AND FFFFFFD0h))
|
||||
@ -250,7 +250,7 @@ There might be some more/unknown things that affect the garbage (eg. opcode
|
||||
fetches from RAM instead of FLASH, partial 8bit/16bit data reads from RAM, or
|
||||
reads from I/O areas, current CPU clock speed, or unpredictable things like
|
||||
temperature).<br/>
|
||||
Note: The garbage_byte is "used" by the pocketstation "Rockman" series games.<br/>
|
||||
Note: The garbage\_byte is "used" by the pocketstation "Rockman" series games.<br/>
|
||||
|
||||
|
||||
|
||||
@ -333,7 +333,7 @@ can be freely read/written in 8bit, 16bit, and 32bit units.<br/>
|
||||
|
||||
#### Waitstates
|
||||
Unknown if and how many waitstates are applied to the different memory regions.
|
||||
The F_WAIT1 and F_WAIT2 registers seem to be somehow waitstate related. FLASH
|
||||
The F\_WAIT1 and F\_WAIT2 registers seem to be somehow waitstate related. FLASH
|
||||
memory does probably have a 16bit bus, so 32bit data/opcode fetches might be
|
||||
slower then 16bit reads...? Similar delays might happen for other memory and
|
||||
I/O regions...?<br/>
|
||||
@ -341,7 +341,7 @@ I/O regions...?<br/>
|
||||
|
||||
|
||||
## Pocketstation IO Video and Audio
|
||||
#### 0D000000h - LCD_MODE - LCD control word (R/W)
|
||||
#### 0D000000h - LCD\_MODE - LCD control word (R/W)
|
||||
```
|
||||
0-2 Draw mode; seems to turn off bits of the screen;
|
||||
0: All 32 rows on ;\
|
||||
@ -363,17 +363,17 @@ I/O regions...?<br/>
|
||||
7 Rotate display by 180 degrees (0=For Handheld Mode, 1=For Docked Mode)
|
||||
8-31 Unknown (should be zero)
|
||||
```
|
||||
Software should usually set LCD_MODE.7 equal to INT_INPUT.Bit11 (docking flag).
|
||||
Software should usually set LCD\_MODE.7 equal to INT\_INPUT.Bit11 (docking flag).
|
||||
In handheld mode, the button-side is facing towards the player, whilst in
|
||||
Docked mode (when the Pocketstation is inserted into the PSX controller port),
|
||||
the button-side is facing towards the PSX, so the screen coordinates become
|
||||
vice-versa, which can be "undone" by the Rotation flag.<br/>
|
||||
|
||||
#### 0D000004h - LCD_CAL - LCD Calibration (maybe contrast or so?)
|
||||
Upon the reset, the kernel sets LCD_CAL = F_CAL AND 0000003Fh. Aside from that,
|
||||
it doesn't use LCD_CAL.<br/>
|
||||
#### 0D000004h - LCD\_CAL - LCD Calibration (maybe contrast or so?)
|
||||
Upon the reset, the kernel sets LCD\_CAL = F\_CAL AND 0000003Fh. Aside from that,
|
||||
it doesn't use LCD\_CAL.<br/>
|
||||
|
||||
#### 0D000100h..D00017Fh - LCD_VRAM - 32x32 pixels, 1bit color depth (R/W)
|
||||
#### 0D000100h..D00017Fh - LCD\_VRAM - 32x32 pixels, 1bit color depth (R/W)
|
||||
This region consists of 32 words (32bit values),<br/>
|
||||
```
|
||||
[D000100h]=Top, through [D00017Ch]=Bottom-most scanline
|
||||
@ -383,19 +383,19 @@ The separate scanlines consist of 32bit each,<br/>
|
||||
Bit0=Left, through Bit31=Right-most Pixel (0=White, 1=Black)
|
||||
```
|
||||
That [D000100h].Bit0=Upper-left arrangement applies if the Rotate bit in
|
||||
LCD_MODE.7 is set up in the conventional way, if it is set the opposite way,
|
||||
LCD\_MODE.7 is set up in the conventional way, if it is set the opposite way,
|
||||
then it becomes [D00017Ch].Bit31=Upper-left.<br/>
|
||||
The LCD_VRAM area is reportedly mirrored to whatever locations?<br/>
|
||||
The LCD\_VRAM area is reportedly mirrored to whatever locations?<br/>
|
||||
|
||||
#### 0D800010h - DAC_CTRL - Audio Control (R/W)
|
||||
#### 0D800010h - DAC\_CTRL - Audio Control (R/W)
|
||||
```
|
||||
0 Audio Enable enable (0=Off, 1=On)
|
||||
1-31 Unknown, usually zero
|
||||
```
|
||||
Note: Aside from the bit in DAC_CTRL, audio must be also enabled/disabled via
|
||||
IOP_STOP/IOP_START bit5. Unknown if/which different purposes that bits have.<br/>
|
||||
Note: Aside from the bit in DAC\_CTRL, audio must be also enabled/disabled via
|
||||
IOP\_STOP/IOP\_START bit5. Unknown if/which different purposes that bits have.<br/>
|
||||
|
||||
#### 0D800014h - DAC_DATA - Audio D/A Converter
|
||||
#### 0D800014h - DAC\_DATA - Audio D/A Converter
|
||||
Unknown how many bits are passed to the D/A converter, probably bit8-15, ie. 8
|
||||
bits...?<br/>
|
||||
```
|
||||
@ -404,7 +404,7 @@ bits...?<br/>
|
||||
16-31 Probably unused, usually sign-expanded from bit15
|
||||
```
|
||||
The Pocketstation doesn't have any square wave or noise generator (nor a sound
|
||||
DMA channel). So the output levels must be written to DAC_DATA by software,
|
||||
DMA channel). So the output levels must be written to DAC\_DATA by software,
|
||||
this is usually done via Timer1/IRQ-8 (to reduce CPU load caused by high audio
|
||||
frequencies, it may be much more recommended to use Timer2/FIQ-13, because the
|
||||
FIQ handler doesn't need to push r8-r12).<br/>
|
||||
@ -417,7 +417,7 @@ probably increased anyways when the speaker is enabled).<br/>
|
||||
|
||||
|
||||
## Pocketstation IO Interrupts and Buttons
|
||||
#### 0A000004h - INT_INPUT - Raw Interrupt Signal Levels (R)
|
||||
#### 0A000004h - INT\_INPUT - Raw Interrupt Signal Levels (R)
|
||||
```
|
||||
Bit Type Meaning
|
||||
0 IRQ Button Fire (0=Released, 1=Pressed)
|
||||
@ -442,30 +442,30 @@ usually used to wakeup). Also, bit9-11 are often read from this register.<br/>
|
||||
The direction keys seem to be separate buttons, ie. unlike as on a joystick or
|
||||
DPAD, Left/Right (and Up/Down) can be simultaneously pressed...?<br/>
|
||||
|
||||
#### 0A000008h - INT_MASK_SET - Set Interrupt Mask (W)
|
||||
#### 0A00000Ch - INT_MASK_CLR - Clear Interrupt Mask (W)
|
||||
#### 0A000008h - INT_MASK_READ - Read Interrupt Mask (R)
|
||||
#### 0A000008h - INT\_MASK\_SET - Set Interrupt Mask (W)
|
||||
#### 0A00000Ch - INT\_MASK\_CLR - Clear Interrupt Mask (W)
|
||||
#### 0A000008h - INT\_MASK\_READ - Read Interrupt Mask (R)
|
||||
```
|
||||
INT_MASK_SET Enable Interrupt Flags (0=No change, 1=Enable) (W)
|
||||
INT_MASK_CLR Disable Interrupt Flags (0=No change, 1=Disable) (W)
|
||||
INT_MASK_READ Current Interrupt Enable Flags (0=Disabled, 1=Enabled) (R)
|
||||
```
|
||||
The locations of the separate bits are same as in INT_INPUT (see there).<br/>
|
||||
The locations of the separate bits are same as in INT\_INPUT (see there).<br/>
|
||||
|
||||
#### 0A000000h - INT_LATCH - Interrupt Request Flags (R)
|
||||
#### 0A000010h - INT_ACK - Acknowledge Interrupts (W)
|
||||
#### 0A000000h - INT\_LATCH - Interrupt Request Flags (R)
|
||||
#### 0A000010h - INT\_ACK - Acknowledge Interrupts (W)
|
||||
```
|
||||
INT_LATCH Latched Interrupt Requests (0=None, 1=Interrupt Request) (R)
|
||||
INT_ACK Clear Interrupt Requests (0=No change, 1=Acknowledge) (W)
|
||||
```
|
||||
The locations of the separate bits are same as in INT_INPUT (see there).<br/>
|
||||
The locations of the separate bits are same as in INT\_INPUT (see there).<br/>
|
||||
The interrupts seem to be edge-triggered (?), ie. when the corresponding bits
|
||||
in INT_INPUT change from 0-to-1. Unknown if the request bits get set when the
|
||||
corresponding interrupt is disabled in INT_MASK...?<br/>
|
||||
in INT\_INPUT change from 0-to-1. Unknown if the request bits get set when the
|
||||
corresponding interrupt is disabled in INT\_MASK...?<br/>
|
||||
|
||||
ATTENTION: The GUI doesn't acknowledge Fire Button interrupts on wakeup... so,
|
||||
it seems as if button interrupts are NOT latched... ie. the button "INT_LATCH"
|
||||
bits seem to be just an unlatched mirror of the "INT_INPUT" bits... that might
|
||||
it seems as if button interrupts are NOT latched... ie. the button "INT\_LATCH"
|
||||
bits seem to be just an unlatched mirror of the "INT\_INPUT" bits... that might
|
||||
also apply for some other interrupt...?<br/>
|
||||
However, after wakeup, the gui does DISABLE the Fire Button interrupt, MAYBE
|
||||
that does automatically acknowledge it... in that case it might be latched...?<br/>
|
||||
@ -485,38 +485,38 @@ them... is that really true?<br/>
|
||||
INT_INPUT.9 RTC IRQ (usually 1Hz) (or 4096Hz when RTC paused)
|
||||
```
|
||||
|
||||
#### 0A800000h - T0_RELOAD - Timer 0 Reload Value
|
||||
#### 0A800010h - T1_RELOAD - Timer 1 Reload Value
|
||||
#### 0A800020h - T2_RELOAD - Timer 2 Reload Value
|
||||
#### 0A800000h - T0\_RELOAD - Timer 0 Reload Value
|
||||
#### 0A800010h - T1\_RELOAD - Timer 1 Reload Value
|
||||
#### 0A800020h - T2\_RELOAD - Timer 2 Reload Value
|
||||
```
|
||||
0-15 Reload Value (when timer becomes less than zero)
|
||||
```
|
||||
Writes to this register are ignored if the timer isn't stopped?<br/>
|
||||
|
||||
#### 0A800004h - T0_COUNT - Timer 0 Current value
|
||||
#### 0A800014h - T1_COUNT - Timer 1 Current value
|
||||
#### 0A800024h - T2_COUNT - Timer 2 Current value
|
||||
#### 0A800004h - T0\_COUNT - Timer 0 Current value
|
||||
#### 0A800014h - T1\_COUNT - Timer 1 Current value
|
||||
#### 0A800024h - T2\_COUNT - Timer 2 Current value
|
||||
```
|
||||
0-15 Current value (decrementing)
|
||||
```
|
||||
Timer interrupts: The timers will automatically raise interrupts if they're
|
||||
enabled, there's no need to set a bit anywhere for IRQs (but you need to enable
|
||||
the respect interrupts in INT_MASK).<br/>
|
||||
the respect interrupts in INT\_MASK).<br/>
|
||||
|
||||
#### 0A800008h - T0_MODE - Timer 0 Control
|
||||
#### 0A800018h - T1_MODE - Timer 1 Control
|
||||
#### 0A800028h - T2_MODE - Timer 2 Control
|
||||
#### 0A800008h - T0\_MODE - Timer 0 Control
|
||||
#### 0A800018h - T1\_MODE - Timer 1 Control
|
||||
#### 0A800028h - T2\_MODE - Timer 2 Control
|
||||
```
|
||||
0-1 Timer Divider (0=Div2, 1=Div32, 2=Div512, 3=Div2 too)
|
||||
2 Timer Enable (0=Stop, 1=Decrement)
|
||||
3-15 Unknown (should be zero)
|
||||
```
|
||||
Timers are clocked by the System Clock (usually 4MHz, when CLK_MODE=7), divided
|
||||
Timers are clocked by the System Clock (usually 4MHz, when CLK\_MODE=7), divided
|
||||
by the above divider setting. Note that the System Clock changes when changing
|
||||
the CPU speed via CLK_MODE, so Timer Divider and/or Timer Reload must be
|
||||
the CPU speed via CLK\_MODE, so Timer Divider and/or Timer Reload must be
|
||||
adjusted accordingly.<br/>
|
||||
|
||||
#### 0B800000h - RTC_MODE - RTC control word
|
||||
#### 0B800000h - RTC\_MODE - RTC control word
|
||||
```
|
||||
0 Pause RTC (0=Run/1Hz, 1=Pause/4096Hz)
|
||||
1-3 Select value to be modified via RTC_ADJUST
|
||||
@ -533,35 +533,35 @@ The selection bits can be:<br/>
|
||||
06h = Year ;/
|
||||
07h = Unknown ;-usually used when RTC isn't paused
|
||||
```
|
||||
When paused, the RTC IRQ bit in INT_INPUT.9 runs at 4096Hz (instead 1Hz).<br/>
|
||||
When paused, the RTC IRQ bit in INT\_INPUT.9 runs at 4096Hz (instead 1Hz).<br/>
|
||||
|
||||
#### 0B800004h - RTC_ADJUST - Modify value (write only)
|
||||
#### 0B800004h - RTC\_ADJUST - Modify value (write only)
|
||||
Writing a value here seems to increment the current selected parameter (by the
|
||||
RTC control). What is perhaps (?) clear is that you have to wait for the RTC
|
||||
interrupt signal to go low before writing to this.<br/>
|
||||
|
||||
#### 0B800008h - RTC_TIME - Real-Time Clock Time (read only) (R)
|
||||
#### 0B800008h - RTC\_TIME - Real-Time Clock Time (read only) (R)
|
||||
```
|
||||
0-7 Seconds (00h..59h, BCD)
|
||||
8-15 Minutes (00h..59h, BCD)
|
||||
16-23 Hours (00h..23h, BCD)
|
||||
24-31 Day of week (1=Sunday, ..., 7=Saturday)
|
||||
```
|
||||
Reading RTC_TIME seems to be somewhat unstable: the BIOS uses a read/retry
|
||||
Reading RTC\_TIME seems to be somewhat unstable: the BIOS uses a read/retry
|
||||
loop, until it has read twice the same value (although it does read the whole
|
||||
32bit at once by a LDR opcode, the data is maybe passed through a 8bit or 16bit
|
||||
bus; so the LSBs might be a few clock cycles older than the MSBs...?).<br/>
|
||||
|
||||
#### 0B80000Ch - RTC_DATE - Real-Time Clock Date (read only) (R)
|
||||
#### 0B80000Ch - RTC\_DATE - Real-Time Clock Date (read only) (R)
|
||||
```
|
||||
0-7 Day (01h..31h, BCD)
|
||||
8-11 Month (01h..12h, BCD)
|
||||
16-23 Year (00h..99h, BCD)
|
||||
24-31 Unknown? (this is NOT used as century)
|
||||
```
|
||||
Reading RTC_DATE seems to require the same read/retry method as RTC_TIME (see
|
||||
Reading RTC\_DATE seems to require the same read/retry method as RTC\_TIME (see
|
||||
there). Note: The century is stored in battery-backed RAM (in the reserved
|
||||
kernel RAM region) rather than in the RTC_DATE register. The whole date,
|
||||
kernel RAM region) rather than in the RTC\_DATE register. The whole date,
|
||||
including century, can be read via SWI 0Dh, GetBcdDate().<br/>
|
||||
|
||||
|
||||
@ -573,7 +573,7 @@ IR is used in Final Fantasy 8's Chocobo World (press Left/Right in the Map
|
||||
screen to go to the IR menu), and in Metal Gear Solid Integral (Press Up in the
|
||||
main screen), and in PDA Remote 1 & 2 (one-directional TV remote control).<br/>
|
||||
|
||||
#### 0C800000h - IRDA_MODE - Controlling the protocol - send/recv, etc. (R/W)
|
||||
#### 0C800000h - IRDA\_MODE - Controlling the protocol - send/recv, etc. (R/W)
|
||||
```
|
||||
0 Transfer Direction (0=Receive, 1=Transmit)
|
||||
1 Disable IRDA (0=Enable, 1=Disable)
|
||||
@ -582,7 +582,7 @@ main screen), and in PDA Remote 1 & 2 (one-directional TV remote control).<br/>
|
||||
4-31 Unknown (should be zero)
|
||||
```
|
||||
|
||||
#### 0C800004h - IRDA_DATA - Infrared TX Data
|
||||
#### 0C800004h - IRDA\_DATA - Infrared TX Data
|
||||
```
|
||||
0 Transmit Data in Send Direction (0=LED Off, 1=LED On)
|
||||
1-31 Unknown (should be zero)
|
||||
@ -590,10 +590,10 @@ main screen), and in PDA Remote 1 & 2 (one-directional TV remote control).<br/>
|
||||
Bits are usually encoded as long or short ON pulses, separated by short OFF
|
||||
pulses. Where long is usually twice as long as short.<br/>
|
||||
|
||||
#### 0C80000Ch - IRDA_MISC
|
||||
#### 0C80000Ch - IRDA\_MISC
|
||||
Unknown? Reportedly reserved.<br/>
|
||||
|
||||
#### INT_INPUT.12 - IRQ - Infrared RX Interrupt
|
||||
#### INT\_INPUT.12 - IRQ - Infrared RX Interrupt
|
||||
Seems to get triggered on raising or falling (?) edges of incoming data. The
|
||||
interrupt handler seems to read the current counter value from one of the
|
||||
timers (usually Timer 2, with reload=FFFFh) to determine the length of the
|
||||
@ -611,12 +611,12 @@ pulse:<br/>
|
||||
```
|
||||
that might be maybe done automatically by the hardware...?<br/>
|
||||
|
||||
Reportedly, Bit4 of Port 0D80000Ch (IOP_DATA) is also somewhat IR related...?<br/>
|
||||
Reportedly, Bit4 of Port 0D80000Ch (IOP\_DATA) is also somewhat IR related...?<br/>
|
||||
|
||||
|
||||
|
||||
## Pocketstation IO Memory-Control
|
||||
#### 06000000h - F_CTRL
|
||||
#### 06000000h - F\_CTRL
|
||||
```
|
||||
0-31 Unknown
|
||||
```
|
||||
@ -631,20 +631,20 @@ The GUI does additionally read from this register (and gets itself trapped in a
|
||||
bizarre endless loop if bit0 was zero). Unknown if it's possible to re-enable
|
||||
ROM at location 00000000h by writing any other values to this register?<br/>
|
||||
|
||||
#### 06000004h F_STAT
|
||||
#### 06000004h F\_STAT
|
||||
```
|
||||
0-31 Unknown
|
||||
```
|
||||
The kernel issues a dummy read from this address (before setting F_CTRL to
|
||||
The kernel issues a dummy read from this address (before setting F\_CTRL to
|
||||
00000001h).<br/>
|
||||
|
||||
#### 06000008h F_BANK_FLG ;FLASH virtual bank mapping enable flags (16 bits)(R/W)
|
||||
#### 06000008h F\_BANK\_FLG ;FLASH virtual bank mapping enable flags (16 bits)(R/W)
|
||||
```
|
||||
0-15 Enable physical banks 0..15 in virtual region (0=Disable, 1=Enable)
|
||||
16-31 Unknown (should be zero)
|
||||
```
|
||||
|
||||
#### 06000100h F_BANK_VAL ;FLASH virtual bank mapping addresses (16 words)(R/W)
|
||||
#### 06000100h F\_BANK\_VAL ;FLASH virtual bank mapping addresses (16 words)(R/W)
|
||||
This region contains 16 words, the first word at 06000100h for physical bank 0,
|
||||
the last word at 0600013Ch for physical bank 15. Each word is:<br/>
|
||||
```
|
||||
@ -652,9 +652,9 @@ the last word at 0600013Ch for physical bank 15. Each word is:<br/>
|
||||
4-31 Should be 0
|
||||
```
|
||||
Unused physical banks are usually mapped to 0Fh (and are additionally disabled
|
||||
in the F_BANK_FLG register).<br/>
|
||||
in the F\_BANK\_FLG register).<br/>
|
||||
|
||||
#### 0600000Ch F_WAIT1 ;waitstates...?
|
||||
#### 0600000Ch F\_WAIT1 ;waitstates...?
|
||||
```
|
||||
0..3 Unknown/not tested
|
||||
4 hangs hardware? but that bit is used in some cases!
|
||||
@ -667,10 +667,10 @@ RAM or BIOS ROM). Normally it is set to the following values:<br/>
|
||||
F_WAIT1=00000010h when CPU Speed = 08h..0Fh
|
||||
```
|
||||
Note: The kernels Docking/Undocking IRQ-11 handler does additionally do this:
|
||||
"F_WAIT1=max(08h,(CLK_MODE AND 0Fh))" (that is a bug, what it actually wants to
|
||||
do is to READ the current F_WAIT.Bit4 setting).<br/>
|
||||
"F\_WAIT1=max(08h,(CLK\_MODE AND 0Fh))" (that is a bug, what it actually wants to
|
||||
do is to READ the current F\_WAIT.Bit4 setting).<br/>
|
||||
|
||||
#### 06000010h F_WAIT2 ;waitstates, and FLASH-Write-Control-and-Status...?
|
||||
#### 06000010h F\_WAIT2 ;waitstates, and FLASH-Write-Control-and-Status...?
|
||||
```
|
||||
0 no effect? but that bit is used in some cases! maybe write-enable?
|
||||
1 hangs hardware?
|
||||
@ -683,7 +683,7 @@ do is to READ the current F_WAIT.Bit4 setting).<br/>
|
||||
8..31 Unknown/not tested
|
||||
```
|
||||
Unknown, seems to control some kind of memory waitstates, maybe for another
|
||||
memory region than F_WAIT1, or maybe F_WAIT2 is for writing, and F_WAIT1 for
|
||||
memory region than F\_WAIT1, or maybe F\_WAIT2 is for writing, and F\_WAIT1 for
|
||||
reading or so. Normally it is set to the following values:<br/>
|
||||
```
|
||||
F_WAIT2=00000000h when CPU Speed = 00h..07h ;\same as F_WAIT1
|
||||
@ -700,8 +700,8 @@ Before completion, those SWIs do additionally,<br/>
|
||||
and then set F_WAIT2=00000000h
|
||||
```
|
||||
|
||||
#### 08002A54h - F_KEY1 - Flash Unlock Address 1 (W)
|
||||
#### 080055AAh - F_KEY2 - Flash Unlock Address 2 (W)
|
||||
#### 08002A54h - F\_KEY1 - Flash Unlock Address 1 (W)
|
||||
#### 080055AAh - F\_KEY2 - Flash Unlock Address 2 (W)
|
||||
Unlocks FLASH memory for writing. The complete flowchart for writing sector
|
||||
data (or header values) is:<br/>
|
||||
```
|
||||
@ -727,27 +727,27 @@ During the write operation one can (probably?) not read data (nor opcodes) from
|
||||
FLASH memory, so the above code must be executed either in RAM, or in BIOS ROM
|
||||
(see SWI 03h, SWI 0Fh, SWI 10h).<br/>
|
||||
|
||||
#### 06000300h - F_SN_LO - Serial Number LSBs
|
||||
#### 06000302h - F_SN_HI - Serial Number MSBs
|
||||
#### 06000308h - F_CAL - Calibration value for LCD
|
||||
#### 06000300h - F\_SN\_LO - Serial Number LSBs
|
||||
#### 06000302h - F\_SN\_HI - Serial Number MSBs
|
||||
#### 06000308h - F\_CAL - Calibration value for LCD
|
||||
```
|
||||
0-15 Data
|
||||
```
|
||||
This seems to be an additional "header" region of the FLASH memory
|
||||
(additionally to the 128K of data). The F_SN registers contain a serial number
|
||||
(additionally to the 128K of data). The F\_SN registers contain a serial number
|
||||
or so (purpose unknown, maybe intended as some kind of an "IP" address for more
|
||||
complex infrared network applications), the two LO/HI registers must be read by
|
||||
separate 16bit LDRH opcodes (not by a single 32bit LDR opcode). The F_CAL
|
||||
register contains a 6bit calibration value for LCD_CAL (contrast or so?).<br/>
|
||||
separate 16bit LDRH opcodes (not by a single 32bit LDR opcode). The F\_CAL
|
||||
register contains a 6bit calibration value for LCD\_CAL (contrast or so?).<br/>
|
||||
Although only the above 3 halfwords are used by the BIOS, the "header" is
|
||||
unlike to be 6 bytes in size, probably there are whatever number of additional
|
||||
"header" locations at 06000300h and up...?<br/>
|
||||
Note: Metal Gear Solid Integral uses F_SN as some kind of copy protection (the
|
||||
game refuses to run and displays "No copy" if F_SN is different as when the
|
||||
Note: Metal Gear Solid Integral uses F\_SN as some kind of copy protection (the
|
||||
game refuses to run and displays "No copy" if F\_SN is different as when the
|
||||
pocketstation file was initially created).<br/>
|
||||
|
||||
#### F_BANK_VAL and F_BANK_FLG Notes
|
||||
Observe that the physical_bank number (p) is used as array index, and that the
|
||||
#### F\_BANK\_VAL and F\_BANK\_FLG Notes
|
||||
Observe that the physical\_bank number (p) is used as array index, and that the
|
||||
virtual bank number (v) is stored in that location, ie. table[p]=v, which is
|
||||
unlike as one may have expected it (eg. on a 80386 CPU it'd be vice-versa:
|
||||
table[v]=p).<br/>
|
||||
@ -759,7 +759,7 @@ ANDed together).<br/>
|
||||
|
||||
|
||||
## Pocketstation IO Communication Ports
|
||||
#### 0C000000h - COM_MODE - Com Mode
|
||||
#### 0C000000h - COM\_MODE - Com Mode
|
||||
```
|
||||
0 Data Output Enable (0=None/HighZ, 1=Output Data Bits)
|
||||
1 /ACK Output Level (0=None/HighZ, 1=Output LOW)
|
||||
@ -767,13 +767,13 @@ ANDed together).<br/>
|
||||
3-31 Unknown (should be zero)
|
||||
```
|
||||
|
||||
#### 0C000008h - COM_DATA - Com RX/TX Data
|
||||
#### 0C000008h - COM\_DATA - Com RX/TX Data
|
||||
```
|
||||
0-7 Data (Write: to be transmitted to PSX, Read: been received from PSX)
|
||||
8-31 Unknown
|
||||
```
|
||||
|
||||
#### 0C000004h - COM_STAT1 - Com Status Register 1 (Bit1=Error)
|
||||
#### 0C000004h - COM\_STAT1 - Com Status Register 1 (Bit1=Error)
|
||||
```
|
||||
0 Unknown
|
||||
1 Error flag or so (0=Okay, 1=Error)
|
||||
@ -785,16 +785,16 @@ is unknown. Aside from checking the error flag, the kernel does issue a dummy
|
||||
read at the end of each transfer, maybe to acknowledge something, maybe the
|
||||
hardware simply resets the error bit after reading (although the kernel doesn't
|
||||
handle the bit like so when receiving the 1st command byte).<br/>
|
||||
Aside from the above error flag, one should check if INT_INPUT.11 becomes zero
|
||||
Aside from the above error flag, one should check if INT\_INPUT.11 becomes zero
|
||||
during transfer (which indicates undocking).<br/>
|
||||
|
||||
#### 0C000014h - COM_STAT2 - Com Status Register 2 (Bit0=Ready)
|
||||
#### 0C000014h - COM\_STAT2 - Com Status Register 2 (Bit0=Ready)
|
||||
```
|
||||
0 Ready flag (0=Busy, 1=Ready) (when 8bits have been transferred)
|
||||
1-31 Unknown
|
||||
```
|
||||
|
||||
#### 0C000010h - COM_CTRL1 - Com Control Register 1
|
||||
#### 0C000010h - COM\_CTRL1 - Com Control Register 1
|
||||
```
|
||||
0 Unknown (should be set AT BEGIN OF A NEW command...?)
|
||||
1 Unknown (0=Disable something, 1=Enable something)
|
||||
@ -810,7 +810,7 @@ When doing the enable thing, Bit1 should be set to 0-then-1...? Bit0 might
|
||||
enable the data shift register... and bit1 might be a master enable and master
|
||||
acknowledge for the COM interrupt... or something else?<br/>
|
||||
|
||||
#### 0C000018h - COM_CTRL2 - Com Control Register 2
|
||||
#### 0C000018h - COM\_CTRL2 - Com Control Register 2
|
||||
```
|
||||
0 Unknown (should be set, probably starts or acknowledges something)
|
||||
1 Unknown (should be set when expecting a NEW command...?)
|
||||
@ -823,24 +823,24 @@ Used values are:<br/>
|
||||
```
|
||||
Maybe that two bits acknowledge the ready/error bits?<br/>
|
||||
|
||||
#### INT_INPUT.6 FIQ (!) COM for the COM_registers? (via /SEL Pin?)
|
||||
#### INT\_INPUT.6 FIQ (!) COM for the COM\_registers? (via /SEL Pin?)
|
||||
```
|
||||
(via FIQ vector, not IRQ vector)
|
||||
```
|
||||
|
||||
#### INT_INPUT.11 IRQ Docked ("IOP") (0=Undocked, 1=Docked to PSX)
|
||||
#### INT\_INPUT.11 IRQ Docked ("IOP") (0=Undocked, 1=Docked to PSX)
|
||||
Probably senses the voltage on the cartridge slots VCC Pin. Becomes zero when
|
||||
Undocked (and probably also when the PSX is switched off).<br/>
|
||||
The Kernel uses IRQ-11 for BOTH sensing docking and undocking, ie. as if the
|
||||
IRQ would be triggered on both 0-to-1 and 1-to-0 transistions... though maybe
|
||||
that feature just relies on switch-bounce. For the same reason (switch bounce),
|
||||
the IRQ-11 handler performs a delay before it checks the new INT_INPUT.11
|
||||
the IRQ-11 handler performs a delay before it checks the new INT\_INPUT.11
|
||||
setting (ie. the delay skips the unstable switch bound period, and allows the
|
||||
signal to stabilize).<br/>
|
||||
|
||||
#### IOP_START/IOP_STOP.Bit1
|
||||
#### IOP\_START/IOP\_STOP.Bit1
|
||||
The BIOS adjusts this bit somehow in relation to communication. Unknown
|
||||
when/why/how it must be used. For details on IOP_START/IOP_STOP see Power
|
||||
when/why/how it must be used. For details on IOP\_START/IOP\_STOP see Power
|
||||
Control chapter.<br/>
|
||||
|
||||
#### Opcode E6000010h (The Undefined Instruction) - Write chr(r0) to TTY
|
||||
@ -862,7 +862,7 @@ ie. which do neither trap data aborts, nor do mirror to existing ports...?<br/>
|
||||
|
||||
|
||||
## Pocketstation IO Power Control
|
||||
#### 0B000000h - CLK_MODE - Clock control (CPU and Timer Speed) (R/W)
|
||||
#### 0B000000h - CLK\_MODE - Clock control (CPU and Timer Speed) (R/W)
|
||||
```
|
||||
0-3 Clock Ratio (01h..08h, see below) (usually 7 = 3.99MHz) (R/W)
|
||||
4 Clock Change State (0=Busy, 1=Ready) (Read-only)
|
||||
@ -882,11 +882,11 @@ the CPU clock, or less, depending on the Timer Divider). Possible values are:<br
|
||||
08h = 7.995392 MHz ;/
|
||||
09h..0Fh = same as 08h ;-aliases
|
||||
```
|
||||
Before changing CLK_MODE, F_WAIT1 and F_WAIT2 should be adjusted accordingly
|
||||
Before changing CLK\_MODE, F\_WAIT1 and F\_WAIT2 should be adjusted accordingly
|
||||
(see there for details). Note that many memory regions have waitstates, the
|
||||
full CPU speed can be reached mainly with code/data in WRAM.<br/>
|
||||
|
||||
#### 0B000004h - CLK_STOP - Clock stop (Sleep Mode)
|
||||
#### 0B000004h - CLK\_STOP - Clock stop (Sleep Mode)
|
||||
Stops the CPU until an interrupt occurs. The pocketstation doesn't have a
|
||||
power-switch nor standby button, the closest thing to switch "power off" is to
|
||||
enter sleep mode. Software should do that when the user hasn't pressed buttons
|
||||
@ -897,9 +897,9 @@ it's using the PSX power supply instead of the battery).<br/>
|
||||
1-15 ?
|
||||
```
|
||||
Wakeup is usually done by IRQ-0 (Fire Button) and IRQ-11 (Docking). If alarm is
|
||||
enabled, then the GUI also enables IRQ-9 (RTC), and compares RTC_TIME against
|
||||
enabled, then the GUI also enables IRQ-9 (RTC), and compares RTC\_TIME against
|
||||
the alarm setting each time when it wakes up.<br/>
|
||||
Before writing to CLK_STOP, one should do:<br/>
|
||||
Before writing to CLK\_STOP, one should do:<br/>
|
||||
```
|
||||
DAC_CTRL=0 ;\disable sound
|
||||
IOP_STOP=20h ;/
|
||||
@ -908,12 +908,12 @@ Before writing to CLK_STOP, one should do:<br/>
|
||||
BATT_CTRL=BATT_CTRL AND FFFFFFFCh ;-do whatever
|
||||
INT_MASK_SET=801h ;-enable Docking/Fire wakeup interrupts
|
||||
```
|
||||
The GUI uses CLK_STOP only for Standby purposes (not for waiting for its 30Hz
|
||||
The GUI uses CLK\_STOP only for Standby purposes (not for waiting for its 30Hz
|
||||
"frame rate" timer 0 interrupt; maybe that isn't possible, ie. probably
|
||||
CLK_STOP does completely disable the system clock, and thus does stop
|
||||
CLK\_STOP does completely disable the system clock, and thus does stop
|
||||
Timer0-2...?)<br/>
|
||||
|
||||
#### 0D800000h - IOP_CTRL - Configures whatever...? (R/W)
|
||||
#### 0D800000h - IOP\_CTRL - Configures whatever...? (R/W)
|
||||
```
|
||||
0-3 Probably Direction for IOP_DATA bit0..3 (0=Input, 1=Output)
|
||||
4-31 Unknown/Unused (seems to be always zero)
|
||||
@ -921,11 +921,11 @@ Timer0-2...?)<br/>
|
||||
Unknown. Set to 0000000Fh by BIOS upon reset. Aside from that, the BIOS does
|
||||
never use that register.<br/>
|
||||
|
||||
#### 0D800004h - IOP_STAT (R) - Read Current bits? -- No, seems to be always 0
|
||||
#### 0D800004h - IOP_STOP (W) - Set IOP_DATA Bits
|
||||
#### 0D800008h - IOP_START (W) - Clear IOP_DATA Bits
|
||||
#### 0D800004h - IOP\_STAT (R) - Read Current bits? -- No, seems to be always 0
|
||||
#### 0D800004h - IOP\_STOP (W) - Set IOP\_DATA Bits
|
||||
#### 0D800008h - IOP\_START (W) - Clear IOP\_DATA Bits
|
||||
These two ports are probably accessing a single register, writing "1" bits to
|
||||
IOP_STOP sets bits in that register, and writing "1" bits to IOP_START clears
|
||||
IOP\_STOP sets bits in that register, and writing "1" bits to IOP\_START clears
|
||||
bits... or vice-versa...? Writing "0" bits to either port seems to leave that
|
||||
bits unchanged. The meaning of most bits is still unknown:<br/>
|
||||
```
|
||||
@ -939,15 +939,15 @@ bits unchanged. The meaning of most bits is still unknown:<br/>
|
||||
7-31 Unknown, never STARTED nor STOPPED by BIOS
|
||||
```
|
||||
Aside from Bit1, it's probably not neccessary to change the unknown bits...?<br/>
|
||||
Sound is usually disabled by setting IOP_STOP=00000020h. IOP_STAT is rarely
|
||||
Sound is usually disabled by setting IOP\_STOP=00000020h. IOP\_STAT is rarely
|
||||
used. Although, one piece of code in the BIOS disables sound by setting
|
||||
IOP_STOP=IOP_STAT OR 00000020h, that is probably nonsense, probably intended to
|
||||
IOP\_STOP=IOP\_STAT OR 00000020h, that is probably nonsense, probably intended to
|
||||
keep bits stopped if they are already stopped (which would happen anyways),
|
||||
however, the strange code implies that reading from 0D800004h returns the
|
||||
current status of the register, and that the bits in that register seem to be
|
||||
0=Started, and 1=Stopped...?<br/>
|
||||
|
||||
#### 0D80000Ch - IOP_DATA (R)
|
||||
#### 0D80000Ch - IOP\_DATA (R)
|
||||
```
|
||||
0 ?
|
||||
1 Red LED (0=On, 1=Off)
|
||||
@ -961,12 +961,12 @@ Connection...? This register is read by Rewrite ID, and by Harvest Moon. Maybe
|
||||
bit4 doesn't mean \<if\> IR connection exist, but rather \<contains\>
|
||||
the received IR data level...?<br/>
|
||||
|
||||
#### 0D800020h - BATT_CTRL - Battery Monitor Control?
|
||||
#### 0D800020h - BATT\_CTRL - Battery Monitor Control?
|
||||
Unknown. Somehow battery saving related. Upon reset, and upon leaving sleep
|
||||
mode, the BIOS does set BATT_CTRL=00000000h. Before entering sleep mode, it
|
||||
does set BATT_CTRL=BATT_CTRL AND FFFFFFFCh, whereas, assuming that BATT_CTRL
|
||||
mode, the BIOS does set BATT\_CTRL=00000000h. Before entering sleep mode, it
|
||||
does set BATT\_CTRL=BATT\_CTRL AND FFFFFFFCh, whereas, assuming that BATT\_CTRL
|
||||
was 00000000h, ANDing it with FFFFFFFCh would simply leave it unchanged...
|
||||
unless the hardware (or maybe a game) sets some bits in BATT_CTRL to nonzero
|
||||
unless the hardware (or maybe a game) sets some bits in BATT\_CTRL to nonzero
|
||||
values...?<br/>
|
||||
|
||||
#### Battery Low Interrupt
|
||||
@ -1055,8 +1055,8 @@ The kernel IRQ handler does (after the IRQ callback) process IRQ-11 (IOP)
|
||||
(which does mainly handle docking/undocking), and IRQ-9 (RTC) (which increments
|
||||
the century if the year wrapped from 99h to 00h).<br/>
|
||||
And the kernel FIQ handler does (before the FIQ callback) process IRQ-6 (COM)
|
||||
(which does, if ComFlags.Bit9 is set, handle bu_cmd's) (both IRQs and FIQs are
|
||||
disabled, and the main program is stopped until the bu_cmd finishes, or until a
|
||||
(which does, if ComFlags.Bit9 is set, handle bu\_cmd's) (both IRQs and FIQs are
|
||||
disabled, and the main program is stopped until the bu\_cmd finishes, or until a
|
||||
joypad command is identified irrelevant, among others that means that
|
||||
sound/timer IRQs aren't processed during that time, so audio output may become
|
||||
distorted when docked).<br/>
|
||||
@ -1077,16 +1077,16 @@ SWI2 can be useful to execute code in privileged mode (eg. to initialize FIQ
|
||||
registers r8..r12 for a FIQ based sound engine) (which usually isn't possible
|
||||
because the main program runs in non-privileged user mode).<br/>
|
||||
|
||||
#### SWI 04h - SetCpuSpeed(speed) out: old_speed
|
||||
#### SWI 04h - SetCpuSpeed(speed) out: old\_speed
|
||||
Changes the CPU speed. The BIOS uses it with values in range 01h..07h. Unknown
|
||||
if value 00h can be also used? The function also handles values bigger than
|
||||
07h, of which, some pieces of BIOS code look as if 08h would be the maximum
|
||||
value...?<br/>
|
||||
Before setting the new speed, the function sets F_WAIT1 and F_WAIT2 to
|
||||
Before setting the new speed, the function sets F\_WAIT1 and F\_WAIT2 to
|
||||
00000000h (or to 00000010h if speed.bit3=1). After changing the speed (by
|
||||
writing the parameter to CLK_MODE) it does wait until the new speed is applied
|
||||
(by waiting for CLK_MODE.bit4 to become zero). The function returns the old
|
||||
value of CLK_MODE, anded with 0Fh.<br/>
|
||||
writing the parameter to CLK\_MODE) it does wait until the new speed is applied
|
||||
(by waiting for CLK\_MODE.bit4 to become zero). The function returns the old
|
||||
value of CLK\_MODE, anded with 0Fh.<br/>
|
||||
|
||||
|
||||
|
||||
@ -1101,16 +1101,16 @@ Can be used to enable/disable communication. When starting an executable,
|
||||
communication is initially disabled, so it'd be a good idea to enable them
|
||||
(otherwise the PSX cannot communicate with the Pocketstation while the game is
|
||||
running).<br/>
|
||||
When flag=0, disables communication: Intializes the COM_registers, disables
|
||||
When flag=0, disables communication: Intializes the COM\_registers, disables
|
||||
IRQ-6 (COM), and clears ComFlags.9. When flag=1, enables communication:
|
||||
Intializes the COM_registers, enables IRQ-6 (COM), sets ComFlags.9 (when
|
||||
docked), or clears Sys.Flags.9 (when undocked), and sets FAST cpu_speed=7 (only
|
||||
when docked). The function returns garbage (r0=retadr to swi_handler).<br/>
|
||||
Intializes the COM\_registers, enables IRQ-6 (COM), sets ComFlags.9 (when
|
||||
docked), or clears Sys.Flags.9 (when undocked), and sets FAST cpu\_speed=7 (only
|
||||
when docked). The function returns garbage (r0=retadr to swi\_handler).<br/>
|
||||
|
||||
#### SWI 06h - GetPtrToComFlags()
|
||||
Returns a pointer to the ComFlags word in RAM, which contains several
|
||||
communication related flags (which are either modified upon docking/undocking,
|
||||
or upon receiving certain bu_cmd's). The ComFlags word consists of the
|
||||
or upon receiving certain bu\_cmd's). The ComFlags word consists of the
|
||||
following bits:<br/>
|
||||
```
|
||||
0-3 Whatever (set/cleared when docked/undocked, and modified by bu_cmd's)
|
||||
@ -1146,7 +1146,7 @@ cartridge slot. The function returns the incoming flags value ANDed with
|
||||
70000h.<br/>
|
||||
|
||||
#### SWI 0Bh - ClearComFlagsBit10()
|
||||
Resets ComFlags.Bit10, ie. enables bu_cmd_57h (write_sector) to write to the
|
||||
Resets ComFlags.Bit10, ie. enables bu\_cmd\_57h (write\_sector) to write to the
|
||||
Broken Sector region in FLASH memory (sector 16..55). SWI 0Bh returns the
|
||||
current ComFlags value (the new value, with bit10=0).<br/>
|
||||
Aside from calling SWI 0Bh, ComFlags.10 is also automatically cleared upon
|
||||
@ -1170,7 +1170,7 @@ does set/clear ComFlags.9 when docked/undocked.<br/>
|
||||
|
||||
#### SWI 17h - GetPtrToFunc3addr()
|
||||
Returns a pointer to a halfword in RAM which contains the FUNC3 address (for
|
||||
bu_cmd_5bh and bu_cmd_5ch). The address is only 16bit, originated at 02000000h
|
||||
bu\_cmd\_5bh and bu\_cmd\_5ch). The address is only 16bit, originated at 02000000h
|
||||
in FLASH (ie. it can be only in the first 64K of the file), bit0 can be set for
|
||||
THUMB code. The default address is zero, which behaves bugged: It accidently
|
||||
sets [00000004h]=00000000h, ie. replaces the Undefined Instruction exception
|
||||
@ -1192,17 +1192,17 @@ SetCallbacks(index,proc), and BU Command 5Dh for details.<br/>
|
||||
|
||||
|
||||
## Pocketstation SWI Execute Functions
|
||||
#### SWI 08h - PrepareExecute(flag,dir_index,param)
|
||||
dir_index should be 0=GUI, or 1..15=First block of game. When calling
|
||||
#### SWI 08h - PrepareExecute(flag,dir\_index,param)
|
||||
dir\_index should be 0=GUI, or 1..15=First block of game. When calling
|
||||
DoExecute, param is passed to the entrypoint of the game or GUI in r0 register
|
||||
(see notes on GUI \<param\> values belows). For games, param may be
|
||||
interpreted in whatever way.<br/>
|
||||
When flag=0, the function simply returns the old dir_index value. When flag=1,
|
||||
the new dir_index and param values are stored in Kernel RAM (for being used by
|
||||
DoExecute); the values are stored only if dir_index=0 (GUI), or if dir_index
|
||||
When flag=0, the function simply returns the old dir\_index value. When flag=1,
|
||||
the new dir\_index and param values are stored in Kernel RAM (for being used by
|
||||
DoExecute); the values are stored only if dir\_index=0 (GUI), or if dir\_index
|
||||
belongs to a file with "SC" and "MCX0" or "MCX1" IDs in it's title sector. If
|
||||
dir_index was accepted, then the new dir_index value is returned, otherwise the
|
||||
old dir_index is returned.<br/>
|
||||
dir\_index was accepted, then the new dir\_index value is returned, otherwise the
|
||||
old dir\_index is returned.<br/>
|
||||
|
||||
#### GUI \<param\> values - for PrepareExecute(1,0,param)
|
||||
PrepareExecute(1,0,param) prepares to execute the GUI (rather than a file).
|
||||
@ -1223,18 +1223,18 @@ The command numbers can be:<br/>
|
||||
Command xxh --> Erase RTC time/date (same as Command 0xh)
|
||||
```
|
||||
For Command 2xh and 3xh, the lower 4bit of the command (x) must be a valid
|
||||
dir_index of the 1st block of a pocketstation executable, otherwise the BIOS
|
||||
dir\_index of the 1st block of a pocketstation executable, otherwise the BIOS
|
||||
erases the RTC time/date. Bit8 is just a "funny" nag feature, allowing the user
|
||||
to change the alarm setting, but with the changes being ignored (bit8 can be
|
||||
actually useful in BU Command 59h, after FUNC2 was used for changing alarm).<br/>
|
||||
|
||||
#### SWI 09h - DoExecute(), or DoExecute(snapshot_saving_flag) for MCX1
|
||||
Allows to return control to the GUI (when dir_index=0), or to start an
|
||||
executable (when dir_index=1..15). Prior to calling DoExecute, parameters
|
||||
should be set via PrepareExecute(1,dir_index,param), when not doing that,
|
||||
#### SWI 09h - DoExecute(), or DoExecute(snapshot\_saving\_flag) for MCX1
|
||||
Allows to return control to the GUI (when dir\_index=0), or to start an
|
||||
executable (when dir\_index=1..15). Prior to calling DoExecute, parameters
|
||||
should be set via PrepareExecute(1,dir\_index,param), when not doing that,
|
||||
DoExecute would simply restart the current executable (which may be a desired
|
||||
effect in some cases).<br/>
|
||||
The "snapshot_saving_flag" can be ommited for normal (MCX0) files, that
|
||||
The "snapshot\_saving\_flag" can be ommited for normal (MCX0) files, that
|
||||
parameter is used only for special (MCX1) files (see Snapshot Notes for
|
||||
details).<br/>
|
||||
Caution: DoExecute fails (and returns r0=unchanged) when ComFlags.9=1 (which
|
||||
@ -1244,19 +1244,19 @@ calling SetComOnOff(0), or it can be updated according to the current
|
||||
docking-state by calling SetComOnOff(1) or SenseAutoCom().<br/>
|
||||
|
||||
#### SWI 16h - GetDirIndex()
|
||||
Returns the dir_index for the currently executed file. If that value is zero,
|
||||
Returns the dir\_index for the currently executed file. If that value is zero,
|
||||
ie. if there is no file executed, ie. if the function is called by the GUI,
|
||||
then it does instead return the "alternate" dir_index (as set via SWI 15h).<br/>
|
||||
then it does instead return the "alternate" dir\_index (as set via SWI 15h).<br/>
|
||||
|
||||
#### SWI 15h - MakeAlternateDirIndex(flag,dir_index) out: alt_dir_index (new/old)
|
||||
Applies the specified dir_index as "alternate" dir_index (for being retrieved
|
||||
via SWI 16h for whatever purpose). The dir_index is applied only when flag=1,
|
||||
and only if dir_index is 0=none, or if it is equal to the dir_index of the
|
||||
#### SWI 15h - MakeAlternateDirIndex(flag,dir\_index) out: alt\_dir\_index (new/old)
|
||||
Applies the specified dir\_index as "alternate" dir\_index (for being retrieved
|
||||
via SWI 16h for whatever purpose). The dir\_index is applied only when flag=1,
|
||||
and only if dir\_index is 0=none, or if it is equal to the dir\_index of the
|
||||
currently executed file (ie. attempts to make other files being the "alternate"
|
||||
one are rejected). If successful, the new dir_index is returned, otherwise the
|
||||
old dir_index is returned (eg. if flag=0, or if the index was rejected).<br/>
|
||||
one are rejected). If successful, the new dir\_index is returned, otherwise the
|
||||
old dir\_index is returned (eg. if flag=0, or if the index was rejected).<br/>
|
||||
|
||||
#### SWI 12h - TestSnapshot(dir_index)
|
||||
#### SWI 12h - TestSnapshot(dir\_index)
|
||||
Tests if the specified file contains a load-able snapshot, ie. if it does have
|
||||
the "SC" and "MCX1" IDs in the title sector, and the 01h,00h,"SE" ID in the
|
||||
snapshot header. If so, it returns r0=1, and otherwise returns r0=0.<br/>
|
||||
@ -1266,9 +1266,9 @@ Snapshots are somewhat automatically loaded/saved when calling DoExecute:<br/>
|
||||
If the old file (the currently executed file) contains "SC" AND "MCX1" IDs in
|
||||
the title sector, then the User Mode CPU registers and User RAM at 200h..7FFh
|
||||
are automatically saved in the files snapshot region in FLASH memory, with the
|
||||
snapshot_saving_flag being applied as bit0 of the 0xh,00h,"SE" ID of the
|
||||
snapshot\_saving\_flag being applied as bit0 of the 0xh,00h,"SE" ID of the
|
||||
snapshot header).<br/>
|
||||
If the new file (specified in dir_index) contains load-able snapshot data (ie.
|
||||
If the new file (specified in dir\_index) contains load-able snapshot data (ie.
|
||||
if it has "SC" and "MCX1" IDs in title sector, and 01h,00h,"SE" ID in the
|
||||
snapshot region), then the BIOS starts the saved snapshot data (instead of
|
||||
restarting the executable at its entrypoint). Not too sure if that feature is
|
||||
@ -1283,7 +1283,7 @@ to underflow after loading one or two snapshots...?<br/>
|
||||
#### SWI 0Ch - SetBcdDateTime(date,time)
|
||||
Sets the time and date, the parameters are having the same format as SWI 0Dh
|
||||
and SWI 0Eh return values (see there). The SWI 0Ch return value contains only
|
||||
garbage (r0=RTC_DATE/10000h).<br/>
|
||||
garbage (r0=RTC\_DATE/10000h).<br/>
|
||||
|
||||
#### SWI 0Dh - GetBcdDate()
|
||||
```
|
||||
@ -1291,7 +1291,7 @@ garbage (r0=RTC_DATE/10000h).<br/>
|
||||
8-11 Month (01h..12h, BCD)
|
||||
16-31 Year (0000h..9999h, BCD)
|
||||
```
|
||||
Returns the current date, the lower 24bit are read from RTC_DATE, the century
|
||||
Returns the current date, the lower 24bit are read from RTC\_DATE, the century
|
||||
in upper 8bit is read from Kernel RAM.<br/>
|
||||
|
||||
#### SWI 0Eh - GetBcdTime()
|
||||
@ -1301,11 +1301,11 @@ in upper 8bit is read from Kernel RAM.<br/>
|
||||
16-23 Hours (00h..23h, BCD)
|
||||
24-31 Day of week (1=Sunday, ..., 7=Saturday)
|
||||
```
|
||||
Returns the current time and day of week, read from RTC_TIME.<br/>
|
||||
Returns the current time and day of week, read from RTC\_TIME.<br/>
|
||||
|
||||
#### SWI 13h - GetPtrToAlarmSetting()
|
||||
Returns a pointer to a 64bit value in Kernel RAM, the upper word (Bit32-63)
|
||||
isn't actually used by the BIOS, except that, the bu_cmd FUNC3 does transfer
|
||||
isn't actually used by the BIOS, except that, the bu\_cmd FUNC3 does transfer
|
||||
the whole 64bits. The meaning of the separate bits is:<br/>
|
||||
```
|
||||
0-7 Alarm Minute (00h..59h, BCD)
|
||||
@ -1349,19 +1349,19 @@ Returns 0=okay, or 1=failed.<br/>
|
||||
|
||||
#### SWI 03h - FlashWriteVirtual(sector,src)
|
||||
The sector number (0..3FFh) is a virtual sector number (originated at
|
||||
02000000h), the function uses the F_BANK_VAL settings to translate it to a
|
||||
02000000h), the function uses the F\_BANK\_VAL settings to translate it to a
|
||||
physical sector number, and does then write the 80h-bytes at src to that
|
||||
location (via the FlashWritePhysical function). Returns 0=okay, or 1=failed (if
|
||||
the write failed, or if the sector number exceeded the filesize aka the
|
||||
virtually mapped memory region).<br/>
|
||||
|
||||
#### SWI 0Ah - FlashReadSerial()
|
||||
Returns the 32bit value from the two 16bit F_SN registers (see F_SN for
|
||||
Returns the 32bit value from the two 16bit F\_SN registers (see F\_SN for
|
||||
details).<br/>
|
||||
|
||||
#### SWI 0Fh - FlashWriteSerial(serial_number) ;old BIOS only!
|
||||
Changes the 32bit F_SN value in the "header" region of the FLASH memory. The
|
||||
function also rewrites the F_CAL value (but it simply rewrites the old value,
|
||||
#### SWI 0Fh - FlashWriteSerial(serial\_number) ;old BIOS only!
|
||||
Changes the 32bit F\_SN value in the "header" region of the FLASH memory. The
|
||||
function also rewrites the F\_CAL value (but it simply rewrites the old value,
|
||||
so it's left unchanged). The function isn't used by the BIOS, no idea if it is
|
||||
used by any games. No return value (always returns r0=0).<br/>
|
||||
This function is supported by the old "061" version BIOS only (the function is
|
||||
@ -1369,7 +1369,7 @@ padded with jump opcodes which hang the CPU in endless loops on newer "110"
|
||||
version).<br/>
|
||||
|
||||
#### SWI 18h - FlashReadWhateverByte(sector)
|
||||
Returns [8000000h+sector*80h+7Eh] AND 00FFh. Purpose is totally unknown... the
|
||||
Returns [8000000h+sector\*80h+7Eh] AND 00FFh. Purpose is totally unknown... the
|
||||
actual FLASH memory doesn't contain any relevant information at that locations
|
||||
(eg. the in the directory sectors, that byte is unused, usually zero)... and,
|
||||
reading some kind of status or manufacturer information would first require to
|
||||
@ -1480,9 +1480,9 @@ aware of that situation. If the file is broken into a Pocketstation Executable
|
||||
region and a PSX Gameposition region, then it may modify the Gameposition stuff
|
||||
even while the Executable is running. If the PSX want to overwrite the
|
||||
executable then it must first ensure that it isn't executed (eg. by retrieving
|
||||
the dir_index of the currently executed file via BU Command 5Ah, and comparing
|
||||
the dir\_index of the currently executed file via BU Command 5Ah, and comparing
|
||||
it against the first block number in the files FCB at the PSX side; for file
|
||||
handle "fd", the first block is found at "[104h]+fd*2Ch+24h" in PSX memory).<br/>
|
||||
handle "fd", the first block is found at "[104h]+fd\*2Ch+24h" in PSX memory).<br/>
|
||||
|
||||
#### Write Error Code FEh (write-protected Broken Sector region, sector 16..55)
|
||||
The write-protection is enabled by ComFlags.bit10 (which can be set/cleared via
|
||||
@ -1517,7 +1517,7 @@ Might be somehow related to FUNC 03h...?<br/>
|
||||
(0) 01h Send dummy/zero, receive another value (01h)
|
||||
```
|
||||
|
||||
#### BU Command 59h (Prepare File Execution with Dir_index, and Parameter)
|
||||
#### BU Command 59h (Prepare File Execution with Dir\_index, and Parameter)
|
||||
```
|
||||
Send Reply Comment
|
||||
81h N/A Memory Card Access
|
||||
@ -1530,29 +1530,29 @@ Might be somehow related to FUNC 03h...?<br/>
|
||||
PAR (0) Send exec_parameter.16-23, receive dummy/zero
|
||||
PAR (0) Send exec_parameter.24-31, receive dummy/zero
|
||||
```
|
||||
The new dir_index can be the following:<br/>
|
||||
The new dir\_index can be the following:<br/>
|
||||
```
|
||||
0000h..000Fh --> Request to Start GUI or File (with above parameter bits)
|
||||
0010h..FFFDh --> Not used, acts same as FFFFh (see below)
|
||||
FFFEh --> Request to Destroy RTC and Start GUI (with parameter 00000000h)
|
||||
FFFFh --> Do nothing (transfer all bytes, but don't store the new values)
|
||||
```
|
||||
Upon dir_index=0000h (Start GUI) or 0001..000Fh (start file), a request flag in
|
||||
Upon dir\_index=0000h (Start GUI) or 0001..000Fh (start file), a request flag in
|
||||
ComFlags.11 is set, the GUI does handle that request, but the Kernel doesn't
|
||||
handle it (so it must be handled in the game; ie. check ComFlags.11 in your
|
||||
mainloop, and call DoExecute when that bit is set, there's no need to call
|
||||
PrepareExecute, since that was already done by the BU Command).<br/>
|
||||
Caution: When dir_index=0000h, then \<param\> should be a value that does
|
||||
Caution: When dir\_index=0000h, then \<param\> should be a value that does
|
||||
NOT erase the RTC time/date (eg. 10h or 20h) (most other values do erase the
|
||||
RTC, see SWI 08h for details).<br/>
|
||||
Upon dir_index=FFFEh, a similar request flag is set in ComFlags.30, and, the
|
||||
Upon dir\_index=FFFEh, a similar request flag is set in ComFlags.30, and, the
|
||||
Kernel (not the GUI) does handle that request in its FIQ handler (however, the
|
||||
request is: To reset the RTC time/date and to start the GUI with uninitialized
|
||||
irq/svc stack pointers, so this unpleasant and bugged feature shouldn't ever be
|
||||
used). Finally, dir_index=FFFFh allows to read the current dir_index value
|
||||
used). Finally, dir\_index=FFFFh allows to read the current dir\_index value
|
||||
(which could be also read via BU Command 5Ah).<br/>
|
||||
|
||||
#### BU Command 5Ah (Get Dir_index, ComFlags, F_SN, Date, and Time)
|
||||
#### BU Command 5Ah (Get Dir\_index, ComFlags, F\_SN, Date, and Time)
|
||||
```
|
||||
Send Reply Comment
|
||||
81h N/A Memory Card Access
|
||||
@ -1661,7 +1661,7 @@ execution is like so:<br/>
|
||||
If value.8-15 = 00h, then ComFlags.bit10=1, else ComFlags.bit10=0.
|
||||
If download_callback<>0 then call download_callback with r0=value.0-23.
|
||||
```
|
||||
In the GUI, the bu_cmd_5dh_hook/callback handles parameter bits as so (and
|
||||
In the GUI, the bu\_cmd\_5dh\_hook/callback handles parameter bits as so (and
|
||||
games should probably handle that bits in the same fashion, too):<br/>
|
||||
```
|
||||
bit0-7 download duration (in whatever units... 30Hz, RTC, seconds...?)
|
||||
@ -1705,7 +1705,7 @@ what you are doing). In the read direction it can read almost anything: RAM,
|
||||
BIOS ROM, I/O Ports, Physical and Virtual FLASH memory. Of which, trying to
|
||||
read unmapped Virtual FLASH does probably (?) cause a Data Abort exception (and
|
||||
crash the Pocketstation), so that region may be read only if a file is loaded
|
||||
(check that dir_index isn't zero, via BU Command 5Ah, and, take care not to
|
||||
(check that dir\_index isn't zero, via BU Command 5Ah, and, take care not to
|
||||
exceed the filesize of that file).<br/>
|
||||
BUG: When sending more than 2 data bytes in the PSX-to-Pocketstation direction,
|
||||
then ADDR must be word-aligned (the BIOS tries to handle odd destination
|
||||
@ -1730,7 +1730,7 @@ when it gets started, that copy isn't affected by FUNC2, so the GUI believes
|
||||
that the old alarm setting does still apply (and writes that old values back to
|
||||
Kernel RAM when leaving the GUI). The only workaround is:<br/>
|
||||
Test if the GUI is running, if so, restart it via Command 59h (with
|
||||
dir_index=0, and param=0120h or similar, ie. with param.bit8 set), then execute
|
||||
dir\_index=0, and param=0120h or similar, ie. with param.bit8 set), then execute
|
||||
FUNC2, then restart the GUI again (this time with param.bit8 zero).<br/>
|
||||
|
||||
#### FUNC 03h - Custom Function 3 (aka FUNC3)
|
||||
@ -1913,7 +1913,7 @@ Each icon frame is 32x32 pixels with 1bit color depth (32 words, =128 bytes),<br
|
||||
bit0 = left-most pixel, bit31 = right-most pixel (0=white, 1=black)
|
||||
```
|
||||
A normal icon occupies 80h bytes, animated icons have more than one frame and
|
||||
do occupy N*80h bytes.<br/>
|
||||
do occupy N\*80h bytes.<br/>
|
||||
|
||||
#### Executable Mono Icon List
|
||||
The number of entries in the Executable Mono Icon List is specified in hdr[56h]
|
||||
@ -2141,8 +2141,8 @@ that it needs to install special transmission handlers):<br/>
|
||||
strne r1,[r0,4] ;func3_buf_len=0 ;/
|
||||
bx lr ;-for PRE data: return r0=func3_info
|
||||
```
|
||||
Usage: Call "init_tty" at the executable's entrypoint (with incoming R0 passed
|
||||
on). Call "tty_wrchr" to output ASCII characters.<br/>
|
||||
Usage: Call "init\_tty" at the executable's entrypoint (with incoming R0 passed
|
||||
on). Call "tty\_wrchr" to output ASCII characters.<br/>
|
||||
Note: The TTY messages are supported only in no$gba debug version (not no$gba
|
||||
gaming version).<br/>
|
||||
|
||||
|
@ -1,29 +1,29 @@
|
||||
# Serial Port (SIO)
|
||||
#### 1F801050h SIO_TX_DATA (W)
|
||||
#### 1F801050h SIO\_TX\_DATA (W)
|
||||
```
|
||||
0-7 Data to be sent
|
||||
8-31 Not used
|
||||
```
|
||||
Writing to this register starts transmit (if, or as soon as, TXEN=1 and CTS=on
|
||||
and SIO_STAT.2=Ready). Writing to this register while SIO_STAT.0=Busy causes
|
||||
and SIO\_STAT.2=Ready). Writing to this register while SIO\_STAT.0=Busy causes
|
||||
the old value to be overwritten.<br/>
|
||||
The "TXEN=1" condition is a bit more complex: Writing to SIO_TX_DATA latches
|
||||
The "TXEN=1" condition is a bit more complex: Writing to SIO\_TX\_DATA latches
|
||||
the current TXEN value, and the transfer DOES start if the current TXEN value
|
||||
OR the latched TXEN value is set (ie. if TXEN gets cleared after writing to
|
||||
SIO_TX_DATA, then the transfer may STILL start if the old latched TXEN value
|
||||
SIO\_TX\_DATA, then the transfer may STILL start if the old latched TXEN value
|
||||
was set; this appears for SIO transfers in Wipeout 2097).<br/>
|
||||
|
||||
#### 1F801050h SIO_RX_DATA (R)
|
||||
#### 1F801050h SIO\_RX\_DATA (R)
|
||||
```
|
||||
0-7 Received Data (1st RX FIFO entry) (oldest entry)
|
||||
8-15 Preview (2nd RX FIFO entry)
|
||||
16-23 Preview (3rd RX FIFO entry)
|
||||
24-31 Preview (4th RX FIFO entry) (5th..8th cannot be previewed)
|
||||
```
|
||||
A data byte can be read when SIO_STAT.1=1. Data should be read only via 8bit
|
||||
A data byte can be read when SIO\_STAT.1=1. Data should be read only via 8bit
|
||||
memory access (the 16bit/32bit "preview" feature is rather unusable).<br/>
|
||||
|
||||
#### 1F801054h SIO_STAT (R)
|
||||
#### 1F801054h SIO\_STAT (R)
|
||||
```
|
||||
0 TX Ready Flag 1 (1=Ready/Started) (depends on CTS) (TX requires CTS)
|
||||
1 RX FIFO Not Empty (0=Empty, 1=Not Empty)
|
||||
@ -42,7 +42,7 @@ memory access (the 16bit/32bit "preview" feature is rather unusable).<br/>
|
||||
Note: Bit0 gets cleared after sending the Startbit, Bit2 gets cleared after
|
||||
sending all bits up to including the Stopbit.<br/>
|
||||
|
||||
#### 1F801058h SIO_MODE (R/W) (eg. 004Eh --\> 8N1 with Factor=MUL16)
|
||||
#### 1F801058h SIO\_MODE (R/W) (eg. 004Eh --\> 8N1 with Factor=MUL16)
|
||||
```
|
||||
0-1 Baudrate Reload Factor (1=MUL1, 2=MUL16, 3=MUL64) (or 0=STOP)
|
||||
2-3 Character Length (0=5bits, 1=6bits, 2=7bits, 3=8bits)
|
||||
@ -52,7 +52,7 @@ sending all bits up to including the Stopbit.<br/>
|
||||
8-15 Not used (always zero)
|
||||
```
|
||||
|
||||
#### 1F80105Ah SIO_CTRL (R/W)
|
||||
#### 1F80105Ah SIO\_CTRL (R/W)
|
||||
```
|
||||
0 TX Enable (TXEN) (0=Disable, 1=Enable, when CTS=On)
|
||||
1 DTR Output Level (0=Off, 1=On)
|
||||
@ -69,37 +69,37 @@ sending all bits up to including the Stopbit.<br/>
|
||||
13-15 Not used (always zero)
|
||||
```
|
||||
|
||||
#### 1F80105Ch SIO_MISC (R/W)
|
||||
#### 1F80105Ch SIO\_MISC (R/W)
|
||||
This is an internal register, which usually shouldn't be accessed by software.
|
||||
Messing with it has rather strange effects: After writing a value "X" to this
|
||||
register, reading returns "X ROR 8" eventually "ANDed with 1F1Fh and ORed with
|
||||
C0C0h or 8080h" (depending on the character length in SIO_MODE).<br/>
|
||||
C0C0h or 8080h" (depending on the character length in SIO\_MODE).<br/>
|
||||
|
||||
#### 1F80105Eh SIO_BAUD (R/W) (eg. 00DCh --\> 9600 bauds; when Factor=MUL16)
|
||||
#### 1F80105Eh SIO\_BAUD (R/W) (eg. 00DCh --\> 9600 bauds; when Factor=MUL16)
|
||||
```
|
||||
0-15 Baudrate Reload value for decrementing Baudrate Timer
|
||||
```
|
||||
The Baudrate is calculated (based on SIO_BAUD, and on Factor in SIO_MODE):<br/>
|
||||
The Baudrate is calculated (based on SIO\_BAUD, and on Factor in SIO\_MODE):<br/>
|
||||
```
|
||||
BitsPerSecond = (44100Hz*300h) / MIN(((Reload*Factor) AND NOT 1),Factor)
|
||||
```
|
||||
|
||||
#### SIO_TX_DATA Notes
|
||||
#### SIO\_TX\_DATA Notes
|
||||
The hardware can hold (almost) 2 bytes in the TX direction (one being currently
|
||||
transferred, and, once when the start bit was sent, another byte can be stored
|
||||
in SIO_TX_DATA). When writing to SIO_TX_DATA, both SIO_STAT.0 and SIO_STAT.2
|
||||
become zero. As soon as the transfer starts, SIO_STAT.0 becomes set (indicating
|
||||
that one can write a new byte to SIO_TX_DATA; although the transmission is
|
||||
in SIO\_TX\_DATA). When writing to SIO\_TX\_DATA, both SIO\_STAT.0 and SIO\_STAT.2
|
||||
become zero. As soon as the transfer starts, SIO\_STAT.0 becomes set (indicating
|
||||
that one can write a new byte to SIO\_TX\_DATA; although the transmission is
|
||||
still busy). As soon as the transfer of the most recently written byte ends,
|
||||
SIO_STAT.2 becomes set.<br/>
|
||||
SIO\_STAT.2 becomes set.<br/>
|
||||
|
||||
#### SIO_RX_DATA Notes
|
||||
#### SIO\_RX\_DATA Notes
|
||||
The hardware can hold 8 bytes in the RX direction (when receiving further
|
||||
byte(s) while the RX FIFO is full, then the last FIFO entry will by overwritten
|
||||
by the new byte, and SIO_STAT.4 gets set; the hardware does NOT automatically
|
||||
by the new byte, and SIO\_STAT.4 gets set; the hardware does NOT automatically
|
||||
disable RTS when the FIFO becomes full).<br/>
|
||||
Data can be read from SIO_RX_DATA when SIO_STAT.1 is set, that flag gets
|
||||
automatically cleared after reading from SIO_RX_DATA (unless there are still
|
||||
Data can be read from SIO\_RX\_DATA when SIO\_STAT.1 is set, that flag gets
|
||||
automatically cleared after reading from SIO\_RX\_DATA (unless there are still
|
||||
further bytes in the RX FIFO). Note: The hardware does always store incoming
|
||||
data in RX FIFO (even when Parity or Stop bits are invalid).<br/>
|
||||
Note: A 16bit read allows to read two FIFO entries at once; nethertheless, it
|
||||
@ -113,19 +113,19 @@ FIFO empty flag gets set, but nethertheless, the last byte can be read two more
|
||||
times, but doing further reads returns 00h).<br/>
|
||||
|
||||
#### Interrupt Acknowledge Notes
|
||||
First reset I_STAT.8, then set SIO.CTRL.4 (when doing it vice-versa, the
|
||||
First reset I\_STAT.8, then set SIO.CTRL.4 (when doing it vice-versa, the
|
||||
hardware may miss a new IRQ which may occur immediately after setting
|
||||
SIO.CTRL.4) (and I_STAT.8 is edge triggered, so that bit can be reset even
|
||||
while SIO_STAT.9 is still set).<br/>
|
||||
When acknowledging via SIO_CTRL.4 with the enabled condition(s) in
|
||||
SIO_CTRL.10-12 still being true (eg. the RX FIFO is still not empty): the IRQ
|
||||
SIO.CTRL.4) (and I\_STAT.8 is edge triggered, so that bit can be reset even
|
||||
while SIO\_STAT.9 is still set).<br/>
|
||||
When acknowledging via SIO\_CTRL.4 with the enabled condition(s) in
|
||||
SIO\_CTRL.10-12 still being true (eg. the RX FIFO is still not empty): the IRQ
|
||||
does trigger again (almost) immediately (it goes off only for a very short
|
||||
moment; barely enough to allow I_STAT.8 to sense a edge).<br/>
|
||||
moment; barely enough to allow I\_STAT.8 to sense a edge).<br/>
|
||||
|
||||
#### SIO_BAUD Notes
|
||||
Timer reload occurs when writing to SIO_BAUD, and, automatically when the
|
||||
#### SIO\_BAUD Notes
|
||||
Timer reload occurs when writing to SIO\_BAUD, and, automatically when the
|
||||
Baudrate Timer reaches zero. There should be two 16bit SIO timers (for TX and
|
||||
RX), the upper 15bit of one of that timers can be read from SIO_STAT (not sure
|
||||
RX), the upper 15bit of one of that timers can be read from SIO\_STAT (not sure
|
||||
which one, and no idea if there's a way to read the other timer, too).<br/>
|
||||
Or... maybe there is only ONE timer, and RX/TX are separated only by separate
|
||||
"timer ellapsed" counters, in that case the MUL1 factor won't work properly,
|
||||
@ -146,7 +146,7 @@ SIO uses I/O Addresses 1F801050h..1F80105Fh, which seem to be organized similar
|
||||
to the Controller/Memory Card registers at 1F801040h..1F80104Fh, though not
|
||||
identical, and with an additional register at 1F80105Ch, which has no
|
||||
corresponding port at 1F80104Ch.<br/>
|
||||
SIO_BAUD is \<effectively\> same as for JOY_BAUD, but, \<internally\>
|
||||
SIO\_BAUD is \<effectively\> same as for JOY\_BAUD, but, \<internally\>
|
||||
they are a bit different:<br/>
|
||||
```
|
||||
JOY_BAUD is multiplied by Factor, and does then ellapse "2" times per bit.
|
||||
@ -167,7 +167,7 @@ serial ports, connected to the expansion port,<br/>
|
||||
|
||||
#### SIO Games
|
||||
The serial port is used (for 2-player link) by Wipeout 2097 (that game
|
||||
accidently assumes BAUDs based on 64*1024*1025 Hz rather than on 600h*44100
|
||||
accidently assumes BAUDs based on 64\*1024\*1025 Hz rather than on 600h\*44100
|
||||
Hz).<br/>
|
||||
Ridge Racer Revolution is also said to support 2P link.<br/>
|
||||
Keitai Eddy seems to allow to connect a mobile phone to the SIO port (the games
|
||||
|
@ -79,7 +79,7 @@ The SPU is connected to a 16bit databus. 8bit/16bit/32bit reads and 16bit/32bit
|
||||
writes are implemented. However, 8bit writes are NOT implemented: 8bit writes
|
||||
to ODD addresses are simply ignored (without causing any exceptions), 8bit
|
||||
writes to EVEN addresses are executed as 16bit writes (eg. "movp r1,12345678h,
|
||||
movb [spu_port],r1" will write 5678h instead of 78h).<br/>
|
||||
movb [spu\_port],r1" will write 5678h instead of 78h).<br/>
|
||||
|
||||
|
||||
|
||||
@ -89,7 +89,7 @@ totally unsupported; leaving apart that one can write uncompressed 16bit PCM
|
||||
samples to the Reverb Buffer, which can be then output at 22050Hz, as long as
|
||||
they aren't overwritten by the hardware).<br/>
|
||||
|
||||
#### 1F801C06h+N*10h - Voice 0..23 ADPCM Start Address (R/W)
|
||||
#### 1F801C06h+N\*10h - Voice 0..23 ADPCM Start Address (R/W)
|
||||
This register holds the sample start address (not the current address, ie. the
|
||||
register doesn't increment during playback).<br/>
|
||||
```
|
||||
@ -98,7 +98,7 @@ register doesn't increment during playback).<br/>
|
||||
Writing to this register has no effect on the currently playing voice.<br/>
|
||||
The start address is copied to the current address upon Key On.<br/>
|
||||
|
||||
#### 1F801C0Eh+N*10h - Voice 0..23 ADPCM Repeat Address (R/W)
|
||||
#### 1F801C0Eh+N\*10h - Voice 0..23 ADPCM Repeat Address (R/W)
|
||||
If the hardware finds an ADPCM header with Loop-Start-Bit, then it copies the
|
||||
current address to the repeat addresss register.<br/>
|
||||
If the hardware finds an ADPCM header with Loop-Stop-Bit, then it copies the
|
||||
@ -162,7 +162,7 @@ two sample rates, and, XA doesn't support looping.<br/>
|
||||
|
||||
|
||||
## SPU ADPCM Pitch
|
||||
#### 1F801C04h+N*10h - Voice 0..23 ADPCM Sample Rate (R/W) (VxPitch)
|
||||
#### 1F801C04h+N\*10h - Voice 0..23 ADPCM Sample Rate (R/W) (VxPitch)
|
||||
```
|
||||
0-15 Sample rate (0=stop, 4000h=fastest, 4001h..FFFFh=usually same as 4000h)
|
||||
```
|
||||
@ -328,7 +328,7 @@ overflow, which has been a hardware glitch on the SNES).<br/>
|
||||
|
||||
|
||||
## SPU Volume and ADSR Generator
|
||||
#### 1F801C08h+N*10h - Voice 0..23 Attack/Decay/Sustain/Release (ADSR) (32bit)
|
||||
#### 1F801C08h+N\*10h - Voice 0..23 Attack/Decay/Sustain/Release (ADSR) (32bit)
|
||||
```
|
||||
____lower 16bit (at 1F801C08h+N*10h)___________________________________
|
||||
15 Attack Mode (0=Linear, 1=Exponential)
|
||||
@ -357,8 +357,8 @@ and switches from Sustain to Release when the software sets the Key OFF flag.<br
|
||||
|
||||
#### 1F801D80h - Mainvolume left
|
||||
#### 1F801D82h - Mainvolume right
|
||||
#### 1F801C00h+N*10h - Voice 0..23 Volume Left
|
||||
#### 1F801C02h+N*10h - Voice 0..23 Volume Right
|
||||
#### 1F801C00h+N\*10h - Voice 0..23 Volume Left
|
||||
#### 1F801C02h+N\*10h - Voice 0..23 Volume Right
|
||||
Fixed Volume Mode (when Bit15=0):<br/>
|
||||
```
|
||||
15 Must be zero (0=Volume Mode)
|
||||
@ -408,7 +408,7 @@ ability to convert stereo CD output to mono, or to swap left/right channels).<br
|
||||
Exponential Increase is a fake (simply changes to a slower linear increase rate
|
||||
at higher volume levels).<br/>
|
||||
|
||||
#### 1F801C0Ch+N*10h - Voice 0..23 Current ADSR volume (R/W)
|
||||
#### 1F801C0Ch+N\*10h - Voice 0..23 Current ADSR volume (R/W)
|
||||
```
|
||||
15-0 Current ADSR Volume (0..+7FFFh) (or -8000h..+7FFFh on manual write)
|
||||
```
|
||||
@ -420,13 +420,13 @@ overwrite the setting (from another internal register) whenever applying a new
|
||||
Step?!<br/>
|
||||
|
||||
#### 1F801DB8h - Current Main Volume Left/Right
|
||||
#### 1F801E00h+voice*04h - Voice 0..23 Current Volume Left/Right
|
||||
#### 1F801E00h+voice\*04h - Voice 0..23 Current Volume Left/Right
|
||||
```
|
||||
0-15 Current Volume Left (-8000h..+7FFFh)
|
||||
16-31 Current Volume Right (-8000h..+7FFFh)
|
||||
```
|
||||
These are internal registers, normally not used by software (the Volume
|
||||
settings are usually set via Ports 1F801D80h and 1F801C00h+N*10h).<br/>
|
||||
settings are usually set via Ports 1F801D80h and 1F801C00h+N\*10h).<br/>
|
||||
|
||||
#### Note
|
||||
Negative volumes are phase inverted, otherwise same as positive.<br/>
|
||||
@ -834,7 +834,7 @@ vIIR works only in range -7FFFh..+7FFFh. When set to -8000h, the multiplication
|
||||
by -8000h is still done correctly, but, the final result (the value written to
|
||||
memory) gets negated (this is a pretty strange feature, it is NOT a simple
|
||||
overflow bug, it does affect the "+[mLSAME-2]" addition; although that part
|
||||
normally shouldn't be affected by the "*vIIR" multiplication). Similar effects
|
||||
normally shouldn't be affected by the "\*vIIR" multiplication). Similar effects
|
||||
might (?) occur on some other volume registers when they are set to -8000h.<br/>
|
||||
|
||||
#### Speed of Sound
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Timers
|
||||
#### 1F801100h+N*10h - Timer 0..2 Current Counter Value (R/W)
|
||||
#### 1F801100h+N\*10h - Timer 0..2 Current Counter Value (R/W)
|
||||
```
|
||||
0-15 Current Counter value (incrementing)
|
||||
16-31 Garbage
|
||||
@ -9,7 +9,7 @@ it to any value). It gets forcefully reset to 0000h on any write to the Counter
|
||||
Mode register, and on counter overflow (either when exceeding FFFFh, or when
|
||||
exceeding the selected target value).<br/>
|
||||
|
||||
#### 1F801104h+N*10h - Timer 0..2 Counter Mode (R/W)
|
||||
#### 1F801104h+N\*10h - Timer 0..2 Counter Mode (R/W)
|
||||
```
|
||||
0 Synchronization Enable (0=Free Run, 1=Synchronize via Bit1-2)
|
||||
1-2 Synchronization Mode (0-3, see lists below)
|
||||
@ -48,7 +48,7 @@ the Mode register, and becomes inverted on each IRQ (in one-shot mode, it
|
||||
remains zero after the IRQ) (in repeat mode it inverts Bit10 on each IRQ, so
|
||||
IRQ4/5/6 are triggered only each 2nd time, ie. when Bit10 changes from 1 to 0).<br/>
|
||||
|
||||
#### 1F801108h+N*10h - Timer 0..2 Counter Target Value (R/W)
|
||||
#### 1F801108h+N\*10h - Timer 0..2 Counter Target Value (R/W)
|
||||
```
|
||||
0-15 Counter Target value
|
||||
16-31 Garbage
|
||||
|
@ -42,9 +42,9 @@ Whereas,<br/>
|
||||
(i16) write full 16bits (ignored if address isn't halfword-aligned)
|
||||
CROP write only lower 16bit (and leave upper 16bit unchanged)
|
||||
```
|
||||
It's somewhat "legit" to use 16bit writes on 16bit registers like RAM_SIZE,
|
||||
I_STAT, I_MASK, and Timer 0-2.<br/>
|
||||
Non-4-byte aligned 8bit/16bit writes to RAM_SIZE do crash (probably because the
|
||||
It's somewhat "legit" to use 16bit writes on 16bit registers like RAM\_SIZE,
|
||||
I\_STAT, I\_MASK, and Timer 0-2.<br/>
|
||||
Non-4-byte aligned 8bit/16bit writes to RAM\_SIZE do crash (probably because the
|
||||
"(w32)" effect is left-shifting the value, so lower 8bit become zero).<br/>
|
||||
Results on unaligned I/O port writes (via SWL/SWR opcodes) are unknown.<br/>
|
||||
|
||||
@ -103,7 +103,7 @@ assembler not to destroy that register behind your back.<br/>
|
||||
The PSX Kernel uses "Full-Decrementing-Wasted-Stack", where "Wasted" means that
|
||||
when calling a sub-function with N parameters, then the caller must
|
||||
pre-allocate N works on stack, and the sub-function may freely use and destroy
|
||||
these words; at [SP+0..N*4-1].<br/>
|
||||
these words; at [SP+0..N\*4-1].<br/>
|
||||
|
||||
#### Locked Locations in Memory and I/O Area
|
||||
```
|
||||
@ -130,7 +130,7 @@ locked regions are same as for first 512MB of KUSEG.<br/>
|
||||
```
|
||||
1F80108Ch+N*10h - D#_CHCR Mirrors - (N=0..6, for DMA channel 0..6)
|
||||
```
|
||||
Read/writeable mirrors of DMA Control registers at 1F801088h+N*10h.<br/>
|
||||
Read/writeable mirrors of DMA Control registers at 1F801088h+N\*10h.<br/>
|
||||
|
||||
#### Garbage Locations in I/O Area
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user