2018.10.18 PS2 TOOL PIF/MRP registers descriptions. This information was gathered from multiple sources. None of the following was tested on an actual TOOL, so much of it may be incorrect. List of the register ranges under the EXTR (EXTRA) SSBUSC device channel: The functions of the DTL-H2000 and other PS1 registers are taken from psx-spx and are presented here only for completeness of the memory map of the EXTR device. 2000 - 3FFF EXTR device range - mapped at 0x1F802000 - 0x1F803FFF. 2000 - 204F DTL-H2000 2000 - 200F ATCONS parallel byte-wide console to PC for bidirectional debug communication 2010 - 201F DTL-H1500 (DECI1DR1) 2020 - 202F DUART 2030 - 2033 IRQ10 secondary controller 2034 - 203F Hardware type: 0x31= DTL-H1500. Used (2034) by DTL-H1500 (DECI1DR1). 2040 - 204F POST and DIP switch 2050 - 205F ? 2060 - 206F ? 2070 - 207F PS2 POST for IOP and EE boot initialization in RESET (and elsewhere?). 2080 - 20FF ? 2100 - 27FF ? 2800 - 2FFF DTL-H1500 (DECI1DR1) u16 2010, 2034, 2800, 2802-281E, 2C00, 2C02-2C1E, 2FFE, 2FFF 3000 - 3FFF PS2 TOOL 3000 - 30FF ? 3100 - 31FF DIP switch DSW602 3200 - 32FF PS2 TOOL - governed by an Altera MAX EPM7128ATC100-7 3200 - 320F config and board ID 3210 - 322F I2C interface for the DVE (early bit-bang interface used on the TOOL) 3220 - 32FF ? 3300 - 37FF ? 3800 - 38FF PIF/MRP for both DECI1 and DECI2 3900 - 3FFF ? 2000 - 2042 DTL-H2000 registers: 2000 DTL-H2000: EXP2: - ATCONS STAT (R) 2002 ATCONS DATA separate raed and write 7:0 TTY/ATCons RX/TX data 2004 ? 16bit 2010 u8 r/w Interrupt status DTL-H1500. 0 sub_6D4: If detected to be set, this reg is written 0, then reg 2800 is read as u16 and this again is checked and if sil clear => exit, else loop back. 1 When set, more processing is done. 7:2 ? u16 sub_6D4() { u16 ret; while (*(vu8*)reg2010 & 1) { if ((*(vu8*)reg2010 & 1) == 0) { ret = *(vu16*)reg2080; if ((*(vu8*)reg2010 & 1) == 0) break; } *(vu8*)reg2010 = 0; } return ret; } void sub_670(u16 val) { vLo = val & 0xFF; vHi = val >>8; while (*(vu8*)reg2010 & 1) { if ((*(vu8*)reg2010 & 1) == 0) { *(vu8*)reg20C0 = vLo; if ((*(vu8*)reg2010 & 1) == 0) { *(vu8*)reg20C0 = vHi; if ((*(vu8*)reg2010 & 1) == 0) break; } } *(vu8*)reg2010 = 0; } return; } 2020 - 202F DUART (external double UART) 2030 u16 Secondary IRQ10 controller flags 0 r/c ? 1 r/c Controllers IRQ: write: 0=noEffect / 1=clear 3:2 ? 4 r/c Acknowledged at 0x1FA00B04, otherwise unused. 5 r/c TTY RX ready 7:6 ? 15:8 unused, but written 0 on 32-it access. Some software uses u32-stores. 2032 u8 r/w Secondary IRQ10 controller enable? 0 cleared on some occasions 3:1 ? unused 4 set on some occasions 7:5 ? unused 2034 u8 r/o Hardware type 7:0 Hardawre type: 0x31 DTL-H1500 2040 r/o u8 DIP swicth DTL-H2000 7:0 value This register selects the DTL-H2000 boot mode, for whatever reason it's called "DIP Switch" register, although the DTL-H2000 boards don't seem to contain any such DIP Switches (instead, it's probably configured via some I/O ports on PC side). Possible values are: DIP=0 --> .. long delay before TTY? with "PSX>" prompt, throws CDROM cmds DIP=1 --> .. long delay before TTY? no "PSX>" prompt PSY-Q? DIP=2 --> .. instant TTY? with "PSX>" prompt DIP=3 --> Lockup DIP=04h..FFh --> Lockup with POST=04h..FFh 2041 (r?)/w u8 POST External 7-segment display 3:0 Current boot status - 0x0 - 0xF. Increments on boot. 7:4 unused = 0. 2042 (r?)/w u8 POST DTL-H2000 POST/LED 7:0 POST/LED 2070 (r?)/w u16 POST Debug LEDs 7:0 r?/w LED control 15:8 ? 16 (or 8?) LEDs are connected here. It is unknown if the high 8 LEDs are really connected to this register. They might be controlled by reg 321C. The LEDs are all red in color and located under the MIF (PCMCIA/AIF) board on DTL-T10000. Most likely 0=low=LED_on / 1=high=LED_off. The counter below is decrementing, and with the value 0xF4240 -> 0x3D should be the max value - the high 2 LEDs wil be on, as well as the high byte. There is another function, which has its counter initialized to 0x7FFFFFFF. In EE/GS self test, sw is used to write it: i = 1000000; //= 0xF4240 while (i>0) { int j = 0x2FFF; while ((--j)>0) {} i -= 0x2FFF; *(vu32*)0xBF802070 = i >>14; // /0x4000 } On IOP boot (RESET) 2070 is written as byte and incrementing numbers, that signify the current boot-phase are written. In case of an error 0xFA is written. Note that the PS1 kernel on the PS2 uses 0x1FA00000 as POST register (written as byte). 2800 - 2FFF DTL-H1500 regsiters: 2800 read u16 / write u8 RX/TX data port. 15:0 Read 7:0 Write twice - like reg 2C00 (after writing reg 2C00). 2802 - 281E Yet another memory written sequentially in u16 chunks. sub_1C8 2C00 read u16 / write u8 RX/TX data port. 15:0 Read 7:0 Write first the low and then the high byte, making sure that reg2010.0 is low while and after writing. The value read from reg 2C00 (after masking with 0xFFFC) is compared to 0xA14C, and if it matches a local flag is set. 2C00 - 2C1E Yet another memory read sequentially in u16 chunks. sub_370 2C20 u16 RX FIFO //sub_410 15:0 data 2FFE u8 r/o? 7:0 ? read value isn't used. 2FFF u8 w/o 0 set after setting local flag 0 to 0. 7:1 ? 3200 DMA Wide ch (channel?) 0 1 2 3 r/w Wide DMA: 0=8/16-bit / 1=32-bit_Wide DMA 4 5 6 7 //Only done for some board models. u8 sv = *(vu8*)0xBF803200; //saved value *(vu8*)0xBF803200 = 0xFF; printf(" DMA_WIDE_CH=%x\n", *(vu8*)0xBF803200); *(vu8*)0xBF803200 = sv; Maybe if wide-DMA is enabled for EXTR, or *on* EXTR (on the side of the MRP), this will return a certain value. 3204 BoardID - see models. Read as byte. //from fps2bios struct t_bootmode { u16 bid; //BoardID u8 id; //Some ID u8 len; //Length of the folowing data int data[0]; }; struct t_bootmode bm; bm.bid = *(vu8*)0xBF803204; bm.id = 0x06; bm.len = 0; RegisterBootMode(&bm); u8 bid = *(vu8*)0xBF803204 & 0xF8; bm.id = 7; if (bid <= 0x20) { if ((bid == 0x00) || (bid == 0x10) || (bid == 0x20)) { bm.bid = 0xC8; } else { bm.bid = 0x26; bm.u01 = 0x01; } } else { if (bid == 0x30) { bm.bid = 0xC8; } else if ((bid == 0x40) || (bid == 0x50)) { bm.bid = 0x2C; bm.u01 = 0x01; } else { bm.bid = 0x26; bm.u01 = 0x01; } } RegisterBootMode(&bm); 3210 I2C bit-bang interface (byte-accessed) 0 Data line: 0=low / 1=high. When outputing data it it set directly to the bit to output. Could be a sink-only (open drain) output. 1 Clock line: 0=low / 1=high. Data should be latched on the low->high transition. 7:2 ? 3210 = 0x03; 3210 = 0x02; 3210 = 0x00; u8 dat = 0x42; //byte to output MSB first: int i; for (i=7; i>0; i--) { u8 bit = (dat >>i) & 1; 3210 = bit; 3210 = bit | 2; 3210 = bit; } 3210 = 0x01; nopdelay(0x3E7); while (3210 != 0) {} It is unclear how the port is swicthed between input and output. Perhaps after reading (after the hardware detects a read) it becomes an input. No delay seems to be added between bits but for that generated by the function used to write the register. 3218 I2C related? 0 ? 1 set to enable (or maybe reset) the I2C interface. - or set before resetting it. Set by writing 0x02 to the wholre reg as u8. 7:2 ? Bit 2 is used for BID 0x40, 0x60, 0x61. 321C LEDs of the DTL-T15000 PA 7:0 LEDs control: 0=on / 1=off Might be that on the PA registers 321C and 2070 are somehoew connected together using flip-flops. But it may simply be that the other 8 bits (but those controlled by 2070) are controlled by register 321C and the function OnLED() is simply limited to lighting only a single LED at a time and always clearing all other. 0xBF803204 (value): 0,1 UMA board value & 0xF8: 0x10 "Gmain-1.0 board DSW602\r\n" 0x20 "Gmain-2.0 board DSW602\r\n" 0x30 "Gmain-3.0 board DSW602\r\n" 0x40 "B3system-1.0 front dipsw\r\n" 0x50 "Gmain-4.0 board DSW602\r\n" 0x58 "Gmain-5.0 board DSW602\r\n" 0x5C Gmain-6.0 GUESS 0x60 "MPU-4.0 board DSW602\r\n" 0x64 Gmain-7.0 GUESS 0x68 Gmain-8.0 GUESS 0x6C Gmain-9.0 GUESS 0x70 "Gmain-10.0/11.0 board DSW602\r\n" 0x78 "Gmain-12.0 board DSW602\r\n" 0x7C "Gmain-13.0 board DSW602\r\n" (this compare can't equalize, because the mask used is 0xF8). PIF Registers: PIF: 0x1F803800 3800 BID Board ID 0x4126 / 0x4127 3804 RST? Receive State? &= 0x100 if == 0 => 3800=0; if (3800 - 0x4126) >= 2 => exit, failing to init. 8 PC size is non-responsive or sth, when set. (init check) 3808 CPR Communication Port Receive if (3808 & 0x0F00 == 0x0F00) on init => success, else fail 380C CPS "Com. Send port Reg." Communication Send port Register. = 0x1300 in sub_2E8 timers stuff The PCI writes to the FIFO connected to the low bits below, while it reads from the FIFO connected to the high bits. 3810 FST RX/TX FIFO Status Register This is only considered if rx counter is = 0. It might be that this specifies the amount of data each side is ready to receive/transmit, and the RX counter (3818) specifies only the amount of data in FIFO). However this doesn't seem to be so. Maybe both are for the FIFO. flags for receive most likely 0 r/o RX Receive (PCI->PS2) FIFO is Empty, when set. 1 RX buffer signaling remaining rather than already filled elements. 2 RX buffer half-way full. 3 RX buffer partially full. 4 RX buffer completely full, when set. 5 6 7 8 TX buffer Completely Empty, when set 9 TX buffer partially full. 10 TX buffer half-way full. 11 TX buffer almost full. 12 TX buffer completely full. 13 14 15 The fill-level points are not certain. ElemCnt 4 3 2 1 0 state 0 0 0 0 0 1 Completely empty 0004-1FFC 0 0 0 1 0 Almost empty ? 2004 0 0 1 0 0 (at least) Half-way full. 2008-3FFC 0 1 0 0 0 Almost full 4000 1 0 0 0 0 Completely full the following might be more correct: ElemCnt 4 3 2 1 0 state 0 0 0 0 0 1 Completely empty 0004-1FFC 0 0 0 1 0 Almost empty ? 2004 0 0 1 1 0 (at least) Half-way full. 2008-3FFC 0 1 1 1 0 Almost full 4000 1 1 1 1 0 Completely full 0 Completely empty. 1 Almost empty: 0= other / 1= 4 bytes in FIFO 2 half-way full: 0= <=0x2000 bytes in FIFO, 1= >=0x2004 bytes in FIFO 3 Almost full: 0= other / 1= 0x3FFC elements in FIFO 4 Completely full. Packets can be of size more or less than the size of the FIFO. This explains why the counters (3814, 3818) can be both =0 and >=1 over different FIFO fill sizes and packets. The code (PS2) reads packets always one at a time. 3814 Tx Counter of Packets read: 15:0 Count of packets in TX FIFO. write: 0 Set to increment counter by 1. 15:1 Unused. 3818 Rx Counter of packets (read) and Rx Counter decrement (write) read: 15:0 Count of packets in RX FIFO. write: 0 Set to decrement counter by 1. This is done in RCV_END_sub_A84. 15:1 Unused. 381C Unused. powerControl and tool_led most likely - as on PCI side. bit 0 is WS LED 15:1 unknown. 3820 wait with timer and pool timer; if takes too long => exit & fail 0 1 Wait for it to become set in loop, counting iterations and timeout. 2 Wait for it to become set with hard-timer and timeout. 3 3824 Interrupt Polarity = 0xE0C0 3828 Data flow-control flags to PC 4 as bit 9. 9 set to enable the PCI putting data in fifo for receive by ps2. 4 Enabled for RCV_ON 9 Enabled for RCV_ON 12 PS2 sets this to signal that it is writing to FIFO. PS2 clears this once it has written the whole packet(s?). 382C = 0x0005 (init) = 4 after waiting for 3820 to become = 4 = 2 after waiting for 3820 to become = 2 Correspond top flags in 3820. Handshake with PCI. - PCi sets a flag, then PS2 waits for it to become set and sets it here. 0 1 2 3 3830 written values: = 0x0001 = 0x0004 3834 "DMA Kick" register 0 ? kept at 0. 1 WideDma = 1 2 set for DMA - maybe fastest-DMA mode enable. 14:3 Should be unimplemented = 0. 15 Set when starting DMA Should auto-clear. 3838 "DMA Wait Cycle" register 7:0 Maybe sets the duration of each cycle - in the fastest DMA mode, the duration is 1. 15:8 r/o Unimplemented 0 (should be). 383C "DMA Slice Count" register. RXC RX Counter Write (to PC) Block count -same value as DMAC BCR high halfWord. 15:0 Number of DMA BCR blocks/slices. 3840 FIFO for both reading and writing - from/to PC. 3842 - as word - both are written in one go. DMA is also used to write fifo. The PS2 does NOT set the direction of DMA prior to starting it, which means that the MRP determines the direction by the use of the /SRD, /SWR lines. This is somewhat strange, as there are a bunch of buffers between the MRP and the PS2 (IOP), so how would they switch in time for the DMA transfer I have no idea. It should be noted that the FIFO(s) can instead by read/written by PIO, so the direction in that case should also be determined somehow. PC side: 00 BID Board Id The MRP driver expects a value of 0x4126. values: 0x4126 PIF (FIFO pre-set free space = 0x3FF) 0x4127 B3 System (FIFO uses smaller pre-set remaining free space 0x7F) 04 RST Reset / receive state / state = 0x8000 when starting mrp_reset() and = 0x7000 when ending. 08 CPS PCI->PS2 Communication Port Send (half-word, but in some cases only low byte) A single byte? Command Parameter Send. PS2 reads(only), PCI writes 0C CPR PS2->PCI Communication Port Receive Called "Com. Send port Reg." CPS = Communication Port Send from PS2 side (PS2->PCI - reverse to the name from PC side). 10 FST RX and TX FIFO State. As 3810. writing 0xC0C0 from PCI side may be for clearing FIFOs completely (their counters). 14 TXC TX Counter of Packets. As 3814. However, this is for packets PCI->PS2! Writing 1 here, causes counter to increment. 18 RXC RX Counter of Packets. As 3818. Writing 1 here, causes counter to decrement. 1C is also called "Poweroff Enable Register" / "Powctrl Reg." on PS2 side 1C F1C Function 1 Control? - controls LEDs and PS2 & SPC power Front panel Control? / "Field 1C". 0 Orange 1=off / 0=on WS (WorkStation) LED 1 Green 1=off / 0=on TOOL LED. Shutdown request (when = 1). Writing 1 here will shutdown the TOOL. 2 PS2 power 0=powered-on / 1=Shut-down This is not entirely certain: although it works correctly when shutdown started by writing 1 to bit 10 of this reg, this it set immediately when "powctrlmod -p" is called, which seems to be what the "shutdown" option of the TOOL server page does. It doesn't initiate any Linux power-off process. This is odd. This is referred to as "Poweroff Enable". Power-off acknowledge (1 = TOOL will not automatically power-off when the power button is held down, 0 = power-off automatically) So when shutting-down, best use the power button - (set) bit 10. 3 0=power-off PC (controls power button) / 1=leave powered-on. 4 i/o enabled ? / incoming data enable ? 7:5 ? 8 r/o DVD mode selected (when = 1) (On the front panel of the TOOL). 9 r/o TOOL mode selected (On the front panel of the TOOL). 10 When set by an external source (powctrld most likely reads/polls it) (maybe power button) causes PC to turn-off (shutdown in initiated). Triggered if the power button is held down, with no known way to be reset via software. 11 unused? 14:12 set together after reset (= 0x7000) and then the whole reg is written 0. 15 Set by mrp_reset() (at the start) maybe resets some part of the MRP interface hardware. Might be for getting control of PS2 DMA regs that are used in the reset. FST is written 0xC0C0 afterwards. There may be a bit in this register that signals that the data in it is valid - i.e. - that the MRP is initialized and enabled. And without it set, the rest of the bits aren't considered. 20 IST r/o Interrupt Status. If the corresponding interrupt cause is active, the bit corresponding to it here, becomes set. When the interrupt cause is no longer active, the corresponding interrupt flag here is cleared. Writing has no effect - controlled by hardware (untested). 15:0 Interrupt status - see interrupt flags. 24 ISP r/w Interrupt Status Polarity When a bit here is set, the corresponding interrupt status flag in IST is inverted so that its active state (and transition) is the opposite of the default. The value last written to this register is returned when reading it (the hardware doesn't modify it). 15:0 Interrupt Status Polarity - see interrupt flags. 28 IER r/w Interrupt Enable Register When a bit here is set, the corresponding interrupt status flag in IST is unmasked so that it can trigger the main interrupt signal on this side. Unmasking an interrupt that has its status flag in IST already set will trigger the main edge-triggered interrupt signal. Masking and unmasking an interrupt multiple times will also trigger the main edge-triggered interrupt signal multiple times. The value last written to this register is returned when reading it (the hardware doesn't modify it). 15:0 Interrupt Enable mask - see interrupt flags. 2C CSI r/c Clear Signal Interrupt on this side. (Command Clear Signal Status Sticky Interrupt) When the other side (through FSI there) causes an interrupt on this one, the corresponding bit in IST gets set. Then to clear it, write that bit set here. 30 FSI r/s Flag Signal Interrupt to the other side. (Function Force Flag Signal Status Sticky Interrupt) Setting a bit here, sets the corresponding Signal Interrupt flag (SI0-SI2) on the other side. Clearing a bit should either have no effect, or should have the same effect as clearing it from CSI on the other side. CSI & FSI: Flags set from one side by FSI are cleared by the other through setting the corresponding bit in CSI. The 'S' in CSI and FSI has the same meaning as that in SI0, SI1, SI2 and probably means "Signal", as they are used for signalling between the two sides. There are two separate sets of Signal interrupt registers, so FSI doesn't affect the Signal interrupts (in IST) on this side and CSI only affects the Signal interrupts on this side. The AEO and AFO registers might have different functions (and names) on PS2 and PCI side, so the PS2 bits in the following reg may not really be for it. 34 AEO (u8) A? Enable Operation ?? 0 This bit is also r/w (according to MRP-diag code on PS2 side (TOOL HDD)). 1 WideDma: 0=off / 1=on 2 Set when starting DMA by PS2 together with bit 15. This is some setting - maybe fastest DMA mode. 3 15 14 1=Rx LDE / 0 = Tx LDE LoaD / Latch Data Enable? 15 Start operation once set(PCI); PS2 also sets this together with bit 2 when starting DMA. PCI sets this after setting bit 14 to the desired value, then waits for this to auto-clear and if it doesn't within a set period, it errs LDE timeout. 38 AFO A? Flags for Operation. AEO, AFO - Available Empty / Full O..? Might these be FIFO pointers? 3C Number of DMA BCR blocks (u16) on PS2 side.