From ead5f8c3700d0dfa771f04e713808ba160fa2343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20H=C3=BCbner?= Date: Mon, 1 Oct 2018 00:11:30 +0200 Subject: [PATCH] assembly/disassembly stuff --- source/app.d | 199 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 194 insertions(+), 5 deletions(-) diff --git a/source/app.d b/source/app.d index d64fa55..3112430 100644 --- a/source/app.d +++ b/source/app.d @@ -346,12 +346,181 @@ struct PixelBuffer { } // PixelBuffer +struct Assembler { + + enum OpCode { + + CLS, // CLS + + RET, // RET + CALL, // CALL addr + + ADD, // ADD Vx, Vy + // ADD Vx, byte + // ADD I, Vx + SUB, // SUB Vx, Vy + // SUB Vx, byte + SUBN, // SUBN Vx, Vy + + SE, // SE Vx, Vy + // SE Vx, byte + SNE, // SNE Vx, byte + SKP, // SKP Vx + SKNP, // SKNP Vx + + SHL, // SHL Vx {, Vy} + SHR, // SHR Vx {, Vy} + XOR, // XOR Vx, Vy + AND, // AND Vx, Vy + OR, // OR Vx, Vy + + LD, // LD Vx, DT + // LD DT, Vx + // LD ST, Vx + // LD Vx, K + // LD [I], Vx + // LD Vx, [I] + + RND // RND Vx, byte + + } + + enum Parameter { + + Vx, + Vy, + + DT, + ST, + K, + + addr, + val + + } + + struct Instruction { + + } + + import std.array; + + Appender!string dissassembly_data; + + void assemble(const char* input) { + + } // assemble + + void assemble(const char[] input) { + + } // assemble + + const (char)[] disassemble(ubyte[] instructions) { + + import std.range : chunks; + + foreach (ref ubyte[] i; instructions.chunks(2)) { + + ushort opcode = (*(cast(ushort*)(i.ptr))); + + switch (opcode & 0xF000) { + case 0x0000: + switch (opcode & 0x0FFF) { + case 0x00E0: // 0x00E0 Clears the screen. + + case 0x00EE: // 0x00EE Returns from a subroutine. + default: // 0x0NNN Calls RCA 1802 program at address NNN. Not necessary for most ROMs. + //assert(0, "0x0NNN RCA 1802 program opcode not implemented!"); + break; + } + break; + case 0x1000: // 0x1NNN Jumps to address NNN. + case 0x2000: // 0x2NNN Calls subroutine at NNN. + case 0x3000: // 0x3XNN Skips the next instruction if VX equals NN. + case 0x4000: // 0x4XNN Skips the next instruction if VX doesn't equal NN. + case 0x5000: // 0x5XYO Skips the next instruction if VX equals VY. + case 0x6000: // 0x6XNN Sets VX to NN. + case 0x7000: // 0x7XNN Adds NN to VX. + case 0x8000: + switch (opcode) { + + case 0x0000: // 0x8XY0 Sets VX to the value of VY. + case 0x0001: // 0x8XY1 Sets VX to VX or VY. + case 0x0002: // 0x8XY2 Sets VX to VX and VY. + case 0x0003: // 0x8XY3 Sets VX to VX xor VY. + case 0x0004: // 0x8XY4 Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't. + case 0x0005: // 0x8XY5 VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't. + case 0x0006: // 0x8XY6 Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift. + case 0x0007: // 0x8XY7 Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't. + case 0x000E: // 0x8XYE Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift. + default: // unhandled for some reason + writefln("unknown opcode: 0x%x", opcode); + break; + + } + + break; + + case 0x9000: // 0x9XYO Skips the next instruction if VX doesn't equal VY. + case 0xA000: // 0xANNN Sets I to the address NNN. + case 0xB000: // 0xBNNN Jumps to the address NNN plus V0. + case 0xC000: // 0xCXNN Sets VX to the result of a bitwise and operation on a random number and NN. + + // 0xDXYN + // Sprites stored in memory at location in index register (I), 8bits wide. + // Wraps around the screen. If when drawn, clears a pixel, register VF is set to 1 otherwise it is zero. + // All drawing is XOR drawing (i.e. it toggles the screen pixels). + // Sprites are drawn starting at position VX, VY. N is the number of 8bit rows that need to be drawn. + // If N is greater than 1, second line continues at position VX, VY+1, and so on. + case 0xD000: + case 0xE000: + switch (opcode & 0x000F) { + case 0x000E: // 0xEX9E Skips the next instruction if the key stored in VX is pressed. + case 0x0001: // 0xEXA1 Skips the next instruction if the key stored in VX isn't pressed. + default: //unhandled for some reason + writefln("unknown opcode: 0x%x", opcode); + break; + } + break; + case 0xF000: + switch (opcode & 0x00FF) { + case 0x0007: // 0xFX07 Sets VX to the value of the delay timer. + case 0x000A: // 0xFX0A A key press is awaited, and then stored in VX. + case 0x0015: // 0xFX15 Sets the delay timer to VX. + case 0x0018: // 0xFX18 Sets the sound timer to VX. + case 0x001E: // 0xFX1E Adds VX to I. + case 0x0029: // 0xFX29 Sets I to the location of the sprite for the character in VX. + // 0xFX33 Stores the Binary-coded decimal representation of VX, + // with the most significant of three digits at the address in I, + // the middle digit at I plus 1, and the least significant digit at I plus 2. + case 0x0033: + case 0x0055: // 0xFX55 Stores V0 to VX in memory starting at address I. + case 0x0065: // 0xFX65 Fills V0 to VX with values from memory starting at address I. + default: // unhandled for some reason + writefln("unknown opcode: 0x%x", opcode); + break; + } + break; + default: + writefln("unknown opcode: 0x%x", opcode); + } + } + + return ""; + + } // dissassemble + +} // Assembler + struct Chip8Status { - //emu ptr + // emu ptr Emulator* run_; Chip8* emu_; + // loaded program + const (char)* loaded_program; + // mem editor // MemoryEditor mem_editor_; @@ -389,6 +558,8 @@ struct Chip8Status { void resetShortcut() { + loaded_program = null; + emu_.reset(); } // resetShortcut @@ -397,6 +568,7 @@ struct Chip8Status { import std.file : read; + loaded_program = "chip8_picture.ch8"; auto buf = read("programs/chip8_picture.ch8"); emu_.load(0x200, buf); // do ze load yes, will copy all the data in @@ -463,14 +635,19 @@ struct Chip8Status { igBegin("Emulator Status"); igBeginChild("General"); - igText("OpCode: 0x%04X", emu_.cpu.opcode); - igText("PC:"); + if (!loaded_program) { + igText("Loaded Program: none"); + } else { + igText("Loaded Program: %s", loaded_program); + } + igText("Opcode: 0x%04X", emu_.cpu.opcode); igSameLine(); - igText("pc: 0x%04X (%hu)", emu_.cpu.pc, emu_.cpu.pc); + igText("| PC: 0x%04X (%hu)", emu_.cpu.pc, emu_.cpu.pc); // igDragInt("##pc", cast(int*)&emu_.cpu.pc, 0.5f, 0, emu_.ram.length); igText("Registers (v0 - vF)"); igColumns(4, null, false); + igIndent(); auto n = 0; foreach (ref chunk; emu_.cpu.v[].chunks(4)) { @@ -483,12 +660,24 @@ struct Chip8Status { } igColumns(1, null, false); + igUnindent(); igText("Index Register: 0x%04X", emu_.cpu.i); igText("Delay Timer: 0x%04X", emu_.cpu.delay_timer); igText("Sound Timer: 0x%04X", emu_.cpu.sound_timer); - if(igButton("Step")) { + if (igButton("Reload")) { + resetShortcut(); + loadShortcut(); + } + + igSameLine(); + + if (igButton("Reset")) { + resetShortcut(); + } + + if (igButton("Step")) { emu_.step(); }