nyeh
This commit is contained in:
parent
4d8fc5814b
commit
5be7d9ce1a
84
source/app.d
84
source/app.d
|
@ -466,7 +466,8 @@ struct Chip8Status {
|
||||||
igText("OpCode: 0x%04X", emu_.cpu.opcode);
|
igText("OpCode: 0x%04X", emu_.cpu.opcode);
|
||||||
igText("PC:");
|
igText("PC:");
|
||||||
igSameLine();
|
igSameLine();
|
||||||
igDragInt("##pc", cast(int*)&emu_.cpu.pc, 0.5f, 0, emu_.ram.length);
|
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)");
|
igText("Registers (v0 - vF)");
|
||||||
igColumns(4, null, false);
|
igColumns(4, null, false);
|
||||||
|
@ -629,9 +630,9 @@ struct Chip8 {
|
||||||
void step() {
|
void step() {
|
||||||
|
|
||||||
cpu.opcode = ram[cpu.pc] << 8 | ram[cpu.pc + 1];
|
cpu.opcode = ram[cpu.pc] << 8 | ram[cpu.pc + 1];
|
||||||
auto pc_target = cast(ProgramCounter)(cpu.pc + 2);
|
ushort pc_target = cast(ProgramCounter)(cpu.pc + 2u);
|
||||||
|
|
||||||
writefln("opcode: 0x%X", cpu.opcode);
|
// writefln("opcode: 0x%X, pc: 0x%X : %d", cpu.opcode, cpu.pc, cpu.pc);
|
||||||
|
|
||||||
switch (cpu.opcode & 0xF000) with (cpu) {
|
switch (cpu.opcode & 0xF000) with (cpu) {
|
||||||
|
|
||||||
|
@ -669,7 +670,7 @@ struct Chip8 {
|
||||||
case 0x3000: // 0x3XNN Skips the next instruction if VX equals NN.
|
case 0x3000: // 0x3XNN Skips the next instruction if VX equals NN.
|
||||||
|
|
||||||
if (cpu.v[cpu.opcode.x] == (cpu.opcode.nn)) {
|
if (cpu.v[cpu.opcode.x] == (cpu.opcode.nn)) {
|
||||||
pc_target += 2;
|
pc_target += 2u;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -677,7 +678,7 @@ struct Chip8 {
|
||||||
case 0x4000: // 0x4XNN Skips the next instruction if VX doesn't equal NN.
|
case 0x4000: // 0x4XNN Skips the next instruction if VX doesn't equal NN.
|
||||||
|
|
||||||
if (cpu.v[cpu.opcode.x] != (cpu.opcode.nn)) {
|
if (cpu.v[cpu.opcode.x] != (cpu.opcode.nn)) {
|
||||||
pc_target += 2;
|
pc_target += 2u;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -685,13 +686,12 @@ struct Chip8 {
|
||||||
case 0x5000: // 0x5XYO Skips the next instruction if VX equals VY.
|
case 0x5000: // 0x5XYO Skips the next instruction if VX equals VY.
|
||||||
|
|
||||||
if (cpu.v[cpu.opcode.x] == cpu.v[cpu.opcode.y]) {
|
if (cpu.v[cpu.opcode.x] == cpu.v[cpu.opcode.y]) {
|
||||||
pc_target += 2;
|
pc_target += 2u;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x6000: // 0x6XNN Sets VX to NN.
|
case 0x6000: // 0x6XNN Sets VX to NN.
|
||||||
writefln("%d, %d", cpu.opcode.x, cpu.opcode & 0x00FF);
|
|
||||||
cpu.v[cpu.opcode.x] = cpu.opcode.nn;
|
cpu.v[cpu.opcode.x] = cpu.opcode.nn;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -701,8 +701,8 @@ struct Chip8 {
|
||||||
|
|
||||||
case 0x8000:
|
case 0x8000:
|
||||||
|
|
||||||
auto x = cpu.opcode.x;
|
ubyte x = cpu.opcode.x;
|
||||||
auto y = cpu.opcode.y;
|
ubyte y = cpu.opcode.y;
|
||||||
|
|
||||||
switch (cpu.opcode.n) {
|
switch (cpu.opcode.n) {
|
||||||
|
|
||||||
|
@ -723,8 +723,8 @@ struct Chip8 {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
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 0x0004: // 0x8XY4 Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't.
|
||||||
auto vx = cpu.v[x];
|
ubyte vx = cpu.v[x];
|
||||||
auto vy = cpu.v[y];
|
ubyte vy = cpu.v[y];
|
||||||
if (cast(ushort)vx + cast(ushort)vy > 255) {
|
if (cast(ushort)vx + cast(ushort)vy > 255) {
|
||||||
cpu.v[0xF] = 1;
|
cpu.v[0xF] = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -734,8 +734,8 @@ struct Chip8 {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
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 0x0005: // 0x8XY5 VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
|
||||||
auto vx = cpu.v[x];
|
ubyte vx = cpu.v[x];
|
||||||
auto vy = cpu.v[y];
|
ubyte vy = cpu.v[y];
|
||||||
if (vx > vy) {
|
if (vx > vy) {
|
||||||
cpu.v[0xF] = 1;
|
cpu.v[0xF] = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -746,26 +746,26 @@ struct Chip8 {
|
||||||
|
|
||||||
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 0x0006: // 0x8XY6 Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift.
|
||||||
|
|
||||||
auto vx = cpu.v[x];
|
ubyte vx = cpu.v[x];
|
||||||
cpu.v[0xF] = (vx & 0b10000000) >> 7;
|
cpu.v[0xF] = vx & 0x1;
|
||||||
cpu.v[x] >>= 1;
|
cpu.v[x] >>= 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
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 0x0007: // 0x8XY7 Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
|
||||||
auto vx = cpu.v[x];
|
ubyte vx = cpu.v[x];
|
||||||
auto vy = cpu.v[y];
|
ubyte vy = cpu.v[y];
|
||||||
if (vy > vx) {
|
if (vy > vx) {
|
||||||
cpu.v[0xF] = 1;
|
cpu.v[0xF] = 1;
|
||||||
} else {
|
} else {
|
||||||
cpu.v[0xF] = 0;
|
cpu.v[0xF] = 0;
|
||||||
}
|
}
|
||||||
cpu.v[x] = cast(Register)(vy - vx); // TODO borrow flag
|
cpu.v[x] = cast(Register)(vy - vx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x000E: // 0x8XYE Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift.
|
case 0x000E: // 0x8XYE Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift.
|
||||||
|
|
||||||
auto vx = cpu.v[x];
|
ubyte vx = cpu.v[x];
|
||||||
cpu.v[0xF] = (vx & 0b10000000) >> 7;
|
cpu.v[0xF] = vx >> 7;
|
||||||
cpu.v[x] <<= 1;
|
cpu.v[x] <<= 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -780,7 +780,7 @@ struct Chip8 {
|
||||||
case 0x9000: // 0x9XYO Skips the next instruction if VX doesn't equal VY.
|
case 0x9000: // 0x9XYO Skips the next instruction if VX doesn't equal VY.
|
||||||
|
|
||||||
if (cpu.v[cpu.opcode.x] != cpu.v[cpu.opcode.y]) {
|
if (cpu.v[cpu.opcode.x] != cpu.v[cpu.opcode.y]) {
|
||||||
pc_target += 2; // do skip yes
|
pc_target += 2u; // do skip yes
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -796,7 +796,7 @@ struct Chip8 {
|
||||||
case 0xC000: // 0xCXNN Sets VX to the result of a bitwise and operation on a random number and NN.
|
case 0xC000: // 0xCXNN Sets VX to the result of a bitwise and operation on a random number and NN.
|
||||||
|
|
||||||
import std.random : uniform;
|
import std.random : uniform;
|
||||||
auto x = cpu.opcode.x;
|
ubyte x = cpu.opcode.x;
|
||||||
cpu.v[x] = uniform(Register.min, Register.max) & (cpu.opcode & 0x00FF);
|
cpu.v[x] = uniform(Register.min, Register.max) & (cpu.opcode & 0x00FF);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -808,29 +808,25 @@ struct Chip8 {
|
||||||
// If N is greater than 1, second line continues at position VX, VY+1, and so on.
|
// If N is greater than 1, second line continues at position VX, VY+1, and so on.
|
||||||
case 0xD000:
|
case 0xD000:
|
||||||
|
|
||||||
auto spr_addr = cpu.i;
|
ProgramCounter spr_addr = cpu.i;
|
||||||
auto x = cpu.opcode.x;
|
ubyte x = cpu.opcode.x;
|
||||||
auto y = cpu.opcode.y;
|
ubyte y = cpu.opcode.y;
|
||||||
auto n = cpu.opcode.n;
|
ubyte n = cpu.opcode.n;
|
||||||
|
|
||||||
foreach(int row; 0 .. n) {
|
foreach(int row; 0 .. n) {
|
||||||
|
|
||||||
ushort pixel = ram[spr_addr + row];
|
ushort pixel = ram[spr_addr + row];
|
||||||
|
|
||||||
foreach (int col; 0 .. 8) {
|
foreach (int col; 0 .. 8) {
|
||||||
if ((pixel & 0x80) > 0) {
|
if ((pixel & (0x80 >> col)) != 0) {
|
||||||
auto x_off = (x + col) % 64;
|
ubyte x_off = cast(ubyte)((x + col) % 64);
|
||||||
auto y_off = (y + row) % 32;
|
ubyte y_off = cast(ubyte)((y + row) % 32);
|
||||||
auto offset = x_off + (y_off * 64);
|
ushort offset = x_off + (y_off * 64);
|
||||||
if (screen_buf[offset] == 1) {
|
if (screen_buf[offset] == 1) {
|
||||||
cpu.v[0xF] = 1;
|
cpu.v[0xF] = 1;
|
||||||
} else {
|
|
||||||
cpu.v[0xF] = 0;
|
|
||||||
}
|
}
|
||||||
screen_buf[offset] ^= 1;
|
screen_buf[offset] ^= 1;
|
||||||
writefln("write to offset: %d", offset);
|
|
||||||
}
|
}
|
||||||
pixel <<= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -841,8 +837,8 @@ struct Chip8 {
|
||||||
|
|
||||||
case 0xE000:
|
case 0xE000:
|
||||||
|
|
||||||
auto x = cpu.opcode.x;
|
ubyte x = cpu.opcode.x;
|
||||||
auto key = cpu.v[x];
|
ubyte key = cpu.v[x];
|
||||||
|
|
||||||
switch (cpu.opcode & 0x000F) {
|
switch (cpu.opcode & 0x000F) {
|
||||||
|
|
||||||
|
@ -883,13 +879,19 @@ struct Chip8 {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x001E: // 0xFX1E Adds VX to I.
|
case 0x001E: // 0xFX1E Adds VX to I.
|
||||||
|
if (cpu.i + cpu.v[cpu.opcode.x] > 0xFF) {
|
||||||
|
cpu.v[0xF] = 1;
|
||||||
|
} else {
|
||||||
|
cpu.v[0xF] = 0;
|
||||||
|
}
|
||||||
cpu.i += cpu.v[cpu.opcode.x];
|
cpu.i += cpu.v[cpu.opcode.x];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0029: // 0xFX29 Sets I to the location of the sprite for the character in VX.
|
case 0x0029: // 0xFX29 Sets I to the location of the sprite for the character in VX.
|
||||||
|
|
||||||
auto vx = cpu.v[cpu.opcode.x];
|
ubyte vx = cpu.v[cpu.opcode.x];
|
||||||
ushort char_addr = 0x200 + (vx * 40); // base of char sprites + value of vx * bits per character
|
// ushort char_addr = 0x200 + (vx * 40); // base of char sprites + value of vx * bits per character
|
||||||
|
ushort char_addr = vx * 0x5;
|
||||||
cpu.i = char_addr;
|
cpu.i = char_addr;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -898,7 +900,7 @@ struct Chip8 {
|
||||||
// the middle digit at I plus 1, and the least significant digit at I plus 2.
|
// the middle digit at I plus 1, and the least significant digit at I plus 2.
|
||||||
case 0x0033:
|
case 0x0033:
|
||||||
|
|
||||||
auto vx = cpu.v[cpu.opcode.x];
|
ubyte vx = cpu.v[cpu.opcode.x];
|
||||||
ram[cpu.i] = vx / 100;
|
ram[cpu.i] = vx / 100;
|
||||||
ram[cpu.i + 1] = (vx / 10) % 10;
|
ram[cpu.i + 1] = (vx / 10) % 10;
|
||||||
ram[cpu.i + 2] = (vx % 100) % 10;
|
ram[cpu.i + 2] = (vx % 100) % 10;
|
||||||
|
@ -906,7 +908,7 @@ struct Chip8 {
|
||||||
|
|
||||||
case 0x0055: // 0xFX55 Stores V0 to VX in memory starting at address I.
|
case 0x0055: // 0xFX55 Stores V0 to VX in memory starting at address I.
|
||||||
|
|
||||||
auto addr = cpu.i;
|
IndexRegister addr = cpu.i;
|
||||||
foreach (reg; cpu.v) {
|
foreach (reg; cpu.v) {
|
||||||
ram[addr++] = reg;
|
ram[addr++] = reg;
|
||||||
}
|
}
|
||||||
|
@ -915,7 +917,7 @@ struct Chip8 {
|
||||||
|
|
||||||
case 0x0065: // 0xFX65 Fills V0 to VX with values from memory starting at address I.
|
case 0x0065: // 0xFX65 Fills V0 to VX with values from memory starting at address I.
|
||||||
|
|
||||||
auto addr = cpu.i;
|
IndexRegister addr = cpu.i;
|
||||||
foreach (ref reg; cpu.v) {
|
foreach (ref reg; cpu.v) {
|
||||||
reg = ram[addr++];
|
reg = ram[addr++];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue