diff --git a/core/chip8.go b/core/chip8.go index 17f706e..5ffede3 100644 --- a/core/chip8.go +++ b/core/chip8.go @@ -61,6 +61,8 @@ func (c8 *Chip8) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHei } func RunChip8(rom []byte, title string) { + Disassemble(rom) + c := cpu.NewCpu() c.LoadROM(rom) diff --git a/core/cpu/cpu.go b/core/cpu/cpu.go index f7ea0d2..8cd703c 100644 --- a/core/cpu/cpu.go +++ b/core/cpu/cpu.go @@ -94,14 +94,14 @@ func (cpu *CPU) clock() { opcode := cpu.decode(data) - switch opcode.instruction { + switch opcode.Instruction { case 0x0000: - if opcode.registerY == 0xC { - cpu.scd(opcode.n) + if opcode.RegisterY == 0xC { + cpu.scd(opcode.N) return } - switch opcode.nnn { + switch opcode.NNN { case 0x0E0: cpu.cls() @@ -124,91 +124,91 @@ func (cpu *CPU) clock() { cpu.ext() default: - cpu.jp(opcode.nnn, 0) + cpu.jp(opcode.NNN, 0) } case 0x1000: - cpu.jp(opcode.nnn, 0) + cpu.jp(opcode.NNN, 0) case 0x2000: - cpu.call(opcode.nnn) + cpu.call(opcode.NNN) case 0x3000: - cpu.skp(cpu.v[opcode.registerX] == opcode.nn) + cpu.skp(cpu.v[opcode.RegisterX] == opcode.NN) case 0x4000: - cpu.skp(cpu.v[opcode.registerX] != opcode.nn) + cpu.skp(cpu.v[opcode.RegisterX] != opcode.NN) case 0x5000: - cpu.skp(cpu.v[opcode.registerX] == cpu.v[opcode.registerY]) + cpu.skp(cpu.v[opcode.RegisterX] == cpu.v[opcode.RegisterY]) case 0x6000: - cpu.ld(opcode.registerX, opcode.nn) + cpu.ld(opcode.RegisterX, opcode.NN) case 0x7000: - cpu.add(opcode.registerX, opcode.nn, false) + cpu.add(opcode.RegisterX, opcode.NN, false) case 0x8000: - switch opcode.n { + switch opcode.N { case 0x0: - cpu.ld(opcode.registerX, cpu.v[opcode.registerY]) + cpu.ld(opcode.RegisterX, cpu.v[opcode.RegisterY]) case 0x1: - cpu.or(opcode.registerX, cpu.v[opcode.registerY]) + cpu.or(opcode.RegisterX, cpu.v[opcode.RegisterY]) case 0x2: - cpu.and(opcode.registerX, cpu.v[opcode.registerY]) + cpu.and(opcode.RegisterX, cpu.v[opcode.RegisterY]) case 0x3: - cpu.xor(opcode.registerX, cpu.v[opcode.registerY]) + cpu.xor(opcode.RegisterX, cpu.v[opcode.RegisterY]) case 0x4: - cpu.add(opcode.registerX, cpu.v[opcode.registerY], true) + cpu.add(opcode.RegisterX, cpu.v[opcode.RegisterY], true) case 0x5: - cpu.sub(opcode.registerX, cpu.v[opcode.registerX], cpu.v[opcode.registerY]) + cpu.sub(opcode.RegisterX, cpu.v[opcode.RegisterX], cpu.v[opcode.RegisterY]) case 0x6: - cpu.shr(opcode.registerX) + cpu.shr(opcode.RegisterX) case 0x7: - cpu.sub(opcode.registerX, cpu.v[opcode.registerY], cpu.v[opcode.registerX]) + cpu.sub(opcode.RegisterX, cpu.v[opcode.RegisterY], cpu.v[opcode.RegisterX]) case 0xE: - cpu.shl(opcode.registerX) + cpu.shl(opcode.RegisterX) } case 0x9000: - cpu.skp(cpu.v[opcode.registerX] != cpu.v[opcode.registerY]) + cpu.skp(cpu.v[opcode.RegisterX] != cpu.v[opcode.RegisterY]) case 0xA000: - cpu.ldi(opcode.nnn) + cpu.ldi(opcode.NNN) case 0xB000: - cpu.jp(opcode.nnn, cpu.v[0x0]) + cpu.jp(opcode.NNN, cpu.v[0x0]) case 0xC000: - cpu.rnd(opcode.registerX, opcode.nn) + cpu.rnd(opcode.RegisterX, opcode.NN) case 0xD000: - switch opcode.n { + switch opcode.N { case 0x0: cpu.schip_drw(opcode) default: cpu.drw(opcode) } case 0xE000: - switch opcode.nn { + switch opcode.NN { case 0x9E: - cpu.skp(cpu.Keys[cpu.v[opcode.registerX]] == 0x01) + cpu.skp(cpu.Keys[cpu.v[opcode.RegisterX]] == 0x01) case 0xA1: - cpu.skp(cpu.Keys[cpu.v[opcode.registerX]] == 0x00) + cpu.skp(cpu.Keys[cpu.v[opcode.RegisterX]] == 0x00) } case 0xF000: - switch opcode.nn { + switch opcode.NN { case 0x07: - cpu.ld(opcode.registerX, cpu.delayTimer) + cpu.ld(opcode.RegisterX, cpu.delayTimer) case 0x15: - cpu.ldt(cpu.v[opcode.registerX]) + cpu.ldt(cpu.v[opcode.RegisterX]) case 0x18: - cpu.lds(cpu.v[opcode.registerX]) + cpu.lds(cpu.v[opcode.RegisterX]) case 0x0A: - cpu.ldk(opcode.registerX) + cpu.ldk(opcode.RegisterX) case 0x1E: - cpu.adi(uint16(cpu.v[opcode.registerX])) + cpu.adi(uint16(cpu.v[opcode.RegisterX])) case 0x29: - cpu.ldi(0x050 + 5*uint16(cpu.v[opcode.registerX])) + cpu.ldi(0x050 + 5*uint16(cpu.v[opcode.RegisterX])) case 0x30: - cpu.ldi(0x0A0 + 10*uint16(cpu.v[opcode.registerX])) + cpu.ldi(0x0A0 + 10*uint16(cpu.v[opcode.RegisterX])) case 0x33: - cpu.bcd(cpu.v[opcode.registerX]) + cpu.bcd(cpu.v[opcode.RegisterX]) case 0x55: - cpu.stm(opcode.registerX) + cpu.stm(opcode.RegisterX) case 0x65: - cpu.ldm(opcode.registerX) + cpu.ldm(opcode.RegisterX) case 0x75: - cpu.srpl(opcode.registerX) + cpu.srpl(opcode.RegisterX) case 0x85: - cpu.lrpl(opcode.registerX) + cpu.lrpl(opcode.RegisterX) } } } @@ -346,11 +346,11 @@ func (cpu *CPU) ldm(vIndex uint8) { } func (cpu *CPU) drw(oc *opcode) { - x := cpu.v[oc.registerX] & (byte(cpu.Graphics.Width - 1)) - y := cpu.v[oc.registerY] & (byte(cpu.Graphics.Height - 1)) + x := cpu.v[oc.RegisterX] & (byte(cpu.Graphics.Width - 1)) + y := cpu.v[oc.RegisterY] & (byte(cpu.Graphics.Height - 1)) cpu.v[0xF] = 0x00 - for i := 0; uint8(i) < oc.n; i++ { + for i := 0; uint8(i) < oc.N; i++ { addr := uint16(i) + cpu.i pixels := byte(cpu.mmu.Fetch(addr) >> 8) xIndex := x @@ -418,8 +418,8 @@ func (cpu *CPU) lrpl(x uint8) { } func (cpu *CPU) schip_drw(oc *opcode) { - x := cpu.v[oc.registerX] & (byte(cpu.Graphics.Width - 1)) - y := cpu.v[oc.registerY] & (byte(cpu.Graphics.Height - 1)) + x := cpu.v[oc.RegisterX] & (byte(cpu.Graphics.Width - 1)) + y := cpu.v[oc.RegisterY] & (byte(cpu.Graphics.Height - 1)) cpu.v[0xF] = 0x00 n := 16 diff --git a/core/cpu/opcode.go b/core/cpu/opcode.go index 74eb65c..8c9988e 100644 --- a/core/cpu/opcode.go +++ b/core/cpu/opcode.go @@ -10,21 +10,21 @@ const ( ) type opcode struct { - instruction uint16 - registerX uint8 - registerY uint8 - n uint8 - nn uint8 - nnn uint16 + Instruction uint16 + RegisterX uint8 + RegisterY uint8 + N uint8 + NN uint8 + NNN uint16 } func NewOpcode(data uint16) *opcode { return &opcode{ - instruction: data & INSTRUCTION_BITMASK, - registerX: uint8((data & X_BITMASK) >> 8), - registerY: uint8((data & Y_BITMASK) >> 4), - n: uint8(data & N_BITMASK), - nn: uint8(data & NN_BITMASK), - nnn: (data & NNN_BITMASK), + Instruction: data & INSTRUCTION_BITMASK, + RegisterX: uint8((data & X_BITMASK) >> 8), + RegisterY: uint8((data & Y_BITMASK) >> 4), + N: uint8(data & N_BITMASK), + NN: uint8(data & NN_BITMASK), + NNN: (data & NNN_BITMASK), } } diff --git a/core/cpu/opcode_test.go b/core/cpu/opcode_test.go index c063483..3dbad12 100644 --- a/core/cpu/opcode_test.go +++ b/core/cpu/opcode_test.go @@ -9,32 +9,32 @@ func TestDecode(t *testing.T) { var expected uint16 = 0xA000 - if opcode.instruction != expected { - t.Errorf("opcode.instruction = 0x%X; expected 0x%X", opcode.instruction, expected) + if opcode.Instruction != expected { + t.Errorf("opcode.Instruction = 0x%X; expected 0x%X", opcode.Instruction, expected) } expected = 0xB - if opcode.registerX != uint8(expected) { - t.Errorf("opcode.registerX = 0x%X; expected 0x%X", opcode.registerX, expected) + if opcode.RegisterX != uint8(expected) { + t.Errorf("opcode.RegisterX = 0x%X; expected 0x%X", opcode.RegisterX, expected) } expected = 0xC - if opcode.registerY != uint8(expected) { - t.Errorf("opcode.registerY = 0x%X; expected 0x%X", opcode.registerY, expected) + if opcode.RegisterY != uint8(expected) { + t.Errorf("opcode.RegisterY = 0x%X; expected 0x%X", opcode.RegisterY, expected) } expected = 0xD - if opcode.n != uint8(expected) { - t.Errorf("opcode.n = 0x%X; expected 0x%X", opcode.n, expected) + if opcode.N != uint8(expected) { + t.Errorf("opcode.N = 0x%X; expected 0x%X", opcode.N, expected) } expected = 0xCD - if opcode.nn != uint8(expected) { - t.Errorf("opcode.n = 0x%X; expected 0x%X", opcode.nn, expected) + if opcode.NN != uint8(expected) { + t.Errorf("opcode.NN = 0x%X; expected 0x%X", opcode.NN, expected) } expected = 0xBCD - if opcode.nnn != expected { - t.Errorf("opcode.n = 0x%X; expected 0x%X", opcode.nnn, expected) + if opcode.NNN != expected { + t.Errorf("opcode.NNN = 0x%X; expected 0x%X", opcode.NNN, expected) } } diff --git a/core/disassembler.go b/core/disassembler.go new file mode 100644 index 0000000..9b697ef --- /dev/null +++ b/core/disassembler.go @@ -0,0 +1,138 @@ +package core + +import ( + "fmt" + + "github.com/gaoliveira21/chip8/core/cpu" +) + +func Disassemble(bytes []byte) { + fmt.Printf("|Bytes |Op |Nemonic\n") + + for i := 0; i < len(bytes); i += 2 { + hb := uint16(bytes[i]) + lb := uint16(bytes[i+1]) + + instruction := (hb << 8) | lb + + opcode := cpu.NewOpcode(instruction) + + switch opcode.Instruction { + case 0x0000: + if opcode.RegisterY == 0xC { + fmt.Printf("0x%.4X - 00CN (SCROLL-DOWN N)\n", instruction) + return + } + + switch opcode.NNN { + case 0x0E0: + fmt.Printf("0x%.4X - 00E0 CLS\n", instruction) + + case 0x0EE: + fmt.Printf("0x%.4X - 00EE RET\n", instruction) + + case 0x0FE: + fmt.Printf("0x%.4X - 00FE (LORES)\n", instruction) + + case 0x0FF: + fmt.Printf("0x%.4X - 00FF (HIRES)\n", instruction) + + case 0x0FB: + fmt.Printf("0x%.4X - 00FB (SCROLL-RIGHT)\n", instruction) + + case 0x0FC: + fmt.Printf("0x%.4X - 00FC (SCROLL-LEFT)\n", instruction) + + case 0x0FD: + fmt.Printf("0x%.4X - 00FD (EXIT)\n", instruction) + + default: + fmt.Printf("0x%.4X - 0NNN JP addr\n", instruction) + } + case 0x1000: + fmt.Printf("0x%.4X - 1NNN JP addr\n", instruction) + case 0x2000: + fmt.Printf("0x%.4X - 2NNN CALL addr\n", instruction) + case 0x3000: + fmt.Printf("0x%.4X - 3XKK SE Vx, byte\n", instruction) + case 0x4000: + fmt.Printf("0x%.4X - 4XKK SNE Vx, byte\n", instruction) + case 0x5000: + fmt.Printf("0x%.4X - 5XY0 SE Vx, Vy\n", instruction) + case 0x6000: + fmt.Printf("0x%.4X - 6XKK LD Vx, byte\n", instruction) + case 0x7000: + fmt.Printf("0x%.4X - 7XKK ADD Vx, byte\n", instruction) + case 0x8000: + switch opcode.N { + case 0x0: + fmt.Printf("0x%.4X - 8XY0 LD Vx, Vy\n", instruction) + case 0x1: + fmt.Printf("0x%.4X - 8XY1 OR Vx, Vy\n", instruction) + case 0x2: + fmt.Printf("0x%.4X - 8XY2 AND Vx, Vy\n", instruction) + case 0x3: + fmt.Printf("0x%.4X - 8XY3 XOR Vx, Vy\n", instruction) + case 0x4: + fmt.Printf("0x%.4X - 8XY4 ADD Vx, Vy\n", instruction) + case 0x5: + fmt.Printf("0x%.4X - 8XY5 SUB Vx, Vy\n", instruction) + case 0x6: + fmt.Printf("0x%.4X - 8XY6 SHR Vx {, Vy}\n", instruction) + case 0x7: + fmt.Printf("0x%.4X - 8XY7 SUBN Vx, Vy\n", instruction) + case 0xE: + fmt.Printf("0x%.4X - 8XYE SHL Vx {, Vy}\n", instruction) + } + case 0x9000: + fmt.Printf("0x%.4X - 9XY0 SNE Vx, Vy\n", instruction) + case 0xA000: + fmt.Printf("0x%.4X - ANNN LD I, addr\n", instruction) + case 0xB000: + fmt.Printf("0x%.4X - BNNN JP V0, addr\n", instruction) + case 0xC000: + fmt.Printf("0x%.4X - CXKK RND Vx, byte\n", instruction) + case 0xD000: + switch opcode.N { + case 0x0: + fmt.Printf("0x%.4X - DXY0 (SPRITE Vx Vy 0)\n", instruction) + default: + fmt.Printf("0x%.4X - DXYN DRW Vx, Vy, nibble\n", instruction) + } + case 0xE000: + switch opcode.NN { + case 0x9E: + fmt.Printf("0x%.4X - EX9E SKP Vx\n", instruction) + case 0xA1: + fmt.Printf("0x%.4X - EXA1 SKNP Vx\n", instruction) + } + case 0xF000: + switch opcode.NN { + case 0x07: + fmt.Printf("0x%.4X - FX07 LD Vx, DT\n", instruction) + case 0x15: + fmt.Printf("0x%.4X - FX15 LD DT, Vx\n", instruction) + case 0x18: + fmt.Printf("0x%.4X - FX18 LD ST, Vx\n", instruction) + case 0x0A: + fmt.Printf("0x%.4X - FX0A LD Vx, K\n", instruction) + case 0x1E: + fmt.Printf("0x%.4X - FX1E ADD I, Vx\n", instruction) + case 0x29: + fmt.Printf("0x%.4X - FX29 LD F, Vx\n", instruction) + case 0x30: + fmt.Printf("0x%.4X - FX30 (i := BIGHEX Vx)\n", instruction) + case 0x33: + fmt.Printf("0x%.4X - FX33 LD B, Vx\n", instruction) + case 0x55: + fmt.Printf("0x%.4X - FX55 LD [I], Vx\n", instruction) + case 0x65: + fmt.Printf("0x%.4X - FX65 LD Vx, [I]\n", instruction) + case 0x75: + fmt.Printf("0x%.4X - FX75 (SAVE FLAGS Vx)\n", instruction) + case 0x85: + fmt.Printf("0x%.4X - FX85 (LOAD FLAGS Vx)\n", instruction) + } + } + } +}