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 0000000..13ba4de Binary files /dev/null and b/screenshots/flags.png differ diff --git a/tests/4-flags.ch8 b/tests/4-flags.ch8 new file mode 100644 index 0000000..431f3b0 Binary files /dev/null and b/tests/4-flags.ch8 differ 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