From 26f6dc5ce3f6b72e4c6413d10410f320f5d99714 Mon Sep 17 00:00:00 2001 From: Nicholas Orlowsky Date: Wed, 10 Apr 2024 21:59:00 -0500 Subject: [PATCH] fpga passes corax+ --- aastructs.sv | 3 +- alu.sv | 46 +++++++ chip8.qsf | 2 +- cpu.sv | 364 ++++++++++++++++++++++++++++++++++++++++++++++++--- makefile | 4 +- the-bomb | 2 +- yayacemu.cpp | 2 +- 7 files changed, 402 insertions(+), 21 deletions(-) diff --git a/aastructs.sv b/aastructs.sv index d45aee1..c880927 100644 --- a/aastructs.sv +++ b/aastructs.sv @@ -1,10 +1,11 @@ package structs; - typedef enum {ADD} alu_op; + typedef enum {ADD, ADDL, SUB, SE, SNE, OR, AND, XOR, SHR, SHL} alu_op; typedef struct packed { logic [7:0] operand_a; logic [7:0] operand_b; + logic [11:0] operand_b_long; alu_op op; } alu_input; diff --git a/alu.sv b/alu.sv index 99fcbaf..44881e8 100644 --- a/alu.sv +++ b/alu.sv @@ -5,6 +5,7 @@ module alu( input wire clk_in, input alu_input in, output logic [7:0] result, + output logic [15:0] result_long, output logic overflow, output logic done ); @@ -39,6 +40,51 @@ module alu( end cnt <= cnt + 1; end + structs::ADDL: begin + result_long <= {8'h00, in.operand_a} + {4'h0, in.operand_b_long}; + done <= 1; + cnt <= cnt + 1; + end + structs::SUB: begin + result_int <= in.operand_a - in.operand_b; + result <= result_int[7:0]; + // FIXME: if this fails, just do vx > vy + overflow <= !result_int[8]; + if (cnt >= 2) begin + done <= 1; + end + cnt <= cnt + 1; + end + structs::SE: begin + result <= {7'b0000000, in.operand_a == in.operand_b}; + done <= 1; + end + structs::SNE: begin + result <= {7'b0000000, in.operand_a != in.operand_b}; + done <= 1; + end + structs::OR: begin + result <= in.operand_a | in.operand_b; + done <= 1; + end + structs::AND: begin + result <= in.operand_a & in.operand_b; + done <= 1; + end + structs::XOR: begin + result <= in.operand_a ^ in.operand_b; + done <= 1; + end + structs::SHR: begin + result <= in.operand_a >> in.operand_b; + overflow <= in.operand_a[0]; + done <= 1; + end + structs::SHL: begin + result <= in.operand_a << in.operand_b; + overflow <= in.operand_a[7]; + done <= 1; + end endcase end end diff --git a/chip8.qsf b/chip8.qsf index 0184d35..0282b01 100644 --- a/chip8.qsf +++ b/chip8.qsf @@ -38,7 +38,7 @@ set_global_assignment -name SDC_FILE chip8.sdc set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW" set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" -set_location_assignment PIN_V11 -to fpga_clk +set_location_assignment PIN_V11 -to fpga_clk set_location_assignment PIN_D8 -to lcd_clk diff --git a/cpu.sv b/cpu.sv index 52f42e3..e685718 100644 --- a/cpu.sv +++ b/cpu.sv @@ -17,6 +17,7 @@ module cpu ( logic [5:0] lcd_led; logic alu_rst; logic [7:0] alu_result; + logic [15:0] alu_result_long; logic alu_overflow; logic alu_done; logic compute_of; @@ -28,6 +29,7 @@ logic [5:0] lcd_led; clk_in, instr.alu_i, alu_result, + alu_result_long, alu_overflow, alu_done ); @@ -86,6 +88,9 @@ logic [5:0] lcd_led; logic [7:0] sound_timer; logic [7:0] delay_timer; + + logic [7:0] ldl_cnt; + typedef enum {ST_FETCH_HI, ST_FETCH_LO, ST_FETCH_LO2, ST_DECODE, ST_EXEC, ST_DRAW, ST_FETCH_MEM, ST_WB, ST_CLEANUP, ST_HALT} cpu_state; @@ -93,7 +98,7 @@ logic [5:0] lcd_led; typedef enum {INIT, DRAW} draw_stage; - typedef enum {CLS, LD, DRW, JP, ALU} cpu_opcode; + typedef enum {CLS, LD, DRW, JP, ALU, CALU, CALL, RET, ALUJ, LDL, BCD} cpu_opcode; typedef enum {REG, IDX_REG, BYTE, MEM, SPRITE_MEM} data_type; struct { @@ -136,6 +141,7 @@ logic [5:0] lcd_led; program_counter = 'h200; wr_go = 0; alu_rst = 1; + stack_pointer = 0; for (int i = 0; i < 1024; i++) begin vram[i] = 0; end @@ -153,30 +159,64 @@ logic [5:0] lcd_led; rd_memory_address <= program_counter[11:0]; program_counter <= program_counter - 1; opcode <= { rd_memory_data, 8'h00 }; - $display("CPU : Opcode HI is %h", rd_memory_data); state <= ST_FETCH_LO2; end ST_FETCH_LO2: begin opcode <= { opcode[15:8], rd_memory_data}; - $display("CPU : Opcode LO is %h", rd_memory_data); state <= ST_DECODE; end ST_DECODE: begin casez (opcode) - 16'h00E0: begin - instr.op <= CLS; - state <= ST_CLEANUP; - program_counter <= program_counter + 2; + 16'h0???: begin + if (opcode == 16'h00e0) begin + instr.op <= CLS; + state <= ST_CLEANUP; + program_counter <= program_counter + 2; + end else if (opcode == 16'h00EE) begin + instr.op <= RET; + state <= ST_EXEC; + end else begin + program_counter <= program_counter + 2; + state <= ST_CLEANUP; + end end 16'h1???: begin instr.op <= JP; instr.src_byte <= opcode[11:0]; state <= ST_EXEC; end + 16'h2???: begin + instr.op <= CALL; + instr.src_byte <= opcode[11:0]; + state <= ST_EXEC; + end + 16'h3???: begin + instr.op <= CALU; + instr.alu_i.op <= structs::SE; + instr.alu_i.operand_a <= opcode[7:0]; + instr.alu_i.operand_b <= registers[opcode[11:8]]; + compute_of <= 0; + state <= ST_EXEC; + end + 16'h4???: begin + instr.op <= CALU; + instr.alu_i.op <= structs::SNE; + instr.alu_i.operand_a <= opcode[7:0]; + instr.alu_i.operand_b <= registers[opcode[11:8]]; + compute_of <= 0; + state <= ST_EXEC; + end + 16'h5??0: begin + instr.op <= CALU; + instr.alu_i.op <= structs::SE; + instr.alu_i.operand_a <= registers[opcode[7:4]]; + instr.alu_i.operand_b <= registers[opcode[11:8]]; + compute_of <= 0; + state <= ST_EXEC; + end 16'h6???: begin - $display("Instruction is LD Vx, Byte"); instr.op <= LD; instr.src <= BYTE; @@ -202,8 +242,146 @@ logic [5:0] lcd_led; state <= ST_EXEC; end + 16'h8??0: begin + instr.op <= LD; + + instr.src <= REG; + instr.src_reg <= opcode[7:4]; + + instr.dst <= REG; + instr.dst_reg <= opcode[11:8]; + + state <= ST_EXEC; + end + 16'h8??1: begin + instr.op <= ALU; + + instr.src <= BYTE; + + instr.dst <= REG; + instr.dst_reg <= opcode[11:8]; + + instr.alu_i.op <= structs::OR; + instr.alu_i.operand_a <= registers[opcode[7:4]]; + instr.alu_i.operand_b <= registers[opcode[11:8]]; + compute_of <= 0; + + state <= ST_EXEC; + end + 16'h8??2: begin + instr.op <= ALU; + + instr.src <= BYTE; + + instr.dst <= REG; + instr.dst_reg <= opcode[11:8]; + + instr.alu_i.op <= structs::AND; + instr.alu_i.operand_a <= registers[opcode[7:4]]; + instr.alu_i.operand_b <= registers[opcode[11:8]]; + compute_of <= 0; + + state <= ST_EXEC; + end + 16'h8??3: begin + instr.op <= ALU; + + instr.src <= BYTE; + + instr.dst <= REG; + instr.dst_reg <= opcode[11:8]; + + instr.alu_i.op <= structs::XOR; + instr.alu_i.operand_a <= registers[opcode[7:4]]; + instr.alu_i.operand_b <= registers[opcode[11:8]]; + compute_of <= 0; + + state <= ST_EXEC; + end + 16'h8??4: begin + instr.op <= ALU; + + instr.src <= BYTE; + + instr.dst <= REG; + instr.dst_reg <= opcode[11:8]; + + instr.alu_i.op <= structs::ADD; + instr.alu_i.operand_a <= registers[opcode[7:4]]; + instr.alu_i.operand_b <= registers[opcode[11:8]]; + compute_of <= 1; + + state <= ST_EXEC; + end + 16'h8??5: begin + instr.op <= ALU; + + instr.src <= BYTE; + + instr.dst <= REG; + instr.dst_reg <= opcode[11:8]; + + instr.alu_i.op <= structs::SUB; + instr.alu_i.operand_a <= registers[opcode[11:8]]; + instr.alu_i.operand_b <= registers[opcode[7:4]]; + compute_of <= 1; + + state <= ST_EXEC; + end + 16'h8??6: begin + instr.op <= ALU; + + instr.src <= BYTE; + + instr.dst <= REG; + instr.dst_reg <= opcode[11:8]; + + instr.alu_i.op <= structs::SHR; + instr.alu_i.operand_a <= registers[opcode[11:8]]; + instr.alu_i.operand_b <= 1; + compute_of <= 1; + + state <= ST_EXEC; + end + 16'h8??7: begin + instr.op <= ALU; + + instr.src <= BYTE; + + instr.dst <= REG; + instr.dst_reg <= opcode[11:8]; + + instr.alu_i.op <= structs::SUB; + instr.alu_i.operand_a <= registers[opcode[7:4]]; + instr.alu_i.operand_b <= registers[opcode[11:8]]; + compute_of <= 1; + + state <= ST_EXEC; + end + 16'h8??E: begin + instr.op <= ALU; + + instr.src <= BYTE; + + instr.dst <= REG; + instr.dst_reg <= opcode[11:8]; + + instr.alu_i.op <= structs::SHL; + instr.alu_i.operand_a <= registers[opcode[11:8]]; + instr.alu_i.operand_b <= 1; + compute_of <= 1; + + state <= ST_EXEC; + end + 16'h9??0: begin + instr.op <= CALU; + instr.alu_i.op <= structs::SNE; + instr.alu_i.operand_a <= registers[opcode[7:4]]; + instr.alu_i.operand_b <= registers[opcode[11:8]]; + compute_of <= 0; + state <= ST_EXEC; + end 16'hA???: begin - $display("Instruction is LD I, Byte"); instr.op <= LD; instr.src <= BYTE; @@ -213,6 +391,16 @@ logic [5:0] lcd_led; state <= ST_EXEC; end + 16'hB???: begin + instr.op <= ALUJ; + + instr.op <= CALU; + instr.alu_i.op <= structs::ADDL; + instr.alu_i.operand_a <= registers[0]; + instr.alu_i.operand_b_long <= opcode[11:0]; + compute_of <= 0; + state <= ST_EXEC; + end 16'hD???: begin instr.op <= DRW; @@ -225,9 +413,63 @@ logic [5:0] lcd_led; state <= ST_FETCH_MEM; end + 16'hF?1E: begin + instr.op <= ALU; + + instr.src <= BYTE; + + instr.dst <= IDX_REG; + + instr.alu_i.op <= structs::ADDL; + instr.alu_i.operand_a <= registers[opcode[11:8]]; + instr.alu_i.operand_b_long <= index_reg[11:0]; + compute_of <= 0; + + state <= ST_EXEC; + end + 16'hF?33: begin + instr.op <= BCD; + + instr.src <= REG; + instr.src_reg <= opcode[11:8]; + + instr.dst <= MEM; + instr.dst_addr <= index_reg[11:0]; + + ldl_cnt <= 0; + + state <= ST_EXEC; + end + 16'hF?55: begin + instr.op <= LDL; + + instr.src <= REG; + instr.src_reg <= opcode[11:8]; //FIXME: need to expand mem? + + instr.dst <= MEM; +/* verilator lint_off WIDTHEXPAND */ + instr.dst_addr <= index_reg[11:0] + opcode[11:8] + 1; //FIXME: need to expand mem? + + /* verilator lint_off WIDTHEXPAND */ + ldl_cnt <= opcode[11:8]; + + state <= ST_EXEC; + end + 16'hF?65: begin + instr.op <= LDL; + + instr.src <= MEM; +/* verilator lint_off WIDTHEXPAND */ + instr.src_addr <= index_reg[11:0] + opcode[11:8]; //FIXME: need to expand mem? + + instr.dst <= REG; + instr.dst_reg <= opcode[11:8]; + + state <= ST_FETCH_MEM; + end default: begin $display("ILLEGAL INSTRUCTION %h at PC 0x%h (%0d)", opcode, program_counter, program_counter); - $fatal(); + state <= ST_HALT; end endcase end @@ -276,7 +518,6 @@ logic [5:0] lcd_led; registers[15] <= 0; end else begin if (draw_state.r == instr.src_sprite_sz + 1) begin - $display("sprite is %0d big at coord %d %d sprite=%b idx=%0d", instr.src_sprite_sz, instr.src_sprite_x, instr.src_sprite_y, instr.src_sprite, instr.src_sprite_addr); state <= ST_CLEANUP; program_counter <= program_counter + 2; end else begin @@ -309,20 +550,108 @@ logic [5:0] lcd_led; instr.src <= BYTE; end end + LDL: begin + if (instr.dst == REG) begin + registers[instr.dst_reg] <= instr.src_byte[7:0]; + + if (instr.dst_reg == 0) begin + program_counter <= program_counter + 2; + state <= ST_CLEANUP; + end else begin + instr.src <= MEM; + instr.dst_reg <= instr.dst_reg - 1; + instr.src_addr <= instr.src_addr - 1; + state <= ST_FETCH_MEM; + end + end + if (instr.dst == MEM) begin + instr.src <= BYTE; + + $display("%0d set to %h (r%0d)", instr.dst_addr,registers[instr.src_reg], instr.src_reg ); + instr.src_byte <= {4'h0, registers[instr.src_reg]}; + instr.src_reg <= instr.src_reg - 1; + instr.dst_addr <= instr.dst_addr - 1; + ldl_cnt <= ldl_cnt - 1; + + + if (ldl_cnt > 15) begin + program_counter <= program_counter + 2; + // state <= ST_HALT; + state <= ST_CLEANUP; + end else begin + state <= ST_WB; + end + end + end + BCD: begin + instr.src <= BYTE; + ldl_cnt <= ldl_cnt + 1; + $display("%0d ldl", ldl_cnt); + case (ldl_cnt) + 0: begin + instr.src_byte <= (registers[instr.src_reg]/100) % 10; + state <= ST_WB; + end + 1: begin + instr.dst_addr <= instr.dst_addr + 1; + instr.src_byte <= (registers[instr.src_reg]/10) % 10; + state <= ST_WB; + end + 2: begin + instr.dst_addr <= instr.dst_addr + 1; + instr.src_byte <= registers[instr.src_reg] % 10; + state <= ST_WB; + end + 3: begin + program_counter <= program_counter + 2; + state <= ST_CLEANUP; + end + endcase + end JP: begin program_counter <= {4'h00, instr.src_byte}; state <= ST_CLEANUP; end + CALU, + ALUJ, ALU: begin alu_rst <= 0; if (alu_done) begin instr.src <= BYTE; - instr.src_byte <= alu_result; + if (instr.dst == IDX_REG) + instr.src_byte <= alu_result_long[11:0]; + else + instr.src_byte <= alu_result; registers[15] <= compute_of ? alu_overflow : registers[15]; - state <= ST_WB; - program_counter <= program_counter + 2; + if (instr.op == ALU) begin + state <= ST_WB; + program_counter <= program_counter + 2; + end else if (instr.op == CALU) begin + state <= ST_CLEANUP; + if (|alu_result) begin + program_counter <= program_counter + 4; + end else begin + program_counter <= program_counter + 2; + end + end else begin + $display("Untested!"); + state <= ST_CLEANUP; + program_counter <= alu_result_long; + end end end + CALL: begin + stack[stack_pointer] <= program_counter; + stack_pointer <= stack_pointer + 1; + program_counter <= instr.src_byte; + state <= ST_CLEANUP; + end + RET: begin + stack_pointer <= stack_pointer - 1; + program_counter <= stack[stack_pointer-1] + 2; + state <= ST_CLEANUP; + end + endcase case (instr.op) @@ -352,7 +681,12 @@ logic [5:0] lcd_led; IDX_REG: index_reg <= {4'h0, instr.src_byte}; endcase - state <= ST_CLEANUP; + if (instr.op != LDL && instr.op != BCD) + state <= ST_CLEANUP; + else begin + state <= ST_EXEC; + instr.src <= REG; + end end ST_CLEANUP: begin diff --git a/makefile b/makefile index b801e26..7196eb0 100644 --- a/makefile +++ b/makefile @@ -11,13 +11,13 @@ build-rom: python3 ./gen_rom.py ${ROM_FILE} rom.bin build: build-rom - verilator --cc --exe --build --timing -j 0 --top-module chip8 *.sv yayacemu.cpp -DDUMMY_GPU -CFLAGS "${SDL_CFLAGS}" -LDFLAGS "${SDL_LDFLAGS}" && clear + verilator --cc --exe --build --timing -j 0 --top-module chip8 *.sv yayacemu.cpp -DDUMMY_GPU -DFAST_CLK -CFLAGS "${SDL_CFLAGS}" -LDFLAGS "${SDL_LDFLAGS}" && clear run: build obj_dir/Vchip8 clean: - rm -rf obj_dir + rm -rf obj_dir db incremental_db format: verible-verilog-format *.sv --inplace && clang-format *.cpp -i diff --git a/the-bomb b/the-bomb index 6d88fb2..def932e 160000 --- a/the-bomb +++ b/the-bomb @@ -1 +1 @@ -Subproject commit 6d88fb2756c80be38c1b35134dca0e66d74dbb94 +Subproject commit def932eef3fc7aa63fef542953de8375c03f3bba diff --git a/yayacemu.cpp b/yayacemu.cpp index bfed10d..9f7ec82 100644 --- a/yayacemu.cpp +++ b/yayacemu.cpp @@ -53,7 +53,7 @@ void draw_screen(const svLogicVecVal *vram) { SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); free(screen); - std::cout << "INF_EMU: Drawing Frame" << '\n'; + //std::cout << "INF_EMU: Drawing Frame" << '\n'; } svBitVecVal get_key() {