Skip to content

Instantly share code, notes, and snippets.

@uyjulian
Created July 24, 2025 00:52
Show Gist options
  • Save uyjulian/f3220a7f55110f05c3664cb40f64b02c to your computer and use it in GitHub Desktop.
Save uyjulian/f3220a7f55110f05c3664cb40f64b02c to your computer and use it in GitHub Desktop.
##############################################################
### DEV9C.txt ###
### v01, 2017.02.11 ###
### by Wisi ###
##############################################################
Dev9 Controller
Also known as:
HDD Controller
SS-BUS Controller
SS-BUS Interface
SSBUS Buffer
It is a signal buffer for the Dev9 expansion interface, with only a few capabilities.
It is perhaps the least complex by far of all ICs in the PS2.
In later revisions, the SPU2 was merged with it in a single ASIC.
The chip used as buffer for the expansion interface (PCMCIA or Expansion Bay) is referred to in this document Dev9Controller. It is connected at SSBUSC channel Dev#12 (0xC). It is significantly different between its PCMCIA and Expansion Bay variant, although the buffering function is retained. This document only describes the Expansion Bay variant.
The Expansion Bay Dev9C also contains an I2C interface for communicating with the Digital Video Encoder, which is not covered here. The I2C interface is accessible at a different base address - 0x16000000 (0xBA000000 on EE side).
Dev9Controller Register definitions.
Registers are accessed as 16-bit, but only the lower 8-bits are used. Base address = 0xBF801460.
1460:
0 Enable Dev9 SPEED buffer (when set). When clear, all Dev9 SPEED lines (for communication with the Network Adapter) would be undriven.
1 Enable Dev5 CDVD buffer (when set). This enabled driving the Dev5 (CDVD) signals from the Expansion Bay. Set bit 6 of this register, before setting this bit, to prevent bus-fights with the CDVD DSP. If this is written, the power button stops working (can't turn off), because it causes the /INT5 line (3-pole on CDVD, open-drain on Dev9C (?)) to be driven by the Dev9C, causing a logic short circuit, when an interrupt from CDVD is generated.
2 Enable Dev8 EXTR(PIO) buffer (when set). /CCSEX (buffered output of /EXTR) is driven only if this is set.
3 Always 0 even if written 1.
4 Always 0 even if written 1.
5 Drives CSIG2 (Dev9C->SPEED) 1=high/0=low level. CSIG2 has nothing to do with SIG2.
6 Drives SIG2 (/DEV5EN) 1=high/0=low level. When 1, the /DEV5EN line disables the CDVD device (Dev5), so that another device can connect through the Expansion Bay interface, in order to emulate it. If this is set, the power button stops working (can't turn off), because the CDVD device is inaccessible. This also disables the CDVD Digital audio output. This is used in the PSX DVR to switch between the PS2 CDVD DSP and the ATAPI drive SPEED chip.
7 When set, enables the Digital audio output of the Dev9C - buffered input signals from the Expansion Bay connector.
1462:
0 Status of CDTCT (client detect) = /HDD_SET line: 0=active_low(When SPEED is connected, even without a HDD, this is brought low), while 1=inctive_high = SPEED disconnected. The network adapter has this line grounded.
1464:
0 Dev9 Wide DMA enable
1 Dev9 ? Most likely read sampling edge, as bit 5.
2 Dev5 Wide DMA enable
3 Dev5 ? Most likely read sampling edge, as bit 5.
4 Dev#8 (EXTR/PIO) Wide (32-bit) DMA Enabled, when set. (See SSBUSC docs.)
5 Dev#8 clock sampling edge for data: 0=High->low / 1=low->High. Test was done with direction Exp.Bay -> Dev9C -> IOP - in this case, data was output to the IOP on the same (sampling) edge.
6 Always 0 even if written 1.
7 Always 0 even if written 1.
The test was carried-out doing a read DMA transfer, and measuring output data of the Dev9C (to IOP). Because the Exp.Bay data bus was just released (unknown why), the line would ramp low when DMA started. A resistor was used to pull it low (faster), so that its ramping would be more stable. In a loop two DMA transfers would be started, with delay between them (>10ms) and different values for this bit (5) before each. On one transfer, the data line to the IOP would go low sooner than on the other - each corresponds to a clock edge.
On DMA write, this bit didn't cause a change in the timing. Data is changed only on the rising edge of the clock.
Can be read and written: minimum value = 0x00, maximum value 0x3F. For the Expansion Bay type Dev9C, values written to it are masked to 0x3F. On initialization, it is written 0x3. In a driver, it is written the value for common (PCMCAI and Expansion Bay) status (= 0x103), with the 0x3F asking.
(BF801466) = 1 Mask Dev9 interrupt.
(BF80146C) = 0 End reset.
(BF801464) = (BF80146C) why? - Maybe they were certain that each register would always return what was last written, so this is just clearing.
(BF801460) = (BF801464) why again?
1466:
0 Masks (turns off) Dev9 interrupt, when set. This bit is ANDed with each input /CINT9 signal from Expansion Bay, to produce, an output /INT9 signal to the IOP. The way it is written 1 then 0, in the Dev9 interrupt handler, would suggest that it actually clears a latch, e.g. - an interrupt is asserted from the Expansion Bay, then this latches it to an output /INT9 line, so that the state remains on the line, even if the /CINT9 line for the Exp.Bay is deasserted, and the /INT9 line is deasserted when this bit first is set and then cleared. However tests proved, that this is not so.(?) This has no effect on the EXTR (Dev8) interrupt (/CINTEX -> /INTEX). /INT5 (CDVD) is untested.
1468: read 0xFFFF - bus looks undriven
146A: read 0xFFFF - bus looks undriven
146C: Power & signal control.
0 Drives the /CRST line (0=low/1=high), which connects to both RST_N and ALLRST_N inputs of the SPEED chip. It is unknown if the state of this bit is ANDed with the global /RST line before connecting to the output. Set after starting power (bit3=1), always cleared before that. Bit 0 of 1460 is set before setting this (on init). On shutdown this is cleared after bit 2 of this register.
1 Unused, always 0.
2 Controls PWR_CTRL line (1=active_high / 0=inactive_low). This goes to the SYSCON and the SPEED. The SYSCON increases the fan speed when this is active, and applies power to the Dev9(?).
3 Controls the SIG3 output (pin 3) - the 54CLK_SEL line to the GS clock generator. This output is only present on the CXD9611BR - it is Not Connected on the CSX9611R, where this bit cannot be set. This is a guess, as the only confirmation is a write to this bit in the eekernel of the post-SCPH-39000 models.
146E: Dev9Controller Type, Revision
*The following table is incomplete and partially wrong.
0x20? CXD9566R PCMCIA TOOL (which?) See AIF docs for more (or less) info.
0x20 CXD9566 PCMCIA GH-? GH-?
0x30 CXD9611R Exp.Bay GH-? GH-007 without SIG3(pin3) = reg. 146C/bit3.
0x30? CXD9611AR Exp.Bay GH-013 GH-014 without SIG3(pin3) = reg. 146C/bit3.
0x31 CXD9611BR Exp.Bay GH-015 later with SIG3(pin3) = reg. 146C/bit3.
0x31 CXD9686BR Exp.Bay
0x32 CXD2955R Exp.Bay +SPU2
DECKARD consoles report 0x31 as type/revision. It is software-emulated by DECKARD.
1470-147F - Unimplemented on CXD9611 (read 0xFFFF - bus looks undriven).
CSIG1 is (always) driven by SIG1. No register seems to show their state, or control their function.
Disabling Dev5 (CDVD) (setting bit 6) and while disabled, pressing the power button, then releasing the power button, and re-enabling Dev5, causes the PS2 to power off when Dev5 is re-enabled (Dev5 sends an interrupt at this point to signal the power button event). This might mean that the /DEV5EN signal can be used to drive Dev5 into disabled state, while otherwise operational, so that its interface lines could be used for other device in that period.
Digital audio input AUXCIN0 has pull-up and is always input (there is no direction-control). The corresponding output responds correctly, when enabled.
/CCSn signals are undriven, when buffering is disabled by 1460/2:0.
/SRD, /SWR, /UBE, the address lines are always buffered by the Dev9C, when it is powered.
Output signals of the Dev9C are driven instantly after input is changed - there are no delays, other than the propagation delays through the logic (~6ns - for chip select signals).
None of the registers in the Dev9C range (0xBF801460) was found to change timing in any way.
The Dev9 chip select range spreads from (IOP) 0xB0000000 to 0xB7FFFFFF. It is common for both the Dev9_2 (Dev#10) and Dev9_3 (Dev9#11) SSBUS devices. Separation between the two is done on the basis of the A26 line. Even though high address lines are used in the selection, the actual memory range of each 'sub-device' is no more than 0x10000 bytes (16 address lines), so most likely the device is mirrored on the next 0x10000 offset. The address lines (A26-A24) below, are the only high(>A15) address lines going to the Dev9C. The following is valid for GH-006.
Addr. lines: 26 25 24 Sub-device
Addressed
Dev9_2:
0xB0000000 0 0 0 SPEED / PCMCIA, The /CCS9 buffered output of /CS9, would only go active in this range.
0xB1000000 0 0 1
0xB2000000 0 1 0
0xB3000000 0 1 1
Dev9_3:
0xB4000000 1 0 0 AIF (TOOL)
0xB5000000 1 0 1
0xB6000000 1 1 0 Dev9C I2C interface for the DVE
0xB7000000 1 1 1
On later models (GH-023), because AIF would be unused, and there were many unused ranges, thy shrunk the selection to only A26, connected the Dev9C input A25 to A26 and Dev9C input A24 would receive the inverted value of /CS9C (0xBF801460):
Addr. lines: 26 25 24 Sub-device
Addressed
Dev9_2:
0xB0000000 0 0 0 SPEED / PCMCIA
0xB1000000 0 0 0 mirror of 0xB0000000
0xB2000000 0 0 0 mirror of 0xB0000000
0xB3000000 0 0 0 mirror of 0xB0000000
Dev9_3:
0xB4000000 1 1 0 Dev9C I2C interface for the DVE
0xB5000000 1 1 0 mirror of 0xB4000000
0xB6000000 1 1 0 mirror of 0xB4000000
0xB7000000 1 1 0 mirror of 0xB4000000
In this case, for the Dev9C, A24 would only go high over the /CS9C rage - 0xBF801460 - 0xBF80147E.
Contrary to logic, the Dev9_3 SSBUS delay register controls DMA timing of the Dev9 DMA channel ... although there might be a way to switch which delay register controls DMA timing. It might be that, because the PCMCIA range came first into existence, its DMA controller (Dev9 DMA) remained configured through its delay reg.
0xBF801460 - 0xBF80147E:
Default values after initialization:
0001 0000 0003 0000 FFFF FFFF 0005 0030
FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF
After writing 0xFFFF to all:
00E7 0000 003F 0001 FFFF FFFF 0005 0030
FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF
After writing 0 to all:
0000 0000 0000 0000 0000 0000 0000 0030
0000 0000 0000 0000 0000 0000 0000 0000
* The unimplemented registers read 0, because the Dev9C drives them 'differently' when it is powered off.
The early PS2 models ~ SCPH-30000 series, have all Dev9C buffered signals on the ExpansionBay connector. (See register 0x1460.) This allows connecting a hardware like the PC-side of the PS2 TOOL, through the Dev8 Exp2 (PIO) interface, and turning the PS2 into a semi-TOOL. It might be possible to remap the Dev9_2 SSBUSC channel over the BIOS ROM memory, and after a soft reset, the PS2 would be booted from an external ROM connected through the Dev9 interface. (This has not been tested, and seems unlikely.)
The capability of connecting an external device in place of the CDVD device, through the ExpansionBay connector, might have been meant for use by a CDVD emulator, similar to the one in the TOOL.
Later ExpansionBay models had all lines, but those necessary for the SPEED device, disconnected.
##############################################################
### DEV9C_PCMCIA.txt ###
### v01, 2017.02.11 ###
### by Wisi ###
##############################################################
This document covers only the PCMCIA Dev9C and the specifics of the SPEED regarding its PCMCIA interface.
It certainly contains errors, because at the time of writing I don't have the necessary hardware to test on. For this reason this is only an attempt to gather SilverBull's information on the PCMCIA Card interface and the Dev9C on ASSEMBlergames (http://assemblergames.com/l/threads/windows-dtl-h10030-driver.39252/). New information is added about the SPEED's PCMCIA interface, which was gathered from tests on a SPEED chip from a Network Adapter.
Abbreviations:
PCIC PC card Interface Controller (The early versions of the Dev9C.)
SSBUS Sub-system Bus (The bus that connects the IOP to the peripheral devices.)
SSB SSBUS. Usually used in line names.
SPEED Sony Peripheral Ethernet/Enhanced Extension/Expansion Device (The "default" expansion device for both the PCMCIA and the ExpansionBay interfaces.)
Speculations:
Initially the designers of the PS2 decided to add the PCMCIA slot to the PS2. It would be used as a multi-purpose expansion slot. It would (does) support standard PCMCIA cards and the proprietary(?) SPEED chip interface in a separate mode.
This went well, but at some point, the generic devices expansion capability would remain unused, because they most likely didn't want to support it from fear of complaints due to potential incompatibility, hacking issues, lack of actual use by users, etc.
So they went with their 'backup' plan - to free space in the PS2's chassis for a HDD and add a network adapter extension, making the standard extension devices (up to that point) integratable in the case of the PS2.
The SPEED chip from the PCMCIA went in the Network Adapter. The PCMCIA support was no longer necessary, so the changed the Dev9Controller/Buffer to one supporting only what was needed, and that was it - the Expansion Bay Dev9C.
Later, they updated the SPEED, the initial PCMCIA versions of which had some issues with the (new) Dev9C.
The SPEED is a proprietary interface & hardware PCMCIA device. That is, it can be connected to a PCMCIA slot and recognized as a PCMCIA card, but that is about it - no standard PCMCIA drivers (and possibly controllers) can interface with its devices (ATA Controller, SMAP, UART, ...).
It has two modes: PCMCIA mode and SSBUS-mode (also called SPEED-devices-mode here, because in PCMCIA mode the devices integrated in the SPEED chip are not actually accessible). It is possible that some early SPEED versions provided access to their devices in PCMCIA mode as well, but this is only a guess.
From PCMCIA-mode, the state can be switched to SPEED-devices mode, through register 0x20.
The SPEED basically "looks" the same way to the PS2 (its registers), once in SPEED mode, regardless whether it is mounted in a PCMCIA Card or in a Network Adapter.
The PS2Linux supports both the SPEED ATA interface and standard PCMCIA cards ATA interface.
Known SPEED models:
Chip Revision Capabilities PCMCIA_IF Found in
?? 0009 "TS" ? shouldHave PCMCIA?
?? 0010 "ES1" ? shouldHave PCMCIA?
CXD9624GG 0011 "ES2" 0003 0002 yes PCMCIA & Network Adapter
CXD9624AGG 0012 ? 000B 0002 yes PCMCIA & Network Adapter
CXD9731GP 0013 ? 000B 0002 yes PCMCIA(?) & Network Adapter
CXD9731AGP 0013? ? 000B 0002 shouldHave PCMCIA(?) & Network Adapter & SCPH-70000 series
CXD9731GP 0013 ? 000B 0002 yes PSX DVR, ATAPI drive.
CXD9764GP 0014 ? 003B 0002 mightNotHave PSX DVR, DVRP I/O, HDD, Flash
CXD9622 Most likely not a SPEED chip. "An old Japanese version that supports up to ATA66. CXD9731AGP supports up to ATA133." Source: from http://bbs.a9vg.com/thread-1410569-1-1.html
Versions after "ES2" are referred to as "after ES2", but is not known if there is an "ES3" version for example.
There are very early version(revision) values, which no known SPEED has.
It is assumed that all SPEED revisions support the "dummy" PCMCIA interface. Tests proved that the CXD9731GP from a Network Adapter does support it. Guess: The very early SPEED chips might support complete PCMCIA interface for the integrated hardware (ATA, SMAP).
Source: l_oliveira ( http://assemblergames.com/l/threads/differences-between-fat-ps2-motherboards-and-dev9-interfaces.56050/ ):
/---
There's "revisions" on the CXD9611 chip. A, B and R, for example. A and B seem to be identical function wise. I believe R would be found on late 3900x up to early 5000x (before they merged the SSBUC with the SPU2).
Funny enough, if your console malfunctions when used with a older network adapter using the CXD9624 chip you can always look for another network adapter made with the newer chip (CXD9731). Apparently the newer chip has fixes in it which make it better in compatibility with all the expansion bay port variations.
\---
At the same time the CXD9731 has the PCMCIA hardware interface, thus the improved compatibility with the Expansion Bay models was not caused by removed hardware/support for PCMCIA.
From SilverBull with some modifications:
Source: http://assemblergames.com/l/threads/windows-dtl-h10030-driver.39252/page-3#post-629011
GND is ground, "L" is low potential, "H" is selected high potential (Vcc, changeable via power control register). Output voltage of CDx and VSx pins cannot be changed for obvious reasons, but other control pins can. The state of Vcc-dependent pins (like BVDx, WP, READY and so on) cannot be read until power has been applied to the card and OE=1 in the power control register.
BEWARE: there is no hardware protection against the wrong voltage being applied to a PCMCIA/CardBus card. Misuse of the power control register can fry a card, so BE CAREFUL.
Dev9C PCMCIA type. Base address = 0x1F801460. Only the low 16 bits are used below to specify registers:
0x1460 Target memory space. Selects which PCMCIA space is accessed via memory accesses to 0xB0000000 on the IOP. Only the lower 3 bits keep a written value.
0 r/w sets /REG line state: 0=act.low / 1=inact.high. (guess)
1 r/w selects the control lines pair: 0=IO_Registers_/IORD(/SRD),/IOWR(/SWR) / 0=Memory_/OE,/WE (guess)
00 PCMCIA I/O registers.
01 PCMCIA DMA; SPEED devices (in SSB mode only).
10 PCMCIA Attribute memory.
11 PCMCIA Common memory.
The following is the original description, which seems more correct than my guess above:
00 PCMCIA Common Memory (P#61/!REG=H, /OE,/WE);
01 PCMCIA I/O Registers (P#61/!REG=L, /IORD,/IOWR);
10 PCMCIA Attribute Memory (config) (P#61/!REG=L, /OE,/WE)
11 PCMCIA DMA or as above?
2 ? r/w, unknown. (changeable, interpretation unknown) Most likely bus-related.
15:3 ? r/o, = 0.
0x1462 Card status pins. r/o all of it.
0 P#36/!CD1: 0=>L
1 P#67/!CD2: 0=>L
2 P#43/!VS1: 0=>L
3 P#57:!VS2: 0=>L
4 P#63/!STSCHG/BVD1: 0=>L (only valid if Vcc+OE)
5 P#62/!SPKR/BVD2: 0=>L (only valid if Vcc+OE)
6 P#33/!IOIS16/WP: 0=>L (only valid if Vcc+OE)
7 P#16/!IREQ/READY: 0=>L (only valid if Vcc+OE)
8 ? Indicates error if 0 after power on
0x1464, 0x1466 (r/w): Edge-triggered Interrupt status register. Bits set when condition occurs, writing a 1 clears the bit. At least 9 bits in use.
0x1464 is for "signal asserted" (e.g., !CD1 going from H to L), 0x1466 is for "signal deasserted" (e.g., !CD1 going from L to H).
0 !CD1
1 !CD2
2 ? Should be P#43/!VS1
3 ? Should be P#57:!VS2
4 !STSCHG/BVD1
5 !SPKR/BVD2
6 !IOIS16/WP
7 !IREQ/READY
8 ? Something related to Vpp ?
0x1468 guess: read=state/write=clear. (PS2Linux writes to it 0xFFFF for rev=0x20 or 0xFF7F for rev=0x10.) It very much seems like the registers above: witing 1 clears the corresponding bit, and each bit reflects some state.
Value 0x0010
0x146A guess: read=state/write=clear. (PS2Linux writes to it 0xFFFF for rev=0x20 or 0xFF7F for rev=0x10.) It very much seems like the registers above: witing 1 clears the corresponding bit, and each bit reflects some state.
Value = 0x0090
0x146C (r/w): Power control. Only the lower 5 bits are known.
0 Reset line state: 1=inact.L (PCMCIA-state is active) / 0=act.Vcc (PCMCIA is in reset state, SPEED is in SSB (SPEED devices) mode) (Only if OE=Vcc, otherwise L); Clearing this might assert high the /REG line as well.
1 1=> OE=Vcc (Vcc-dependent outputs enabled); 0=> OE=L (Vcc-dependent outputs to GND)
3:2 00/11=> Vcc=0V; 01=>Vcc=3V3; 10=>Vcc=5V On rev = 0x1_ these two seem to be in reverse.
4 Vpp enable: 1=> Vpp=Vcc; 0=> Vpp=GND.
5 ?
6 set in PS2Linux.
7 set in PS2Linux.
0x146E (r/o): Device identification register. See Dev9C document for more info.
3:0 Revision
7:4 Type: 0x1=PCMCIA_old? / 0x2=PCMCIA / 0x3=ExpansionBay
0x1470 ? usually = 0.
0x1472 ? usually = 0x01.
0x1474 PCIC Bus Voltage Configuration
0 Set on mode=3, before setting bit 1.
1 Enable power / enable bus. Set only once voltage has been configured by bits 0 & 2.
2 Set on mode=5, together with bit 0, before setting bit 1 as well.
2:0 011=3.3V / 111=5.0V
3 ?
15:4 ?
0x1476 r/w? PS2Linux writes to it 0x1 for rev=0x10.
0x1478 ?
0x147A r/w? PS2Linux writes to it 0x0 for rev=0x10.
0x147C r/w? PS2Linux writes to it 0x1 for rev=0x10.
0x147E r/w? PS2Linux writes to it 0x1 for rev=0x20 or 0x0 for rev=0x10.
Memory segments:
/OE & /WE /IORD & /IOWR
/REG
inact.high CommonMem DMA; SPEED devices in SSB mode.
active.low AttribMem I/O Registers
On SPEED, there is no /WE, so Attribute Memory & Common Memory are read-only.
Attribute memory is implemented on the (known versions of the) SPEED, but PCMCIA Common Memory and PCMCIA DMA are not.
Only a single PCMCIA I/O Register (or in the "DMA"-range perhaps) exists - at offset 0x20 - bit 0 is a write-only, set-only soft-switch which masks (forces set) the SSB_MODE line function to put the SPEED into SSB (SPEED devices) mode. This soft-switch can only be reset by power-cycling the SPEED or applying a reset pulse to the /ALL_RST_N line.
Reading the PCMCIA Common Memory, I/O registers, DMA ranges returns 0.
Reading Attribute Memory yeilds (the rest of the SPEED address space up to +0x10000 is 0):
0xb0000000: 01 00 03 00 d9 00 01 00 ff 00 1c 00 04 00 02 00 ................
0xb0000010: d9 00 01 00 ff 00 20 00 04 00 f1 00 00 00 00 00 ...... .........
0xb0000020: 53 00 21 00 02 00 fe 00 01 00 15 00 5c 00 07 00 S.!.........\...
0xb0000030: 00 00 28 00 43 00 29 00 32 00 30 00 30 00 30 00 ..(.C.).2.0.0.0.
0xb0000040: 20 00 53 00 6f 00 6e 00 79 00 20 00 43 00 6f 00 .S.o.n.y. .C.o.
0xb0000050: 6d 00 70 00 75 00 74 00 65 00 72 00 20 00 45 00 m.p.u.t.e.r. .E.
0xb0000060: 6e 00 74 00 65 00 72 00 74 00 61 00 69 00 6e 00 n.t.e.r.t.a.i.n.
0xb0000070: 6d 00 65 00 6e 00 74 00 20 00 49 00 6e 00 63 00 m.e.n.t. .I.n.c.
0xb0000080: 2e 00 20 00 41 00 6c 00 6c 00 20 00 72 00 69 00 .. .A.l.l. .r.i.
0xb0000090: 67 00 68 00 74 00 73 00 20 00 72 00 65 00 73 00 g.h.t.s. .r.e.s.
0xb00000a0: 65 00 72 00 76 00 65 00 64 00 2e 00 00 00 48 00 e.r.v.e.d.....H.
0xb00000b0: 44 00 44 00 20 00 26 00 20 00 45 00 74 00 68 00 D.D. .&. .E.t.h.
0xb00000c0: 65 00 72 00 6e 00 65 00 74 00 20 00 49 00 2f 00 e.r.n.e.t. .I./.
0xb00000d0: 46 00 20 00 66 00 6f 00 72 00 20 00 50 00 53 00 F. .f.o.r. .P.S.
0xb00000e0: 32 00 00 00 ff 00 14 00 00 00 ff 00 00 00 00 00 2...............
0xb00000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Note: Once the mode is switched to SPEED-devices SSB-mode, by the use of register 0x20 of the PCMCIA I/O range, the value 0x01 can be read back from any register of the PCMCIA I/O range (untested - could be due to the bus becoming undriven after the switching). To complete the switch to SPEED devices mode, the RST_N line has to be brought high (reg. 0x146C bit 0 = 0).
/SSB_RST = 1; /ALL_RST_N = 1; /SSB_CS = pulsed low on access.
/RST_N SSB_MODE /SSB_REG /SSB_OE /SRD,/SWR
1 1 1 1 pulseLow SPEED Devices mode. Default state in Network Adapter.
1 1 NotCare NotCare pulseLow As above.
0 0 0 pulseLow inactOrPulse PCMCIA Attribute Memory.
0 0 1 pulseLow inactOrPulse? PCMCIA Common Memory.
0 0 0 1 pulseLow PCMCIA I/O Registers.
0 0 1 1 pulseLow PCMCIA DMA.
All other combinations basically result in no activity (nothing read/written).
PCMCIA Card with SPEED chip connections:
Pin# PCMCIA Connects to direc- SPEED Function
name tion name
Connected (used) lines:
36 !CD1 GND card-> - Card Detect 1 (Card insertion/removal detection.)
67 !CD2 GND card-> - Card Detect 2
43 !VS1 GND card-> - Voltage Select 1 (Defines the voltage of operation of the card.)
57 !VS2 R118, missing! card-> ? Reserved, Voltage Select 2 *Not connected (normal).
- - Vcc+delay(RC)? ->card /ALLRST_N low=reset / high=operational (Connection is a guess.)
58 RESET R110 ->card /SSB_RST (/SSB_AST) Bus reset. low=reset / high=operational. (This may be incorrect.)
58 RESET R110 ->card /RST_N Card Reset. + MODE switching: low=PCMCIA / high=SSB_mode. (This is most likely correct.)
- - GND (guess) ->card SSB_MODE low=PCMCIA_mode+SoftSwitchToSSBUS_mode / high=SSBUS_mode_only
61 !REG ->card /SSB_REG Register select and I/O Enable
7 !CE1 R115 ->card /SSB_CS9 Card Enable 1
9 !OE hard to trace ->card /SSB_OE Output Enable
44 !IORD R113 ->card /SRD I/O Read Strobe
45 !IOWR R114 ->card /SWR I/O Write Strobe
16 READY_!IREQ card-> /SSB_INT9 Ready or Busy/Interrupt Request
59 !WAIT card-> /SSB_WAIT Extend Bus Cycle
60 !INPACK L101 card->? /SSB_SSCLK? Input Port Acknowledge Direction: card-> only?
63 !STSCHG card-> ? Card Status Changed. *Usable as DREQ.
33 !IOIS16 R111 card-> /IOIS16? Write Protect / IO Port Is 16-bit. *Usable as DREQ.
? ->card /SSB_RT (SSB_AT) Read Timing.
A23 Most likely DMA lines - at least DACK. Or maybe /RT.
A25 Most likely DMA lines - at least DACK. Or maybe /RT.
Not connected lines:
42 !CE2
15 !WE
18 Vpp1
52 Vpp2
55 A24
62 !SPKR
RESET (PCMCIA line) net:
-R110-\->R101(pull-up)-Vcc
\->C108-GND
\->R013(not mounted)-?
\->/RST_N input of SPEED (Not absolutely certain.)
The following only shows the lines between the Dev9C interface and the SPEED chip (address and data lines are not shown).
/---Dev9C_IF---\
SPEED Exp.Bay PCMCIA
/ALLRST_N /CRST ? All SPEED hardware devices reset.
/RST_N /CRST RESET low=SPEED_devices_reset / high=PCMCIA_reset.
/SSB_RST /CSRST ? Bus reset.
SSB_MODE -,high GND
SSB_SSCLK CCLK /INPACK Clock (/INPACK - guess - because of shielding.)
/SSB_REG -,high /REG
/SSB_OE -,high /OE Output Enable for Common & Attribute Memory (Read).
- - /WE Write Enable for Common & Attribute Memory. Unsupported by SPEED (at lest the known versions).
/SSB_SRD /CRD /IORD (I/O) Read Strobe.
/SSB_SWR /CWR /IOWR (I/O) Write Strobe.
/SSB_CS9 /CCS9 /CE1 Chip Select signal for the SPEED.
SSB_DREQ9 CDREQ9 ? DMA Request by SPEED. Has other uses in normal PCMCIA modes.
SSB_DACK9 CDACK9 ? DMA Acknowledge.
/SSB_INT9 /CINT9 /IREQ Interrupt request.
On PCMCIA cards, the MODE switching from PCMCIA_mode to SSBUS_mode is done by writing 1 to register 0x20 in the PCMCIA I/O range.
Both SSB_MODE and /RST_N inputs have to be in the same state (PCMCIA_mode / SSBUS_mode) for that mode to be active. Tests showed, that SSB_MODE might have higher priority over /RST_N. By pulsing SSB_MODE from /SRD, through (1k || 10k) resistor (/SRD is kept connected to /SRD of the SPEED as well), keeping /SSB_REG=low and /SSB_OE=low, using SSBUSC read timing of 0xB with other options zeroed, the Attributes Memory could be partially read (with errors in data). This did not work, if /SSB_OE was pulsed instead.
SSB_RST line function
Once the SSB_RST line is pulsed low, the SPEED device range will start returning always 0 (while it is low and after it is brought back high). Then, to make the SPEED devices registers accessible again, one has to pulse /RST_N or MODE or /ALL_RST low. The SSB_RST line has no effect on the PCMCIA range.
/SSB_RST was most likely connected to the PCMCIA RESET line. Attributes Memory can be read with this line either low or high, while SPEED device registers are accessible only when it is inactive high (and /RST_N or /ALL_RST_N or SSB_MODE was pulsed low afterwards, to clear the /SSB_RST state), so connecting it to RESET of the PCMCIA bus would work fine.
Tests were done on a Network Adapter SCPH-10350, PCB BA-007 with CXD9731GP.
##############################################################
### IOP_DMAC.txt ###
### v01, 2017.02.11 ###
### by Wisi ###
##############################################################
IOP Direct Memory Access Controller
The IOP contains "three" DMA controllers, though that is not exactly so.
DMAC1 Original PS1 DMAC with (almost) no known change. Channels: 7.
DMAC2 Added for PS2 peripherals and used together with DMAC1 on the PS2. Channels: 6 internal and 1 external for USB.
DMAC1 and DMAC2 (and maybe DMAC3) use the same hardware, but each channel has its own configuration registers that set the state of the hardware when it has to carry-out a transfer.
Although DMAC1 and DMAC2 are examined separately below, they should be considered the same hardware device.
DMAC3 Exclusively for i-Link. Uses i-Link hardware specific registers. Channels: 3 internal, but specific to the i-Link hardware. The iLink DMA channels are not covered by this version of this document.
The DPCR and DICR registers for DMAC1 are referred to here as DPCR1 and DICR1.
"Slice" and "Block" are used interchangeably here, as volume of data transferred continuously in Slice mode.
When viewing this document, use tab width of three intervals.
Registers:
Only the low 16-bits of the address are shown below.
DMAC1
Address range: 0x1F801080 - 0x1F8010FF
DMAC1
Channel MADR BCR CHCR TADR TBCR
0 MDEC_IN 0x1080 0x1084 0x1088 - -
1 MDEC_OUT 0x1090 0x1094 0x1098 - -
2 PGPU/SIF2 0x10A0 0x10A4 0x10A8 - -
3 CDVD 0x10B0 0x10B4 0x10B8 - -
4 SPU1 0x10C0 0x10C4 0x10C8 0x10CC 0x1568
5 PIO/Extr 0x10D0 0x10D4 0x10D8 - -
6 OTC 0x10E0 0x10E4 0x10E8 - -
0x10F0 DPCR1 DMA Priority Control Register 1
0x10F4 DICR1 DMA Interrupt Control Register 1
0x10F8 r/o Returns the value of 0x1568 SPU TBCR. It could simply be an unimplemented register like the other registers that return value of MADR registers.
0x10FC r/o Unimplemented, returns the value of 0x1500 (SPU2 ch7 MADR).
0x10nC, n=0x8..0xB and n=0xD..0xE: r/o The unimplemented TADR registers. Reading any of them usually returns the value of the MADR register for the same channel. It is possible to start a tag-chain transfer on a channel with unimplemented TADR register, but bcause the address of the tag is read from the MADR register, the transfer behavior is mostly unpredictable.
DMAC2
Address range: 0x1F801500 - 0x1F80107F
Channel MADR BCR CHCR TADR TBCR
7 SPU2 0x1500 0x1504 0x1508 -* -*
8 Dev9 0x1510 0x1514 0x1518 - -
9 SIF0 0x1520 0x1524 0x1528 0x152C 0x1560
A SIF1 0x1530 0x1534 0x1538 - 0x1564
B SIO2_IN 0x1540 0x1544 0x1548 - -
C SIO2_OUT 0x1550 0x1554 0x1558 - -
*It is not known whether the SPU2 DMA channel supports tag-chain transfer and whether and how it is related to the SPU1 DMA channel. Most likely SPU2 (ch.7) does not support tag-chain transfer.
Because SIF1 is fixed in direction EE->IOP, the IOP side DMA channel lacks a TADR, but does have a TBCR, which shows the remaining words for the currently received tag (when in tag-chain mode).
0x15nC, n=0x0..0x1 and n=0x3..0x5: r/o The unimplemented TADR registers. Reading any of them usually returns the value of the MADR register for the same channel.
0x156C r/o Unimplemented - returns the value of 0x1520 (SIF0 MADR).
0x1570 DPCR2 DMA Priority Control Register 2
0x1574 DICR2 DMA Interrupt Control Register 2
0x1578 DMAC Global Control.
0x157C DMAC Global Interrupt Control.
DMAC3 - Specifically for iLink.
channels 13, 14, 15.
Registers layout in memory
MADR BCR CHCR TADR
0xBF801080,0xBF801084,0xBF801088,0xBF80108C, 00 MDEC_IN
0xBF801090,0xBF801094,0xBF801098,0xBF80109C, 01 MDEC_OUT
0xBF8010A0,0xBF8010A4,0xBF8010A8,0xBF8010AC, 02 SIF2/PGPU
0xBF8010B0,0xBF8010B4,0xBF8010B8,0xBF8010BC, 03 CDVD
0xBF8010C0,0xBF8010C4,0xBF8010C8,0xBF8010CC, 04 SPU1
0xBF8010D0,0xBF8010D4,0xBF8010D8,0xBF8010DC, 05 Exp2/PIO
0xBF8010E0,0xBF8010E4,0xBF8010E8,0xBF8010EC, 06 OTC for PGPU
DPCR1 DICR1 reserved reserved
0xBF8010F0,0xBF8010F4,0xBF8010F8,0xBF8010FC,
MADR BCR CHCR TADR
0xBF801500,0xBF801504,0xBF801508,0xBF80150C, 07 SPU2
0xBF801510,0xBF801514,0xBF801518,0xBF80151C, 08 DEV9
0xBF801520,0xBF801524,0xBF801528,0xBF80152C, 09 SIF0
0xBF801530,0xBF801534,0xBF801538,0xBF80153C, 10 SIF1
0xBF801540,0xBF801544,0xBF801548,0xBF80154C, 11 SIO2in
0xBF801550,0xBF801554,0xBF801558,0xBF80155C, 12 SIO2out
SIF0_TBCR SIF1_TBCR SPU1_TBCR reserved
0xBF801560,0xBF801564,0xBF801568,0xBF80156C
DPCR2 DICR2 DMACEN DMACINTEN
0xBF801570,0xBF801574,0xBF801578,0xBF80157C,
Register descriptions
Channel registers:
MADR Memory Address Register
23:0 r/w Start address of transfer in RAM.
31:24 r/o always 0.
The MADR is always updated, on every BCR block / linked-list entry transferred, so that in the end of a transfer it holds the end address. It contains 0x00FFFFFC after transfering a linked-list.
BCR Block Count Register
15:0 r/w Block size in 32-bit words. 0x0001 .. 0xFFFF words, 0 = 0x10000 words.
31:16 r/w Number of blocks (of size BCR.BlockSize) to transfer. This is decremented after each block has been transferred.
TADR Tag Address Register (valid in Chain mode)
23:0 r/w Start address of list with IOP DMA tags in RAM.
31:24 r/o always 0.
TBCR Tag remaining Block Count Register (made-up name) (valid in Chain mode)
23:0 r/w Number of blocks (of size set by BCR.BlockSize) of the current tag remaining to be transferred. This is decremented after each block has been transferred.
31:24 r/o always 0.
CHCR Channel Control Register
0 Transfer Direction: 0= Peripheral -> RAM / 1= RAM -> Peripheral.
1 Memory Address Step: 0= +4 bytes / 1= -4 bytes.
7:2 r/o, 0.
10:8 Transfer mode - see "Transfer modes" for details.
8 Burst mode: Cycle Stealing (Chopping) Enable, when =1.
Slice mode: Transfer causes DMAC to hang with DACK high, when =1.
Linked-list and Chain mode: Transfer header/tag before data, when =1.
9 Transfer Mode: 0= Burst / 1= Slice.
When this is 0, only the low 16 bits of BCR are valid. They specify the transfer length in 32-bit words. A value of 0 means 0x10000 words - which is the maximum. Transfers are done with /DACK held active high constantly (1.8ms for 0x10000-word transfer BCR=0, in fastest DMA and wide DMA). Synchronize blocks to DMA requests: Once /DREQ goes active, a single block (BCR lower 16 bits) is transferred. While that happens, the state of the /DREQ line is disregarded. Then on the next block boundary the transfer is paused until /DREQ goes active again. The check for /DREQ (on block boundaries) adds some very small delay, so transferring in bigger blocks should be faster, but beware that the transfer will fail (garbage - what is on the bus will be read/written data will be lost) if the device can't send/receive block of the set size in one go. The largest block size is determined b the peripheral hardware and its FIFO size and amount of data.
10 When this is set: CHCR.9 = 0: Linked-list mode / CHCR.9 = 1: Chain mode.
11 r/w For iLink DMAC only. Unknown (according to iLink_internal.h in the PS2SDK). Most likely something very similar to Linked-list for iLink or some other auto-processing for iLink.
15:12 r/o, 0.
18:16 Chopping DMA Window Size (1 << N) words. Valid only when in Burst mode Cycle Stealing is enabled (CHCR.8=1).
19 r/o, 0.
22:20 Chopping CPU Window Size (1 << N) clocks. Valid only when in Burst mode Cycle Stealing is enabled (CHCR.8=1).
23 r/o, 0.
24 r/w Start Transfer. 0= Stopped,Completed / 1= Activate,Busy. Cleared by hardware on transfer completion.
27:25 r/o, 0.
28 r/w Force-Start Transfer, without waiting for DREQ from device. Cleared by hardware after a block (slice) of data or a linked-list entry (or all the data in Burst mode) has been transferred.
29 r/w Don't clear the Force-Transfer bit (CHCR.28) after transferring a slice (Slice, Chain and Linked-list mode). In Forced-Burst mode, this would pause the transfer while set. It has no effect on transfer started by DREQ.
30 r/w BSN Bus Snooping: 0= Disable / 1= Enable. It was never tested whether this is really Bus Snooping.
31 r/w AR Automatic Response: 0= Disable / 1= Enable. Valid for the iLink DMAC3 only.
After writing to CHCR to start a transfer, CHCR has to be read once, otherwise transfer might not start or work as it should.
Valid CHCR bits:
For the majority of DMA channels of DMAC1 & DMAC2, bits 0,1,8,9,10,18:16,22:20,24,28,29,30 are valid.
Exceptions:
DMAC1/Ch.6 has only bits 24,28 and 30 r/w, bit 1 is hard-wired to 1 (reverse direction), while all other bits are hard-wired to 0.
Common registers:
DMAC1:
0x10F0 DPCR (DPCR1) DMA Priority Control Register.
Each 4 bits correspond to a channel:
2:0 Priority: 0=Highest .. 7=Lowest.
3 Enable switch: 0=Channel disabled / 1=Enabled.
3:0 Channel 0
7:4 Channel 1
11:8 Channel 2
15:12 Channel 3
19:16 Channel 4
23:20 Channel 5
27:24 Channel 6
31:28 Channel 'C' (=67 = 0x43) CPU priority. The enable switch (bit 31) here has no effect, even though it is r/w. The CPU priority switching is always enabled.
Activating the transfer for channels with equal priority, with DREQ signal active over the same time period is determined by a Round-Robin: A "counter" loops through the active channels with equal priority and asserted DREQ signals in direction highest_number -> 0. The first encountered channel that is active for transfer and with asserted DREQ signal, with highest priority among the ready-for-transfer channels is started for transfer. Once the transfer on it completes (this depends of the transfer mode selected), the "counter" continues through the channels.
A channel is eligible for selection only if it is ready for transfer - the CHCR is set to start transfer and the DREQ signal is asserted. Because of this, even if a high priority channel is transferring, if its DREQ signal is not active at the time of arbitration, a lower priority channel, that is ready (CHCR start bit & DREQ - asserted) will be started for transfer. Just the same way, the CPU will be granted access to the bus between DMA slices, even if the CPU priority is lower than the currently enabled (CHCR) channel, if no channel is ready for transfer.
Initial value on PS1 reset is 0x07654321. If two or more channels have the same priority setting, then the priority is determined by the channel number (0 = Lowest, highest number = Highest).
Initial value on PS2 reset is 0x0777777.
0x10F4 DICR (DICR1) DMA Interrupt Control Register.
6:0 IRM "Individual Request Mask" (name-guess): Chanels 0-6. 0= A bit in 30:24 would get set ONLY when the entire transfer on the corresponding channel is completed / 1= A bit in 30:24 would get set at the end of every block transfer or entry of a linked-list. The corresponding mask bit in 22:16 has to be set, for any of the status flag bits 30:24 to become set. This field only affects when a DMA completion interrupt flag (30:24) will be set (i.e. it controls the function of bits 22:16) - it does not enable the flag by itself.
7 Unimplemented, r/o, 0.
14:8 Unimplemented, r/o, 0.
15 Reserved Memory / DMA Bus Error Interrupt. If a channel transfers to/from RAM outside the set limits by the RAM configuration, this will become set, together with the common interrupt flag - bit 31. Cleared by writing 0. Writing 1 here, sets bit 31, thus forcing a DMA interrupt. Bit 31 is set when this one is set, even if all other bits in this register are clear. The state of this bit is OR-ed into bit 31, regardless of the state of bit 23.
22:16 DMA Transfer Completion Interrupt Mask. Channels 0-6. Enabled when =1. When a bit here is set, the corresponding bit in 30:24 becomes set when the transfer on that channel has completed. Bits 16-22 correspond to channels 0-6. IRM (bits 6:0) set the condition on which the interrupt flags (30:24) trigger: IRM=0: Interrupt triggers when the entire transfer has been completed (all blocks / linked-list entries) / IRM=1: Interrupt triggers after the transfer of each block/linked-list entry.
23 Master enable for DMA channel-interrupt sources. Bit 31 becomes set if this bit is set AND a bit in 30:24 is set.
30:24 DMA completion interrupt flags. Bits 24-30 correspond to channels 0-6. Writing 1 clears a flag. A bit here can only get set, if the corresponding bit in 22:16 is set as well and the DMA channel is in the state that triggers that interrupt.
31 DMA Master Interrupt Flag. r/o
MasterIntrFlag(31) = DmaBusError(15) | ( MasterChannelsIntrEnable(23) & ( Ch_0_IntrFlag(24) | Ch_1_IntrFlag(25) | ... | Ch_5_IntrFlag(29) | Ch_6_IntrFlag(30) ) )
Ch_0_IntrFlag(24) = Ch_0_DmaIntrMask(16) & ( Ch_0_DmaCompletionState | ( Ch_0_IRM(0) & Ch_0_IRM_State ) )
Ch_1_IntrFlag(25) = Ch_1_DmaIntrMask(17) & ( Ch_1_DmaCompletionState | ( Ch_1_IRM(1) & Ch_1_IRM_State ) )
...
Ch_5_IntrFlag(29) = Ch_5_DmaIntrMask(21) & ( Ch_5_DmaCompletionState | ( Ch_5_IRM(5) & Ch_5_IRM_State ) )
Ch_6_IntrFlag(30) = Ch_6_DmaIntrMask(22) & Ch_6_DmaCompletionState
Burst transfers (CHCR=0x11000001 or 0x01000001) completion results in activation of the entire-transfer-complete state.
In every mode of transfer, completion of the entire transfer results in activation of the entire-transfer-complete state.
In Linked-list transfers (CHCR=0x11000401 or 0x01000401), if only a single entry of the list has been transferred, the IRM state is activated.
In Slice mode transfers (CHCR=0x11000201 or 0x01000201), if only a single entry of the list has been transferred, the IRM state is activated.
0x10F8 r/o TBCR Tag Block-count register (made-up name). Remaining word-count of transfer of the current TAG for SPU1 Tag-chain mode. This mirrors register 0x1568, which is r/w unlike this one (writable up to 0x00FFFFFF). This (actually 0x1568) register is used to determine how much of the data for the current tag was transferred and in case a transfer needs to be restarted from some intermediate point in the data, register 0x1568 can be written with the remaining number of words, and the rest of the registers set accordingly, so that the transfer can be resumed from this point.
Because of how the DMAC (DMAC1) hardware is constructed, if a Chan (tagged) transfer is started on any channel 0-5 (but 4), this register would function just the way it does for SPU1, but because the other channels lack a TADR register, the address where the tag would be read from would be some random address in RAM, thus this will contain strange values.
According to psx-spx: "1F8010F8h (usually 7FFAC68Bh? or 0BFAC688h) (changes to 7FE358D1h after DMA transfer)."
This register might function differently in PS1 mode. However, most likely it would have the same purpose and SPU1 should support tag-chain mode on the PS1 as well.
0x10FC r/o, returns the value of 0x1500 (SPU2 ch7 MADR). According to psx-spx: "1F8010FCh (usually 00FFFFF7h) (...maybe OTC fill-value) (stays so even after DMA transfer) Contains strange read-only values (but not the usual "Garbage"). Not yet tested during transfer, might be remaining length and address?"
DMAC2:
0x1570 r/w DPCR2 DMA Priority Control Register 2
Each 4 bits correspond to a channel:
2:0 Priority: 0=Highest .. 7=Lowest.
3 Enable switch: 0=Channel disabled / 1=Enabled.
3:0 Channel 7
7:4 Channel 8
11:8 Channel 9
15:12 Channel 0xA
19:16 Channel 0xB
23:20 Channel 0xC
27:24 Channel 'U' (=85 = 0x55) USB DMA channel. It is controlled through the USB Controller registers.
31:28 Unknown. Isn't for IOP Core access (like DPCR1.31:28), isn't for EE access to IOP memory either. Could be for another USB channel, but unlikely. Shouldn't be for iLink or SIO2 as both have designated DPCR fields. No effect was observed when this was set to priority value between those of two other channels - the transfers of the channels were not separated in time when this was enabled, thus whatever this is for, it wasn't active at the time of testing.
0x1574 DICR2 DMA Interrupt Control Register 2
12:0 IQE Interrupt on tag Queue Event (guess). Correspond to DMA channel numbers 0-12. Enables the interrupt triggered by the interrupt flag (0x40) in the tag (in chain mode). Only bits 4 (SPU, ch.4), 9 (SIF0, ch.9) and 10 (SIF1, ch.0xA) can be read back once written. These are also the only channels that support tag-chain mode, so this is not surprising. Most likely all other bits are ineffective.
0= A flag in the Interrupt Status flags (DICR2.19:24) will not be set when a tag with an interrupt flag (0x40) is encountered.
1= The corresponding flag in the Interrupt Status flags (DICR2.19:24) will be set once all the data of the tag with an interrupt flag (0x40) is transferred.
Bits 6:0 correspond to DMAC1 and for this reason their status flags are in DICR1.30:24. Because of this, the corresponding mask bit in (DICR1.22:16) has to be enabled as well, for the status bit to become set on an interrupt condition. This is valid only for SPU1.
15:13 r/o, 0.
21:16 r/w DMA Transfer Completion Interrupt Mask. Enabled when =1. Channels 7-12.
0= A flag in the Interrupt Status flags (DICR2.19:24) will not be set when the entire transfer on the corresponding channel completes.
1= The corresponding flag in the Interrupt Status flags (DICR2.19:24) will be set once the entire transfer completes.
29:24 r/w Interrupt Status flags. Channels 7-12. A flag here is set only if the corresponding mask bit in 21:16 or 12:0 is set and the interrupt conditions have been met. Cleared by writing 1. The DMA interrupt Master Flag (bit 31 of DICR1) is set if a bit here is set and the DMA interrupt Master Enable (bit 23 in DICR1) is set as well.
31:30 r/o, 0.
The AND product of the Master Interrupt Enable switch (DICR1.23) AND 0x157C.0 enables routing the DICR2 interrupt states (DICR2.29:24) to the Master Interrupt flag (DICR1.31) (as well as the DICR1 interrupt states (DICR1.30:24)).
0x1578 DMAC Global Control.
0 r/w DMAC (DMAC1 and DMAC2 and DMAC3?) Enable =1.
0=Suspend transfers.
1=Resume transfers.
When suspending, write 0 to this register once and wait until reading back yeilds value of 0. When resuming, write 1 to this register once and wait in a loop, until the value read-back is 1. Suspending and resuming transfers does not harm ongoing transfers.
31:1 r/o, 0.
0x157C DMAC Global Interrupt Control.
0 r/w Enable DMAC (DMAC1 and DMAC2) channel interrupts.
0= Disable
1= Enable
When this is disabled, the Master Interrupt flag (DICR1.31) is kept clear in all cases but in BusError (DICR1.15). This switch is valid for the interrupt sources in DICR1 as well. Basically this has the same effect as the Master Interrupt Mask (DICR1.23) and the output mask is: 0x157C.0 AND 0x10F4.23.
1 r/w Mask Global DMAC Interrupt:
0= Default - the state of the Master Interrupt Flag (0x10F4.31) is passed to the Interrupt Controller (0x1070.3).
1= The Master Interrupt Flag (0x10F4.31) is masked so the Interrupt Controller DMAC interrupt (0x1070.3) never becomes set.
The state of this switch does not influence the DICR registers.
31:2 r/o, 0.
When a DMA BusError / Out of RAM condition is detected, the DMA transfer is stopped and a DMA completion interrupt is not generated (not entirely confirmed).
Chain mode
The physical transfer in Chain mode is done the same as in Slice mode - the data is transferred in slices (blocks) according to BCR blockSize.
On the IOP, tags are stored sequentially in list, and the start address of this list is written to TADR.
Two types of tags (lists) exist:
Single IOP tag. Each IOP tag is 2 32-bit words in size and the next IOP tag is placed just after it. IOP tags are spread two words apart.
IOP tag + EE tag. Each IOP tag (2 32-bit words in size) is followed by an EE tag (also 2 32-bit words in size). The EE tag is send to the EE, as a quadWord, aligned to the start of the quadWord. The next IOP tag is placed after the EE tag - these packets are spread 4 words apart.
Interrupt by tag (IRQ / 0x40000000 bit in tag's first word) - The interrupt is triggered only once all the data for this tag has been transferred. For example if a forced transfer is used (no hardware DREQ is active), for each BCR block transferred before the end of the tag data, the interrupt will NOT trigger. Only when all the data is transferred it will. The IQE in DICR2 must be enabled for the interrupt by tag. DICR2.21:16 don't need to be enabled for interrupt by tag (IQE).
For SPU1 IQE the 0x10F4.22:16 has to be set as well.
Because the transfer-completion bits in DPCR2 are separate from the IQE bits, the two can be enabled separately.
The ERT flag (0x80) in the tag only signifies the end of the tag table. When the end is reached, the effect (and interrupt triggered) is the same as when the transfer in completed in slice mode (or burst mode).
Interrupt by tag:
0x1574.29:24 <- IQE_MASKS(DICR2.12:0) AND IQE_SOURCE(tag)
Transfer completion:
0x1574.29:24 <- 0x1574.21:16 AND DMAC2.TRANSFER_COMPLETE_STATUS
Channel interrupt status flags to Master Interrupt Status flag:
0x10F4.31 <- ( 0x157C.0 AND 0x10F4.23 ) AND ( 0x1574.29:24 OR 0x10F4.30:24)
DMAC Master Interrupt Status flag to Interrupt Controller:
0x1074.3 <- 0x10F4.31 AND INV(0x157C.1)
Chain transfer examples:
IOP-only tag-list:
u32 Tadr[4];
Tag[0] = 0x40000000; //Interrupt flag set, MADR = 0x00000000
Tag[1] = 0x80; //Size = 0x80 words.
Tag[2] = 0x80000000; //ERT flag set, MADR = 0x00000000
Tag[3] = 0x40;
MADR = 0x00000000;
BCR = 0x00000020;
TBCR = 0;
TADR = (u32)&Tag[0]; // = 0x001BC220
CHCR = 0x01000601; // Below CHCR |= 0x10000000; before each read.
MADR BCR CHCR TADR TBCR DICR2
00000080 FFFF0020 01000601 001BC220 00000060 00040200
00000100 FFFE0020 01000601 001BC220 00000040 00040200
00000180 FFFD0020 01000601 001BC220 00000020 00040200
Data for first tag has been processed, IQE interrupt is triggered:
00000200 FFFC0020 01000601 001BC220 00000000 04040200
Next tag is loaded, MADR, TADR, TBCR are updated.
00000080 FFFB0020 01000601 001BC228 00000020 00040200
All the data for the second tag has been transferred, ERT encountered => entire chain transfer completed, transfer-completion interrupt generated:
00000100 FFFA0020 00000601 001BC228 00000000 04040200
The block-count in BCR will always get decremented, even though this isn't simple slice mode.
Above, the interrupt was cleared after each read of the registers. If it wasn't, DICR2.25 would remain set.
The test was done with SIF0.
IOP-EE combined tags in list:
u32 Tadr[4];
Tag[0] = 0x40000000; //Interrupt flag set, MADR = 0x00000000
Tag[1] = 0x80; //Size = 0x80 words.
Tag[2] = 0; //EE tag word 0.
Tag[3] = 0; //EE tag word 1.
Tag[4] = 0x80000000; //ERT flag set, MADR = 0x00000000
Tag[5] = 0x40;
Tag[6] = 0; //EE tag word 0.
Tag[7] = 0; //EE tag word 1.
MADR = 0x00000000;
BCR = 0x00000020;
TBCR = 0;
TADR = (u32)&Tag[0]; // = 0x001BC230
CHCR = 0x01000701; // Below CHCR |= 0x10000000; before each read.
MADR BCR CHCR TADR TBCR DICR2
00000070 FFFF0020 01000701 001BC230 00000064 00000200
000000F0 FFFE0020 01000701 001BC230 00000044 00000200
00000170 FFFD0020 01000701 001BC230 00000024 00000200
000001F0 FFFC0020 01000701 001BC230 00000004 00000200
Data for first tag has been processed, IQE interrupt is triggered:
00000200 FFFB0020 01000701 001BC230 00000000 04000200
Next tag is loaded: MADR, TADR, TBCR are updated:
00000070 FFFA0020 01000701 001BC240 00000024 00000200
000000F0 FFF90020 01000701 001BC240 00000004 00000200
All the data for the second tag has been transferred, ERT encountered => entire chain transfer completed, transfer-completion interrupt generated:
00000100 FFF80020 00000701 001BC240 00000000 04000200
At the start of ever tag transfer, the value of MADR is not 0x80 (0x20*4) because a quadWord (with the two words of EE tag in its start) is sent before the data, and transfers are done in 0x20 words.
Transfer modes
Mode bits Mode
10 9 8
0 0 0 Burst mode. Transfer length (word count) - according to BCR block size. Uninterrupted.
0 0 1 Burst mode with cycle stealing.
0 1 0 Slice mode. Block size and count - according to BCR.
0 1 1 Unimplemented? Causes endless transfer - DACK is kept at high level "forever".
1 0 0 Linked-list mode, with MADR pointing to the list.
1 0 1 Linked-list mode, but the header of each linked-list entry is sent before the entry data.
1 1 0 Chain of tags, pointed to by TADR. No EE tag is placed (after IOP tag) in table.
1 1 1 Chain of tags, but EE tag is sent to the EE after it is read from address after the IOP tag.
Physical transfer modes:
Burst mode:
In burst mode all the data is transferred continuously, without interruption, but for potential DRAM refresh. The peripherals should be capable of transferring the set amount of data in one go without interruptions, otherwise data loss can occur.
When Cycle Stealing is enabled, the IOP Core is let to run for a set number of cycles, between every set number of words transferred by the DMAC, but no Bus arbitration is performed. BCR.blockSize sets the length of the transfer in words.
BCR.blockCount is disregarded.
Transfer length = BCR.blockSize = 0x0001 .. 0xFFFF, 0x0000 (0x0000 = 0x10000) words.
In one test, the maximum transfer length seemed to be BCR blockSize = 0x4000 (or 0x3FFF) words. Setting higher values would result in the same length of transfer.
MADR sets the start address in memory.
TADR, TBCR are disregarded.
Slice mode:
In Slice mode bus arbitration is performed on every block boundary. The state of the DREQ line is checked only on block boundaries. For this reason, starting a transfer with block-size larger than the amount the peripheral can continuously send/receive in one go would cause loss of data. For most devices this is the amount of free space / data in their internal buffer when a transfer is started.
BCR.blockCount sets the number of blocks of size BCR.blocklSize words, to transfer.
BCR.blockCount is updated on every block boundary.
MADR sets the start address in memory.
TADR, TBCR are disregarded.
Setting Slice mode with Cycle Stealing results in hardware becoming unresponsive (DACK kept active high indefinitely). Perhaps this isn't implemented.
Values of 0 for TADR and MADR are valid and have no special purpose.
Linked-list mode:
Linked-list mode is (should be) functional on all DMA channels, but channel 6 (OTC Ordering Table Clear - sets-up an empty ordering table for PS1 GPU).
Linked-list mode is known to have been used when sending data to the PS1 GPU. This is a separate mode from the Chain mode that uses a tag.
The physical transfer mode is Burst mode, but each entry is equivalent to a block in Slice mode.
The block-count in BCR is not updated and its value is not regarded.
The block-size in BCR is not regarded - a single entry is transferred without DACK interruptions.
TADR and TBCR registers are disregarded.
Bus arbitration is performed between linked-list entries. The DMAC waits for DREQ at the start of each entry.
Cycle Stealing is not performed while transferring an entry.
On transfer completion, when the end-code (0xFFFFFF) in the address field of the list header is encountered, MADR contains 0x00FFFFFC and CHCR.24 is cleared. Transfer completion interrupt is generated.
When CHCR.8 is set, the header word for each entry is sent before the data of the entry.
Linked-list mode might not be compatible with transfers over SIF because CHCR.8 controls the EE-tag-send flag to the EE SIF as well. Also the entry size would have to be less than that of the SIF FIFO.
Linked-list entry:
struct iopDmacLinkedListHdr {
u32 iopDmacLinkedListHdr *nextEntryHdr :24 ;
u32 entryDataLength :8 ; // = 0x00 .. 0xFF words.
u32 data[]; //Of size entryDataLength.
};
When nextEntryHdr contains the end-code 0xFFFFFF, the transfer is completed by transferring the entryDataLength words after this entry.
Data after the endCode is also transferred, if the high byte in the header is != 0.
So the DMAC does:
iopDmacLinkedListHdr *llHdr;
llHdr = (void*)MADR; //The address in MADR.
while (((u32)llHdr->nextEntryHdr & 0x00FFFFFF) != 0x00FFFFFF) {
for (i=0; i < llHdr->entryLength; i++) {
somewnhereToPutData = llHdr->data[i];
}
llHdr = llHdr->nextEntryHdr; //Next entry.
}
To start a Linked-list transfer:
struct iopDmacLinkedListHdr llHdr1; //Assume there is data after each of these in memory.
struct iopDmacLinkedListHdr llHdr2;
llHdr1.nextEntryHdr = &llHdr2;
llHdr1.entryDataLength = someLength1;
llHdr2.nextEntryHdr = 0xFFFFFF;
llHdr2.entryDataLength = someLength2;
//BCR, TADR, TBCR are disregarded.
MADR = &llHdr1;
CHCR = 0x01000401;
CHCR; //Read.
Timing (assuming that the single-cycle, wide DMA mode is used):
DACK active period = entryWordCount + n [cycles]:
CHCR.8
Words | 0 1
> 0 +9cy +10cy
= 0 +4cy +5cy
With SIF2:
CHCR.8 = 0
______________________
DACK _____/ \______________
_____________ ________
/BEn \________________/
|
CHCR.8 = 1: |
______________________
DACK _____/ \______________
_______ __ ________
/BEn \__/ \________________/
|A|B |C | D------------->|
|E|
A = 2.5cy
B = 2cy
C = 3cy
D = wordCount + 1 cy
E = 0.5cy
The chcr.8=0 is the same, but the first /BEn pulse is missing. The overall length is the same.
The /BEn pulse 'B' is where the two words of EE tag are transferred.
This measurement was done with IOP->EE SIF2, linked-list.
In 'B' period there are two words: the second one is the linked-list header. The first one is maybe 0 (at least bit 1 is 0). The first word is not the word before or after the header.
With both CHCR.8 = 0 and =1 there is one additional data pulse (in DACK) before the data.
With CHCR.8 = 1, the pulse is further before the data (5cy) while with CHCR.8 = 0 it is 1cy before data.
Chain mode with tags:
The physical transfer mode is Slice mode.
The block-count in BCR is updated (decremented) just like in Slice mode. The value of the block-count in BCR does not affect the transfer.
The BCR block-size sets the size of the slices in which the data will be transferred (like in Slice mode).
When CHCR.8 is 0, the list with tags pointed to by TADR, is processed as only containing IOP tags (each 2 words in size).
When CHCR.8 is 1, the list with tags pointed to by TADR, is processed as only containing packets of an IOP tag followed by an EE tag (each two words in size). The tag-step is 4 words and the EE tag is transferred to the EE, before the data. The /BD0 line of the SBUS is activated over the period when a tag is to be sent, only if one is sent (CHCR.8 = 1). Although this regards the SIF0 DMA channel, the SPU1 DMA channel has the same function, so it can send the two words of data after each IOP tag if configured to do so.
SIF1 receives the IOP tag before the data. The EE sends it as the first quadWord before the data, by inserting it into the data buffer - the first 7 quadWords of data are copied to a separate buffer and then sent with a separate EE DMA tag. So the EE DMAC has no special IOP-tag-sending capability like that of the IOP.
This is not a linked-list transfer per se, because the tags are laid sequentially in a list, and a tag cannot set the address of the next tag, but rather the tag simply sets the address and length of the data. Because the tag can be received with the transfer data (SIF0 EE->IOP for example) this makes possible the Destination-Chain transfer.
*Note that the SifCmdHeader looks quite packed - could it at some point have meant to be used directly with hardware..?
IOP DMAC TAG:
23:0 dataAddr
29:34 more flags?
30 IRQ - Causes the IQE interrupt, when enabled in DICR2.
31 ERT - end tarnsfer
55:32 length
63:56 unused maybe
struct iopDmaTag {
u32 iopAddr :24 ; //Address in IOP RAM
u32 iopFlags :8 ; //Transfer-control flags.
u32 lenght :24 ; //In 32-bit words.
u32 unk07 :8 ; //?
//The EE tag should be place here - after the IOP tag, when doing Destination-Chain IOP->EE.
};
iopDmaTag.iopAddr The address in IOP RAM, where the data is to be read from / written to.
23:0 0x000000 .. 0xFFFFFF
iopDmaTag.iopFlags Flags used to control the transfer:
5:0 Unknown.
6 DMA_INT When =1, cause DMAC IQE interrupt when all the data for this tag has been transferred.
7 DMA_ERT End Reference Transfer (guess) ("ref" is the EE tag ID that resembles the way the IOP tag works). Once the transfer of the data of the tag with this flag is complete, the DMA channel is stopped: The CHCR.24 (DMA channel active) is cleared and in the case of the SIF channels, the corresponding IOP-bit in BD4 (BD4.5:4) is cleared as well. A DMA-completion interrupt is triggered on transfer completion as usual.
iopDmaTag.length Size of data in 32-bit words.
23:0 0x000000 .. 0xFFFFFF
iopDmaTag.unk07 Unused.
To enable interrupt by tag: EnableIntr(INT_DMAn | IMODE_DMA_IQE);
It is assumed that IOP Source-Chain and Destination-Chain tags are identical.
EE DMAC Destination-Chain tag:
15:0 quadWordCount: 1..0xFFFF, 0=invalid value
25:16 unused
27:26 priority control
30:28 tag "ID"
31 local interrupt request flag
-----
62:32 dataAddress
63 RAM/SPR
struct eeDmaDestChainTag {
u32 quadWordCount :16 ;
u32 unk02 :10 ;
u32 idFlags :6 ;
u32 dataAddr :32 ;
};
Example with IOP tag only (CHCR.8 = 0):
struct iopTag {
struct iopDmaTag iopTag;
};
struct iopTag tagList[SIZE];
tagList[0].iopTag.iopAddr = DATA_1_IOP_ADDR;
tagList[0].iopTag.iopFlags = 0x40; //DMA_INT - example with triggering interrupt.
tagList[0].iopTag.length = DATA_1_SZ / 4;
tagList[0].iopTag.unk07 = 0;
tagList[1].iopTag.iopAddr = DATA_2_IOP_ADDR;
tagList[1].iopTag.iopFlags = 0x80; //DMA_ERT - End of tag list.
tagList[1].iopTag.length = DATA_2_SZ / 4;
tagList[1].iopTag.unk07 = 0;
CHCR = 0; //If a previous transfer is ongoing, stop it. In case it needs to be resumed, TBCR should not be cleared.
TBCR = 0; //Make sure TBCR is 0, otherwise it will resume an old transfer. MADR is disregarded when TBCR == 0.
TADR = (u32)&tagList;
BCR = blockSize; //[32-bit words] According to the peripheral's receiving capability.
CHCR = 0x01000601; //Start transfer.
Example with an EE tag after each IOP tag (CHCR.8 = 1):
struct iopEeTag {
struct iopDmaTag iopTag;
struct eeDmaDestChainTag eeTag;
};
struct iopEeTag tagList[SIZE];
tagList[0].iopTag.iopAddr = DATA_1_IOP_ADDR;
tagList[0].iopTag.iopFlags = 0x40; //DMA_INT - example with triggering interrupt.
tagList[0].iopTag.length = DATA_1_SZ / 4;
tagList[0].iopTag.unk07 = 0;
tagList[0].eeTag.quadWordCount = DATA_1_SZ / 16;
tagList[0].eeTag.unk02 = 0;
tagList[0].eeTag.idFlags = 1;
tagList[0].eeTag.dataAddr = DATA_1_EE_ADDR;
tagList[1].iopTag.iopAddr = DATA_2_IOP_ADDR;
tagList[1].iopTag.iopFlags = 0x80; //DMA_ERT - End of tag list.
tagList[1].iopTag.length = DATA_2_SZ / 4;
tagList[1].iopTag.unk07 = 0;
tagList[1].eeTag.quadWordCount = DATA_2_SZ / 16;
tagList[1].eeTag.unk02 = 0;
tagList[1].eeTag.idFlags = 7;
tagList[1].eeTag.dataAddr = DATA_2_EE_ADDR;
CHCR = 0; //If a previous transfer is ongoing, stop it. In case it needs to be resumed, TBCR should not be cleared.
TBCR = 0; //Make sure TBCR is 0, otherwise it will resume an old transfer. MADR is disregarded when TBCR == 0.
TADR = (u32)&tagList;
BCR = blockSize; //[32-bit words] According to the peripheral's receiving capability.
CHCR = 0x01000701; //Start transfer.
Resuming Chain mode (untested):
If TBCR contains a non-zero value when transfer is started (CHCR.24 = 1), transfer will be resumed with the current MADR, TBCR, TADR, BCR values. That is - the number of words in TBCR, starting at MADR will be transferred (TBCR is decremented for each). The next tag (once TBCR is decremented to 0) will be read from TADR.
Chain transfer notes:
As far it is known, when a Destination-Chain tag is sent to the receiving side, it is always sent as a quadWord, or at least this is the case when the EE send the IOP a Destination-Chain tag. It is possible that CHCR.8 is somehow related to IOP sending a Destination-Chain tag to the EE (with size of 2 words perhaps).
Bus Arbitration
Cycle Stealing:
Cycle Stealing (Chopping) (CHCR.8 = 1) is only applicable in Burst mode. In Slice mode, it causes the DMAC to hang in DACK constantly active state. In Linked-list and Chan modes CHCR.8 has a different function.
It is not affected by DMA channels' priorities in the DPCR registers, and Bus-arbitration is not performed between the "chops" of the transfer - only the CPU is let to run for a fixed period of cycles every set amount of words transferred.
The CPU is let to run for (1 << (CHCR.22:20)) cycles, specified by CHCR.
CPU cycles = ( 1 << (CHCR.22:20) ) + 4 (Instruction fetch from RAM?) + accessDelay
accessDelay is 0, if the load/store completes within the set number of cycles. When a lost/store is started within the time-frame the CPU is let to execute, the CPU does not release the bus until the load/store operation is completed. Thus the CPU access to the bus could be elongated by as much as the longest load/store operation takes to complete.
Multiple load/store instructions can be executed within the set CPU-active period, as long as all of them start within the set number of cycles. Note this is different from the way Bus Arbitration is performed in Slice mode!
DMA words = (1 << (CHCR.18:16))
DMA cycles = ( DMA words * dmaTiming) + 2
Arbitration by DMA priority (DPCR):
The DMA priority setting is applied only in Slice transfer mode. This is different and is not related to Cycle Stealing, even though it has similar purpose.
On every Slice boundary, bus arbitration is performed. This is valid only for Slice, Chain (which uses Slice mode as well) and Linked-list transfers.
DMA access timing doesn't affect switching between channels.
The bus arbiter checks all the channels and starts a transfer on the first encountered channel with highest priority (among all) that is both enabled (CHCR.24 = 1) and its DREQ signal is active. Once a single slice (BCR block / linked-list entry) has been transferred, bus arbitration is performed again, by going through all channels, starting from the one that last one active, in direction from the channel with highest number to lowest number. If a channel with higher priority is encountered, that is both enabled and has DREQ active, transfer is started on it.
When channels with equal priority are ready for transfer at the same time (CHCR.24 = 1 and DREQ = active), a BCR block (slice or linked-list entry) is transferred on each, and then processing switches with the next channel in descending order according to channel number. This way the transfers on several channels can be "interleaved", which can increase the overall transfer rate in some conditions.
If no higher priority channel is ready for transfer, the bus is released to a lower priority channel and if no such is found, the bus is released to the CPU.
*The EE can access IOP memory (only) in the same time-frames when the IOP Core has control over the bus. (This is untested.) The IOP has to first grant the EE access (after a request from the EE) before the EE can access the bus. There is no known separate priority setting for EE access to IOP memory though the SBUS.
Each of the DMAC Channels has a priority setting in one of the DPCR registers.
The IOP Core has a separate priority setting: DPCR1.31:28 (however the enable bit DPCR1.31 is ineffective, even though it is r/w - the priority setting is always enabled). It is only let to run between the blocks (slices) of transfers of DMA cannels, if its priority is equal or higher than the DMA channel(s) in question.
The IOP Core is treated similar to a DMA channel with variable block-size - in this case "active period". When the CPU takes control over the bus, it is left in control (only) for a fixed number of operations, which is determined by the type of instructions executed. Unlike DMA channels, the CPU access to the bus is always ended when its "active period" is exhausted (but for the cases when a load or store operation has to complete).
The CPU's active period is 1 or 2 instructions, but that is not confirmed. It seems like at times (according to the type of instructions) it executes around 5 instructions, but that could have simply been a period of fetching code from RAM. It always executes at most a single load/store instruction, regardless of the timing of the device.
Examples - code executed in an endless loop after starting transfer:
Cycles Code
5 CHCR pooling for completion once or only reading
5 7 NOPs
10 20 NOPs, but only the first 2 CPU active periods were 10cy, while the rest were 5cy.
5+Timing Access to memory-mapped peripheral device. Timing = device access timing.
It is possible that the active period ends right after branch instructions as well.
There is no known way to set the active period.
Although the above is not conclusive about what exactly is executed, it does show how transfer speed can be improved:
If DMA has to complete as soon as possible, but CPU should still run in the gaps between DMA slices and the CPU priority should be higher than that of the DMA channel, then pooling CHCR is appropriate. On the other hand, executing multiple NOP (or ADDIU for example) instructions in sequence would delay transfer considerably. (This is not absolutely certain.) If only one instruction is executed for loop iteration, the delay will be reduced. Accessing a peripheral device with slow timing would delay the transfer greatly (the overall period could increase to several times).
Example:
The instructions after writing to CHCR do not necessarily need to be executed in a loop - they could simply be the next of the program code.
Very slow:
DPCR = // CPU priority >= DMA channel priority
CHCR = 0x01000200;
*(vu32*)0xBFC00000; ... *(vu32*)0xBFC00000; //Repeated multiple times
Slow:
DPCR = // CPU priority >= DMA channel priority
CHCR = 0x01000200;
asm("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); //Repeated multiple times
Decent speed:
DPCR = // CPU priority >= DMA channel priority
CHCR = 0x01000200;
CHCR; //Repeated multiple times or while (CHCR & 0x01000000) {}
Fast:
DPCR = // CPU priority < DMA channel priority
CHCR = 0x01000200;
CHCR; //Repeated multiple times or while (CHCR & 0x01000000) {}
*The last two examples don't suggest reading CHCR multiple times, but rather that access to registers of devices internal to the IOP is faster.
Carrying-out an "interleaved" transfer:
The PS2 hardware is configured by default (by the software) to interleave transfers that overlap in time. This is set by the equal default priorities of all channels (but the IOP Core) in the DPCR registers and the use of Slice and Chain transfer modes for basically all channels.
A need for interleaved transfer arouses when a SifDma (or SifCmd) transfer has to be done regularly together with another (or several other) transfers. The SIF DMA transfers have long inactive intervals between DREQ pulses, would degrade overall performance if left only for the IOP to execute code in them. This is also true for any peripheral that is not immediately ready with data from transfer after one block has been transferred.
To start an "interleaved" transfer do (order doesn't matter):
SIF_CHCR.Start = 1;
Peripheral_CHCR.Start = 1;
If the block-size of the peripheral can be configured, it is best to test in real condition which block-size gives best performance. If for some reason the SIF transfer starts considerably later than that to the peripheral, then bigger block size for the peripheral should be used, and the other way around.
Multiple DMA transfers can (and will) be interleaved this way.
For the purposes of testing, the DMAC can be disabled (0x1578=0) before setting the CHCR registers of all channels, and then re-enabled (0x1578=1) afterwards, to begin all transfers at the same point in time:
__ __ __
DACK_A _____/ \____________/ \____________/ \_____________
__ __ __
DACK_B _________/ \____________/ \____________/ \_________
__ __ __
DACK_C _____________/ \____________/ \____________/ \_____
__ __ __
IOP Core _________________/ \____________/ \____________/ \_
Force-starting a transfer:
For any transfer to take place, the start bit (CHCR.24) has to be set. The start bit is cleared at the end of a complete transfer by hardware.
In order for the transfer to begin, the peripheral device has to assert the DREQ line and (before of after that) CHCR.24 has to be set.
The state of the DREQ line is checked on every block boundary (or linked-list entry). If DREQ is not asserted at that point in time, the transfer is paused until DREQ is asserted (or the transfer is stopped or forced to start by software). While the transfer is in a paused state, the CPU can run and other DMA transfers (even with lower priority) can be processed.
CHCR.28 r/w Force-start transfer. This switch emulates the function of the DREQ line. When it is set together (but not necessarily at the same time) with CHCR.24, a transfer is started immediately, regardless of the state of the DREQ line. Only a single block (or linked-list entry) is transferred and after that CHCR.28 is cleared by hardware, and the channel enters a paused state if DREQ is not asserted.
This can be used for testing hardware, and for devices that are always ready to transfer. It can even be used with slower devices, for accessing a FIFO register (if the device allows that) if the DMA timing for this SSBUSC channel is configured to use PIO timing.
CHCR.29 r/w 1= (Slice mode:) Don't clear CHCR.28 on end of slice (block).
When CHCR.29 is set, in Slice mode (and Linked-list mode), and CHCR.28 is set as well, a complete transfer is force-started, rather than a single slice (CHCR.28 - set by itself). All blocks will be transferred, as if DREQ is kept always active, regardless of the state of DREQ.
In Burst mode, when CHCR.29 is set together with CHCR.28, a forced transfer does not start until CHCR.29 is cleared (CHCR.28 has to remain set).
In Burst mode, a transfer initiated by the DREQ line starts regardless whether CHCR.29 is set or CHCR.28 and CHCR.29 are both set.
Setting this bit, with CHCR.28 clear doesn't seem to have any effect in any mode.
CHCR.24 is set in all cases considered above.
Special thanks to:
- noca$h and all the sources of the psx-spx: http://problemkaputt.de/psx-spx.htm Almost half of this document is based on psx-spx.
- the creators of the fps2bios project and [RO]man.
- SP193 - for the much help, information and questions regarding the PS2 "mysteries", which were the main reason for the creation of this document.
- the many contributors to the PS2SDK and many sources of information on the net.
##############################################################
### IOP_Memory_Map.txt ###
### v01, 2017.02.11 ###
### by Wisi ###
##############################################################
IOP Memory Map
There are certainly errors in this document. This document is incomplete.
Some devices are remappable (by the SSBUSC). They are not bound to any particular memory range, so their mapping in the following might differ for some rare configuration.
Regardless of the base address a device is mapped to, it receives the address bus unshifted (unconfirmed for all), e.g. - if it is mapped to base address 0x4, accessing this address would result is accessing address 0x4 of the device, and not 0x0.
Devices can only be mapped to boundaries multiple of their address range size.
It would make more sence to exclude the remappable devices (SSBUSC) from this list, as their different mappings make it more confusing.
PS1 devices are included too. Changes between PS1 and PS2 ("IOP") modes of the IOP should be marked.
/-- Fixed / Remappable address
| /-- usable in mode for playstation 1/2/Both/Special(dependable)
| |
| |
0x00000000 0x00FFFFFF F? B DRAM 2/8/16MB
0x01000000 0x ???
0x10000000 0x13FFFFFF F* 2 Dev#10 Dev9 or PCMCIA (Memory range - /OE, /WE)? interface - according to PS2 model. SPEED is here.
0x14000000 0x17FFFFFF R 2 Dev#11 PCMCIA I/O range (/DIOR, /DIOW)?, but the above is used in PS2Linux, so maybe it could be switched. AIF Additional InterFace (guessed name) - a HDD and RTC for the TOOL for WorkStation mode with PS2Linux.
0x16000000 0x160000?? F* 2 I2C interface for the DVE. Resides in the Dev9C. Under Dev9_3. Only present on some PS2 models (at this memory).
0x18000000 0x1BFFFFFF ?
0x1D000000 0x1D0000FF F 2 SIF control - access to 0x1000F200 on EE side, over SBUS.
0x1E000000 0x1EFFFFFF R 2 Dev1 ROM for DVD player.
0x1F000000 0x1F000001 R B Dev0 Exp1 Expansion region 1 (PIO), meant for BIOS expansion on PS1. On early PS2 models (SCPH-30003) this is mapped to a different place and the SSBUSC config - registers are 'tied' to the registers of Dev9_3 - changing one changes the other.
0x1F400000 0x1F4001FF R 2 Dev#9 SPU2_Core1 was mapped here, while testing, all returns 0xFFFFFFFF.
0x1F402000 0x1F40203F R 2 Dev5 CDVD
Scratchpad/Cache is accessible only from the IOP through the cached segment (?).
0x1F800000 0x1F8003FF R B Scratchpad/Cache 0 Mapped by 0xFFFE0144.
0x1F800400 0x1F8007FF R 2? Scratchpad/Cache 1 Mapped by 0xFFFE0140.
0x1F800800 0x1F800FFF ?
0x1F801000 0x1F801023 F B SSBUS Memory mapping & timing configuration
0x1F801024 0x1F80102F Bus Error, to above.
0x1F801030 0x1F80103F ?
0x1F801040 0x1F80104F F 1? SIO0 SPI Serial port for Controllers and Memory Cards on PS1.
0x1F801050 0x1F80105F F 1? SIO1 UART Serial port for PS1 inter-console connection, used by games.
0x1F801060 0x1F801063 F B IOP RAM Configuration
0x1F801064 0x1F80106F ?
0x1F801070 0x1F801073 F B I_STAT Interrupt status
0x1F801074 0x1F801077 F B I_MASK Interrupt mask
0x1F801078 0x1F80107B F B SBUS mode/PS1 mode - unknown?
0x1F80107C 0x1F80107F F ? Causes some err when accessed..?
0x1F801080 0x1F8010FF F B DMA Controller
0x1F801100 0x1F80112F F 1? Timers (aka Root counters)
0x1F801130 0x1F8011FF ?empty
0x1F801200 0x1F8013FF ?empty
0x1F801400 0x1F801423 F 2 SSBUSController. Added for PS2.
0x1F801424 0x1F80142F ?empty; - Bus error, to above. part of SSBUSC range Dev13 DECKARD ROM goes here.
0x1F801428 is DECKARD's ROM Dev #13 delay reg. (there is no address register?)
0x1F801430 0x1F80144F ?empty; Bus Error (both 1430 & 1440).
0x1F801450 0x1F801457 F 2 IOP SBUS control.
0x1F801458 0x1F80145F ?empty to IOP SBUS range
0x1F801460 0x1F80147F R 2 Dev#12 Dev9C Dev9 Controller
0x1F801480 0x1F80148B F 2 T3 IOP Counter
0x1F801490 0x1F80149B F 2 T4
0x1F8014A0 0x1F8014AB F 2 T5
0x1F8014B0 0x1F8014BF F 2 Some unmapped registers for timers. Writing 0xFFFFFFFF to one, writes to all 'random' values. Top 16bits have the same value as lower 16bits. Reading one clears only it to 0 - the other registers retain their (same) value up to when they are read.
0x1F8014C0 0x1F8014C3 F 2 According to pcsx2: "RTC_HOLDMODE"
0x1F8014C4 0x1F8014FF ?empty; to above device?
0x1F801500 0x1F80157F F 2 DMAC 2 - additional to PS1, for PS2 devices.
0x1F801580 0x1F8015FF F 2 DMAC 3 - for iLink only; On latest DECKARD models (no iLink) 0x1F801584 is used in PS1 emulation.
0x1F801600 0x1F8017FF F 2 USB OHCI Controller
0x1F801680 0x1F801687 F 2 USB 'unknown', 1680 can be set to 1 and is written in USB drivers.
0x1F801688 0x1F8016FF ?
0x1F801700 0x1F8017FF ?
0x1F801800 0x1F801803 R 1 CD-ROM PS1
0x1F801804 0x1F80180F ?empty; to CD-ROM PS1
0x1F801810 0x1F801817 F 1? PS1 GPU In PS2 mode might be connected to SIF FIFO
0x1F801818 0x1F80181F F 1? Something ? 181C looks like some timer - decrements Wipeout uses it
0x1F801820 0x1F801827 F 1? PS1 MDEC reading one of these causes halt in PS2 mode.
0x1F801828 0x1F80182F F 1? Something ?
0x1F801830 0x1F8018FF ?
0x1F801900 0x1F80191F F 2 Latest slim (DECKARD) models I2C/SPI(?) interface in IOP for DVE and other HW.
0x1F801830? 0x1F801BFC..??? SPU2 RAM?? or a lot of registrers are somehow mapped here..
0x1F801C00 0x1F801E?? R B* SPU PS1 ~= SPU2_Core0 - basicaly the regs. are at the same place as with PS2.
0x1F801DA8 0x1F801FFF R B* Dev4 SPU2_Core0 *multiple mappings used! * the SSBUS mapping size migh use fixed offset, so that SPU2 would not spread above 0x1F802000 - Depending on the size of the mapped segment, mapping happens only to the first reached even boundry of such size: effectively the fisrst even boundry of 0x800 (2kB), before 0x1F801DA8 is 0x1F801800, thus mapping will hapeen up to 0x1F802000 (= 0x1F801800 + 0x800), but because of the start address, the memory below it will be unmapped - free for other devices.
0x1F802000 0x1F803FFF R B Dev8 Exp2 Expansion region 2, for debug & other. Device is not really connected on retail PS2. One of the ranges of the PIO port. The connection with the PC side of the TOOL.
0x1F804000 0x1F807FFF ? Reading this range doesn't seem to cause bus error (?) but sometimes stalls the IOP and strange symbols appear in ps2link terminal.
0x1F808000 0x1F8081FF Most likely internal work memory area of SIO2. Anyhing can be written and then read back - so it doesn't look like control registers. It is internal to the IOP as accessing it results in no /SRD/SWR on the SSBUS.
0x1F808200 0x1F8082FF? F 2 SIO2 Controller & Memory Card SPI ports.
0x1F808300 0x1F8083FF ?
0x1F808400 0x1F80854F? F 2 FireWire iLink
0x1F808600 ???? empty area for remapping???
0x1F900000 0x1F9FFFFF R 2 SPU2_Core1, empty area for remapping
0x1FA00000 0x1FA00000 R ? POST3 (similar to POST, but PS2 BIOS uses this address), empty area for remapping.
0x1FB00000 0x1FBFFFFF R 2 empty area - for remapping ?
0x1FC00000 0x1FFFFFFF R* B Dev2 BIOS ROM. Remappable, but you can't boot without BIOS.
Accessible only from the IOP(?):
0xFFFE0130 0xFFFE0133 F B Cache control
0xFFFE0140 0xFFFE0147 F 2? Scratchpad mapping address
##############################################################
### SPEED.txt ###
### v01, 2016.12.25 ###
### by Wisi ###
##############################################################
This document may very well contain incorrect or misleading information, for which the author takes no responsibility.
This following information is based on multiple sources, some of which may have been misinterpreted.
Credits go to:
- SP193 for the much help and explanations about the PS2.
- Maximus32 for his work on making PS2Linux better, leading to the need to understand how SPEED transfers could be optimized.
- many other contributors to the PS2SDK and to information on the forums.
The SPEED chip is the "default" expansion device, that connects to the Dev9Controller (Dev9C / SSBUS-Buffer / ...). On early PS2 models, the Dev9C is a PCIC (PC Card Interface Controler), that supports standard PCMCIA interface (and cards) and a custom "SSBUS-mode". For these PS2 models, the SPEED is housed in a PCMCIA card. On later PS2 versions, the Dev9C has simpler buffer-only function (among other capabilities), a Network Adapter houses the SPEED chip, and the connection is made through the Expansion Bay connector.
Abbreviations:
ATA Advanced Technology Attachment (Used as nickname in this document for the HDD Controller interface built-in the SPEED chip.)
PCIC PC card Interface Controller (The early versions of the Dev9C.)
EMAC3 Ethernet Media Access Controller 3
UART Universal Asynchronous Receiver / Transmitter. (The "Serial port" interface, used for modem, built-in the SPEED chip.)
PSX DVR PlayStation "PSX" Digital Video Recorder (In this document this refers to the DVR and not to the original PS1 (PSX).)
SSBUS Sub-system Bus (The bus that connects the IOP to the peripheral devices.)
SSB SSBUS. Usually used in line names.
SPEED Sony Peripheral Ethernet/Enhanced Extension/Expansion Device (?) (The "default" expansion device for both the PCMCIA and the ExpansionBay interfaces.)
SMAP Sony Media Access Peripheral (?) (The Ethernet controller in the SPEED chip.)
The SPEED chip contains a number of separate sub-devices (controllers):
- ATA ATA Controller. Supports parallel ATA interface with Ultra DMA mode 5 (max).
- SMAP Ethernet controller. Contains EMAC3.
- UART Universal Asynchronous Receiver / Transmitter. Serial port used for the modem, built-in the PCMCIA card / Network Adapter.
Devices that might not be implemented in the SPEED chip, but rather with external circuitry:
- FLASH Flash memory interface. Used OSDSYS updates. The SCPH-50000 series BOOT ROM contains a driver for it and it is used in the PSX DVR. The actual hardware is known to exist only on PSX DVR(?). The hardware for the FLASH in the PSX DVR seems to be "patched" on the SPEED chip by additional programmable logic IC (together with other PSX-specific features). This may be only valid for one of the models of PSX. It is unknown how this would have been implemented in the Network Adapter.
- DVR Provides control of the Digital Video Recorder - specific circuitry for the PSX DRV.
Because the SPEED uses only a single interrupt and DMA channel, peripherals integrated into it, share these channels.
The PCMCIA-mode of the SPEED, can only be used to read the PCMCIA Attribute Memory. None of the SPEED devices is accessible in this mode.
In SSBUS-mode, the hardware interface is changed, although not too much.
In each of the two modes, only the corresponding memory (device-control registers) can be accessed, and not that of the other.
Once initialization is complete (and the SPEED is switched to SSBUS mode), the SPEED "appears" to the IOP the same way - in SSBUS mode, regardless whether it is connected through a PCMCIA or an Expansion Bay type Dev9C interface.
The SPEED was (most likely) initially made as a proprietery/custom PCMCIA device. Most likely first it supported only HDD or Ethernet. There are "early" version (revision) values (0x09, 0x10), which no known SPEED has.
The SPEED is commonly referred to as "SPEED-Lite", so it might be, that initially there was a more complete version, which would make the SPEED devices accessible through the PCMCIA interface as well.
Known SPEED models:
Chip Revision (BCD) Capabilities Found in
CXD9622 ? ? ?
?? 0009 "TS" ? ?
?? 0010 "ES1" ? ?
CXD9624GG 0011 "ES2" 0003 0002 ATA, SMAP PCMCIA & Network Adapter
CXD9624AGG 0012 ? 000B 0002 ATA, SMAP, UART PCMCIA & Network Adapter
CXD9731GP 0013 ? 000B 0002 ATA, SMAP, UART PCMCIA(?) & Network Adapter
CXD9731AGP 0013? ? 000B 0002 ATA, SMAP, UART PCMCIA(?) & Network Adapter & SCPH-70000 series
CXD9731GP 0013 ? 000B 0002 ATA, SMAP, UART PSX DVR, for the ATAPI drive.
CXD9764GP 0014 ? 003B 0002 ATA, SMAP, UART, DVR, Flash PSX DVR, for connecting with the DVRP, the HDD and the Flash device.
CXD2976GB 0013 ? 0009 0000 SMAP, UART SCPH-79000 series. This is what the actual hardware reports.
DECKARD-SW 0013 ? 0003 0002 ATA, SMAP SCPH-79000 series. This is what the emulator reports.
Revision numbering
The way values 0x0A-0x0F in the Revision register are skipped as "unknown", suggests that this is a Binary-Coded Decimal number. Values 0x00-0x08 are considered "unknown" by the known drivers as well.
Revision names: "TS" might stand for "Test/Tentative Series", while "ES1"/"ES2" - for "Enhanced Series".
"ES" is also used in TOOL boot log: "id:BF08E3: chkrev: == current BoardID=MPU4-01-12, EE=2.6-2.9, GS=ES4.91, IOP=ES3.1, SPU2=ES6, PCIC=CXD9566"
ATAD from SCPH-30003 would print "Device is not after ES2\n" if Dev9C reg. 0x1F80146C & 0xFF == 0xFF. This possibly points-out that SPEED chips with revisions before 0x0010 (included) were integrated in / connected with the Dev9C chip, or it was missing altogether (thus the 0xFF value - as of a floating bus). So whatever device (PS2) had them, they were quite possibly integrated inside it. The TOOL's MIF board is detachable, and thus replaceable, so one could assume that at some point a different board might have been used (one with a SPEED chip on it). Another possibility would be that the SPEED of the "Blue TOOL" (Performance Analyzer) was such (given that it was indeed inside the PA), however that is highly doubtful, because the PA came to existence much later than the TOOL.
SPEED chip numbers:
CXD9624GG (C) 2000 SCEI 08J3955 1030D0058C KOREA *'D' might be 0
CXD9624GG (C)2000 SCEI 08J3955 1B14A009BC JAPAN *Here there's no space between the "(C)" and "2000". "1B14A009BC" might start with 'I' instead.
CXD9731GP (C) 2002 SCEI JAPAN 0328HAL D3509YAG
CXD9731AGP (C) 2002 SCEI 6TMOXBG0003 JAPAN0533HCL 887560
CXD9764GP (C) 2003 SCEI 6TT6XBG0001 TAIWAN 034BHAL 09831YA
More detailed information about each revision
CXD9622 Most likely not a SPEED chip. "An old Japanese version that supports up to ATA66. CXD9731AGP supports up to ATA133." Source: from http://bbs.a9vg.com/thread-1410569-1-1.html
CXD9731GP, rev=0013, caps=000B.0002, from PSX DVR. It is a normal CXD9731GP chip, used for the ATAPI writer drive. It is mapped at 0xBF410000 - after the CDVD DSP. The buffer for it (the Dev9C buffer channel for the CDVD drive - reg. 0xBF801460 bit 1 should be set), in the Dev9C has to be enabled, for it to be accessible, and the CDVD DSP has to be disabled by 0xBF801460.6 = 1.
CXD9764GP, from PSX DVR. It is a SPEED chip with extended capabilities, used for connecting with the DVRP, the HDD and Flash device. It has capability to limit the access to the HDD to a set maximum size. It has command/packet interface, through which the IOP communicates with the DVRP. The same interface is used when the IOP communicates with the dvr_hdd0: device. It is mapped at 0xB0000000, just like the standard SPEED.
CXD2976GB SCPH-79000 series. From post-SCPH-75000 (included) PS2 models with emulated IOP (by DECKARD on PPC-IOP). The CXD2976GB is an ASIC that combines EE, EE RDRAM, IOP, SPU, SPEED, ...
On post-SCPH-75000 PS2 models ("DECKARD-consoles"), only the SMAP of the SPEED hardware devices is considered functional, although DECKARD emulates the capabilities register as 0003.0002 ATA, SMAP. The actual SPEED hardware is integrated in the IOP ASIC (later to be merged together with the EE and a lot of the PS2 hardware). The SPEED is mapped at offset 0xB1000000 (=0xB5000000 from EE side) (instead of at 0xB0000000). Based on the way the registers can be modified, the hardware seems to support SMAP and UART. The registers for the ATA Controller and other devices are always zero, even when writing 1. It is unknown if the UART and PIO port (used for the SPEED EEPROM and HDD Activity LED) lines are accessible on these ASICs. The PPC-IOP has a separate (PPC-specific) UART, the I/O lines of which are accessible, but it has nothing to do with the one of the SPEED.
Specific differences between revisions:
Revisions after 0x11 (included) use "SMAP_REG8(SMAP_R_BD_MODE) = SMAP_BD_SWAP;": if (SPD_REG16(SPD_R_REV_1) < 0x11) SPD_REG8(0x100) = 1;
Register 0x24 SPD_R_DMA_CTRL:
if (dmaCtrlVal >= 0 && dmaCtrlVal <= 1 )
else if (dmaCtrlVal >=2 && dmaCtrlVal <=3) dmaCtrlVal = (4 << dmaCtrlVal); // 2 -> bit 4 (0x10), 3 -> bit 5 (0x20)
if (Rev_1 <= 0x11) DMA_CTRL = dmaCtrlVal & 0x03 | 0x04;
else DMA_CTRL = dmaCtrlVal & 0x01 | 0x04 | 0x02;
SPEED registers:
Registers are at 16-bit offsets. Both 8- and 16-bit registers exists, but accesses should be 16-bit.
"r/o" Read-Only - after setting/clearing, the written value can't be read-back. Writing can still have effects, but no test showed any.
"r/w" Read/Write - by writing (or reading - special cases), the value can be both set and cleared. If no other information is specified, then assume that writing 1 returns 1 on read and vice-versa.
Sub-devices offsets:
0x0000 - 0x000F Version and revision.
0x0010 - 0x001F Read-only, always 0.
0x0020 - 0x002F Common interface control: IOP DMA interface, interrupts, PIO port.
0x0030 - 0x003F ATA SPEED-IOP interface control, transfer and FIFO buffer management.
0x0040 - 0x005F ATA registers - directly accessing the ATA peripheral.
0x0060 - 0x007F ATA SPEED-HDD interface control, DMA configuration & some unknown stuff.
0x0080 - 0x00BF UART.
0x00C0 - 0x00FF Always 0.
0x0100 - 0x01FF? SMAP-related. (Writing 0xFFFF results in: 0x102=1 & 0x104=3)
...
0x1000 - 0x1FFF SMAP common.
0x2000 - 0x2??? SMAP EMAC3.
0x3000 - 0x33FF SMAP buffer descriptors. Can be written anything and retains the data written. RST_N & ALL_RST_N have no effect on it.
0x4000 - 0x43FF? DVR control (PSX DVR). (At lest up to 0x42FF.)
...
0x4800 - 0x481F? External Flash. The SCPH-50000 series BOOT ROM contains a driver for it and it is used in the PSX DVR as well. Hardware seen only on PSX DVR(?). The hardware for the EXTFLASH in the PSX DVR seems to be "patched" on the SPEED chip by additional programmable logic IC (together with other PSX-specific features). This may be only valid for one of the models of PSX. It is unknown how this would have been implemented in the Network Adapter.
Only registers 0x00-0x7E - Common SPEED registers and ATA Controller are documented below.
Version and Revision registers
0x00 SPD_R_REV_1, SPD_R_REV Base address for revision registers.
15:0 r/o, 0.
0x02 SPD_R_REV_2 SPEED Revision (binary-coded decimal):
15:0 r/o.
0x00-0x08 "unknown" for unknown values only the revision in reg 0x02 gets printed by the driver.
0x09 "TS"
0x0A-0x0F "unknown" (Unused due to BCD.)
0x10 "ES1"
0x11 "ES2"
... ?
0x04 SPD_R_REV_3 SPEED Capabilities:
15:0 r/o.
0 SPD_CAPS_SMAP
1 SPD_CAPS_ATA
2 ? Well, this *has* to be something...
3 SPD_CAPS_UART
4 SPD_CAPS_DVR
5 SPD_CAPS_FLASH
0x06-0x0C are usually = 0;
0x0E SPD_R_REV_8
Usually = 0x2.
0x10-0x1E are always = 0;
Common interface control:
0x20 SSB_MODE status. Bit 0 of this register gives the status of the SSB_MODE line OR the written value (0/1) to register 0x20 in the PCMCIA I/O range, which can be used to force the MODE to 1. MODE controls whether the SPEED (its interface to the Dev9C) is in PCMCIA_mode=0 or in SSBUS_mode=1. MODE_and_reg_0x20_on_read = Register_0x20 | SSB_MODE. This register can only be written (value of 1) in PCMCIA I/O mode. It cannot be written in SSBUS_mode (with a value of 0). PCMCIA I/O range is accessed when: SSB_MODE=0, /RST_N=0, /REG=0, /SRW(/DIOW)(or /SRD(/DIOR)) is used for data strobe (ALL_RST_N=1, SSB_RST=1). Once this register has been written 0x1, from the PCMCIA I/O range, the SPEED can only be switched back to PCMCIA mode by resetting it through the /ALL_RST_N input.
0 r/o Read: SPEED Dev9C interface mode: 0=PCMCIA_mode / in 1=SSBUS_mode (in both PCMCIA I/O range and SSBUS mode. Write in PCMCIA I/O range: 0=NoEffect / 1=Force_MODE_to_1. Write in SPEED devices range ("SSBUS-mode"): NoEffect.
15:1 r/o Always 0.
0x22 ?
15:0 r/o Always 0.
0x24 SPD_R_DMA_CTRL SPEED-IOP DMA interface configuration:
0 r/w DMA target: 0=ATA / 1=SMAP
1 r/w Fastest DMA mode (when set). This is always set on post-12 (included) revisions otherwise the value in the register is kept (read & write back) on earlier revisions. Selects the "Fastest DMA mode", which was auto-supported on early revisions, but perhaps the logic for that was a bit too bulky (would require both the SSCLK and /SRD,/SWR to generate data clock, which is error-prone as well). Maybe has to do with PCMCIA DMA mode.
2 r/w Wide (32-bit) DMA mode (when set).
3 r/w, no visible effect. *Might have effect on write SPEED<-IOP or in modes other than UDMA. Or could be valid only for SMAP. It doesn't seem to be for enabling 8-bit DMA. It could be clock sampling edge - like the bits in the 0x1464 register of the Dev9C.
4 r/w Pause SPEED-IOP DMA (while set). While set, SPEED keeps DREQ inactive, even when all other conditions to start transfer are met. Clearing this after setting it, brings DREQ back active, resuming transfer. While this is set, the DMAEN_EX output (unconnected, but for a 10kohm R to Vcc - why when it isn't an input?) goes inactive low. In all other cases, DMAEN_EX is active high. DMAEN_EX is always actively driven.
7:5 Unimplemented.
15:8 Unimplemented.
0x26
15:0 r/o Always 0.
0x28 SPD_R_INTR_STAT r/o
15 Buffer completely full. Or Error/underflow/overfolw(?).
14 Buffer completely empty.
13 //There are probably more UART stuff here.
12 PD_INTR_UART
11 ?
10 ?
9 SPD_INTR_DVR
8 ? //There has to be something here. - Possibly the external interrupts INT9_EX00 and INT9_EX01. In fact, it is very possible, that bit 8 is INT9_EX00 and bit 9 is INT9_EX01 (while the rest have no function). There could also be "interrupt on change" for the PIO port.
7 ?
6 SMAP_INTR_EMAC3
5 SMAP_INTR_RXEND
4 SMAP_INTR_TXEND
3 SMAP_INTR_RXDNV /* descriptor not valid */
2 SMAP_INTR_TXDNV /* descriptor not valid */
1 SPD_INTR_ATA1 Set while there is data in FIFO (tested on HDD->FIFO->IOP) (auto-cleared(?) once all data is drained). For a 4-sector transfer HDD->IOP, this will be set once data from HDD goes to SPEED and cleared only once the IOP's DMAC has read more than 510 bytes (or bytes?) (of 512). The reason it happens only after the 510-th word is read (rather than after the 512-th word's read), could be because it was necessary to clear the interrupt before the transfer ends.
On DMA (in 16-bit words - not wide DMA) transfer IOP->SPEED, this gets set early - even when there is no complete sector in FIFO.
0 SPD_INTR_ATA0 Reads the state of the INTRQ line directly: 0=inact.low(no_IRQ) / 1=act.high(IRQ). It doesn't seem like this bit is latched. HDD driving might only be to high state. On DMA, the HDD usually asserts this on completion of the entire transfer. It is unknown if the SPEED masks this until a transfer is complete - most likely it doesn't, but the following note suggests that it does: HDD-specific "issue" (which seems entirely normal): The INTRQ line is a bit odd: When bit 0 above is 0 - before and after I/O functions, the INTRQ line is low and can be pulled high by 1k resistor, but there is no effect in the interrupt bits. When the line is high, bit 0 above is high, but the line cannot be pulled sufficiently low (less than 0.5V drop (to ~3V) after loading with 100 ohm resistor to gnd).
0x2A SPD_R_INTR_MASK The Dev9 interrupt to the IOP is triggered (active) when (while) ((reg0x28 & reg0x2A) != 0).
Correspond to the flags of register 0x28.
0x2C SPD_R_PIO_DIR r/w. Enables the output buffer of each line of the SPEED's PIO port.
7:0 Writing 1 enables the output buffer of the corresponding line of the port in the Data register.
0x2E SPD_R_PIO_DATA r/w. Drives SPEED's PIO port directly, according to the set direction of each line. On read, returns the state of the lines of the port.
1:0 Dev9 LED Control. 0=On/1=Off. Clearing either to 0 will light the LED. Each is connected to the cathode of a diode, sharing a common anode. The anode has a 10kohm pull-up to Vcc, and is connected to the base of an PNP transistor, with collector grounded and emitter, connecting through a 240ohm resistor to the ACS_LED pin (90) of the Expansion Bay connector. It connects to the cathode of the HDD Activity LED in the PS2, the anode of which connects through 180ohm resistor to +5V.
3:2 On SCPH-70000, each is connected through 10kohm R to Vcc, so they were inputs once. On the SCPH-10350 Network Adapter - as well.
4 SPD_PP_DOUT Lines 7:4 connect to the EEPROM in the Netword Adapter.
5 SPD_PP_DIN
6 SPD_PP_SCLK
7 SPD_PP_CSEL
15:8 Unimplemented.
ATA SPEED-IOP interface control, transfer and FIFO buffer management:
0x30 r/o, always 0.
0x32 SPD_R_XFR_CTRL This register most likely only controls SPEED's from/to IOP DMA (maybe only for ATA) (and is not related to the SPEED<->HDD DMA). It may be related to (affect) FIFO.
7 r/w DMA "start" bit. Enables the SPEED making DMA requests (DREQ) to the IOP. The SPEED will get data from HDD (in DMA) fine (until its buffer is full) but will not make DMA request to the IOP until this is set.
6:3 ?r/o or w/o, 0.
2 ?w/o, 0. write= Set always by ata_set_dir(). Clearing changed the 0xFF50 to 0xDF50 (register 0x60), but nothing else (UDMA read).
1 ?w/o, 0. write= Set always by ata_set_dir(). Clearing doesn't visibly affect read UDMA transfer.
0 r/w DMA direction: 0=Read / 1=Write. Affects the direction of the FIFO: once set, the FIFO counter (reg. 0x38) would be set at 0x10 and filling (by IOP) would decrement it - it shows the number of free sectors (to be filled by IOP) in FIFO.
Given that bits 1 and 2 cannot be read-back, they might be for some reset function - reset FIFO/UDMA CRC/...
Besides the direction (bit 0) only bit 1 is (constantly) set by dmarelay (ata_dma_setup()). Bit 7 is set only (OR-ed) after that.
0x34 Total number of bytes, read from SPEED on one (complete) transfer (by IOP or HDD(untested for HDD)). This grows beyond the SPEED's FIFO size.
13:0 r/w When writing 0xFFFF, the value read-back is 0x3FFC. No error conditions are triggered by this, nor changes are made to other registers. Overflowing from this state by reading words by HDD or IOP would most likely result in an underflow, for which there may not be any indication bits.
15:14 r/o, 0.
Values as large as 0x2200 have been observed here. The buffer shouldn't underflow from IOP DMA read, because the SPEED either will pause DMA when the FIFO is empty, or simply won't increment this counter further than the 0x36 counter.
0x36 Total number of bytes, written to SPEED on one (complete) transfer (by IOP or HDD). This grows beyond the SPEED's FIFO size.
13:0 r/w When writing 0xFFFF, the value read-back is 0x3FFC. Writing 0x3FFF or 0x3FF8 and then using UDMA and clocking 4 words in, so that it overflows, causes reg. 0x38 which was first 0x3F and at reg. 0x62 with bits 14:12 changing from 0x3 to 0x4, it became 0xC0, interrupt reg. (0x28) became 0xC002 (bits 14 and 15 became set) and reg. 0x36 was cleared. This didn't change after new words entered the SPEED.
Number of byte written to buffer by IOP or HDD. For IOP->SPEED DMA, this icrements in 2 bytes for 16-bit DMA and 4 bytes - for Wide (32-bit) DMA. For HDD->SPEED UDMA, one increment is 8 bytes (unknown why), while for MWDMA it is (untested) 2 bytes. Because with DMA transfer is usually done in words, this has only be seen to contain values like 0, 4, ... 0x1FC, 0x200 (1 sector) ... 0x1FFC, 0x2000 ... 0x2200. Values as large as 0x2200 have been observed here. This holds the total amount of bytes ever written (to SPEED) through a single transfer (until reset).
When this steps from 0x1FF to 0x200 (512 bytes = 1 sector), the sector counter in reg 0x38 gets incremented (or decremented - for DMA writes by IOP).
15:14 r/o, 0.
0x38 SPD_R_DBUF_STAT Read: Flags and Total number of sectors that can be transferred between SPEED and IOP. For read (SPEED->IOP) this shows the number of sectors the IOP can get (are already in SPEED's FIFO), while on write - the number of free sectors, the IOP can put in the FIFO. This number increments/decrements on the byte counter (reg. 0x36) going from 0x1FC to 0x200.
4:0 r/o (values 0x00 - 0x10)
IOP->DMA->SPEED: Number of free sectors remaining in buffer - it will increase once the HDD starts reading from the FIFO. = The number of sectors the IOP can write right now. Example reg. 0x38 values: IOP filling FIFO: 0x50, 0x2F, 0x2E, ..., 0x21, 0x20.
SPEED->DMA->IOP: Number of non-free sectors written by HDD and not yet read by IOP. = The number of sectors the IOP can get right now. This can only(?) increment past 0x10 if a large value is written to register 0x36. This doesn't cause an overflow condition, though. An overflow will occur only if a few more words are written to FIFO, so that the counter overflows (both 0x36 & 0x38). Example reg. 0x38 values: HDD filling FIFO: 0x60, 0x20, 0x21, ..., 0x2F, 0x30.
5 HDD->SPEED: Buffer has free space (sectors or words?) =1. / IOP->SPEED: Buffer is completely empty (not even a single byte/word) =1.
6 HDD->SPEED: Buffer completely empty (set while reg. 0x36 is still at 0 (tested in UDMA only)). IOP->SPEED: One or more sectors in buffer, when =1.
7 Buffer completely full, when =1.
15:8 r/o, 0.
When bits 6 and 7 are set at the same time (HDD->SPEED on UDMA), this signifies overflow (error). At this case, bits 14 and 15 of the interrupt register (0x28) would get set as well.
Write to register 0x38:
0 ?Reset ATA DMA FIFO (only, or also for PIO?) OR Reset FIFO errors, or something that wasn't active in the tested conditions. Does it perhaps reset the byte counter reg. 0x34? Most likely for clearing errors, or other states.
1 Reset FIFO (HDD->SPEED & IOP->SPEED). Resets the FIFO counter (reg 0x38 & 0x1F) to 0, reg 0x38 becomes on read = 0x60. Reg 0x36 becomes 0. Unknown if 0x34 changes - most likely resets it as well. Reg 0x28 bit 1 gets cleared (because there is now no new data in FIFO). Reg 0x28 bit 14 becomes set - FIFO empty. No other visible changes.
15:2 no effect on HDD->SPEED FIFO & regs.
0x3A r/o, always 0.
0x3C r/o, always 0.
0x3E w/o? Debug/Test/Reset perhaps. It is NOT master SPEED devices reset, but it has similar effect.
Values 0000, - DF00 in increments of 0x0100 don't reset. Values starting with F000 also don't reset.
It (values with highest nibble = 0xE) resets the ATA controller, interrupt mask register, PIO port, registers at offsets 0x102 and maybe even SMAP.
Only values with highest nibble = 0xE do reset (all of them, but the first ones have intermediate values). Once a reset-causing value is written, the reset will be completed after a fixed period of time (~0x30 cycles in the loop used, but it accessed arrays, so the exact duration is unmeasured, access is from the EE). Within this period, the values of registers (0x3000 was only tested in this case) would either preserve their previous values or take different values (unknown why), up to the end of the reset, when all registers will be initialized to their power-on/reset default values. The case with the "intermediate values" was observed in different conditions, but it seems most stable when a loop is used that writes to this registers values from 0x0000 to 0xFF00, in increments of 0x0100. In such a test, once the value 0xE000 is written (only it has this effect and only in these conditions), the read value from reg. 0x3000 will change throughout the "reset-period" between different values (0xFFFF, 0xEFFF, 0xFFFB, 0x0014(only once near the start)).
The lower bits seem to have some special purpose, that is not really timing related, but rather it resets something perhaps.
Value 0xE005 (not 0xE004 or 0xE001, or other values) was once observed to cause a great delay and turn off the fast-fan mode. I couldn't replicate this again though.
The undetermined behavior of this reg. suggests that it either controls some circuitry for clock or reset or data-pre-set or I/O lines purpose-change or Test mode, etc, but not something meant to be used in normal operation. Furthermore, the way the delay between writes and the data written seems to matter, suggests that this could be some parallel/serial port to some debug state-machine/circuitry, that executes commands, based on the written data. The SPEED does have a good deal of test inputs and the "SMODE" input with unknown function, so maybe there is a lot more circuitry in it than I initially though (even if one doesn't count the SMAP).
Tests were done by setting bit 0 in reg. 0x102 (which swaps the bytes in registers 0x3000 - 0x33FF), then writing some word to register 0x3000, and reading that word while writing values to reg. 0x3E, to see when its bytes will gets swapped again (the reset logic will clear reg. 0x102 thus swap the bytes back). Register 0x3000 retains its initial value after this "reset" (but for the swapped bytes).
0x40 - 0x5F ATA registers.
ATA SPEED-HDD interface control:
0x60, 0x68 - 0x6E, 0x7A - 0x7E: There commonly return 0xFF7F, and sometimes 0x0000. They read the HDD data bus, because by specifications DD7 of it, should be the only line to lack a pull-up resistor, and as seen above all data has bit 7 low, with all others - high. They read the HDD data bus without actually making an /DIOR, /DIOW bus cycle (it ceratinly doesn't cause /DIOR, /DIOW to go active), or they read some intermediate/SPEED-internal bus. Reading them has no effect on DMACK/ DMARQ. They have different (from each-other) values over (DMA) transfer, maybe because the test code reads them in sequence.
Register 0x60: 0x60 also reads the HDD data bus, like 0x68 - 0x6E, 0x7A-0x7E. It is different from them in that it contains similar values after transfer. It usually contains 0x0050, and after transfer(s) 0xFF50. But on some occasions (changed read UDMA high nibble timing - 0xBF50. Changes together with reg 0x62 - from 0x00 to 0x80. It resembles the 0x68-0x6E, 0x7A-0x7E registers - it contains 0xFF7F, when all registers here are written 0xFFFF.
0x62 State of (Ultra ?) DMA transfer and lines. r/o(?).
0 ?
1 ? Set (together with bit 7) when doing transfer and SPD_R_IF_CTRL bit 3 (0x08) is clear. Transfer seems correct.
2 ?
3 ?
4 ?
5 IORDY line state (inverted) (in UDMA only?) 0=IORDY_high / 1=IORDY_low.
6 Ready to acknowledge DMA transfer and DMA transfer is running.
7 State of the INTRQ line: 0=inact.low / 1=act.high. In DMA it can be considered DMA transfer was completed.
11:8 ?Never seen set. If this is anything, it might be a counter of the bits in a 16-bit word (the extension being in bits 14:12). Then this might be related to CRC generation - if a sequential shift-register was used.
14:12 Counter of 16-bit words for UDMA (only?). Might be related to reg. 0x36, which increments with 8 bytes on 3->4 and 7->0 transitions of this value. This grows from 0 to 7. Increments on every clock (DSTROBE / HSTROBE(?)) transition (both l->H & H->l). On tests, this would change from 0 to 1 on STROBE low (bit 5 =1) to high (bit 5 =0).
15 ?
0x64 SPD_R_IF_CTRL Most likely controls SPEED's HDD interface (only).
7 r/w SPD_IF_ATA_RESET Reset the ATA interface of the SPEED, when =1.
6 r/w HDD Reset. Drives the HDD /RST line directly: 0=act.low/1=inact.high.
5 ?w/o Bits 5 & 4 are set as well (reg 0x64 = 0x7C) in ata_dma_setup() from dmarelay, ulike ps2atad, where only = 0x4C is written. Bit 5 most likely resets something.
4 ?r/w
3 r/w When clear doesn't cause transfer to fail. Most likely sets some config option of DMA. Set after the reset. Set by ata_set_dir().
2 r/w SPD_IF_DMA_ENABLE Enable SPEED acknowledging DMA requests from HDD. Auto-cleared on transfer end (and(?) buffer full). *Note SPEED<->IOP DREQ won't be activated by SPEED if FIFO is empty, so don't be surprised, if clearing this causes the IOP to hang on waiting for DMA. In dmarelay, only it is cleared of this reg, when stopping DMA.
1 r/w DMA direction: 0=Write_to_HDD / 1=Read_from_HDD.
0 r/w 0=MDMA / 1=UDMA mode. Bit is kept in its initial state by ata_set_dir() (only this bit).
0x66 r/w?
Commonly 0x1, sometimes (on DMA write to HDD) 0xFF(?). Writable up to 0xFF (any combination.)
7:0 r/w
15:8 r/o, 0.
0x68 - 0x6E See reg. 0x60.
0x70 SPD_R_PIO_MODE
4:0 /DIOR, /DIOW active low period:
--------------------------------------------------------
value 0 1 2 3 4 5 6 7
t[ns] 30 50 60 80 90 110 120 140
--------------------------------------------------------
value 8 9 A B C D E F
t[ns] 150 170 180 200 210 230 240 260
--------------------------------------------------------
value 10 11 12 13 14 15 16 17
t[ns] 270 290 300 320 330 350 360 380
--------------------------------------------------------
value 18 19 1A 1B 1C 1D 1E 1F
t[ns] 390 410 420 440 450 470 480 500
--------------------------------------------------------
7:5 Minimal /DIOR, /DIOW active low period. This doesn't seem to be some "added" period. Where the two values, separated by '/' are different, two different durations were measured, which occurred throughout the multiple reads. The two values don't necessarily switch-around on consecutive accesses. They can't be caused by /IORDY delay, because this effect is missing from the faster timings.
Maybe these bits control some other parameters, but I can't think of what that might be - perhaps it is related to /CSn, or address lines driving timings (unlikely)...
--------------------------------------------------------
value 0 1 2 3
/DIOR t[ns] 120/110 110/100 90/80 80/70
/DIOW t[ns] 90/80 80/70 60/50 50/40
--------------------------------------------------------
value 4 5 6 7
/DIOR t[ns] 60/50 50/40 30/30 30/30
/DIOW t[ns] 30/30 30/30 30/30 30/30
--------------------------------------------------------
*The periods of 30ns are actually 31.1ns.
15:8 r/o, 0.
Standard Programmed I/O timing configuration values:
--------------------------------------------------------
PIO Mode 0 1 2 3 4
value[hex] 92 72 32 24 23
--------------------------------------------------------
Programmed I/O transfer notes:
/IORDY (most likely) is one source of the /WAIT signal of the SSBUS.
The SPEED will activate the /WAIT signal to the SSBUS (regardless of /IORDY), to elongate an access cycle, so that it matches the one configured through the PIO timing register (0x70).
A FIFO buffer is not used (no test showed that it was / there was one).
0x72 SPD_R_MWDMA_MODE
3:0 /DIOR, /DIOW active low period:
--------------------------------------------------------
value 0 1 2 3 4 5 6 7
t[ns] 20 30 50 60 80 90 110 120
--------------------------------------------------------
value 8 9 A B C D E F
t[ns] 140 150 170 180 200 210 230 240
--------------------------------------------------------
7:4 /DIOR, /DIOW inactive high period:
--------------------------------------------------------
value 0 1 2 3 4 5 6 7
t[ns] 30 40 60 70 90 100 120 130
--------------------------------------------------------
value 8 9 A B C D E F
t[ns] 150 160 180 190 210 220 240 250(/DIOR)/280?(/DIOW)
--------------------------------------------------------
It is unknown whether this register affects the circuitry that processes reads, but it most likely does not.
Standard MultiWord DMA timing configuration values:
--------------------------------------------------------
MWDMA Mode 0 1 2
value[hex] FF 45 24
--------------------------------------------------------
0x74 SPD_R_UDMA_MODE
3:0 HSTROBE (DIOR-:HDMARDY-:HSTROBE) (host - SPEED->HDD strobe) cycle time:
--------------------------------------------------------
value 0 1 2 3 4 5 6 7
t[ns] 40 60 100 120 160 180 220 240
--------------------------------------------------------
value 8 9 A B C D E F
t[ns] 280 300 340 360 400 420 460 480
--------------------------------------------------------
The high and low periods are always of identical length.
7:4 ? Guess: Read data sampling or timeout condition (used to detect bad/skipped cycle of DSTROBE). The function of this is unknown.
Standard Ultra DMA timing configuration values:
--------------------------------------------------------
UDMA Mode 0 1 2 3 4 5
value[hex] A7 85 63 62 61 60*
--------------------------------------------------------
*Although the upper nibble's value for UDMA Mode 5 is uncertain.
0x76 CRC Initial value (first word) for UDMA. Default value is 0x4ABA. The SPEED processes this as the first word, rather than an initial value (initial value is 0), so after the "real" first word of data is transferred, the CRC result (read from reg. 0x78) would contain a value that is a CRC over both the contents of reg. 0x76 (as the first word) and the first data word (the initial value is actually 0). NOTE: The above could be wrong - erroneous test due to bad DSTROBE initial state. The initial value is rest to 0x4ABA when the SPEED ATA Controller is reset - reg. 0x64 / bit 7 is set. By default contains 0x4ABA.
15:0 r/w, Any value can be written and then read back. Register 0x78 is immediately updated (with the written data) once this register (or it) is written.
0x78 CRC result register for UDMA on read. On write, this has no effect(?).
15:0 r/w, On write any value can be written and then read back from both this and register 0x76 (unconfirmed).
Before transfer it contains 0x4ABA, like reg. 0x76, but on incomplete/failed transfers, contains intermediate CRC values. The value here is updated over UDMA transfer, though one can't really check the value for a specific word in the transferred sector, because the transfer is much faster than the IOP's (and EE's) capability of accessing through the SSBUS.
0x7A - 0x7E: See reg. 0x60.
--------------------------------------------------------
More information on usage:
To reset the SPEED ATA interface and the HDD, write to reg. 0x64: first value 0x80 (HDD /RST goes active.low, SPEED is reset), delay, write 0x00 (Enable SPEED ATA), delay, write 0x48 (HDD /RST goes inact.high).
Resetting the SPEED's ATA Controller (setting reg. 0x64 / bit 7) causes the following:
- FIFO buffer is reset (?).
- Interrupt states are reset(?).
- Registers are reset to their default values:
0x62 0x0020
0x64 0x001A (The reset bit is auto-cleared.)
0x66 0x0001 (It almost always contains that?)
0x70 0x0024 PIO Mode 3.
0x72 0x0035 Like MWDMA Mode 2 = 0x45.
0x74 0x0083 Like UDMA Mode 2, but the upper nibble is not 0x6.
0x76 0x4ABA (And consequently 0x78 = 0x4ABA.)
Stopping UDMA by clearing reg. 0x64, bit 2 would reset the UDMA CRC output value. It is unknown whether there is a way to stop/pause UDMA, to read the CRC up to a specific word.
Anything that causes the DMARQ (or /DMACK) line to go inactive over UDMA would reset the CRC.
For experiments on UDMA CRC disconnect HDD and:
- connect a 470ohm resistor between one of the /CS signals and DMARQ (to simulate constant request).
- connect another 470ohm resistor between /RESET and IORDY:DSTROBE, then use bit 6 of reg. 0x64 to change the level of DSTROBE. Each edge causes clocking of data. The "default" data on the bus is 0xFF7F (bit 8 lacks a pull-up - see ATA specification).
Using 0000 as data and a pre-written 0x76 value of 0, results in CRC always = 0 (over multiple words).
0x76w data results
0000 0000 all 0000
4ABA 0000 3F09, 8482, ...
0001 0000 3730, AA51, B861,...
see: http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
Select the pre-set "CRC16_CCIT_ZERO", then switch to custom and set:
"Input reflected" and "Result reflected" - both unchecked.
Polynomial = 0x1021 (default) G(x) = x^16 + x^12 + x^5 + x^0
Initial value = the value of reg. 0x76
Final XOR value = 0
CRC input data = "bytes"
And input the data as: 0x<highOrderByte_0> 0x<lowOrderByte_0> 0x<highOrderByte_1> 0x<lowOrderByte_1>
Example (default bus state): 0xFF 0x7F 0xFF 0x7F (and so-on)
Note that the CRCoutput value that reg. 0x78 holds after transferring the first 16-bit word, correspond to the the second word in the online calculator.
One way to overcome this, is to set the Initial value to 0 and add the word 0x4ABA (initial value of the SPEED) as the first word in the online calculator. This is most likely how the SPEED does it.
The way to get SPEED to output the polynomial, is to set the initial value (reg. 0x76) to 0x0000 and feed a single 16-bit word of 0x0001. Then reg. 0x78 (CRC output) will contain 0x1021.
##############################################################
### SPEED_UART.txt ###
### v01, 2016.12.25 ###
### ###
##############################################################
Universal Asynchronous Receiver / Transmitter in the SPEED chip.
It is used in the (US) Network Adapters, that contain a Dial-up modem.
Its hardware should be present in all SPEED revisions, that have the corresponding bit set in their Capabilities register.
It is a NS16550 / NS16550A / NS16450 - compatible UART. It resembles the one in the TMPR7901, the EE (EE SIO) and the PPC405GP.
The bits in the registers of the PPC405GP UART are in reverse order (LSB-MSB), to that of the other UARTs above.
There may be some differences between the devices above.
The SPEED's UART is different from the standard one, in that it has most of its bit-fields either write-only or/and hard-wired. For this reason, the driver uses shadow registers for IER, LCR, MCR & MSR.
It is not yet known if status bits states are latched by the hardware registers. It is quite possible that they are not. This is most likely the case with the MSR register, the value of which, once read, is stored in a shadow register.
It is yet unknown if it has FIFOs.
Registers:
0x00 RX/TX Data port: Read = RBR (RX data FIFO?) / Write = THR (TX Holding Register).
0x02 IER Interrupt Enable Register - write-only
DLL Divisor Latch LS - write-only
0x04 IIR read-only, FCR write-only
0x06 LCR write-only
0x08 MCR write-only
0x0A LSR read-only
0x0C MSR
0x0E Scratch register. Seems unimplemented. Reading gives different values on different resets, but the value doesn't change while the PS2 is on.
0x10 Pre-scaler low byte read/write(?), 8-bit
0x12 Pre-scaler high byte read/write(?), 8-bit
0x14 - 0x1E Mirror the Scratch register (0x0E) on read and write(?).
Registers after 0xFFFF is written to all:
80: 0000 0000 0001 0000 0000 0060 0000 00FF
90: 001F 00FF 00FF 00FF 00FF 00FF 00FF 00FF
A0: 00FF 00FF 00FF 00FF 00FF 00FF 00FF 00FF
B0: 00FF 00FF 00FF 00FF 00FF 00FF 00FF 00FF
Registers after 0 is written to all:
80: 0000 0000 0001 0000 0000 0060 0000 0048
90: 001B 0084 0048 0048 0048 0048 0048 0048
A0: 0048 0048 0048 0048 0048 0048 0048 0048
B0: 0048 0048 0048 0048 0048 0048 0048 0048
See documentation on similar UART controllers for more information.
Modem in the Network Adapter:
The actual modem in the Network Adapter seems to be P2109-V90.
IOP SSBUSC
Sub-System Bus Controller of the IOP documentation
compiled by Wisi
rev. 2018.01.06
This document is compiled from multiple sources and tests.
Sources and people who helped in creating this document:
- ps2sdk - information from various sources and developers
- SP193 who guided me when I still had no idea what hardware the IOP was comprised of
- psx-spx documents and all their sources, where a lot of the following information came from
- many others I may have forgotten over the time while writing and testing
The IOP uses an on-chip (external) peripheral bus controller (the SSBUSC) to communicate with external peripheral devices.
The SSBUS is (in PIO mode) a non-Address-Data-multiplexed 8-bit or 16-bit parallel bus with per-device configurable address range and timing. It supports DMA, both as a pseudo-PIO (that can appear as PIO access to the peripheral device) mode and fast and/or wide (32-bit) DMA mode, through which the maximal bandwidth of the bus can be attained.
The SSBUSC interfaces the IOP internal system bus to the external SSBUS.
The SSBUSC in the PS2 IOP is extended upon the SSBUSC of PS1 CPU, with complete backward compatibility. It is possible that the IOP even supports connecting the PS1 GPU to the IOP SBUS (untested) (see PGIF document).
Glossary:
Dev<number> SSBUSC channel (usually) used for that device number, but also refers to the device itself.
Dev#<number> Unofficial sequential numbering given to the channels, based on the numbering in the SSBUSC IRX. All channels (and even a few non-existing) are listed through this numbering. This is deprecated in favour of "Sbc" i.e. "Sbc4" is Dev4, "Sbc8" is Extr, "Sbc9" is SPU2, "Sbc10" is Dev9M.
Sbc<number> SsBusc Channel sequential number according to the SSBUSC IRX. This is a new, unofficial naming, based on the official numbering from SSBUSC IRX.
/CS<number> Chip Select line of the an SSBUSC channel, that corresponds to the given device number.
DREQ<number> DMA Request line of the an SSBUSC channel, that corresponds to the given device number.
DACK<number> DMA Acknowledge line of the an SSBUSC channel, that corresponds to the given device number.
/INT<number> Interrupt request line, usually used by the given device number.
Dev9C The Dev9 Controller chip. Also known as SSBUS Interface, SSBUS Controller, HDD Controler, etc. It interfaces the SSBUS with the Expansion Bay Expansion bus. When referring to early versions of it that supported PCMCIA cards, it is called "the PCMCIA Dev9C" or "the PCIC Dev9C". Its /CS signal is also called /CS9C and its SSBUSC channel is called Dev9C / Dev9_1.
PCIC PC Card Interfcae Controller - the PCMCIA Dev9C is called this way.
Address space and device memory-range mapping
The limits of the SSBUSC address space are 0x10000000 - 0x1FFFFFFF. However recent tests showed that Dev4 can be remapped all the way down to 0x00000000, so the prior statement is not entirely true. However there are several IOP-internal devices with fixed-mapping that are not connected through the SSBUS and thus those ranges (should) fall outside the SSBUSC address range. Such devices are:
- SBUS control registers at 0x1D000000 - 0x1DFFFFFF(?)
- All the IOP devices not accessed through the SSBUS in the range 0x1F800000 - 0x1F900000.
Note that there are devices internal to the CPU core that are not accessible through the internal IOP bus. Such are the cache (scratchpad) (0x1F7FFC00 - 0x1F8007FF) and its configuration registers (around 0xFFFE130). See Cache_Scratchpad document). Because they are internal to the IOP Core, and because in accessing the IOP system bus from the EE, the EE "goes in the place of" the IOP Core, the EE cannot access memory (mapped registers) internal to the IOP Core.
It is unknown what are the effects of remapping over an internal device.
Mapping different SSBUSC devices over each-other is not thoroughly tested (maybe it causes bus error, but sometimes seems to cause more serious unrecoverable errors).
Accesses to internal IOP devices are not forwarded to the SSBUS, so its /SRD, /SWR, /RT, address, data, ... lines do not change state to reflect the accessed register.
Access to unmapped registers (including PS2-mode-specific registers (0xBF8014xx) 0xBF801460 for example in PS1 mode) does not cause access on the SSBUS (/SRD /SWR /RT).
The SSBUSC consists of several mostly identically-functioning channels. Each channel is referred to as "Dev<deviceNumber>", however for some channels, there is no correlation between the Dev<number> and the number in the /CS, /INT and DMA lines. This document uses a numbering scheme (Sbc<number>), based on the numbering in the SSBUSC IRX module, and extended with PPC-IOP SSBUSC devices (numbering there is unofficial).
The INTC uses a separate channel numbering, and because it is not connected to the SSBUSC there is no direct relation between an interrupt and an SSBUSC channel (other than that defined by the external connections and software).
The DMAC channels are connected to (some of) the SSBUSC channels. The SSBUSC "delay" registers are used to set the timing and bus-width parameters of both the SSBUSC channel in PIO mode and its DMAC counterpart in DMA mode.
There is no correlation between DMAC channel numbering and SSBUSC channel numbering.
It is unknown if the PS1 SSBUSC supports Wide DMA mode, but registers' bit-fields maximum values show that it does not.
SSBUSC signals
signal direction
A26:A16 IOP-> High address bus. States are usually latched (unconfirmed) or floats low when not in bus access cycle (untested).
A15:A0 IOP<-> Low address bus. As above. In Wide (32-bit) DMA mode it is used as the high 16-bits of the data bus, when it become bi-directional.
D15:D0 IOP<-> Data bus. Floats high (week pull-ups) when not in bus cycle. See /RT for direction.
SYSCLK0 IOP-> PS1 mode bus clock. ~33MHz.
SYSCLK1 IOP-> PS2 mode bus clock. ~36MHz.
Peripheral devices that support both PS1 and PS2 mode have both clock inputs.
/SRD IOP-> Read strobe signal. Goes active low when reading from peripheral. With default settings, data is output on the falling edge and latched (by the IOP) on the rising edge.
/SWR IOP-> Write strobe signal. Goes active low when writing to peripheral. With default settings, data is output on the falling edge and latched (by the peripheral) on the rising edge.
/CS IOP-> Chip Select signal (one for each SSBUSC channel). For channels lacking a /CS signal, such should be generated from the address bus externally, matching the set address range in SSBUSC registers.
While in DMA transfer (DACK active high) /CS is also kept active low. Because of this, one can do pseudo-DMA transfers in PIO mode of the peripheral (without DMA lines connected). Note however that the state of the address lines in DMA is not guaranteed (untested).
DREQ ->IOP DMA Request. A peripheral device asserts this high to request (signal that it is ready for) a DMA transfer. Once the transfer is acknowledged (DACK) this is usually deasserted and DMA is started. This has no direct relation in time to the start of the DMA bus cycles.
DACK IOP-> DMA Acknowledge. Once the IOP has received a DREQ and a DMA channel is enabled for transfer or a DMA channel is forced to start transfer (see IOP DMAC document), this is asserted high and a DMA transfer is started. This line marks the exact beginning and end of a DMA transfer and while active the bus (and the IOP) is DMA mode.
/RT IOP-> Read-Time Active low only when the SSBUS controller lets a device output data on the data bus. Assume that in all other cases a device should not output data.
Stays active low on 4 consecutive 8-bit accesses (32-bit read) and jumps high for shorter period than the inactive period, only between every 4 accesses. Connects to SSB_SSAT at the SPEED chip, after being buffered by the Dev9C.
Signifies a single read access cycle (only reads). Basically a copy of any /CS, but only for reads. Works just the same in Programmed I/O and DMA modes.
Example: reading an 8-bit device as 32-bit:
__ __ ___
/CS \_______A_______/ \_______A_______/
__ __ ___
/RT \_______A_______/ \_______A_______/
___ _ _ _ _ _ _ _ ____ _ _ _ _ _ _ _ ____
/SRD _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
This is for controlling the bus direction of external buffers. The line would go low, when the CPU lets a device output data on its bus. The Dev9Controller ('SSBUS Interface'), surely uses this line to set the bus drivers (buffers) direction.
/UBE IOP-> Upper Byte Enable. Goes active low, when the upper byte of the 16-bit data bus has valid data. The state of this line is latched - once it changes state it keeps it up to the next change. For 8-bit devices (SSBUSC channels set to 8-bit width), this is always inactive high, while for 16-bit devices it always goes active low.
/UBE is always inactive high in PS1 mode, even for devices configured for 16-bit wide bus.
/IOIS16 ->IOP Used by a peripheral device to signal to the IOP that the accessed register is 16-bit (rather than 8-bit) (when asserted low).
It is unknown how this should affect the load/store operation - perhaps overrides the set bus-width in the SSBUSC delay/config register. It is only available for the Dev9 (Dev9M, Dev9I) channel (untested), but tests couldn't determine its exact function.
The Dev9C drives it always, regardless of its configuration registers. The SPEED buffer of the Dev9C has to be enabled (1460.0 = 1) for the state of the /CIOIS16 line (->Dev9C) to appear on the /IOIS16 line.
This is most likely a left-over from some early PCMCIA interface. On Network Adapters /CIOIS16 is unconnected; the SPEED chip has no pin for such signal (as far as it is known).
See Dev9C and Dev9C PCMCIA documents for more information.
/WAIT ->IOP When asserted by a peripheral device low, and the /WAIT signal is enabled for that SSBUSC channel, when reading from the device, the IOP stalls before reading the data until /WAIT is deasserted, and the data transfer takes place. The drivers of this seem to should be open-collector or open-drain, or tri-state, gated on /CS.
/SSRST IOP-> Sub-System bus Reset. On power-up ramps slowly high (with power supply perhaps.
On power-down first drops from 3.44V to 2.28V and stays at 2.28V for 80ms. Then drops at 0V and stays at 0V for 28ms. Then goes back to 2.28V and stays so for 18ms, until finally slowly ramping down to 0V.
__3.44V_____
|<--80ms--->|<28ms>|18ms|
|___2.28V___ ____
| | \\
| | \\
| | \\...
|__0V__| ****---______640mV_(PS2_sandby_off)______
On power-up (from standby): from 640mV goes quickly to 0V then ramps-up for 40ms to 3.44V.
On reset to PS1 mode it is pulsed low. /SSRST is kept low while /SRST (EE->SBUS->IOP) is low (while reg. F240.19 = 1), but only if IOP reset is enabled by 1450.5 (=1), otherwise it keeps high.
When driving input lines, older PS2 models require stronger drivers. For sinking some lines, a resistor of ~330 ohm may be necessary.
For finished devices, use resistors according to the correct line termination specifications (usually 22-33ohm).
Very simplified IOP block diagram:
The SIF interface logic includes PS1 GPU registers and DMA emulation in PS1 mode.
When EE takes control over IOP memory, the EE does that through the SIF interface logic in the IOP, and controls the IOP System Bus, but not the IOP core internal bus.
The IOP Core, through its internal bus, controls the IOP System Bus just the same way as the EE controls it, when it has taken control over the controllable IOP memory, through the SBUS, with the SIF acting as a controller.
______________________________________________
| IOP (ASIC) |
| ___________________________________ |
| |IOP Core | |
| | | |
| | I| | |
| | n| ________________ | |
| | t|-------|Cache/Scratchpad| | |
| | e| |________________| | |
| | r| | |
| | n| _________________ | |
| | a|-------|InternalRegisters| | |
| | l| |_________________| | |
| | B| | |
| | u| | |
| | s| | |
| |_____|_____________________________| |
| | |
| | IOP SystemBus _____________ | SBUS
| ------+---+---------------+-|SIF interface|---------- EE
| | | |_____________| |
| _______|_____________ | _________ | SSBUS
| |Internal IOP Devices | | | SSBUSC |-------------- IOP peripheral devices
| |SIO2, USB, iLink, ...| +-|_________| |
| |_____________________| | | |
| _________ | ____|____ |
| |EDO DRAMC|-----+-| DMAC | |
| |_________| |_________| |
| | \-------------/ |
| | |
|_______________|______________________________|
|
EDO DRAM
SSBUSC Channels
The channels on the PS2 IOP include the channels already available on the PS1 CPU and a few PS2-specific channels. Later, on PPC-IOP (DECKARD) -models, a few more channels are added and a few of the already-existing ones are left unused and possibly unfunctioning.
The SSBUSC is configured through two sets of registers - at 0x1F801000 (legacy channels from the PS1 CPU) and at 0x1F801400 (added for the PS2).
Channel Dev Default DMA INTC ------lines-----
Sbc name device channel channel /CS DMA /INT
--- PS1 Mode of the PS2 IOP: ---
Sbc0 Dev0 Dev0 ROM Exp1 - - ExGe - -
Sbc1 Dev1 Dev1 DVD ROM Exp3 - - 1 - -
Sbc2 Dev2 Dev2 BOOT ROM - - 2 - -
Sbc3 Not known to have ever existed.
Sbc4 Dev4 SPU1 4 9 4 4 4
Sbc5 Dev5 CDVD 3 2 5 5 5
Sbc6 Not known to have ever existed.
Sbc7 Dev7? PS1 GPU (SIF2?) 2 1 7 2 1
Sbc8 Extr? PIF/MRP(TOOL) Exp2 5 23 /EXTR *EX *EX
--- Added on the MIPS-IOP for the PS2: ---
Sbc9 Dev8? SPU2 7 12 8 8 8
Sbc10 Dev9_2 Expansion Bus Mem 8 13 9 9 9
Sbc11 Dev9_3 Expansion Bus I/O 8 13 9 9 9
Sbc12 Dev9_1 Dev9ControllerCfg - - 9C - -
--- Added on the PPC-IOP on DECKARD-models: ---
Sbc13 PPC? PPC BOOT ROM - - PPC - -
Sbc14 ? Dev9_2 new channel 8 26 InternalDevice
ExGe = Externally Generated /CS signal from the address bus.
N/A = Not Available
- = Not Available
*Each category above includes those preceding it.
There are strange stuff in interrupt emulation code of DECKARD, which suggest that there may be differences in other devices' interrupt mappings.
Unlike on the PS2 in PS1 mode, on the PS1 Dev0 has uses the /CS0 signal, while Sbc8 doesn't have a /CS signal (it is formed from the address lines).
Dev0 is unusable in PS2 mode.
Sbc7 above is only added for completeness. Sbc3, Sbc6, Sbc7 do not exist as SSBUSC channels, even if devices under those names (still) exist.
On PS2 IOP /CS7 and the other signals of Dev7 which is assumed to be the PS1 GPU are not present, but in PS1 mode should be available at the SBUS signals. One can suspect that in PS1 mode the SBUS signals are identical to those of the System Bus in the PS1 between the CPU and the GPU. For more information see SIF/SBUS and PGIF documents. Dev7 is not an SSBUSC channel, as it isn't connected through the SSBUSC. (see SCPH-9000 SM)
Speculation: Channels Sbc 3 and 6 might have been for SIO0, SIO1 and MDEC before they were integrated in the PS1 CPU ASIC in an early prototype.
On the PPC-IOP the /CS, DMA and /INT signals of the following devices are not available, because they are integrated in the IOP/PS2-on-chip ASIC: Sbc: 4, 5, 9, 10, 11, 12, 14. The /CSPPC (/CS13) is added for the BOOT ROM of the PPC-IOP (a part of the PS2 BOOT ROM).
All PS2 Mode-specific devices are unusable in PS1 mode and access to their control registers results in a bus error. This is only true for non-PPC MIPS-IOPs.
In PS1 mode for Sbc8, interrupt 23 - /INTEX is not available and the equivalent is the PIO 10 interrupt caused by the controllers /HTR0 and /HTR1 lines (as on a real PS1). See INTC document for more info.
The Dev9_2 Sbc10 PIO timing is valid for PIO mode of the actual Dev9 at 0x10000000, while DMA timing of the Dev9_3 (Sbc11) is valid for Dev9 DMA timing.
This is most likely due to Dev9_2 being Dev9M - the memory range part of the complete Dev9 range and Dev9_3 Dev9I being the I/O range - as DMA should be tied to the I/O range. This separation is most likely a leftover from some early method of directly connecting a PCMCIA card to the SSBUS (with a very simple Dev9C PCIC).
The above is further supported by the fact that early SPEED chips are known to have been connected directly to the SSBUS (source TOOL / PA TOOL MIF, SMAP, SPEED diagnostic programs on HDD). Another fact in support of this is the presence of SSBUS signals /IOIS16 and /WAIT (/IOIS16 - only supported on the Dev9M / Dev9I channel).
It is unknown what the DMA timing setting of Dev9_2 Sbc10 controls. It may very well be a dummy bit-field or be put into use by some unknown bit-field of the Dev9 DMA registers or the Dev9 SSBUSC registers, or it may only be used for one particular DMA mode (slice/burst)(unlikely).
Sbc10 Dev9M and Sbc11 Dev9I activate the same /CS9 signal. The peripheral (Dev9Controller) tells them apart by A26. This is possible because Dev9M is "locked" at 0x10000000 - 0x13FFFFFF (A26=0) and Dev9I (abeit its start address is changeable) it limited within 0x14000000 - 0x17FFFFFF (A26=1). Using A26, A25, A24, a total of 8 sub-ranges can be selected under the common channel Dev9. The ExpansionBay version of the Dev9C has inputs for A26 A25, A24, which define where in memory the SPEED chip and the I2C interface will be mapped.
Notice that by sequential numbering Dev9C takes number 12 = 0xC - one more reason to be abbreviated as "Dev9C".
For some unknown hardware called "njig", the Dev9M range was used for a Flash memory device. (source: TOOL romflash utility) "njig" might stand for Namco jig and this memory might have been used by the Namco PS2 arcades. This is only a speculation (quite possibly incorrect).
On the Namco System 246 / 256 the Dev9 channel is used for arcade-specific hardware, including memory devices. It is unknown if this is related to the separation of Dev9 to Dev9M and Dev9I, but most likely it is not.
Register map
Any (32 / 16 / 8 -bit) access should be supported. 32 and 16 -bit wide accesses are known to be used.
Base addresses:
0x1F801000 - 0x1F80103F - PS1 and PS2 devices
0x1F801400 - 0x1F80144F - PS2 devices
Addr Ch# Type Device
1000 0 addr Dev0 Exp1
1004 8 addr Extr Exp2 PIO/EXTR/...
1008 0 del Dev0 Exp1
100C 1 del Dev1 ROM-DVD Exp3
1010 2 del Dev2 ROM-BOOT
1014 4 del Dev4 SPU1
1018 5 del Dev5 CDVD
101C 8 del Extr Exp2 PIO/EXTR/...
1020 common delay cfg -
1400 1 addr Dev1 ROM-DVD Exp3
1404 4 addr Dev4 SPU1
1408 5 addr Dev5 CDVD
140C 9 addr Dev8 SPU2
1410 11 addr Dev9_3 I/O
1414 9 del Dev8 SPU2
1418 10 del Dev9_2 Mem
141C 11 del Dev9_3 I/O
1420 12 del Dev9_1 Cfg
1424 13 addr PPC BOOT ROM
1428 13 del PPC BOOT ROM
142C 14 addr PPC Dev9/SPEED
1430 14 del PPC Dev9/SPEED
ch# -registers-
delay addr
0 1008 1000
1 100C 1400
2 1010 (0x1FC00000)
3 - -
4 1014 1404
5 1018 1408
6 - -
7 - -
8 101C 1004
9 1414 140C
A 1418 (0x10000000)
B 141C 1410
C 1420 (0x1F801460)
D 1428 1424
E 1430 142C
*Address values in brackets mean that no register for setting the address exists and it is hard-wired to that value.
In PS2 mode (SCPH-30003) the registers of Dev0 and Sbc11 mirror each other on both read and write. Dev0 is basically unusable, because it *is* Dev9I in PS2 mode. This is most likely because the channel of Dev0 was (mis-)used for Dev9I once Dev0 was deemed unused in PS2 mode. Dev0 behaves differently (the available address range) between PS1 and PS2 modes.
Limits of registers configurability
PS1 mode
(SCPH-30003 GH-006)
ch# ------ address ------- ----- delay/cfg ------ /WAIT - Notes
min max min max capable
0 0x1F000000 0x1FFFFFFF 0x00000000 0xAF1FFFFF selectable
1 (0x1FA00000) 0x00000000 0x2F1FFFFF no, hardwired
2 (0x1FC00000) 0x00000000 0x2F1FFFFF no, hardwired
3 - -
4 (0x1F801C00) 0x00000000 0x2F1FFFFF yes, hardwired Fixed sz=0x4000
5 (0x1F801800) 0x00000000 0x2F1FFFFF no, hardwired Fixed sz=0x4
6 - -
7 - -
8 0x1F000000 0x1FFFFFFF 0x00000000 0x2F1FFFFF yes, hardwired
Accessing any PS2-specific SSBUSC register (0x1F801400 - 144F) results in a bus error.
Dev0 can in fact have the /WAIT signal (bit 31 = 1) enabled and it is fully-functional - when asserted low, accessing in the Dev0 range causes IOP to stall until /WAIT is deasserted.
For Dev4 and Dev5 the range-sizes are fixed to the specified values regardless of the settings.
When the size of a memory range is fixed, this affects where the /CS signal goes active, as well as where bus error occurs.
PS2 mode
(SCPH-30003 GH-006)
ch# ------ address ------- ----- delay/cfg ------
min max min max
0 Mirrors channel 11.
1 0x1E000000 0x1FFFFFFF 0x00000000 0xEF1FFFFF
2 (0x1FC00000) 0x00000000 0xEF1FFFFF
3 - -
4 0x00000000* 0x1FFFFFFF 0x00000000 0xEF1FFFFF
5 0x1E000000 0x1FFFFFFF 0x00000000 0xEF1FFFFF
6 - -
7 - -
8 0x1E000000 0x1FFFFFFF 0x00000000 0xEF1FFFFF
9 0x1E000000 0x1FFFFFFF 0x00000000 0xEF1FFFFF
A (0x10000000) 0x00000000 0xEF1FFFFF
B 0x14000000 0x17FFFFFF 0x00000000 0xEF1FFFFF
C (0x1F801460) 0x00000000 0xEF1FFFFF
It is curious that in PS2 mode channel 4 can be remapped below 0x1F000000 and even below 0x10000000 -all the way down to 0x00000000 (tested with 0x00200000 and 0x00800000), which defies MIPS logic, where anything below 0x10000000 is RAM (and not memory-mapped hardware).
Test was done from EE - accessing IOP RAM at 0xBC200000 works too (0x00200000 for Dev4 base addr), but DMAC seems to see this as unmapped RAM and doesn't increment MADR - maybe doesn't do any transfer. It can also be mapped over RAM (below 0x00200000), but it doesn't activate /CS there.
The DMA channel for Extr was used.
It is untested whether any channel is locked by size or address regardless of its settings (which is observed for some channels in PS1 mode), but the way they are used in different cases (the PSX DVR, etc.) suggests that channels should be directly affected by all their settings (bit-fields).
Given that all channels have DMA timing settings' bit-fields even though it is certain that ROM channels do not have counterpart DMA channels, suggests that the registers logic was just copied for all regardless whether those bit-fields were connected to anything.
To prevent IOP from crashing by channels' ranges overlapping, set first the start address of the range to either one with a lot of free space after it, or the highest address possible (0x1FFFFFFF) which will make the range span for only a single byte regardless of the set size.
Default configuration values
In PS2 mode, the SSBUSC configuration registers are first initialized by RESET. The IRX SSBUSC provides functions for setting them, while some modules write to them directly (DEV9, ...).
PS1 mode
ch# address delay/cfg
0 0x1F000000 0x00142455 1MB, 8bit
1 (0x1FA00000) 0x00153044 2MB, 16bit
2 (0x1FC00000) 0x0015243F 2MB, 8bit
3 - -
4 (0x1F801C00) 0x200931E1 512B, 16bit
5 (0x1F801800) 0x00020943 4B, 8bit
6 - -
7 - -
8 0x1F802000 0x000D2077 8kB, 8bit
PS2 mode
TODO: Add values in PS2 mode and those used by drivers.
ch# address delay/cfg
0 0x14000000 0xEF1A3043 64MB, 16bit
1 0x1E000000 0x00183444 16MB, 16bit
2 (0x1FC00000) 0x0016244F 4MB, 8bit
3 - -
4 0x1F801DA8 0x200B31E1 2kB, 16bit
5 0x1F402000 0x6F060011 64B, 8bit
6 - -
7 - -
8 0x1F802000 0x000D2077 8kB, 8bit
9 0x1F400010 0x200931E1 512B, 16bit
A (0x10000000) 0xE01A3043 64MB, 16bit
B 0x14000000 0xEF1A3043 64MB, 16bit
C (0x1F801460) 0x00051011 32B, 16bit
PS2 mode on DECKARD-models
ch# address delay/cfg
0 0x1F000000 0x800026FF 1B, 8bit
1 0x1E000000 0x00183444 16MB, 16bit
2 (0x1FC00000) 0x0016244F 4MB, 8bit
3 - -
4 0x1F801DA8 0x300B31E1 2kB, 16bit
5 0x1F402000 0x6F060011 64B, 8bit
6 - -
7 - -
8 0x1F802000 0x000D3655 8kB, 16bit
9 0x1F400010 0x200931E1 512B, 16bit
A (0x10000000) 0xE0183043 16MB, 16bit
B 0x14000000 0xEF1A3043 64MB, 16bit
C (0x1F801460) 0x00051011 32B, 16bit
D 0x1FC00000 0x0018244F 16MB, 8bit
E 0x11000000 0xE0183043 16MB, 16bit
TODO: On PPC-IOP in the above test, Dev4 returned Address Error =1 => find what cause that and what sets this flag. Perhaps the unaligned (to the size of the range -i.e. the range's size wil be reduced due to start address being unaligned) start address?
Base address registers:
All base address registers are similar, only differing by memory limits.
3 3 2 2 2 2 2 2 0
1 0 9 8 5 6 4 3 0
-----------------------
| | R | S |
| - | L T |
| | I A |
| | M | D |
-----------------------
28:0 r/w STAD Base (start) physical address of the memory range to which this SSBUSC channel is mapped (its /CS goes active and its timing and other setting are applied to the SSBUSC). Accessing any unmapped memory results in a bus error, thus mapping a channel in a certain memory range makes accesses to that range not result in bus error.
RLIM Range Limits: The highest bits 28:24 / 28:25 / 28:26 are fixed to different values (0x1F / 0x1E / 0x14) for the different channels (see Limits of registers configurability), which limits the address range they can be mapped in.
When the start address is on an unaligned boundary of the size of the range, then the memory made available to this channel spans from the start address to the first boundary aligned to the size of the memory range (untested). If is possible that this is not so, but rather the available memory range is the whole region of the chosen size, starting from the first boundary, divisible by the size of the range, before (or on) the start address to the next one. I.e. if the size of the range is 0x20 and the start address is 0x15, the range will either span 0x15 - 0x1F, or 0x10 - 0x1F (untested, but assume the former).
31:29 r/o, always 0.
Delay / Configuration channel registers:
All bit-fields are r/w unless otherwise noted.
3 3 2 2 2 2 2 2 2 1 1 1 1 1 1 1 0 0 0 0 0 0
1 0 9 8 7 4 3 1 0 6 5 4 3 2 1 0 9 8 7 4 3 0
--------------------------------------------------
|W|W|D|A| D | | D |E|I|A|A|S|F|H|R| R | W |
|A|D|M|D| M | - | E |X|O|I|T|T|L|O|E| D | R |
|I|M|A|E| A | | C |D|I|N|Y|R|O|L|C| D | D |
|T|A|F|R| T | | R |L|S|C|P|B|T|D|V| L | L |
--------------------------------------------------
3:0 WRDL Write delay: /SWR active low period: 0-15 [cycles+1]
7:4 RDDL Read delay: /SRD active low period: 0-15 [cycles+1]
8 RECV Recovery period: 0= off / 1= use commonDelay.3:0
9 HOLD Hold period: 0= off / 1= use commonDelay.7:4
10 FLOT Floating period: 0= off / 1= use commonDelay.11:8
11 STRB Pre-Strobe period: 0= off / 1= use commonDelay.15:12
12 ATYP Access type: 0= 8bit / 1= 16bit. Also affects DMA bus width, when not using Wide DMA mode.
13 AINC Increment address when accessing a register shorter than the access instruction: 0= off / 1= increment. Example: when reading a word from a byte-wide bus, this option sets whether the address on each consecutive 8-bit access would increment or not. If disabled the byte at the base address of the word would be read 4 times, otherwise the bytes at +0, +1, +2, +3 will be read in that order. This is useful (to be disabled) for devices like ATA interfaces, where some ATA registers are written twice for extended LBA (which can be done with a single word-access).
14 IOIS16 I/O is 16-bit: /IOIS16 signal: 0= don't use it / 1= regard it. Supported by only(?) DEV9 (but which Dev9M or Dev9I(more likely) or both?). Most likely overrides the Access Type (8/16 -bit) setting (tested, but doesn't seem to have any effect). /IOIS16 should be an input to the IOP, but is marked as output. A peripheral signals by this signal that the register accessed is 16-bit (when low). See Dev9C document for more info.
From PCMCIA specs (volume 2 / r7.0, february 1999).
-----
The IOIS16# output signal is asserted when the address at the socket corresponds to an I/O address to which the card responds, and the I/O port addressed is capable of 16-bit access.
When this signal is not asserted during a 16-bit I/O access, the system will generate 8-bit references to the even and odd byte of the 16-bit port being accessed.
-----
15 EXDL Extended delay: MSb of /SRD active low period. Not found to have any effect (regardless of reg. 1020).
20:16 DECR Decoding range = 2^n bytes. Values: 0 - 27 = 1B - 128MB.
23:21 r/o Unused, 0.
27:24 DMAT DMA timing: /SRD /SWR active.low period: 0-14 [cycles+1]. The inactive period is always 1cycle.
0=1cycle, 1=2cycles, ..., 14=15cy
15(0xF)= '0.5cycles' Each word still remains on the bus for 1cy, but there are no inactive pauses between the words. - 'fastest' DMA mode: /SRD/SWR is kept active low over the whole transfer and the SSCLK clocks the data words.
On some devices (PS2 mode only?) the /SRD active low period cannot be 1 cycle, thus with DMAT = 0 or 1, the resulting period is 2cy. It is unknown if this is caused by some setting. The /SWR period is unaffected.
28 ADER r/o Address error flag (when =1). When the an address error within the memory range of this channel occurs this bit becomes set. Writing 1 clears it. Unknown what Address Error means. This doesn't become set by unaligned access. It might be for the DMAC accessing RAM past its end when doing DMA through this SSBUSC channel, but it doesn't activate on that either.
29 DMAF DMA select timing source flag: 0= use PIO timing / 1= use DMA timing bit-field 28:24 for DMA.
30 WDMA Wide DMA mode. When = 1 this overrides the Access Type (8/16 bit) setting, and causes 32 bits to be transferred in one go. The low 16bits are mapped to the SD15:SD0 data lines, and the high 16bits - to the low address lines SA15:SA0, which become inputs, if the transfer is done 'to RAM'.
This is why most devices get all the low 16 address bits, even though their address space is much smaller than 64kbyte. The SPU2 doesn't get all 16 low address lines, so this is disabled for it, while it is enabled for the CDVD and Dev9_2, Dev9_3.
31 WAIT /WAIT signal. When = 1 enables the IOP waiting on the /WAIT (input to IOP) signal, when accessing the range of the given device.
Slow devices can make the IOP wait (indefinitely) before transferring data, by asserting the /WAIT line low while a PIO access is being done (after the device detected assertion of /CS and decoded the address).
On read, once /WAIT is deasserted, IOP loads the data (it was made to wait for) from the device/bus (on read) and continues execution.
On write the write operation completes even if /WAIT is asserted low and the IOP can continue executing. This is true for any device. However if /WAIT is kept asserted low and another write (or a read) access is done (to any device - even such with /WAIT hardwired to disabled state), then the IOP will stall before (or after?) transferring any data, until /WAIT is deasserted. This can be used as a hack to use /WAIT even of devices that have it disabled (like the BOOT ROM for example): write a device that has it enabled (while /WAIT is low) then access (r/w) the BOOT ROM and the IOP will stall until /WAIT is deasserted.
/WAIT should be driven most likely by OC/OD drivers (or a tri-state output enabled on /CS). The output of the Dev9C seems to be just such.
There are two main modes of transfer: PIO and DMA.
The timing parameters of the PIO mode can be set in detail, while for the DMA mode a symmetric clock is assumed only with period configurable. PIO timing configuration can be used for DMA transfers too.
For DMA on read (->IOP) both for 0 and 1 DMA periods 1 cycle is added, which results in 2 cycle transfer - reason unknown. On write, 0->1cycle, 1->2cycles (reason unknown).
Besides the /SRD /SWR active.low periods that can be set individually for each channel, the following parameters exist, that can only be enabled for the individual channels, but the value is common for all. Their values are set by the Common Delay register.
1020 Common delay register r/w:
3:0 Recovery period 0 - 15 cycles.
7:4 Hold period 0 - 15 cycles.
11:8 Floating release delay 0 - 15 cycles.
15:12 Strobe active-going edge delay 0 - 15 cycles.
16 r/w ? 0 by default.
17 r/w ? 0 by default.
31:18 r/o, = 0 unused.
No effect was observed from any combination of the comDelay high bits 16 and 17. Maybe they set relations between some delays or sampling edges.
Maybe the high bits in the common register are for Wide DMA or outputing/latching adds or outputing addess while in DMA or something related to DMA, or some of the dysfuinctional bits in the individual delay registers?
Recovery period: Elongates with commonDelay.3:0 cycles the period after the data bus is released by the IOP (write) (after the added hold period, if any) or after /SRD goes inact.high, to the next active /SRD/SWR pulse or /CS going inactive transition, to give the device more time to release the bus on read or give more bus turnaround time to the next access on write.
Hold period: The period after /SWR goes inact.high when the data bus keeps its data valid, necessary for signal propagation and correct latching. The /SWR active.low inter-pulse period will be elongated with commonDelay.7:4 cycles in which after /SWR goes inactive.high the data output from the IOP would still be kept valid. This setting has no effect on /SRD read timing.
Floating period: Elongate the /CS (active low) and the inter-/SRD pulses periods after /SRD goes inactive to give the device more time to leave the bus floating after driving it (for slow devices that release the bus slowly). Give the device commonDelay.11:8 cycles more after /SRD goes inactive to the next /SRD pulse or the end of the cycle (/CS -> inact.high), to leave the bus floating. When set to 0, the period /SRD inact.high-going edge to /CS inact.high -going edge is 1/2 cycle and is 1cy between /SRD pulses act.low pulses. This setting has no effect on /SWR write timing.
Pre-Strobe period: Delay from the start of data output (and /CS going active.low) to the active.low -going edge of /SRD or /SWR: Shifts the active-going edge of /SWR the commonDelay.15:12 cycles later than it would usually come, so data can be read on the active-going falling edge. If the active period of the act.low pulse is less than this strobe delay, then the inactive periods between pulses are elongated to account for that. The active pulse is shrunk to a minimum of 1cy in this case. /CS act.low-going edge to /SRD or /SWR act-low going edge is of this number of cycles (otherwise = 0).
While delayReg./SRD/SWR_act.low_period <= strobePeriod, no change in the total period is done. Pulse active.low period = max((delayReg.act.low_period - strobePer), 1). - at least 1 cy. This has the same effect on both /SRD and /SWR.
The two 8-bit accesses in a common /CS access are just an example - they could also be two 16-bit accesses in a 32-bit /CS access, or 4 8-bit accesses in a 32-bit access.
_______ _______________ _ _______________ __________
Data from IOP X_______________X X_______________X
| valid data | | valid data |
|F| |G|J|H| |I|
|<----C---->|<-D->|<----C---->|
_________| |_____| |____________
/SWR(/SRD) \___________/ \___________/
| 8bit 8bit |
_______|A| access access |B|__________
/CS \_________________________________/
| 16-bit access |
|<---------------E--------------->|
* The period J (old_DATA_valid to new_DATA_valid in a single access) may always be 0, because the IOP switches from the old to the new data immediately (however that still requires some time for data to become certainly valid).
D = G+J+H
E = A+C+D+C+B
The above periods (A-J) are sometimes different for /SRD and /SWR. In case they don't match, they are marked as <period>_R (read) and <period>_W (write).
The following periods are also defined:
M = /CS inactive pause between RD->RD (two reads)
N = /CS inactive pause between RD->WR (a write following a read)
O = /CS inactive pause between WR->RD (a read following a write)
P = /CS inactive pause between WR->WR (two writes)
(Almost) no test were done to determine exactly when the IOP latches input data and whether the settings have any effect on that, as that is too difficult to determine. It is assumed that the IOP latches input data on the rising (inactive.high-going) edge of /SRD.
The measurements (in us) below are somewhat inaccurate. The measurements were done in PS2 mode with ~36MHz clock, but the specified values in [cycles] ([cy]) are valid for PS1 mode at ~33MHz as well.
The followng measurements were done with example commonDelay register values (0x00001225), but from them one can understand the behavior of the bus for any setting.
###########################################
No added delays (strobe, float, hold, recovery):
Delay register = 0x000D2077 :
/CS inact pause RD->RD M = 3cy 81ns
/CS inact pause RD->WR N = 3cy 81ns
/CS inact pause WR->RD O = 1cy
/CS inact pause WR->WR P = 1cy
/CS active Read E_R = 18cy 486ns
/CS active Write E_W = 18cy 486ns
/SRD active period C_R = (delay+1)cy
/SWR active period C_W = (delay+1)cy
/SRD inact between 2x8bit D_R = 1cy
/SWR inact between 2x8bit D_W = 1cy
/CS ->act to /SRD ->act A_R = 0.5cy 12ns
/CS ->act to /SWR ->act A_W = 0.5cy 12ns
/SRD ->inact to /CS ->inact B_R = 0.5cy 16ns
/SWR ->inact to /CS ->inact B_W = 0.5cy 16ns
DATA_valid to /SWR_act F = 0
/SWR_inact to DATA_inval. ITM* G = 1cy
Bus free over /SWR inact. ITM* J = 0
DATA_valid to /SWR_act ITM* H = 0
/SWR_inact to DATA_inval. I = 2cy 54ns
*ITM = Intermediate timing between the two 8-bit accesses in an 16-bit access of a 8-bit device. 32-bit access of 8-bit or 16-bit device should have the same internal timing. The above is usually the case, however some configurations use the ITM for all consecutive writes (not only 16<-8 and 32<-16). It is better to consider the F and G periods relative to ever 'first' access, while the H and I periods - to all the next consecutive accesses in a single CPU read/write.
Note that 12ns + 16ns = 28ns - exactly one period. 12ns one half-period of the master clock, while 16ns is the other. The measurements may not be correct - so both can equal 13.5ns.
###########################################
Recovery delay enabled
Delay register = 0x000D2177
Increases all RECOVERY periods (between every access) to (commonDelay.3:0) 5cy, for devices, which need more time to release the bus or process written data.
/CS inact pause RD->RD M = 5cy 135ns
/CS inact pause RD->WR N = 5cy 135ns
/CS inact pause WR->RD O = 5cy 135us
/CS inact pause WR->WR P = 5cy 135us
/CS active Read E_R = 22cy 594ns
/CS active Write E_W = 22cy 594ns
/SRD active period C_R = (delay+1)cy
/SWR active period C_W = (delay+1)cy
/SRD inact between 2x8bit D_R = 5cy 135us
/SWR inact between 2x8bit D_W = 5cy 135us
/CS ->act to /SRD ->act A_R = 0.5cy 12ns
/CS ->act to /SWR ->act A_W = 0.5cy 12ns
/SRD ->inact to /CS ->inact B_R = 0.5cy 16ns
/SWR ->inact to /CS ->inact B_W = 0.5cy 16ns
DATA_valid to /SWR_act F = 2cy(4cy) 54us(108ns) *
/SWR_inact to DATA_inval. ITM* G = 1cy
Bus free over /SWR inact. ITM* J = 0
DATA_valid to /SWR_act ITM* H = 4cy 108ns
/SWR_inact to DATA_inval. I = 2cy 54ns
*Because the minimum inactive period has to equal or be more than 5, on consecutive writes, the 'DATA_valid to /SWR_act' period will be 4cy(rather than 2cy), making the total /SWR inactive period 6cy, and the /CS inactive period - 5cy.
*ITM = Intermediate timing between the two 8-bit accesses in an 16-bit access of a 8-bit device. 32-bit access of 8-bit or 16-bit device should have the same internal timing. In this mode, subsequent Write accesses to the one and the same device have the same intermediate timing.
This mode is an exception in that subsequent writes to the same device have the intermediate delay(G,H), rather that the end delay(I,F).
###########################################
Hold delay enabled
Delay register = 0x000D2277
Hold the data on the bus for (commonDelay.7:4) 2cy more, after /SWR goes inactive to make certain that a slow device will latch it correctly.
/CS inact pause RD->RD M = 3cy 81ns
/CS inact pause RD->WR N = 3cy 81ns
/CS inact pause WR->RD O = 1cy
/CS inact pause WR->WR P = 1cy
/CS active Read E_R = 18cy 486ns
/CS active Write E_W = 22cy 594ns
/SRD active period C_R = (delay+1)cy
/SWR active period C_W = (delay+1)cy
/SRD inact between 2x8bit D_R = 1cy 27ns
/SWR inact between 2x8bit D_W = 3cy 81ns
/CS ->act to /SRD ->act A_R = 0.5cy 12ns
/CS ->act to /SWR ->act A_W = 0.5cy 12ns
/SRD ->inact to /CS ->inact B_R = 0.5cy 16ns
/SWR ->inact to /CS ->inact B_W = 2.5cy 67ns
DATA_valid to /SWR_act F = 0.5cy(2cy) 12ns(54ns) *
/SWR_inact to DATA_inval. ITM* G = 3cy 81ns
Bus free over /SWR inact. ITM* J = 0
DATA_valid to /SWR_act ITM* H = 0
/SWR_inact to DATA_inval. I = 2cy 54ns
*On consecutive writes, F will equal 2cy, rather than 0.5cy, making the /SWR inactive period there - 4cy.
########################################### uncertain
Floating bus delay enabled
Delay register = 0x000D2477
Elongate the /CS or /SRD inactive period after each /SRD goes inactive (commonDelay.11:8) +2cy to give the device more time to release the bus floating.
/CS inact pause RD->RD M = 1cy
/CS inact pause RD->WR N = 1cy
/CS inact pause WR->RD O = 1cy
/CS inact pause WR->WR P = 1cy
/CS active Read E_R = 22cy 594ns
/CS active Write E_W = 18cy 486ns
/SRD active period C_R = (delay+1)cy
/SWR active period C_W = (delay+1)cy
/SRD inact between 2x8bit D_R = 3cy 81ns
/SWR inact between 2x8bit D_W = 1cy 27ns
/CS ->act to /SRD ->act A_R = 0.5cy 12ns
/CS ->act to /SWR ->act A_W = 0.5cy 12ns
/SRD ->inact to /CS ->inact B_R = 2.5cy 67ns
/SWR ->inact to /CS ->inact B_W = 0.5cy 16ns
DATA_valid to /SWR_act F = 0
/SWR_inact to DATA_inval. ITM* G = 1cy
Bus free over /SWR inact. ITM* J = 0
DATA_valid to /SWR_act ITM* H = 0
/SWR_inact to DATA_inval. I = 2cy 54ns
###########################################
Pre-Strobe delay at the expense of the /SRD /SWR active low pulse (delays only the active-going edge)
Delay register = 0x000D2877
Moves the active-going transitions of /SRD /SWR (commonDelay.15:12) 1 cycle later. That way there is an extra cycle of valid data before the active-going strobe edge. Shifts the active-going (H->L) /SRD /SWR edge commonDelay.15:12 cycles later - for devices which latch the data on the inactive-to-active /SWR transition. The /SWR active period is decreased that way, so commonDelay.15:12 cannot be more than (the_write_delay (bits 3:0) + 1). I.e. the A, F and H periods are increased by commonDelay.15:12 and the C periods are decreased with commonDelay.15:12. All other signals remain the same.
/CS inact pause RD->RD M = 3cy 81ns
/CS inact pause RD->WR N = 3cy 81ns
/CS inact pause WR->RD O = 1cy
/CS inact pause WR->WR P = 1cy
/CS active Read E_R = 18cy 486ns
/CS active Write E_W = 18cy 486ns
/SRD active period C_R = (delay)cy *
/SWR active period C_W = (delay)cy *
/SRD inact between 2x8bit D_R = 2cy 54ns
/SWR inact between 2x8bit D_W = 2cy 54ns
/CS ->act to /SRD ->act A_R = 1.5cy 43ns *
/CS ->act to /SWR ->act A_W = 1.5cy 43ns *
/SRD ->inact to /CS ->inact B_R = 0.5cy 12ns
/SWR ->inact to /CS ->inact B_W = 0.5cy 12ns
DATA_valid to /SWR_act F = 1cy
/SWR_inact to DATA_inval. ITM G = 1cy
Bus free over /SWR inact. ITM J = 0
DATA_valid to /SWR_act ITM H = 1cy
/SWR_inact to DATA_inval. I = 2cy 54us
*Enables /SRD/SWR commonDelay.15:12 cycles later (strobe-like mode). So 43ns = 16ns (as it usualy is) + 27ns (the cycle taken from the strobe period).
Timing diagrams of the SSBUS and relations to the EDO DRAM bus and the ExpansionBay bus.
-------------------------------------------------------------------------------
The inactive spike, that appears sometimes in 'the fastest' DMA mode is the /RAS refresh, that needs to be done every 1-2ms per row address combination. The DRAM controller issues it.
Transfer (read) from RAM:
Data on SSBUS changes while SSCLK_1 is high (on the /CAS H->L transition). While data output from RAM changes on /CAS L->H transition. Data stays on the bus 1cycle. Data that RAM has output on its bus, appears on the SSBUS 1.5cycles later! But, that corresponds to 2cy after the /CAS that triggered the data. The same 'delay' is probably valid for writes to RAM as well.
All the timing for a write to RAM is the same for read too.
Transfer (write) to RAM:
/MWE is held constantly active (low) when writing to RAM in 'the fastest' DMA mode.
In write to RAM mode: the first active /CAS (H->L) occurs 81ns (3cy) after DACK and 67ns (2.5cy) after /SRD. /MWE goes active 2cycles (54ns) after /SRD and 2.5cy after DACK.
DACK's transition to low occurs while SSCLK_1 is high (not on its transition).
/CAS is 90 degrees offset from the SSCLK_1 too - it goes active low on SSCLK_1 high. /CAS goes back high, when (while) SSCLK_1 is low.
/SRD goes active, low while SSCLK_1 is low.
------------------------------------------------------------------------------
The following diagrams are 'to-scale' - each character equals 1/4 cycle. This is not true for most of the other diagrams in this document.
DRAM and DMA timings:
*A /RAS DRAM refresh can occur over a DMA transfer. In that case the transfer is interrupted (DACK, /SRD/SWR), while the refresh takes place.
IOP DMA Read from SSBUS device - SSBUS and DRAM timings in the 'fastest' (DMA Timing = 15) DMA mode.
_
/RAS \______Goes_inactive_when_it's_time_to_refresh_DRAM
________________________________________________
DACK ___/
_____
/SRD \______________________________________________
_ _ _ _ _ _ _ _ _ _ _ _ _
SSCLK \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
_____________
/MWE \______________________________________
_______________ _ _ _ _ _ _ _ _ _
/CAS \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \
_____________ ___ _______ ___ ___
RAM DATA IN \___/ \___/ \___/ \___/ \___
_________ ___ _______ ___ ___
SSBUS DATA IN \___/ \___/ \___/ \___/ \_______
_______ ___ _______ ___ ___
Exp.Bay.Con. \___/ \___/ \___/ \___/ \_________
|A| B |
A Expansion Bay Connector data change to SSBUS data change = 1/2cy
B SSBUS data change to DRAM bus data change = 1cy
The above seems to be correct, but I really am not sure about anything now, after recording it all....
SSBUS data arrives at DRAM DATA bus 1 cycle later.
Dev9 (on SSBUS) outputs data either on SSCLK H->low and it gets delayed so we see it on the very beginning of l->h or it outputs on l->h very fast.
IOP DMA Write to SSBUS device - SSBUS and DRAM timings in the 'fastest' (DMA Timing = 15) DMA mode.
_
/RAS \______Goes_inactive_when_it's_time_to_refresh_DRAM
________________________________________________
DACK ___/
_____________
/SWR \______________________________________
_ _ _ _ _ _ _ _ _ _ _ _ _
SSCLK \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
_______ _ _ _ _ _ _ _ _ _ _ _
/CAS \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \
____________ ___ _______ ___ ___
RAM DATA OUT \___/ \___/ \___/ \___/ \___
___________________ ___ _______ ___
SSBUS DATA OUT \___/ \___/ \___/ \___/
>|\< |
|A |
|<--B-->|
A /CAS active to DRAM DATA out ~1/4cy - depends on DRAM.
B /CAS active to SSBUS DATA out = 2cycles.
Note that the SSCLK actually precedes all signals by about 1/8-1/4cycles. This delay, introduced by the logic gates, can make measuring the signal offsets very tricky.
Data out from IOP SSBUS appears in the end of the L->H SSCLK transition, and /CAS goes low at the same point.
RAM output data changes over the SSCLK high, because that is what follows /CAS going active low.
IOP data out - write to device:
DMA Timing = 0 (Fastest DMA mode that still uses /SRD/SWR as a strobe.) Example data = 0101...
________________________________
DACK ____/
_ _ _ _ _ _ _ _ _ _
SSCLK \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
______ ___ ___ ___ __
/SWR \___/ \___/ \___/ \___/
______ _______ ______
IOP DATA \_______/ \_______/
device samples ^ ^ ^ ^
IOP data in - read from device:
DMA Timing = 0 (Fastest DMA mode that still uses /SRD/SWR as a strobe.) Example data = 0101...
________________________________
DACK ____/
_ _ _ _ _ _ _ _ _ _
SSCLK \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
______ ___ ___ ___ __
/SRD \___/ \___/ \___/ \___/
______ _______ ______
DEV DATA \_______/ \_______/
IOP samples ^ ^ ^ ^
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment