From fa7998f2764cdfb59d9288073cd4405401c0322f Mon Sep 17 00:00:00 2001 From: Nicholas Orlowsky Date: Tue, 30 Jan 2024 19:54:35 -0600 Subject: [PATCH] graphics working --- .gitignore | 1 + README.md | 45 +++++++++++++++ makefile | 16 ++++++ rom_loader.sv | 23 ++++++++ screenshots/chip8-logo.png | Bin 0 -> 7416 bytes screenshots/ibm-logo.png | Bin 0 -> 6627 bytes tests/1-chip8-logo.ch8 | Bin 0 -> 260 bytes tests/2-ibm-logo.ch8 | Bin 0 -> 132 bytes yayacemu.cpp | 105 +++++++++++++++++++++++++++++++++ yayacemu.out | 71 +++++++++++++++++++++++ yayacemu.sv | 115 +++++++++++++++++++++++++++++++++++++ 11 files changed, 376 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 makefile create mode 100644 rom_loader.sv create mode 100644 screenshots/chip8-logo.png create mode 100644 screenshots/ibm-logo.png create mode 100644 tests/1-chip8-logo.ch8 create mode 100644 tests/2-ibm-logo.ch8 create mode 100644 yayacemu.cpp create mode 100755 yayacemu.out create mode 100644 yayacemu.sv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..697cf4f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +obj_dir/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..ef07fcd --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Yet Another Yet Another Chip-8 Emulator (yayacemu) + +[Because one just wasn't enough](https://github.com/nickorlow/yacemu). + +A Chip-8 emulator (interpreter) written in SystemVerilog with I/O simulated with C++ also depends on SDL2. + +### Building & Testing + +In order to run yayacemu, you must have sdl2, verilator, and make installed. + +Once you have the dependencies installed, you can build the emulator with: +```shell +make build +``` + +You can build start the emulator with: +```shell +make run ROM_FILE=[PATH_TO_YOUR_ROM] +``` + + +### Running + +If you have a binary, you can run it with the following: + +```shell +yayacemu [PATH_TO_YOUR_ROM] +``` + +### Todo +- [x] Graphics +- [ ] Corax+ Required Instructions +- [ ] Proper Flag Handling +- [ ] Working Input +- [ ] More Instructions +- [ ] Tetris Working Running +- [ ] Pass Quirks Test (DispQuirk is a bit touchy) +- [ ] Add beeper (instead of sound, screen becomes red) +- [ ] Code cleanup +- [ ] All Instructions + +### Screenshots + +![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) diff --git a/makefile b/makefile new file mode 100644 index 0000000..d821024 --- /dev/null +++ b/makefile @@ -0,0 +1,16 @@ +SDL_CFLAGS = `sdl2-config --cflags` +SDL_LDFLAGS = `sdl2-config --libs` + +lint: + verilator --lint-only --timing yayacemu.sv rom_loader.sv + +build: lint + verilator --cc --exe --build --timing -j 0 yayacemu.sv rom_loader.sv yayacemu.cpp -CFLAGS "${SDL_CFLAGS}" -LDFLAGS "${SDL_LDFLAGS}" && clear + +run: build + obj_dir/Vyayacemu ${ROM_FILE} + +clean: + rm -rf obj_dir + + diff --git a/rom_loader.sv b/rom_loader.sv new file mode 100644 index 0000000..237d98f --- /dev/null +++ b/rom_loader.sv @@ -0,0 +1,23 @@ +module rom_loader ( + output bit [7:0] memory [0:4095], + output logic rom_ready + ); + + import "DPI-C" function int load_rom(); + import "DPI-C" function bit [7:0] get_next_instr(); + import "DPI-C" function void close_rom(); + + int rom_size; + int i; + + initial begin + rom_size = load_rom(); + $display("HW : ROM size is %0d bytes (%0d bits) (%0d instructions)", rom_size, rom_size * 8, rom_size / 2); + for (i = 0; i < rom_size; i++) begin + memory[i] = get_next_instr(); + end + close_rom(); + $display("HW : ROM loaded successfully"); + rom_ready = 1; + end +endmodule diff --git a/screenshots/chip8-logo.png b/screenshots/chip8-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0b69ff939a69bb67cdb4f8a75d70e11856840463 GIT binary patch literal 7416 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 +#include + +#include "Vyayacemu.h" +#include "verilated.h" + +#include +#include +#include +#include +#include + +#define SCREEN_WIDTH 64 +#define SCREEN_HEIGHT 32 + +FILE *rom_file; +SDL_Window *window; +SDL_Renderer *renderer; +SDL_Texture *texture; +char* rom_name; + +void init_screen() { + SDL_Init(SDL_INIT_EVERYTHING); + window = + SDL_CreateWindow("Yet Another Yet Another Chip-8 Emulator", // creates a window + SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + SCREEN_WIDTH * 10, SCREEN_HEIGHT * 10, 0); + renderer = + SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_STREAMING, + SCREEN_WIDTH, SCREEN_HEIGHT); + printf("INF_EMU: Screen initialized\n"); +} + +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); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + printf("INF_EMU: Drawing Frame\n"); +} + +int load_rom() { + printf("INF_EMU: Loading ROM %s\n", rom_name); + + rom_file = fopen(rom_name, "r"); + + if (rom_file == NULL) { + printf("INF_EMU: Error reading ROM file. Panicing.\n"); + exit(1); + } + + fseek(rom_file, 0L, SEEK_END); + int rom_size = ftell(rom_file); + fseek(rom_file, 0L, SEEK_SET); + printf("INF_EMU: ROM size is %d bytes\n", rom_size); + + return rom_size; +} + +svBitVecVal get_next_instr() { + return (uint8_t) fgetc(rom_file); +} + +void close_rom() { + fclose(rom_file); +} + +int get_num() { + return 1; +} + +int main(int argc, char** argv) { + if (argc < 2) { + printf("Use: yayacemu [ROM_NAME]"); + exit(1); + } + rom_name = argv[1]; + VerilatedContext* contextp = new VerilatedContext; + contextp->commandArgs(argc, argv); + Vyayacemu* top = new Vyayacemu{contextp}; + //while (!contextp->gotFinish()) { + top->pc_out = 0; + while (top->pc_out < 100) { + top->clk_in ^= 1; + top->pc_in = top->pc_out; + top->eval(); + usleep(500); + } + printf("TB : Testbench has reached end of simulation. Pausing for 10 seconds before exiting"); + fflush(stdout); + usleep(10000000); + delete top; + delete contextp; + return 0; +} diff --git a/yayacemu.out b/yayacemu.out new file mode 100755 index 0000000..a31c378 --- /dev/null +++ b/yayacemu.out @@ -0,0 +1,71 @@ +#! /usr/bin/vvp +:ivl_version "12.0 (stable)" "(v12_0-dirty)"; +:ivl_delay_selection "TYPICAL"; +:vpi_time_precision + 0; +:vpi_module "/usr/lib/ivl/system.vpi"; +:vpi_module "/usr/lib/ivl/vhdl_sys.vpi"; +:vpi_module "/usr/lib/ivl/vhdl_textio.vpi"; +:vpi_module "/usr/lib/ivl/v2005_math.vpi"; +:vpi_module "/usr/lib/ivl/va_math.vpi"; +:vpi_module "/usr/lib/ivl/v2009.vpi"; +S_0x5617a32fb170 .scope package, "$unit" "$unit" 2 1; + .timescale 0 0; +S_0x5617a32fb300 .scope module, "chip8_processor" "chip8_processor" 3 1; + .timescale 0 0; + .port_info 0 /INPUT 16 "opcode"; +o0x7f10d36a7018 .functor BUFZ 16, C4; HiZ drive +v0x5617a32fb490_0 .net "opcode", 15 0, o0x7f10d36a7018; 0 drivers +v0x5617a33439a0_0 .var "opcode2", 15 0; + .scope S_0x5617a32fb300; +T_0 ; + %wait E_0x0; + %pushi/vec4 4064, 0, 16; + %store/vec4 v0x5617a33439a0_0, 0, 16; + %load/vec4 v0x5617a33439a0_0; + %dup/vec4; + %pushi/vec4 224, 0, 16; + %cmp/z; + %jmp/1 T_0.0, 4; + %dup/vec4; + %pushi/vec4 238, 0, 16; + %cmp/z; + %jmp/1 T_0.1, 4; + %dup/vec4; + %pushi/vec4 0, 4095, 16; + %cmp/z; + %jmp/1 T_0.2, 4; + %dup/vec4; + %pushi/vec4 4096, 4095, 16; + %cmp/z; + %jmp/1 T_0.3, 4; + %dup/vec4; + %pushi/vec4 8192, 4095, 16; + %cmp/z; + %jmp/1 T_0.4, 4; + %jmp T_0.5; +T_0.0 ; + %vpi_call/w 3 9 "$display", "CLS" {0 0 0}; + %jmp T_0.5; +T_0.1 ; + %vpi_call/w 3 10 "$display", "RET" {0 0 0}; + %jmp T_0.5; +T_0.2 ; + %vpi_call/w 3 11 "$display", "SYS" {0 0 0}; + %jmp T_0.5; +T_0.3 ; + %vpi_call/w 3 12 "$display", "JP" {0 0 0}; + %jmp T_0.5; +T_0.4 ; + %vpi_call/w 3 13 "$display", "CALL" {0 0 0}; + %jmp T_0.5; +T_0.5 ; + %pop/vec4 1; + %vpi_call/w 3 15 "$display", "yayacemu" {0 0 0}; + %jmp T_0; + .thread T_0; +# The file index is used to find the file name in the following table. +:file_names 4; + "N/A"; + ""; + "-"; + "yayacemu.sv"; diff --git a/yayacemu.sv b/yayacemu.sv new file mode 100644 index 0000000..f78c297 --- /dev/null +++ b/yayacemu.sv @@ -0,0 +1,115 @@ +module yayacemu ( + input wire clk_in, + input int pc_in, + output int pc_out + ); + 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]; + logic [7:0] index_reg; + logic rom_ready; + int pc; + + rom_loader rl (memory, rom_ready); + chip8_cpu cpu (memory, clk_in, vram, index_reg, registers, pc_in, pc_out); + chip8_gpu gpu (vram); + + initial begin + init_screen(); + end + +endmodule + +module chip8_cpu( + input bit [7:0] memory [0:4095], + input wire clk_in, + output wire [31:0] vram [0:2047], + output wire [7:0] index_reg, + output wire [7:0] registers [0:15], + input int pc_in, + output int pc_out + ); + + logic [15:0] opcode; + logic [15:0] scratch; + + 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; + + int r; + int c; + always_ff @(posedge clk_in) begin + opcode = {memory[pc_in], memory[pc_in+1]}; + $display("HW : opcode is 0x%h (%b)", opcode, opcode); + $display("HW : PC %0d", pc_in); + + casez(opcode) + 'h00E0: begin + $display("HW : INSTR CLS"); + for(i = 0; i < 2048; i++) begin + vram[i] = 0; + end + end + 'h00EE: $display("HW : INSTR RET"); + 'h0???: $display("HW : INSTR SYS addr"); + 'h1???: $display("HW : INSTR JP addr"); + 'h2???: $display("HW : INSTR CALL addr"); + '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 + 'hA???: begin + $display("HW : INSTR LD I, addr"); + scratch = (opcode & 'h0FFF); + index_reg = scratch[7:0]; + end + 'hD???: begin + $display("HW : INSTR DRW Vx, Vy, nibble"); + x_cord = {24'h000000, registers[(opcode & 'h0F00) >> 8]}; + y_cord = {24'h000000, registers[(opcode & 'h00F0) >> 4]}; + + scratch = (opcode & 'h000F); + size = scratch[7:0]; + + for (r = 0; r < size; r++) begin + for ( c = 0; c < 8; c++) begin + screen_pixel = vram[((r + y_cord) * 64) + (x_cord + c)]; + sprite_pixel = memory[{24'h000000, 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)] = screen_pixel ^ 32'hFFFFFFFF; + end + end + end + end + default: $display("HW : ILLEGAL INSTRUCTION"); + endcase + + pc_out <= pc_in + 2; + end +endmodule + +module chip8_gpu ( + input wire [31:0] vram [0:2047] + ); + import "DPI-C" function void draw_screen(logic [31:0] vram [0:2047]); + always_comb begin + draw_screen(vram); + end +endmodule