Skip to content

Latest commit

 

History

History
318 lines (243 loc) · 12 KB

File metadata and controls

318 lines (243 loc) · 12 KB

Cpuspecifications

Source: https://problemkaputt.de/psx-spx.htm Section: Cpuspecifications

CPU Specifications CPU

CPU Registers

CPU Opcode Encoding

CPU Load/Store Opcodes

CPU ALU Opcodes

CPU Jump Opcodes

CPU Coprocessor Opcodes

CPU Pseudo Opcodes

System Control Coprocessor (COP0)

COP0 - Register Summary

COP0 - Exception Handling

COP0 - Misc

COP0 - Debug Registers

CPU Opcode Encoding

Primary opcode field (Bit 26..31)

00h=SPECIAL 08h=ADDI  10h=COP0 18h=N/A   20h=LB   28h=SB   30h=LWC0 38h=SWC0
01h=BcondZ  09h=ADDIU 11h=COP1 19h=N/A   21h=LH   29h=SH   31h=LWC1 39h=SWC1
02h=J       0Ah=SLTI  12h=COP2 1Ah=N/A   22h=LWL  2Ah=SWL  32h=LWC2 3Ah=SWC2
03h=JAL     0Bh=SLTIU 13h=COP3 1Bh=N/A   23h=LW   2Bh=SW   33h=LWC3 3Bh=SWC3
04h=BEQ     0Ch=ANDI  14h=N/A  1Ch=N/A   24h=LBU  2Ch=N/A  34h=N/A  3Ch=N/A
05h=BNE     0Dh=ORI   15h=N/A  1Dh=N/A   25h=LHU  2Dh=N/A  35h=N/A  3Dh=N/A
06h=BLEZ    0Eh=XORI  16h=N/A  1Eh=N/A   26h=LWR  2Eh=SWR  36h=N/A  3Eh=N/A
07h=BGTZ    0Fh=LUI   17h=N/A  1Fh=N/A   27h=N/A  2Fh=N/A  37h=N/A  3Fh=N/A

Secondary opcode field (Bit 0..5) (when Primary opcode = 00h)

00h=SLL   08h=JR      10h=MFHI 18h=MULT  20h=ADD  28h=N/A  30h=N/A  38h=N/A
01h=N/A   09h=JALR    11h=MTHI 19h=MULTU 21h=ADDU 29h=N/A  31h=N/A  39h=N/A
02h=SRL   0Ah=N/A     12h=MFLO 1Ah=DIV   22h=SUB  2Ah=SLT  32h=N/A  3Ah=N/A
03h=SRA   0Bh=N/A     13h=MTLO 1Bh=DIVU  23h=SUBU 2Bh=SLTU 33h=N/A  3Bh=N/A
04h=SLLV  0Ch=SYSCALL 14h=N/A  1Ch=N/A   24h=AND  2Ch=N/A  34h=N/A  3Ch=N/A
05h=N/A   0Dh=BREAK   15h=N/A  1Dh=N/A   25h=OR   2Dh=N/A  35h=N/A  3Dh=N/A
06h=SRLV  0Eh=N/A     16h=N/A  1Eh=N/A   26h=XOR  2Eh=N/A  36h=N/A  3Eh=N/A
07h=SRAV  0Fh=N/A     17h=N/A  1Fh=N/A   27h=NOR  2Fh=N/A  37h=N/A  3Fh=N/A

Opcode/Parameter Encoding

31..26 |25..21|20..16|15..11|10..6 |  5..0  |
6bit  | 5bit | 5bit | 5bit | 5bit |  6bit  |
-------+------+------+------+------+--------+------------
000000 | N/A  | rt   | rd   | imm5 | 0000xx | shift-imm
000000 | rs   | rt   | rd   | N/A  | 0001xx | shift-reg
000000 | rs   | N/A  | N/A  | N/A  | 001000 | jr
000000 | rs   | N/A  | rd   | N/A  | 001001 | jalr
000000 |  | 00110x | sys/brk
000000 | N/A  | N/A  | rd   | N/A  | 0100x0 | mfhi/mflo
000000 | rs   | N/A  | N/A  | N/A  | 0100x1 | mthi/mtlo
000000 | rs   | rt   | N/A  | N/A  | 0110xx | mul/div
000000 | rs   | rt   | rd   | N/A  | 10xxxx | alu-reg
000001 | rs   | 00000|  | bltz
000001 | rs   | 00001|  | bgez
000001 | rs   | 10000|  | bltzal
000001 | rs   | 10001|  | bgezal
000001 | rs   | xxxx0|  | bltz  ;\undocumented dupes
000001 | rs   | xxxx1|  | bgez  ;/(when bit17-19=nonzero)
00001x |  | j/jal
00010x | rs   | rt   |  | beq/bne
00011x | rs   | N/A  |  | blez/bgtz
001xxx | rs   | rt   |  | alu-imm
001111 | N/A  | rt   |  | lui-imm
100xxx | rs   | rt   |  | load rt,[rs+imm]
101xxx | rs   | rt   |  | store rt,[rs+imm]
x1xxxx |  | coprocessor (see below)

Coprocessor Opcode/Parameter Encoding

31..26 |25..21|20..16|15..11|10..6 |  5..0  |
6bit  | 5bit | 5bit | 5bit | 5bit |  6bit  |
-------+------+------+------+------+--------+------------
0100nn |0|0000| rt   | rd   | N/A  | 000000 | MFCn rt,rd_dat  ;rt = dat
0100nn |0|0010| rt   | rd   | N/A  | 000000 | CFCn rt,rd_cnt  ;rt = cnt
0100nn |0|0100| rt   | rd   | N/A  | 000000 | MTCn rt,rd_dat  ;dat = rt
0100nn |0|0110| rt   | rd   | N/A  | 000000 | CTCn rt,rd_cnt  ;cnt = rt
0100nn |0|1000|00000 |  | BCnF target ;jump if false
0100nn |0|1000|00001 |  | BCnT target ;jump if true
0100nn |1|  | COPn imm25
010000 |1|0000| N/A  | N/A  | N/A  | 000001 | COP0 01h  ;=TLBR   ;\if any
010000 |1|0000| N/A  | N/A  | N/A  | 000010 | COP0 02h  ;=TLBWI  ; (not on
010000 |1|0000| N/A  | N/A  | N/A  | 000110 | COP0 06h  ;=TLBWR  ; psx)
010000 |1|0000| N/A  | N/A  | N/A  | 001000 | COP0 08h  ;=TLBP   ;/
010000 |1|0000| N/A  | N/A  | N/A  | 010000 | COP0 10h  ;=RFE
1100nn | rs   | rt   |  | LWCn rt_dat,[rs+imm]
1110nn | rs   | rt   |  | SWCn rt_dat,[rs+imm]

Illegal Opcodes

All opcodes that are marked as "N/A" in the Primary and Secondary opcode tables are causing a Reserved Instruction Exception (excode=0Ah).

The unused operand bits (eg. Bit21-25 for LUI opcode) should be usually zero, but do not necessarily trigger exceptions if set to nonzero values.

CPU ALU Opcodes

arithmetic instructions

addt rd,rs,rt    add   rd,rs,rt         rd=rs+rt (with overflow trap)
add  rd,rs,rt    addu  rd,rs,rt         rd=rs+rt
subt rd,rs,rt    sub   rd,rs,rt         rd=rs-rt (with overflow trap)
sub  rd,rs,rt    subu  rd,rs,rt         rd=rs-rt
addt rt,rs,imm   addi  rt,rs,imm        rt=rs+(-8000h..+7FFFh) (with ov.trap)
add  rt,rs,imm   addiu rt,rs,imm        rt=rs+(-8000h..+7FFFh)

The opcodes "with overflow trap" do trigger an exception (and leave rd unchanged) in case of overflows.

comparison instructions

setlt slt   rd,rs,rt  if rs  Rs            FFFFFFFFh
sdiv    0..+7FFFFFFFh   0   -->  Rs            -1
sdiv    -80000000h..-1  0   -->  Rs            +1
sdiv    -80000000h      -1  -->  0             -80000000h

For udiv, the result is more or less correct (as close to infinite as possible). For sdiv, the results are total garbage (about farthest away from the desired result as possible).

Note: After accessing the lo/hi registers, there seems to be a strange rule that one should not touch the lo/hi registers in the next 2 cycles or so... not yet understood if/when/how that rule applies...?

CPU Coprocessor Opcodes

Coprocessor Instructions (COP0..COP3)

mov  rt,cop#Rd(0-31)       mfc# rt,rd       ;rt = cop#datRd ;data regs
mov  rt,cop#Rd(32-63)      cfc# rt,rd       ;rt = cop#cntRd ;control regs
mov  cop#Rd(0-31),rt       mtc# rt,rd       ;cop#datRd = rt ;data regs
mov  cop#Rd(32-63),rt      ctc# rt,rd       ;cop#cntRd = rt ;control regs
mov  cop#cmd,imm25         cop# imm25       ;exec cop# command 0..1FFFFFFh
mov  cop#Rt(0-31),[rs+imm] lwc# rt,imm(rs)  ;cop#dat_rt = [rs+imm]  ;word
mov  [rs+imm],cop#Rt(0-31) swc# rt,imm(rs)  ;[rs+imm] = cop#dat_rt  ;word
jf   cop#flg,dest          bc#f dest        ;if cop#flg=false then pc=$+disp
jt   cop#flg,dest          bc#t dest        ;if cop#flg=true  then pc=$+disp
rfe                        rfe              ;return from exception (COP0)
tlb                    tlb          ;virtual memory related (COP0)

Caution - Load Delay

When reading from a coprocessor register, the next opcode cannot use the destination register as operand (much the same as the Load Delays that occur when reading from memory; see there for details).

Reportedly, the Load Delay applies for the next TWO opcodes after coprocessor reads, but, that seems to be nonsense (the PSX does finish both COP0 and COP2 reads after ONE opcode).

Caution - Store Delay

In some cases, a similar delay occurs when writing to a coprocessor register. COP0 is more or less free of store delays (eg. one can read from a cop0 register immediately after writing to it), the only known exception is the cop2 enable bit in cop0r12.bit30 (setting that cop0 bit acts delayed, and cop2 isn't actually enabled until after 2 clock cycles or so).

Writing to cop2 registers has a delay of 2..3 clock cycles. In most cases, that is probably (?) only 2 cycles, but special cases like writing to IRGB (which does additionally affect IR1,IR2,IR3) take 3 cycles until the result arrives in all registers).

Note that Store Delays are counted in numbers of clock cycles (not in numbers of opcodes). For 3 cycle delay, one must usually insert 3 cached opcodes (or one uncached opcode).

COP0 - Register Summary

COP0 Register Summary

cop0r0-r2   - N/A
cop0r3      - BPC - Breakpoint on execute (R/W)
cop0r4      - N/A
cop0r5      - BDA - Breakpoint on data access (R/W)
cop0r6      - JUMPDEST - Randomly memorized jump address (R)
cop0r7      - DCIC - Breakpoint control (R/W)
cop0r8      - BadVaddr - Bad Virtual Address (R)
cop0r9      - BDAM - Data Access breakpoint mask (R/W)
cop0r10     - N/A
cop0r11     - BPCM - Execute breakpoint mask (R/W)
cop0r12     - SR - System status register (R/W)
cop0r13     - CAUSE - (R)  Describes the most recently recognised exception
cop0r14     - EPC - Return Address from Trap (R)
cop0r15     - PRID - Processor ID (R)
cop0r16-r31 - Garbage
cop0r32-r63 - N/A - None such (Control regs)

COP0 - Misc

cop0r15 - PRID - Processor ID (R)

0-7   Revision
8-15  Implementation
16-31 Not used

PRID=00000001h on Playstation with CPU CXD8530BQ/CXD8530CQ

PRID=00000002h on Playstation with CPU CXD8606CQ

cop0r6 - JUMPDEST - Randomly memorized jump address (R)

The is a rather strange totally useless register. After certain exceptions, the CPU does memorize a jump destination address in the register. Once when it has memorized an address, the register becomes locked, and the memorized value won't change until it becomes unlocked by a new exception. Exceptions that do unlock the register are Reset and Interrupts (cause.bit10). Exceptions that do NOT unlock the register are syscall/break opcodes, and software generated interrupts (eg. cause.bit8).

In the unlocked state, the CPU does more or less randomly memorize one of the next some jump destinations - eg. the destination from the second jump after reset, or from a jump that occured immediately before executing the IRQ handler, or from a jump inside of the IRQ handler, or even from a later jump that occurs shortly after returning from the IRQ handler.

The register seems to be read-only (although the Kernel initialization code writes 0 to it for whatever reason).

cop0r0..r2, cop0r4, cop0r10, cop0r32..r63 - N/A

Registers 0,1,2,4,10 control virtual memory on some MIPS processors (but there's none such in the PSX), and Registers 32..63 (aka "control registers") aren't used in any MIPS processors. Trying to read any of these registers causes a Reserved Instruction Exception (excode=0Ah).

cop0cmd=10h - RFE

Return from exception.

cop0cmd=01h,02h,06h,08h - TLBR,TLBWI,TLBWR,TLBP

The PSX supports only one cop0cmd (cop0cmd=10h aka RFE). Trying to execute the TLBxx opcodes causes a Reserved Instruction Exception (excode=0Ah).

cop0cmd=00h,03h..05h,07h,09h..0Fh,11h..1Fh - Unused

These are unused commands (unknown if they have any function). They can be executed without triggering exceptions (unlike RFE, that works even in User Mode with COP0 disabled).

cop0cmd=20h..1FFFFFFh - mirrors of cop0cmd=00h..1Fh

Mirrors, the upper 16bit of the 25bit command number are ignored.

jf/jt cop0flg,dest - conditional cop0 jumps

mov [mem],cop0reg / mov cop0reg,[mem] - coprocessor cop0 load/store

These opcodes are not implemented on PSX. However, there are some glitches when trying to execute them:

When SR.bit28=1, doesn't trigger any exception, but doesn't do anything useful:

jump condition seems to be always false (jf jumps always, jt jumps never)
mov [mem],cop0reg - stores garbage (next opcode) in memory
mov cop0reg,[mem] - does dummy memory read without changing cop0reg?

When SR.bit28=0, triggers Coprocessor Unusable Exception (excode=0Bh), this does happen even in Kernal Mode (unlike other COP0 opcodes which do ignore SR.bit28=0 in Kernal Mode).

cop0r16-r31 - Garbage

Trying to read these registers returns garbage (but doesn't trigger any exception). When reading one of the garbage registers shortly after reading a valid cop0 register, the garbage value is usually the same as that of the valid register. When doing the read later on, the return value is usually 00000020h, or when reading much later it returns 00000040h, or even 00000100h. No idea what is causing that effect...?

Note: The garbage registers can be accessed (without causing an exception) even in "User mode with cop0 disabled" (SR.Bit1=1 and SR.Bit28=0); accessing any other existing cop0 registers (or executing the rfe opcode) in that state is causing Coprocessor Unusable Exceptions (excode=0Bh).