Deformat a bit.

This commit is contained in:
Nicolas 'Pixel' Noble 2020-07-23 13:41:06 -07:00
parent a9cc30ff6e
commit 9c394320d4
22 changed files with 566 additions and 563 deletions

View File

@ -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/>

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)
```

View File

@ -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(/&lt;/, "\\<");
gsub(/&gt;/, "\\>");
gsub(/*/, "\\*");
gsub(/_/, "\\_");
gsub(/~/, "\\~");
}
gsub(/&amp;/, "\\&");

View File

@ -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

View File

@ -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/>

View File

@ -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/>

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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/>

View File

@ -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

View File

@ -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/>

View File

@ -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)

View File

@ -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/>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
```