Class: PSX::COP0

Inherits:
Object
  • Object
show all
Defined in:
lib/psx/cop0.rb

Overview

Coprocessor 0 - System Control Handles exceptions, interrupts, and memory management

Constant Summary collapse

BPC =

Register indices

3
BDA =

Breakpoint on execute

5
JUMPDEST =

Breakpoint on data access

6
DCIC =

Jump destination (for branch delay debugging)

7
BADVADDR =

Breakpoint control

8
BDAM =

Bad virtual address

9
BPCM =

Data access breakpoint mask

11
SR =

Execute breakpoint mask

12
CAUSE =

Status register

13
EPC =

Exception cause

14
PRID =

Exception program counter

15
SR_IEC =

Status register bits

0x01
SR_KUC =

Interrupt Enable Current

0x02
SR_IEP =

Kernel/User Mode Current (0=kernel)

0x04
SR_KUP =

Interrupt Enable Previous

0x08
SR_IEO =

Kernel/User Mode Previous

0x10
SR_KUO =

Interrupt Enable Old

0x20
SR_IM =

Kernel/User Mode Old

0xFF00
SR_ISC =

Interrupt Mask (bits 8-15)

0x1_0000
SR_SWC =

Isolate Cache

0x2_0000
SR_PZ =

Swap Caches

0x4_0000
SR_CM =

Parity Zero

0x8_0000
SR_PE =

Cache Miss

0x10_0000
SR_TS =

Parity Error

0x20_0000
SR_BEV =

TLB Shutdown

0x40_0000
SR_RE =

Boot Exception Vectors

0x200_0000
SR_CU0 =

Reverse Endianness

0x1000_0000
SR_CU1 =

COP0 Enable

0x2000_0000
SR_CU2 =

COP1 Enable (no FPU on PSX, but enable bit exists)

0x4000_0000
SR_CU3 =

COP2 (GTE) Enable

0x8000_0000
EXC_INT =

Exception codes (for CAUSE register bits 2-6)

0x00
EXC_MOD =

Interrupt

0x01
EXC_TLBL =

TLB modification

0x02
EXC_TLBS =

TLB load

0x03
EXC_ADEL =

TLB store

0x04
EXC_ADES =

Address error (load/fetch)

0x05
EXC_IBE =

Address error (store)

0x06
EXC_DBE =

Bus error (instruction fetch)

0x07
EXC_SYS =

Bus error (data load/store)

0x08
EXC_BP =

Syscall

0x09
EXC_RI =

Breakpoint

0x0A
EXC_CPU =

Reserved instruction

0x0B
EXC_OV =

Coprocessor unusable

0x0C
IRQ_SOFTWARE0 =

Interrupt bits in CAUSE (bits 8-15, matches SR mask)

0x0100
IRQ_SOFTWARE1 =
0x0200
IRQ_HARDWARE =

External hardware interrupt (active when I_STAT & I_MASK != 0)

0x0400

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCOP0

Returns a new instance of COP0.



63
64
65
66
# File 'lib/psx/cop0.rb', line 63

def initialize
  @regs = Array.new(32, 0)
  @regs[PRID] = 0x0000_0002  # R3000A processor ID
end

Instance Attribute Details

#regsObject (readonly)

Returns the value of attribute regs.



61
62
63
# File 'lib/psx/cop0.rb', line 61

def regs
  @regs
end

Instance Method Details

#bev?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/psx/cop0.rb', line 107

def bev?
  (@regs[SR] & SR_BEV) != 0
end

#cache_isolated?Boolean

Returns:

  • (Boolean)


103
104
105
# File 'lib/psx/cop0.rb', line 103

def cache_isolated?
  (@regs[SR] & SR_ISC) != 0
end

#causeObject



95
96
97
# File 'lib/psx/cop0.rb', line 95

def cause
  @regs[CAUSE]
end

#enter_exception(code, pc, in_delay_slot: false, bad_addr: nil, coprocessor: nil) ⇒ Object

Enter exception handler. Returns the exception vector address. ‘coprocessor` is the COP number (0-3) reported in CAUSE.CE for Coprocessor-Unusable exceptions.



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/psx/cop0.rb', line 135

def enter_exception(code, pc, in_delay_slot: false, bad_addr: nil, coprocessor: nil)
  @regs[EPC] = in_delay_slot ? pc - 4 : pc
  @regs[BADVADDR] = bad_addr if bad_addr

  # CAUSE: preserve interrupt-pending bits, set ExcCode, BD, and CE.
  ce = coprocessor ? ((coprocessor & 0x3) << 28) : 0
  @regs[CAUSE] = (@regs[CAUSE] & 0x0000_FF00) |
                 (code << 2) |
                 ce |
                 (in_delay_slot ? 0x8000_0000 : 0)

  # Shift IE/KU stack: current -> previous -> old.
  mode = @regs[SR] & 0x3F
  @regs[SR] = (@regs[SR] & ~0x3F) | ((mode << 2) & 0x3F)

  bev? ? 0xBFC0_0180 : 0x8000_0080
end

#epcObject



99
100
101
# File 'lib/psx/cop0.rb', line 99

def epc
  @regs[EPC]
end

#interrupt_pending?Boolean

Returns:

  • (Boolean)


115
116
117
118
119
120
121
122
# File 'lib/psx/cop0.rb', line 115

def interrupt_pending?
  # Check if any unmasked interrupt is pending
  return false unless interrupts_enabled?

  mask = (@regs[SR] >> 8) & 0xFF
  pending = (@regs[CAUSE] >> 8) & 0xFF
  (mask & pending) != 0
end

#interrupts_enabled?Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/psx/cop0.rb', line 111

def interrupts_enabled?
  (@regs[SR] & SR_IEC) != 0
end

#read(reg) ⇒ Object



68
69
70
# File 'lib/psx/cop0.rb', line 68

def read(reg)
  @regs[reg]
end

#return_from_exceptionObject

Return from exception (RFE instruction)



154
155
156
157
158
159
# File 'lib/psx/cop0.rb', line 154

def return_from_exception
  # Shift interrupt enable/kernel mode bits back
  # Old -> Previous -> Current
  mode = @regs[SR] & 0x3F
  @regs[SR] = (@regs[SR] & ~0x0F) | ((mode >> 2) & 0x0F)
end

#set_hardware_irq(active) ⇒ Object



124
125
126
127
128
129
130
# File 'lib/psx/cop0.rb', line 124

def set_hardware_irq(active)
  if active
    @regs[CAUSE] |= IRQ_HARDWARE
  else
    @regs[CAUSE] &= ~IRQ_HARDWARE
  end
end

#srObject



87
88
89
# File 'lib/psx/cop0.rb', line 87

def sr
  @regs[SR]
end

#sr=(value) ⇒ Object



91
92
93
# File 'lib/psx/cop0.rb', line 91

def sr=(value)
  write(SR, value)
end

#write(reg, value) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/psx/cop0.rb', line 72

def write(reg, value)
  case reg
  when SR
    # Most bits are writable
    @regs[SR] = value & 0xF4C7_9C3F
  when CAUSE
    # Only software interrupt bits (8-9) are writable
    @regs[CAUSE] = (value & 0x0300) | (@regs[CAUSE] & ~0x0300)
  when PRID
    # Read-only
  else
    @regs[reg] = value
  end
end