diff --git a/makefile b/makefile index d821024..c99007c 100644 --- a/makefile +++ b/makefile @@ -2,10 +2,10 @@ SDL_CFLAGS = `sdl2-config --cflags` SDL_LDFLAGS = `sdl2-config --libs` lint: - verilator --lint-only --timing yayacemu.sv rom_loader.sv + verilator --lint-only --timing *.sv build: lint - verilator --cc --exe --build --timing -j 0 yayacemu.sv rom_loader.sv yayacemu.cpp -CFLAGS "${SDL_CFLAGS}" -LDFLAGS "${SDL_LDFLAGS}" && clear + verilator --cc --exe --build --timing -j 0 --top-module yayacemu *.sv yayacemu.cpp -CFLAGS "${SDL_CFLAGS}" -LDFLAGS "${SDL_LDFLAGS}" && clear run: build obj_dir/Vyayacemu ${ROM_FILE} diff --git a/yayacemu.cpp b/yayacemu.cpp index 7465205..735c0cb 100644 --- a/yayacemu.cpp +++ b/yayacemu.cpp @@ -37,15 +37,18 @@ void init_screen() { printf("INF_EMU: Screen initialized\n"); } -void draw_screen(const svLogicVecVal* vram, const svBit beep) { - uint32_t *screen = (uint32_t*) malloc(SCREEN_WIDTH*SCREEN_HEIGHT*32); - for(int i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) { - screen[i] = vram[i].aval; - } +void set_beep(const svBit beep) { if (beep > 0) SDL_SetTextureColorMod(texture, 255, 0, 0); else SDL_SetTextureColorMod(texture, 255, 255, 255); +} + +void draw_screen(const svLogicVecVal* vram) { + uint32_t *screen = (uint32_t*) malloc(SCREEN_WIDTH*SCREEN_HEIGHT*32); + for(int i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) { + screen[i] = vram[i].aval; + } SDL_UpdateTexture(texture, NULL, screen, sizeof(screen[0]) * SCREEN_WIDTH); SDL_RenderClear(renderer); diff --git a/yayacemu.sv b/yayacemu.sv index 5ba46ba..a1a180e 100644 --- a/yayacemu.sv +++ b/yayacemu.sv @@ -1,8 +1,6 @@ module yayacemu ( input wire clk_in ); - import "DPI-C" function void init_screen(); - wire [31:0] vram [0:2047]; bit [7:0] memory [0:4095]; wire [7:0] registers [0:15]; @@ -25,8 +23,9 @@ module yayacemu ( randomizer randy(clk_in, program_counter, keyboard, cycle_counter, rand_num); keyboard kb(clk_in, keyboard); rom_loader rl (memory, rom_ready); - chip8_cpu cpu (memory, clk_in, keyboard, rand_num, vram, stack, index_reg, stack_pointer, registers, delay_timer, sound_timer, cycle_counter, program_counter, halt, watch_key); - chip8_gpu gpu (vram, sound_timer); + cpu cpu (memory, clk_in, keyboard, rand_num, vram, stack, index_reg, stack_pointer, registers, delay_timer, sound_timer, cycle_counter, program_counter, halt, watch_key); + beeper beeper(sound_timer); + gpu gpu (vram); int i; initial begin @@ -61,349 +60,6 @@ module yayacemu ( cycle_counter = 0; program_counter = 'h200; stack_pointer = 4'b0000; - init_screen(); end endmodule - -module keyboard ( - input wire clk_in, - output bit keyboard [15:0] - ); - int i; - import "DPI-C" function bit [7:0] get_key(); - bit[7:0] keyval; - always_ff @(posedge clk_in) begin - keyval = get_key(); - if (keyval != 8'b11111111) begin - keyboard[keyval[3:0]] = keyval[7]; - end - end -endmodule - -module chip8_cpu( - output bit [7:0] memory [0:4095], - input wire clk_in, - input wire keyboard [15:0], - input wire [7:0] random_number, - output wire [31:0] vram [0:2047], - output wire [15:0] stack [0:15], - 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, - output bit halt, - output int watch_key - ); - - 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; - logic [31:0] screen_pixel; - logic [7:0] sprite_pixel; - - int i; - logic [7:0] i8; - - int r; - int c; - always_ff @(posedge clk_in) begin - opcode = {memory[program_counter+0], memory[program_counter+1]}; - $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 % 20 == 0) begin - if (delay_timer > 0) - delay_timer--; - if (sound_timer > 0) - sound_timer--; - end - - casez(opcode) - 'h00E0: begin - $display("HW : INSTR CLS"); - for(i = 0; i < 2048; i++) begin - vram[i] = 0; - end - end - 'h00EE: begin - $display("HW : INSTR RET"); - stack_pointer--; - program_counter = stack[stack_pointer]; - end - 'h0???: $display("HW : INSTR SYS addr (Treating as NOP)"); - 'h1???: begin - $display("HW : INSTR JP addr"); - program_counter = (opcode & 'h0FFF) - 2; - end - 'h2???: begin - $display("HW : INSTR CALL addr"); - stack[stack_pointer] = program_counter; - stack_pointer++; - program_counter = (opcode & 'h0FFF) - 2; - end - 'h3???: begin - $display("HW : INSTR SE Vx, byte"); - scratch = (opcode & 'h00FF); - if (scratch[7:0] == registers[(opcode & 'h0F00) >> 8]) begin - program_counter += 2; - end - end - 'h4???: begin - $display("HW : INSTR SNE Vx, byte"); - scratch = (opcode & 'h00FF); - if (scratch[7:0] != registers[(opcode & 'h0F00) >> 8]) begin - program_counter += 2; - end - end - 'h5??0: begin - $display("HW : INSTR SE Vx, Vy"); - if (registers[(opcode & 'h00F0) >> 4] == registers[(opcode & 'h0F00) >> 8]) begin - program_counter += 2; - end - end - 'h6???: begin - $display("HW : INSTR LD Vx, byte"); - scratch = (opcode & 'h00FF); - registers[(opcode & 'h0F00) >> 8] = scratch[7:0]; - end - 'h7???: begin - $display("HW : INSTR ADD Vx, byte"); - scratch = (opcode & 'h00FF); - registers[(opcode & 'h0F00) >> 8] += scratch[7:0]; - end - 'h8??0: begin - $display("HW : INSTR LD Vx, Vy"); - registers[(opcode & 'h0F00) >> 8] = registers[(opcode & 'h00F0) >> 4]; - end - 'h8??1: begin - $display("HW : INSTR OR Vx, Vy"); - registers[(opcode & 'h0F00) >> 8] |= registers[(opcode & 'h00F0) >> 4]; - registers[15] = 0; - end - 'h8??2: begin - $display("HW : INSTR AND Vx, Vy"); - registers[(opcode & 'h0F00) >> 8] &= registers[(opcode & 'h00F0) >> 4]; - registers[15] = 0; - end - 'h8??3: begin - $display("HW : INSTR XOR Vx, Vy"); - registers[(opcode & 'h0F00) >> 8] ^= registers[(opcode & 'h00F0) >> 4]; - registers[15] = 0; - 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 = {8'h00, random_number} % 16'h0100; - scratch2 = (opcode & 'h00FF); - registers[(opcode & 'h0F00) >> 8] = scratch[7:0] & scratch2[7:0]; - end - 'hD???: begin - if (cycle_counter % 20 != 0) begin - halt = 1; - end else begin - halt = 0; - $display("HW : INSTR DRW Vx, Vy, nibble"); - x_cord = {24'h000000, registers[(opcode & 'h0F00) >> 8]}; - y_cord = {24'h000000, registers[(opcode & 'h00F0) >> 4]}; - - x_cord %= 64; - y_cord %= 32; - - scratch = (opcode & 'h000F); - size = scratch[7:0]; - registers[15] = 0; - - for (r = 0; r < size; r++) begin - for ( c = 0; c < 8; c++) begin - if (r + y_cord >= 32 || x_cord + c >= 64) - continue; - screen_pixel = vram[((r + y_cord) * 64) + (x_cord + c)]; - sprite_pixel = memory[{16'h0000, index_reg} + r] & ('h80 >> c); - - if (|sprite_pixel) begin - if (screen_pixel == 32'hFFFFFFFF) begin - registers[15] = 1; - end - vram[((r + y_cord) * 64) + (x_cord + c)] ^= 32'hFFFFFFFF; - end - end - end - end - end - 'hE?9E: begin - $display("HW : INSTR SKP Vx"); - if (keyboard[{registers[(opcode & 'h0F00) >> 8]}[3:0]] == 1) begin - program_counter += 2; - end - end - 'hE?A1: begin - $display("HW : INSTR SNE Vx"); - if (keyboard[{registers[(opcode & 'h0F00) >> 8]}[3:0]] != 1) begin - program_counter += 2; - end - end - 'hF?07: begin - $display("HW : INSTR LD Vx, DT"); - registers[(opcode & 'h0F00) >> 8] = delay_timer; - end - 'hF?0A: begin - $display("HW : INSTR LD Vx, K"); - halt = 1; - for(i = 0; i < 16; i++) begin - if (watch_key == 255) begin - if (keyboard[i]) begin - watch_key = i; - end - end else begin - if (!keyboard[watch_key]) begin - halt = 0; - watch_key = 255; - end - end - end - 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?29: begin - $display("HW : INSTR LDL F, Vx"); - index_reg = registers[(opcode & 'h0F00) >> 8] * 5; - 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 - if (!halt) - program_counter += 2; - cycle_counter++; - end -endmodule - -// pseudo random number generator -module randomizer ( - input wire clk_in, - input wire [15:0] pc, - input bit keyboard [15:0], - input int cycle_counter, - output bit [7:0] rand_bit - ); - - bit [7:0] last; - int i; - - always_ff @(posedge clk_in) begin - for (i = 0; i < 8; i++) begin - rand_bit[i] ^= ~keyboard[i] ? cycle_counter[i] : cycle_counter[7-i]; - rand_bit[i] ^= (cycle_counter % 7) == 0 ? pc[i] : ~pc[i]; - rand_bit[i] ^= keyboard[i+7] ? ~last[i] : last[i]; - end - last = rand_bit; - $display("Randomizer is: %b", rand_bit); - end -endmodule - -module chip8_gpu ( - input wire [31:0] vram [0:2047], - input wire [7:0] sound_timer - ); - import "DPI-C" function void draw_screen(logic [31:0] vram [0:2047], bit beep); - always_comb begin - draw_screen(vram, sound_timer > 0); - end -endmodule