Compare commits
3 Commits
d0b7670eca
...
a35c316800
Author | SHA1 | Date |
---|---|---|
Robin Hübner | a35c316800 | |
Robin Hübner | 31d3f9f31e | |
Robin Hübner | ead5f8c370 |
232
source/app.d
232
source/app.d
|
@ -346,12 +346,218 @@ struct PixelBuffer {
|
||||||
|
|
||||||
} // PixelBuffer
|
} // PixelBuffer
|
||||||
|
|
||||||
|
struct Assembler {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Instruction Glossary:
|
||||||
|
0x0nnn - SYS addr
|
||||||
|
0x00E0 - CLS
|
||||||
|
0x00EE - RET
|
||||||
|
0x1nnn - JP addr
|
||||||
|
0x2nnn - CALL addr
|
||||||
|
0x3xkk - SE Vx, byte
|
||||||
|
0x4xkk - SNE Vx, byte
|
||||||
|
0x5xy0 - SE Vx, Vy
|
||||||
|
0x6xkk - LD Vx, byte
|
||||||
|
0x7xkk - ADD Vx, byte
|
||||||
|
0x8xy0 - LD Vx, Vy
|
||||||
|
0x8xy1 - OR Vx, Vy
|
||||||
|
0x8xy2 - AND Vx, Vy
|
||||||
|
0x8xy3 - XOR Vx, Vy
|
||||||
|
0x8xy4 - ADD Vx, Vy
|
||||||
|
0x8xy5 - SUB Vx, Vy
|
||||||
|
0x8xy6 - SHR Vx {, Vy}
|
||||||
|
0x8xy7 - SUBN Vx, Vy
|
||||||
|
0x8xyE - SHL Vx {, Vy}
|
||||||
|
0x9xy0 - SNE Vx, Vy
|
||||||
|
0xAnnn - LD I, addr
|
||||||
|
0xBnnn - JP V0, addr
|
||||||
|
0xCxkk - RND Vx, byte
|
||||||
|
0xDxyn - DRW Vx, Vy, nibble
|
||||||
|
0xEx9E - SKP Vx
|
||||||
|
0xExA1 - SKNP Vx
|
||||||
|
0xFx07 - LD Vx, DT
|
||||||
|
0xFx0A - LD Vx, K
|
||||||
|
0xFx15 - LD DT, Vx
|
||||||
|
0xFx18 - LD ST, Vx
|
||||||
|
0xFx1E - ADD I, Vx
|
||||||
|
0xFx29 - LD F, Vx
|
||||||
|
0xFx33 - LD B, Vx
|
||||||
|
0xFx55 - LD [I], Vx
|
||||||
|
0xFx65 - LD Vx, [I]
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 Argument {
|
||||||
|
|
||||||
|
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 {
|
struct Chip8Status {
|
||||||
|
|
||||||
// emu ptr
|
// emu ptr
|
||||||
Emulator* run_;
|
Emulator* run_;
|
||||||
Chip8* emu_;
|
Chip8* emu_;
|
||||||
|
|
||||||
|
// loaded program
|
||||||
|
const (char)* loaded_program;
|
||||||
|
|
||||||
// mem editor
|
// mem editor
|
||||||
// MemoryEditor mem_editor_;
|
// MemoryEditor mem_editor_;
|
||||||
|
|
||||||
|
@ -389,6 +595,8 @@ struct Chip8Status {
|
||||||
|
|
||||||
void resetShortcut() {
|
void resetShortcut() {
|
||||||
|
|
||||||
|
loaded_program = null;
|
||||||
|
|
||||||
emu_.reset();
|
emu_.reset();
|
||||||
|
|
||||||
} // resetShortcut
|
} // resetShortcut
|
||||||
|
@ -397,6 +605,7 @@ struct Chip8Status {
|
||||||
|
|
||||||
import std.file : read;
|
import std.file : read;
|
||||||
|
|
||||||
|
loaded_program = "chip8_picture.ch8";
|
||||||
auto buf = read("programs/chip8_picture.ch8");
|
auto buf = read("programs/chip8_picture.ch8");
|
||||||
emu_.load(0x200, buf); // do ze load yes, will copy all the data in
|
emu_.load(0x200, buf); // do ze load yes, will copy all the data in
|
||||||
|
|
||||||
|
@ -463,14 +672,19 @@ struct Chip8Status {
|
||||||
igBegin("Emulator Status");
|
igBegin("Emulator Status");
|
||||||
|
|
||||||
igBeginChild("General");
|
igBeginChild("General");
|
||||||
igText("OpCode: 0x%04X", emu_.cpu.opcode);
|
if (!loaded_program) {
|
||||||
igText("PC:");
|
igText("Loaded Program: none");
|
||||||
|
} else {
|
||||||
|
igText("Loaded Program: %s", loaded_program);
|
||||||
|
}
|
||||||
|
igText("Opcode: 0x%04X", emu_.cpu.opcode);
|
||||||
igSameLine();
|
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);
|
// igDragInt("##pc", cast(int*)&emu_.cpu.pc, 0.5f, 0, emu_.ram.length);
|
||||||
|
|
||||||
igText("Registers (v0 - vF)");
|
igText("Registers (v0 - vF)");
|
||||||
igColumns(4, null, false);
|
igColumns(4, null, false);
|
||||||
|
igIndent();
|
||||||
|
|
||||||
auto n = 0;
|
auto n = 0;
|
||||||
foreach (ref chunk; emu_.cpu.v[].chunks(4)) {
|
foreach (ref chunk; emu_.cpu.v[].chunks(4)) {
|
||||||
|
@ -483,11 +697,23 @@ struct Chip8Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
igColumns(1, null, false);
|
igColumns(1, null, false);
|
||||||
|
igUnindent();
|
||||||
|
|
||||||
igText("Index Register: 0x%04X", emu_.cpu.i);
|
igText("Index Register: 0x%04X", emu_.cpu.i);
|
||||||
igText("Delay Timer: 0x%04X", emu_.cpu.delay_timer);
|
igText("Delay Timer: 0x%04X", emu_.cpu.delay_timer);
|
||||||
igText("Sound Timer: 0x%04X", emu_.cpu.sound_timer);
|
igText("Sound Timer: 0x%04X", emu_.cpu.sound_timer);
|
||||||
|
|
||||||
|
if (igButton("Reload")) {
|
||||||
|
resetShortcut();
|
||||||
|
loadShortcut();
|
||||||
|
}
|
||||||
|
|
||||||
|
igSameLine();
|
||||||
|
|
||||||
|
if (igButton("Reset")) {
|
||||||
|
resetShortcut();
|
||||||
|
}
|
||||||
|
|
||||||
if (igButton("Step")) {
|
if (igButton("Step")) {
|
||||||
emu_.step();
|
emu_.step();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue