From 9277a1c3fd845cc5784a9fa1291606614fb7840f Mon Sep 17 00:00:00 2001 From: Nicholas Orlowsky Date: Wed, 31 Jan 2024 12:05:04 -0600 Subject: [PATCH] flag handling --- README.md | 3 +- screenshots/flags.png | Bin 0 -> 6829 bytes tests/4-flags.ch8 | Bin 0 -> 1041 bytes yayacemu.cpp | 5 +- yayacemu.sv | 135 +++++++++++++++++++++++++++++++----------- 5 files changed, 104 insertions(+), 39 deletions(-) create mode 100644 screenshots/flags.png create mode 100644 tests/4-flags.ch8 diff --git a/README.md b/README.md index bae3192..7ca6d05 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ yayacemu [PATH_TO_YOUR_ROM] ### Todo - [x] Graphics - [x] Corax+ Required Instructions -- [ ] Proper Flag Handling +- [x] Proper Flag Handling - [ ] Working Input - [ ] More Instructions - [ ] Tetris Working Running @@ -46,3 +46,4 @@ yayacemu [PATH_TO_YOUR_ROM] ![Chip 8 Logo Demo](https://github.com/nickorlow/yayacemu/blob/main/screenshots/chip8-logo.png?raw=true) ![IBM Logo Demo](https://github.com/nickorlow/yayacemu/blob/main/screenshots/ibm-logo.png?raw=true) ![CORAX+ Test Demo](https://github.com/nickorlow/yayacemu/blob/main/screenshots/corax.png?raw=true) +![Flag Test Demo](https://github.com/nickorlow/yayacemu/blob/main/screenshots/flags.png?raw=true) diff --git a/screenshots/flags.png b/screenshots/flags.png new file mode 100644 index 0000000000000000000000000000000000000000..13ba4deefb92ea38b83fe73d1f4f34e226137fc7 GIT binary patch literal 6829 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 literal 0 HcmV?d00001 diff --git a/yayacemu.cpp b/yayacemu.cpp index 3408c98..de51840 100644 --- a/yayacemu.cpp +++ b/yayacemu.cpp @@ -14,6 +14,7 @@ #define SCREEN_WIDTH 64 #define SCREEN_HEIGHT 32 +#define EMULATION_HZ 480 FILE *rom_file; SDL_Window *window; @@ -89,10 +90,10 @@ int main(int argc, char** argv) { contextp->commandArgs(argc, argv); Vyayacemu* top = new Vyayacemu{contextp}; //while (!contextp->gotFinish()) { - for (int i = 0; i < 20000; i++) { + for (int i = 0; i < 2000; i++) { top->clk_in ^= 1; top->eval(); - usleep(500); + usleep(1000000/EMULATION_HZ); } printf("TB : Testbench has reached end of simulation. Pausing for 10 seconds before exiting"); fflush(stdout); diff --git a/yayacemu.sv b/yayacemu.sv index 999e81d..57ad06c 100644 --- a/yayacemu.sv +++ b/yayacemu.sv @@ -8,16 +8,22 @@ module yayacemu ( wire [7:0] registers [0:15]; logic [3:0] stack_pointer; wire [15:0] stack [0:15]; + logic [7:0] delay_timer; + logic [7:0] sound_timer; + int cycle_counter; logic [15:0] index_reg; logic rom_ready; logic [15:0] program_counter; rom_loader rl (memory, rom_ready); - chip8_cpu cpu (memory, clk_in, vram, stack, index_reg, stack_pointer, registers, program_counter); + chip8_cpu cpu (memory, clk_in, vram, stack, index_reg, stack_pointer, registers, delay_timer, sound_timer, cycle_counter, program_counter); chip8_gpu gpu (vram); initial begin + sound_timer = 0; + delay_timer = 0; + cycle_counter = 0; program_counter = 'h200; stack_pointer = 4'b0000; init_screen(); @@ -33,13 +39,20 @@ module chip8_cpu( output wire [15:0] index_reg, output wire [3:0] stack_pointer, output wire [7:0] registers [0:15], + output logic [7:0] delay_timer, + output logic [7:0] sound_timer, + output int cycle_counter, output wire [15:0] program_counter ); logic [15:0] opcode; + logic [15:0] scratch; logic [15:0] scratch2; + logic [7:0] scratch_8; + logic [7:0] scratch_82; + logic [31:0] x_cord; logic [31:0] y_cord; logic [7:0] size; @@ -56,6 +69,14 @@ module chip8_cpu( $display("HW : opcode is 0x%h (%b)", opcode, opcode); $display("HW : PC %0d 0x%h", program_counter, program_counter); + // 480Hz / 8 = 60 Hz + if (cycle_counter % 8 == 0) begin + if (delay_timer > 0) + delay_timer--; + if (sound_timer > 0) + sound_timer--; + end + casez(opcode) 'h00E0: begin $display("HW : INSTR CLS"); @@ -127,28 +148,57 @@ module chip8_cpu( end 'h8??4: begin $display("HW : INSTR ADD Vx, Vy"); + scratch_8 = registers[(opcode & 'h0F00) >> 8]; registers[(opcode & 'h0F00) >> 8] += registers[(opcode & 'h00F0) >> 4]; + registers[15] = {7'b0000000, scratch_8 > registers[(opcode & 'h0F00) >> 8]}; end 'h8??5: begin $display("HW : INSTR SUB Vx, Vy"); + scratch_8 = registers[(opcode & 'h0F00) >> 8]; registers[(opcode & 'h0F00) >> 8] -= registers[(opcode & 'h00F0) >> 4]; + registers[15] = {7'b0000000, scratch_8 >= registers[(opcode & 'h0F00) >> 8]}; end 'h8??6: begin $display("HW : INSTR SHR Vx {, Vy}"); + scratch_8 = registers[(opcode & 'h0F00) >> 8]; registers[(opcode & 'h0F00) >> 8] = registers[(opcode & 'h00F0) >> 4]>> 1; + registers[15] = {7'b0000000, ((scratch_8 & 8'h01) == 8'h01)}; end 'h8??7: begin $display("HW : INSTR SUBN Vx, Vy"); + scratch_8 = registers[(opcode & 'h00F0) >> 4]; + scratch_82 = registers[(opcode & 'h0F00) >> 8]; registers[(opcode & 'h0F00) >> 8] = registers[(opcode & 'h00F0) >> 4] - registers[(opcode & 'h0F00) >> 8]; + registers[15] = {7'b0000000, (scratch_8 >= scratch_82)}; end 'h8??E: begin $display("HW : INSTR SHL Vx {, Vy}"); + scratch_8 = registers[(opcode & 'h0F00) >> 8]; registers[(opcode & 'h0F00) >> 8] = registers[(opcode & 'h00F0) >> 4]<< 1; + + registers[15] = {7'b0000000, (scratch_8[7]) }; + end + 'h9??0: begin + $display("HW : INSTR SNE Vx, Vy"); + if (registers[(opcode & 'h00F0) >> 4] != registers[(opcode & 'h0F00) >> 8]) begin + program_counter += 2; + end end 'hA???: begin $display("HW : INSTR LD I, addr"); index_reg = (opcode & 'h0FFF); end + 'hb???: begin + $display("HW : INSTR JP V0, addr"); + program_counter = {8'h00, registers[0]} + (opcode & 'h0FFF) - 2; + end + 'hc???: begin + $display("HW : RND Vx, addr"); + // TODO: use a real RNG module, this is not synthesizeable + scratch = {$urandom()%256}[15:0]; + scratch2 = (opcode & 'h00FF); + registers[(opcode & 'h0F00) >> 8] = scratch[7:0] & scratch2[7:0]; + end 'hD???: begin $display("HW : INSTR DRW Vx, Vy, nibble"); x_cord = {24'h000000, registers[(opcode & 'h0F00) >> 8]}; @@ -174,45 +224,58 @@ module chip8_cpu( end end end - end - 'hF?33: begin - $display("HW : INSTR LD B, Vx"); - scratch = {8'h00, registers[(opcode & 'h0F00) >> 8]}; - scratch2 = scratch % 10; - memory[index_reg + 2] = scratch2[7:0]; - scratch /= 10; - scratch2 = scratch % 10; - memory[index_reg + 1] = scratch2[7:0]; - scratch /= 10; - scratch2 = scratch % 10; - memory[index_reg + 0] = scratch2[7:0]; - end - 'hF?55: begin - $display("HW : INSTR LD [I], Vx"); - scratch = (opcode & 'h0F00) >> 8; - for (i8 = 0; i8 <= scratch[7:0]; i8++) begin - scratch2 = index_reg + {8'h00, i8}; - memory[scratch2[11:0]] = registers[i8[3:0]]; - end - index_reg++; - end - 'hF?65: begin - $display("HW : INSTR LD Vx, [I]"); - scratch = (opcode & 'h0F00) >> 8; - for (i8 = 0; i8 <= scratch[7:0]; i8++) begin - scratch2 = index_reg + {8'h00, i8}; - registers[i8[3:0]] = memory[scratch2[11:0]]; - end - index_reg++; - end - 'hF?1E: begin - $display("HW : INSTR ADD I, Vx"); - index_reg = index_reg + {8'h00, registers[(opcode & 'h0F00) >> 8]}; - end + end + 'hF?07: begin + $display("HW : INSTR LD Vx, DT"); + registers[(opcode & 'h0F00) >> 8] = delay_timer; + end + 'hF?15: begin + $display("HW : INSTR LD DT, Vx"); + delay_timer = registers[(opcode & 'h0F00) >> 8]; + end + 'hF?18: begin + $display("HW : INSTR LD ST, Vx"); + sound_timer = registers[(opcode & 'h0F00) >> 8]; + end + 'hF?1E: begin + $display("HW : INSTR ADD I, Vx"); + index_reg = index_reg + {8'h00, registers[(opcode & 'h0F00) >> 8]}; + end + 'hF?33: begin + $display("HW : INSTR LD B, Vx"); + scratch = {8'h00, registers[(opcode & 'h0F00) >> 8]}; + scratch2 = scratch % 10; + memory[index_reg + 2] = scratch2[7:0]; + scratch /= 10; + scratch2 = scratch % 10; + memory[index_reg + 1] = scratch2[7:0]; + scratch /= 10; + scratch2 = scratch % 10; + memory[index_reg + 0] = scratch2[7:0]; + end + 'hF?55: begin + $display("HW : INSTR LD [I], Vx"); + scratch = (opcode & 'h0F00) >> 8; + for (i8 = 0; i8 <= scratch[7:0]; i8++) begin + scratch2 = index_reg + {8'h00, i8}; + memory[scratch2[11:0]] = registers[i8[3:0]]; + end + index_reg++; + end + 'hF?65: begin + $display("HW : INSTR LD Vx, [I]"); + scratch = (opcode & 'h0F00) >> 8; + for (i8 = 0; i8 <= scratch[7:0]; i8++) begin + scratch2 = index_reg + {8'h00, i8}; + registers[i8[3:0]] = memory[scratch2[11:0]]; + end + index_reg++; + end default: $display("HW : ILLEGAL INSTRUCTION"); endcase program_counter += 2; + cycle_counter++; end endmodule