psx.wiki

CPU Instruction Set

Encoding, operation and timing of every R3000A instruction on the PlayStation.

Summary

The PlayStation CPU executes the R3000A instruction set. Every instruction is one 32-bit word, and bits 26 to 31 hold the primary opcode. Primary opcode 00h (SPECIAL) uses bits 0 to 5 as a secondary opcode, and primary opcode 01h (BcondZ) uses bits 16 to 20 to choose the branch condition.1

An opcode marked N/A in the tables below causes a reserved instruction exception (excode 0Ah). Unused operand bits, such as bits 21 to 25 of LUI, should be zero, but setting them does not necessarily cause an exception.2

Registers

The CPU has 32 general-purpose registers of 32 bits, a program counter and the HI and LO registers that receive multiply and divide results. R0 always reads 0. The compiler assigns each register a use, and assembler code that works with compiled code must follow the same assignment. The CPU page lists the assignments in Sony's table.34

R31 (RA) is an ordinary register, but JAL, BLTZAL and BGEZAL write their return address there. JALR may write its return address to any register from R1 to R30 instead, and exceptions store theirs in the COP0 EPC register.4

Instruction Encoding

The fields of an instruction word are as follows:1

Table 1: Instruction fields
Bits Width Field
26 to 31 6 Primary opcode
21 to 25 5 rs, source register
16 to 20 5 rt, target register (or the BcondZ condition)
11 to 15 5 rd, destination register
6 to 10 5 imm5, shift amount
0 to 5 6 Secondary opcode (SPECIAL)
0 to 15 16 imm16, immediate or branch offset
0 to 25 26 imm26, jump target

Primary Opcodes

Table 2: Primary opcode field (bits 26 to 31)
Row +0h +1h +2h +3h +4h +5h +6h +7h
00h SPECIAL BcondZ J JAL BEQ BNE BLEZ BGTZ
08h ADDI ADDIU SLTI SLTIU ANDI ORI XORI LUI
10h COP0 COP1 COP2 COP3 N/A N/A N/A N/A
18h N/A N/A N/A N/A N/A N/A N/A N/A
20h LB LH LWL LW LBU LHU LWR N/A
28h SB SH SWL SW N/A N/A SWR N/A
30h LWC0 LWC1 LWC2 LWC3 N/A N/A N/A N/A
38h SWC0 SWC1 SWC2 SWC3 N/A N/A N/A N/A

Secondary Opcodes

Table 3: Secondary opcode field (bits 0 to 5 of SPECIAL)
Row +0h +1h +2h +3h +4h +5h +6h +7h
00h SLL N/A SRL SRA SLLV N/A SRLV SRAV
08h JR JALR N/A N/A SYSCALL BREAK N/A N/A
10h MFHI MTHI MFLO MTLO N/A N/A N/A N/A
18h MULT MULTU DIV DIVU N/A N/A N/A N/A
20h ADD ADDU SUB SUBU AND OR XOR NOR
28h N/A N/A SLT SLTU N/A N/A N/A N/A
30h N/A N/A N/A N/A N/A N/A N/A N/A
38h N/A N/A N/A N/A N/A N/A N/A N/A

Instruction Formats

Each group of instructions places its operands as shown below:1

Table 4: Instruction formats
31..26 25..21 20..16 15..11 10..6 5..0 Group
000000 rt rd imm5 0000xx Shift by immediate
000000 rs rt rd 0001xx Shift by register
000000 rs 001000 JR
000000 rs rd 001001 JALR
000000 20-bit comment 00110x SYSCALL, BREAK
000000 rd 0100x0 MFHI, MFLO
000000 rs 0100x1 MTHI, MTLO
000000 rs rt 0110xx Multiply and divide
000000 rs rt rd 10xxxx ALU with registers
000001 rs 00000 imm16 BLTZ
000001 rs 00001 imm16 BGEZ
000001 rs 10000 imm16 BLTZAL
000001 rs 10001 imm16 BGEZAL
00001x imm26 J, JAL
00010x rs rt imm16 BEQ, BNE
00011x rs imm16 BLEZ, BGTZ
001xxx rs rt imm16 ALU with immediate
001111 rt imm16 LUI
100xxx rs rt imm16 Load rt from [rs+imm]
101xxx rs rt imm16 Store rt to [rs+imm]
x1xxxx Coprocessor specific Coprocessor

Load and Store Instructions

Loads and stores address memory as rs plus a sign-extended 16-bit offset. A load that faults leaves rt unchanged.5

Table 5: Load and store instructions
Instruction Opcode Operation
LB rt,imm(rs) 20h rt = byte at [imm+rs], sign-extended
LBU rt,imm(rs) 24h rt = byte at [imm+rs], zero-extended
LH rt,imm(rs) 21h rt = halfword at [imm+rs], sign-extended
LHU rt,imm(rs) 25h rt = halfword at [imm+rs], zero-extended
LW rt,imm(rs) 23h rt = word at [imm+rs]
SB rt,imm(rs) 28h byte at [imm+rs] = rt AND FFh
SH rt,imm(rs) 29h halfword at [imm+rs] = rt AND FFFFh
SW rt,imm(rs) 2Bh word at [imm+rs] = rt
LWL rt,imm(rs) 22h Load the left (upper) bytes of rt
LWR rt,imm(rs) 26h Load the right (lower) bytes of rt
SWL rt,imm(rs) 2Ah Store the left (upper) bytes of rt
SWR rt,imm(rs) 2Eh Store the right (lower) bytes of rt

Alignment

The R3000 requires strict address alignment. Word data must start at a multiple of 4 and halfword data at a multiple of 2, and a data load, data store or instruction fetch that breaks this rule causes an address error. Bytes have no alignment restriction.35

Load Delay

The loaded data is not available to the next instruction, because the target register is updated only after that instruction completes. If the next instruction reads the target register it usually receives the old value. However, if an interrupt occurs between the two instructions, the load completes during the interrupt and the next instruction receives the new value.6

Reads from coprocessor registers with MFC2 and CFC2 have the same 1-instruction delay.6

Stores and the Write Queue

A store enters the 4-word write queue and completes in one cycle unless the queue is full, in which case the CPU waits for a free entry. During an 8-bit or 16-bit store all 32 bits of the source register are placed on the bus. A narrow store to a 32-bit I/O register therefore writes the full register value.7

Unaligned Access

LWL, LWR, SWL and SWR access a word at any address. LWR and SWR transfer the low bytes of rt up to the next word boundary, and LWL and SWL transfer the high bytes down to the previous boundary. The bytes not transferred stay unchanged in both rt and memory, so a pair of instructions covers a whole unaligned word.8

Table 6: LWR and SWR byte transfer
Address Bytes of rt Memory
N x 4 + 0 All 32 bits N x 4 + 0 to 3
N x 4 + 1 Lower 24 bits N x 4 + 1 to 3
N x 4 + 2 Lower 16 bits N x 4 + 2 to 3
N x 4 + 3 Lower 8 bits N x 4 + 3
Table 7: LWL and SWL byte transfer
Address Bytes of rt Memory
N x 4 + 0 Upper 8 bits N x 4 + 0
N x 4 + 1 Upper 16 bits N x 4 + 0 to 1
N x 4 + 2 Upper 24 bits N x 4 + 0 to 2
N x 4 + 3 All 32 bits N x 4 + 0 to 3

LWL and LWR need no delay between them, even though both write the same register. The load delay applies only after the second of the two:8

lwl   r2,$0003(t0)   ;no delay required between these
lwr   r2,$0000(t0)   ;although both access r2
nop                  ;load delay before reading r2
and   r2,r2,0ffffh   ;r2 now holds the unaligned data

ALU Instructions

ADD, SUB and ADDI trap on signed overflow and leave the destination unchanged. The other arithmetic instructions never trap, and the shift instructions do not raise exceptions on overflow either.9

Table 8: Arithmetic instructions
Instruction Opcode Operation
ADD rd,rs,rt 00h/20h rd = rs + rt, with overflow trap
ADDU rd,rs,rt 00h/21h rd = rs + rt
SUB rd,rs,rt 00h/22h rd = rs - rt, with overflow trap
SUBU rd,rs,rt 00h/23h rd = rs - rt
ADDI rt,rs,imm 08h rt = rs + (-8000h to +7FFFh), with overflow trap
ADDIU rt,rs,imm 09h rt = rs + (-8000h to +7FFFh)

SLTIU sign-extends its immediate and then compares without sign. Its immediate therefore covers 0 to 7FFFh and FFFF8000h to FFFFFFFFh.9

Table 9: Comparison instructions
Instruction Opcode Operation
SLT rd,rs,rt 00h/2Ah rd = 1 if rs < rt (signed), else 0
SLTU rd,rs,rt 00h/2Bh rd = 1 if rs < rt (unsigned), else 0
SLTI rt,rs,imm 0Ah rt = 1 if rs < sign-extended imm (signed), else 0
SLTIU rt,rs,imm 0Bh rt = 1 if rs < sign-extended imm (unsigned), else 0

The logical instructions with an immediate zero-extend it:9

Table 10: Logical instructions
Instruction Opcode Operation
AND rd,rs,rt 00h/24h rd = rs AND rt
OR rd,rs,rt 00h/25h rd = rs OR rt
XOR rd,rs,rt 00h/26h rd = rs XOR rt
NOR rd,rs,rt 00h/27h rd = FFFFFFFFh XOR (rs OR rt)
ANDI rt,rs,imm 0Ch rt = rs AND (0000h to FFFFh)
ORI rt,rs,imm 0Dh rt = rs OR (0000h to FFFFh)
XORI rt,rs,imm 0Eh rt = rs XOR (0000h to FFFFh)

Unlike most instructions, the shifts take rt as their second operand rather than their third. A variable shift uses only the low 5 bits of rs.9

Table 11: Shift instructions
Instruction Opcode Operation
SLL rd,rt,imm 00h/00h rd = rt SHL (00h to 1Fh)
SRL rd,rt,imm 00h/02h rd = rt SHR (00h to 1Fh)
SRA rd,rt,imm 00h/03h rd = rt SAR (00h to 1Fh)
SLLV rd,rt,rs 00h/04h rd = rt SHL (rs AND 1Fh)
SRLV rd,rt,rs 00h/06h rd = rt SHR (rs AND 1Fh)
SRAV rd,rt,rs 00h/07h rd = rt SAR (rs AND 1Fh)
LUI rt,imm 0Fh rt = (0000h to FFFFh) SHL 16

Multiply and Divide

The multiply and divide instructions write their result to HI and LO. Starting the operation takes one cycle, and the CPU continues with the next instructions while the unit works. A read of HI or LO before the operation is complete halts the CPU until the result is ready.10

Table 12: Multiply and divide instructions
Instruction Opcode Operation
MULT rs,rt 00h/18h HI:LO = rs x rt (signed)
MULTU rs,rt 00h/19h HI:LO = rs x rt (unsigned)
DIV rs,rt 00h/1Ah LO = rs / rt, HI = rs mod rt (signed)
DIVU rs,rt 00h/1Bh LO = rs / rt, HI = rs mod rt (unsigned)
MFHI rd 00h/10h rd = HI
MTHI rs 00h/11h HI = rs
MFLO rd 00h/12h rd = LO
MTLO rs 00h/13h LO = rs

A multiply takes longer as rs grows. A small value in rs times a large value in rt is therefore faster than the reverse. A divide always takes 36 cycles:10

Table 13: Multiply and divide execution time
Instruction Cycles rs
MULTU 6 00000000h to 000007FFh
MULTU 9 00000800h to 000FFFFFh
MULTU 13 00100000h to FFFFFFFFh
MULT 6 00000000h to 000007FFh, or FFFFF800h to FFFFFFFFh
MULT 9 00000800h to 000FFFFFh, or FFF00000h to FFFFF801h
MULT 13 00100000h to 7FFFFFFFh, or 80000000h to FFF00001h
DIV, DIVU 36 Any

For example, up to six cached ALU instructions, or one read from main RAM with its 6-cycle access time, fit between MULTU 123h,12345678h and MFLO without slowing the program.10

A divide never raises an exception. A division by zero or the overflow of -80000000h / -1 gives the following results:10

Table 14: Divide error results
Instruction rs rt HI (remainder) LO (result)
DIVU 0 to FFFFFFFFh 0 rs FFFFFFFFh
DIV 0 to +7FFFFFFFh 0 rs -1
DIV -80000000h to -1 0 rs +1
DIV -80000000h -1 0 -80000000h

psx-spx also notes an unconfirmed rule that HI and LO should not be touched in the 2 cycles after they are accessed.10

Jump and Branch Instructions

The instruction after a jump or branch, the branch delay slot, is always executed. A branch adds its sign-extended offset times 4 to the address of the delay slot, while J and JAL replace the low 28 bits of the program counter.11

Table 15: Jump and branch instructions
Instruction Opcode Operation
J dest 02h pc = (pc AND F0000000h) + imm26 x 4
JAL dest 03h pc = (pc AND F0000000h) + imm26 x 4, ra = $+8
JR rs 00h/08h pc = rs
JALR rd,rs 00h/09h pc = rs, rd = $+8
BEQ rs,rt,dest 04h if rs = rt then pc = $+4 + imm16 x 4
BNE rs,rt,dest 05h if rs <> rt then pc = $+4 + imm16 x 4
BLEZ rs,dest 06h if rs <= 0 then pc = $+4 + imm16 x 4
BGTZ rs,dest 07h if rs > 0 then pc = $+4 + imm16 x 4
BLTZ rs,dest 01h, rt=00h if rs < 0 then pc = $+4 + imm16 x 4
BGEZ rs,dest 01h, rt=01h if rs >= 0 then pc = $+4 + imm16 x 4
BLTZAL rs,dest 01h, rt=10h if rs < 0 then pc = $+4 + imm16 x 4; ra = $+8
BGEZAL rs,dest 01h, rt=11h if rs >= 0 then pc = $+4 + imm16 x 4; ra = $+8

BLTZAL and BGEZAL write RA whether or not the branch is taken. When rs is RA, they compare the value RA held before the link.11

JR and JALR may jump to an unaligned address. The address error (AdEL) is then raised on the next instruction fetch.11

JALR Cautions

Assemblers differ in their JALR syntax: the IDT79R3041 manual writes "jalr rs,rd" and the MIPS32 manual "jalr rd,rs". JALR must not use one register for both operands (for example "jalr r31,r31").12

The reason is the delay slot. If an interrupt occurs between JALR and its delay slot, BD is set and EPC points back to the JALR. The JALR therefore executes a second time, and by then its target register has been overwritten with the return address.12

Exception Instructions

SYSCALL raises a system call exception and BREAK raises a breakpoint exception. Unlike jumps and branches they take effect at once, and the next instruction is not executed. The CPU ignores the 20-bit field in bits 6 to 25. The exception handler may read the field from the instruction word.13

Table 16: Exception instructions
Instruction Opcode Operation
SYSCALL imm20 00h/0Ch System call exception (excode 08h)
BREAK imm20 00h/0Dh Breakpoint exception (excode 09h)

The COP0 page describes exception handling.

Coprocessor Instructions

The coprocessor instructions move data to and from the data and control registers of a coprocessor and send it commands. On the PlayStation they reach COP0 and COP2 (the GTE), since COP1 and COP3 do not exist.1415

Table 17: Coprocessor instructions
Instruction Encoding Operation
MFCn rt,rd 0100nn 00000 rt = data register rd
CFCn rt,rd 0100nn 00010 rt = control register rd
MTCn rt,rd 0100nn 00100 data register rd = rt
CTCn rt,rd 0100nn 00110 control register rd = rt
BCnF dest 0100nn 01000, rt=00000 Branch if the coprocessor flag is false
BCnT dest 0100nn 01000, rt=00001 Branch if the coprocessor flag is true
COPn imm25 0100nn 1 Execute coprocessor command imm25
LWCn rt,imm(rs) 1100nn Coprocessor data register rt = word at [rs+imm]
SWCn rt,imm(rs) 1110nn word at [rs+imm] = coprocessor data register rt
RFE 010000 1 0000, bits 0 to 5 = 010000 Return from exception (COP0)

COP0 accepts only the RFE command. The TLB commands TLBR, TLBWI, TLBWR and TLBP (COP0 commands 01h, 02h, 06h and 08h) cause a reserved instruction exception.1416

Coprocessor Load and Store Delays

A read from a coprocessor register has the same 1-instruction load delay as a read from memory. Some documents give the delay as two instructions, but the PlayStation completes both COP0 and COP2 reads after one.14

Writes to COP0 take effect at once, apart from the COP2 enable bit in SR bit 30, which takes about 2 cycles. Writes to COP2 registers take 2 to 3 cycles, the 3-cycle case being IRGB because it also changes IR1 to IR3. These delays are counted in clock cycles. A 3-cycle delay therefore needs 3 cached instructions or one uncached instruction.14

Pseudo Instructions

Assemblers provide pseudo instructions that expand to one or more real instructions. Some of them use R1 (AT) as a scratch register, so code that uses R1 must be sure its assembler does not change it behind its back. Sony's register table also reserves AT for the assembler, and C code may not use it.1718

Table 18: Pseudo instructions of the native assemblers
Pseudo instruction Expansion
nop sll r0,r0,0
move rd,rs addu rd,rs,r0
la rx,imm32 lui rx / addiu rx
li rx,imm32 lui rx / ori rx
li rx,imm16 ori, range 0 to FFFFh
li rx,-imm15 addiu, range -1 to -8000h
li rx,imm16 x 10000h lui
lw rx,imm32 lui rx / lw rx,rx
sw rx,imm32 lui r1 / sw rx,r1 (changes r1)
alu rx,op alu rx,rx,op
jalr rx jalr ra,rx
subi(u) rt,rs,imm addi(u) rt,rs,-imm
beqz rx,dest beq rx,r0,dest
bnez rx,dest bne rx,r0,dest
b dest beq r0,r0,dest
bal dest bgezal r0,dest

Stack Convention

The CPU has no stack instructions. By convention R29 (SP) is the stack pointer, and the compiler stores the head address of the function frame in FP.1920

The BIOS uses a full decrementing stack with wasted argument space. SP is decremented to allocate, and it points to the lowest allocated word. A caller that passes N arguments reserves N words at SP+0 upward, and the called function may use and destroy them. For example, a function that saves RA, R16 and R17 subtracts 20h from SP and stores RA at SP+14h, R16 at SP+18h and R17 at SP+1Ch. The 20h bytes are then used as follows:20

Table 19: Stack frame for saving three registers
Offset Use
SP+00h to 0Fh Wasted stack (may be used by called functions)
SP+10h to 13h 8-byte alignment padding
SP+14h to 1Fh Saved registers

References


  1. ^ a b c psx-spx. CPU Specifications, CPU Opcode Encoding. https://psx-spx.consoledev.net/cpuspecifications/

  2. ^ psx-spx. CPU Specifications, Illegal Opcodes. https://psx-spx.consoledev.net/cpuspecifications/

  3. ^ a b Sony Computer Entertainment Inc. PlayStation Hardware. August 1998. Page 2-5.

  4. ^ a b psx-spx. CPU Specifications, CPU Registers. https://psx-spx.consoledev.net/cpuspecifications/

  5. ^ a b psx-spx. CPU Specifications, CPU Load/Store Opcodes. https://psx-spx.consoledev.net/cpuspecifications/

  6. ^ a b psx-spx. CPU Specifications, Caution - Load Delay. https://psx-spx.consoledev.net/cpuspecifications/

  7. ^ psx-spx. CPU Specifications, Store instructions and Caution - 8/16-bit writes to certain IO registers. https://psx-spx.consoledev.net/cpuspecifications/

  8. ^ a b psx-spx. CPU Specifications, Unaligned Load/Store. https://psx-spx.consoledev.net/cpuspecifications/

  9. ^ a b c d psx-spx. CPU Specifications, CPU ALU Opcodes. https://psx-spx.consoledev.net/cpuspecifications/

  10. ^ a b c d e psx-spx. CPU Specifications, Multiply/divide. https://psx-spx.consoledev.net/cpuspecifications/

  11. ^ a b c psx-spx. CPU Specifications, CPU Jump Opcodes. https://psx-spx.consoledev.net/cpuspecifications/

  12. ^ a b psx-spx. CPU Specifications, JALR cautions. https://psx-spx.consoledev.net/cpuspecifications/

  13. ^ psx-spx. CPU Specifications, exception opcodes. https://psx-spx.consoledev.net/cpuspecifications/

  14. ^ a b c d psx-spx. CPU Specifications, CPU Coprocessor Opcodes. https://psx-spx.consoledev.net/cpuspecifications/

  15. ^ psx-spx. I/O Map, Coprocessor Registers. https://psx-spx.consoledev.net/iomap/

  16. ^ psx-spx. CPU Specifications, COP0 - Misc. https://psx-spx.consoledev.net/cpuspecifications/

  17. ^ psx-spx. CPU Specifications, CPU Pseudo Opcodes; Unpredictable Things, CPU Register Problems. https://psx-spx.consoledev.net/cpuspecifications/

  18. ^ Sony Computer Entertainment Inc. PlayStation Hardware. August 1998. Page 2-6.

  19. ^ Sony Computer Entertainment Inc. PlayStation Hardware. August 1998. Page 2-7.

  20. ^ a b psx-spx. CPU Specifications, R29 (SP) - Full Decrementing Wasted Stack Pointer. https://psx-spx.consoledev.net/cpuspecifications/

Categories: Hardware