aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpu/cpu.go12
-rw-r--r--cpu/instructions.go5
-rw-r--r--cpu/opcodes.go13
-rw-r--r--tests/cpu_test.go36
4 files changed, 65 insertions, 1 deletions
diff --git a/cpu/cpu.go b/cpu/cpu.go
index 79199a2..fb673b7 100644
--- a/cpu/cpu.go
+++ b/cpu/cpu.go
@@ -16,6 +16,7 @@ type CPU struct {
Bus Bus
Cycles uint64
+ Jammed bool
extraCycles int
}
@@ -65,9 +66,13 @@ func (c *CPU) Reset() {
c.Status = FlagU | FlagI
c.PC = c.read16(vectorReset)
c.Cycles = 7
+ c.Jammed = false
}
func (c *CPU) IRQ() {
+ if c.Jammed {
+ return
+ }
if c.flag(FlagI) {
return
}
@@ -76,6 +81,9 @@ func (c *CPU) IRQ() {
}
func (c *CPU) NMI() {
+ if c.Jammed {
+ return
+ }
c.interrupt(vectorNMI, false)
c.Cycles += 7
}
@@ -94,6 +102,10 @@ func (c *CPU) interrupt(vector uint16, brk bool) {
}
func (c *CPU) Step() int {
+ if c.Jammed {
+ c.Cycles++
+ return 1
+ }
before := c.Cycles
opcode := c.read(c.PC)
diff --git a/cpu/instructions.go b/cpu/instructions.go
index b390f5c..b74a2db 100644
--- a/cpu/instructions.go
+++ b/cpu/instructions.go
@@ -221,3 +221,8 @@ func iscExec(c *CPU, op operand) {
c.writeOperand(op, v)
c.addWithCarry(^v)
}
+
+func jamExec(c *CPU, op operand) {
+ c.Jammed = true
+ c.PC--
+}
diff --git a/cpu/opcodes.go b/cpu/opcodes.go
index 00b1563..13f9612 100644
--- a/cpu/opcodes.go
+++ b/cpu/opcodes.go
@@ -235,6 +235,19 @@ func init() {
def(0xDC, "NOP", ModeAbsoluteX, 4, true, nopExec)
def(0xFC, "NOP", ModeAbsoluteX, 4, true, nopExec)
+ def(0x02, "JAM", ModeImplied, 2, false, jamExec)
+ def(0x12, "JAM", ModeImplied, 2, false, jamExec)
+ def(0x22, "JAM", ModeImplied, 2, false, jamExec)
+ def(0x32, "JAM", ModeImplied, 2, false, jamExec)
+ def(0x42, "JAM", ModeImplied, 2, false, jamExec)
+ def(0x52, "JAM", ModeImplied, 2, false, jamExec)
+ def(0x62, "JAM", ModeImplied, 2, false, jamExec)
+ def(0x72, "JAM", ModeImplied, 2, false, jamExec)
+ def(0x92, "JAM", ModeImplied, 2, false, jamExec)
+ def(0xB2, "JAM", ModeImplied, 2, false, jamExec)
+ def(0xD2, "JAM", ModeImplied, 2, false, jamExec)
+ def(0xF2, "JAM", ModeImplied, 2, false, jamExec)
+
def(0xEB, "SBC", ModeImmediate, 2, false, sbcExec)
def(0xA7, "LAX", ModeZeroPage, 3, false, laxExec)
diff --git a/tests/cpu_test.go b/tests/cpu_test.go
index 87743b1..269f9ee 100644
--- a/tests/cpu_test.go
+++ b/tests/cpu_test.go
@@ -232,6 +232,40 @@ func TestUnimplementedOpcodePanics(t *testing.T) {
t.Fatalf("expected panic for illegal opcode")
}
}()
- c, _ := newTestCPU([]uint8{0x02})
+ c, _ := newTestCPU([]uint8{0x8B})
c.Step()
}
+
+func TestJamStopsCPU(t *testing.T) {
+ c, _ := newTestCPU([]uint8{0xA9, 0x42, 0x02, 0xEA})
+ c.Step()
+ c.Step()
+ if !c.Jammed {
+ t.Fatal("Jammed = false, want true")
+ }
+ if c.PC != 0x8002 {
+ t.Fatalf("PC = 0x%04X, want 0x8002", c.PC)
+ }
+ for i := 0; i < 3; i++ {
+ if cycles := c.Step(); cycles != 1 {
+ t.Fatalf("cycles = %d, want 1", cycles)
+ }
+ }
+ if c.PC != 0x8002 || c.A != 0x42 {
+ t.Fatalf("PC = 0x%04X, A = 0x%02X; want 0x8002, 0x42", c.PC, c.A)
+ }
+}
+
+func TestJammedIgnoresInterruptsUntilReset(t *testing.T) {
+ c, bus := newTestCPU([]uint8{0x02})
+ bus.mem[0xFFFA], bus.mem[0xFFFB] = 0x00, 0x90
+ c.Step()
+ c.NMI()
+ if c.PC != 0x8000 {
+ t.Fatalf("PC after NMI = 0x%04X, want 0x8000", c.PC)
+ }
+ c.Reset()
+ if c.Jammed {
+ t.Fatal("Jammed = true after Reset, want false")
+ }
+}