From e72ae0fe2714c1d1ee51322fa2d54bb5606ed6f4 Mon Sep 17 00:00:00 2001 From: Bruno Duarte Gouveia Date: Sat, 4 May 2019 22:31:20 +0100 Subject: [PATCH 1/2] GENERAL: added Kitrinx's Game Genie Code --- Gameboy.qsf | 1 + Gameboy.sv | 34 +++++++++++++++++++-- gamegenie.sv | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++ gb.v | 27 +++++++++++++++-- 4 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 gamegenie.sv diff --git a/Gameboy.qsf b/Gameboy.qsf index 34f08f4..5d3e8a2 100644 --- a/Gameboy.qsf +++ b/Gameboy.qsf @@ -351,6 +351,7 @@ set_location_assignment PIN_W20 -to SW[3] set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:sys/build_id.tcl" +set_global_assignment -name SYSTEMVERILOG_FILE gamegenie.sv set_global_assignment -name CDF_FILE jtag.cdf set_global_assignment -name QIP_FILE sys/sys.qip set_global_assignment -name QIP_FILE t80/T80.qip diff --git a/Gameboy.sv b/Gameboy.sv index b7add1b..2b77a4c 100644 --- a/Gameboy.sv +++ b/Gameboy.sv @@ -147,6 +147,8 @@ localparam CONF_STR1 = { "OEF,System,Auto,Gameboy,Gameboy Color;", "-;", "OC,Inverted color,No,Yes;", + "FC,GG,Game Genie Code;", + "OH,Game Genie,ON,OFF;", "O1,Palette,Grayscale,Custom;" }; @@ -250,9 +252,11 @@ hps_io #(.STRLEN(($size(CONF_STR1)>>3) + ($size(CONF_STR2)>>3) + ($size(CONF_STR /////////////////////////////////////////////////// wire cart_download = ioctl_download && (filetype == 8'h01 || filetype == 8'h41 || filetype == 8'h80); -wire palette_download = ioctl_download && (filetype == 8'h05 || filetype == 8'h00); +wire palette_download = ioctl_download && (filetype == 8'h07 || filetype == 8'h00); wire bios_download = ioctl_download && (filetype == 8'h40); +wire type_gg = filetype == 8'h04; + wire [1:0] sdram_ds = cart_download ? 2'b11 : {cart_addr[0], ~cart_addr[0]}; wire [15:0] sdram_do; wire [15:0] sdram_di = cart_download ? ioctl_dout : 16'd0; @@ -553,7 +557,10 @@ gb gb ( .lcd_data ( lcd_data ), .lcd_mode ( lcd_mode ), .lcd_on ( lcd_on ), - .speed ( speed ) + .speed ( speed ), + + .gg (status[17]), + .gg_code (gg_code) ); // the lcd to vga converter @@ -634,6 +641,29 @@ dpram_dif #(12,8,11,16) boot_rom_gbc ( .q_b () ); +///////////////////////// GAME GENIE ////////////////////////////////// + +reg [34:0] gg_code; + +// Code layout: +// {clock bit, enable, compare enable, 15'b address, 8'b compare, 8'b replace} +// 34 33 32 31:16 15:8 7:0 +reg [3:0] old_ioctl_addr; +always_ff @(posedge clk_sys) begin + gg_code[34] <= 1'b0; + old_ioctl_addr <= ioctl_addr[3:0]; + gg_code[34] <= 1'b0; + + if (ioctl_download && type_gg) begin + case (ioctl_addr[3:0]) + 0: gg_code[32] <= ioctl_dout[0]; // Compare Enable + 4: gg_code[31:16] <= ioctl_dout; // Address + 8: gg_code[15:8] <= ioctl_dout[7:0]; // compare byte + 12: gg_code[7:0] <= ioctl_dout[7:0]; // replace byte + 14: gg_code[34] <= 1'b1; // Clock it in + endcase + end +end ///////////////////////// BRAM SAVE/LOAD ///////////////////////////// diff --git a/gamegenie.sv b/gamegenie.sv new file mode 100644 index 0000000..6d413b2 --- /dev/null +++ b/gamegenie.sv @@ -0,0 +1,86 @@ +// NES Game Genie handling by Kitrinx +// Apr 21, 2019 + +// Code layout: +// {clock bit, enable, compare enable, 15'b address, 8'b compare, 8'b replace} +// 34 33 32 31:16 15:8 7:0 + +localparam MAX_CODES = 32; + +module geniecodes( + input clk, + input reset, + input enable, + input [15:0] addr_in, + input [7:0] data_in, + input [37:0] code, + output genie_ovr, + output [7:0] genie_data +); + +reg [33:0] codes[MAX_CODES]; + +// If MAX_INDEX is changes, these need to be made larger +wire [4:0] index, dup_index; +reg [4:0] next_index; +wire found_dup; + +assign index = found_dup ? dup_index : next_index; + +// See if the code exists already, so it can be disabled if loaded again +always_comb begin + int x; + dup_index = 0; + found_dup = 0; + + for (x = 0; x < MAX_CODES; x = x + 1'b1) begin + if (codes[x][31:16] == code[31:16]) begin + dup_index = x[4:0]; + found_dup = 1'b1; + end + end +end + +reg code_change; +always_ff @(posedge clk) begin + int x; + if (reset) begin + next_index <= 0; + code_change <= 0; + for (x = 0; x < MAX_CODES; x = x + 1) codes[x] <= 34'd0; + end else begin + code_change <= code[34]; + if (code[34] & ~code_change) begin // detect posedge + // Disable the code if it's the exact same code loaded again, otherwise, + // replace it enabled if it has the same address, otherwise, add a new code + codes[index] <= found_dup ? ((codes[index][15:0] == code[15:0]) ? {codes[index][33] ? 1'b0 : 1'b1, code[32:0]} : {1'b1, code[32:0]}) : {1'b1, code[32:0]}; + if (~found_dup) next_index <= next_index + 1'b1; + end + end +end + +always_comb begin + int x; + genie_ovr = 1'b0; + genie_data = 8'd0; + x = 0; + + if (enable) begin + for (x = 0; x < MAX_CODES; x = x + 1'b1) begin + if (codes[x][33] && codes[x][31:16] == addr_in) begin + if (codes[x][32]) begin // Check for compare bit if needed + if (codes[x][15:8] == data_in) begin + genie_ovr = 1'b1; + genie_data = codes[x][7:0]; + end + end else begin // Otherwise just match + genie_ovr = 1'b1; + genie_data = codes[x][7:0]; + end + end + end + end +end + + +endmodule \ No newline at end of file diff --git a/gb.v b/gb.v index 689b31f..470e2a6 100644 --- a/gb.v +++ b/gb.v @@ -51,7 +51,10 @@ module gb ( output [1:0] lcd_mode, output lcd_on, - output speed //GBC + output speed, //GBC + + input gg, + input [34:0] gg_code ); // include cpu @@ -151,11 +154,31 @@ GBse cpu ( .HALT_n ( ), .BUSAK_n ( ), .A ( cpu_addr ), - .DI ( cpu_di ), + .DI ( genie_ovr ? genie_data : cpu_di), .DO ( cpu_do ), .STOP ( cpu_stop ) ); +// -------------------------------------------------------------------- +// --------------------------- Game Genie ----------------------------- +// -------------------------------------------------------------------- + +wire genie_ovr; +wire [7:0] genie_data; + + +geniecodes codes ( + .clk (clk2x), + .reset (reset), + .enable (~gg), + .addr_in (cpu_addr), + .data_in (cpu_di), + .code (gg_code), + .genie_ovr (genie_ovr), + .genie_data (genie_data) +); + + // -------------------------------------------------------------------- // --------------------- Speed Toggle KEY1 (GBC)----------------------- // -------------------------------------------------------------------- From c84c10761d84ecffa58531cae39f4718f86e2374 Mon Sep 17 00:00:00 2001 From: Bruno Duarte Gouveia Date: Sun, 5 May 2019 01:47:43 +0100 Subject: [PATCH 2/2] GENERAL: only reset game genie module when changing game --- Gameboy.sv | 1 + gb.v | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Gameboy.sv b/Gameboy.sv index 2b77a4c..729bc46 100644 --- a/Gameboy.sv +++ b/Gameboy.sv @@ -531,6 +531,7 @@ gb gb ( .reset ( reset ), .clk ( clk_cpu ), // the whole gameboy runs on 4mhnz .clk2x ( clk_cpu2x ), // ~8MHz in dualspeed mode (GBC) + .new_game_load ( cart_download), .fast_boot ( 0 ), .joystick ( joystick ), diff --git a/gb.v b/gb.v index 470e2a6..da72b13 100644 --- a/gb.v +++ b/gb.v @@ -21,6 +21,7 @@ module gb ( input reset, + input new_game_load, input clk, input clk2x, @@ -169,7 +170,7 @@ wire [7:0] genie_data; geniecodes codes ( .clk (clk2x), - .reset (reset), + .reset (new_game_load), .enable (~gg), .addr_in (cpu_addr), .data_in (cpu_di),