diff --git a/Gameboy.sv b/Gameboy.sv index d9f20ce..72aaf72 100644 --- a/Gameboy.sv +++ b/Gameboy.sv @@ -194,13 +194,15 @@ assign AUDIO_MIX = status[8:7]; // 0 1 2 3 4 5 6 // 01234567890123456789012345678901 23456789012345678901234567890123 // 0123456789ABCDEFGHIJKLMNOPQRSTUV 0123456789ABCDEFGHIJKLMNOPQRSTUV -// XXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX XXXXXXX +// XXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX XXXXXXXXXX `include "build_id.v" localparam CONF_STR = { "GAMEBOY;SS3E000000:40000;", "FS1,GBCGB BIN,Load ROM;", "OEF,System,Auto,Gameboy,Gameboy Color,MegaDuck;", + "D7o79,Mapper,Auto,WisdomTree,Mani161,MBC1,MBC3;", + "-;", "ONO,Super Game Boy,Off,Palette,On;", "d5FC2,SGB,Load SGB border;", "-;", @@ -322,6 +324,10 @@ wire [15:0] joy0_rumble; wire [32:0] RTC_time; +wire sys_auto = (status[15:14] == 0); +wire sys_gbc = (status[15:14] == 2); +wire sys_megaduck = (status[15:14] == 3); + hps_io #(.CONF_STR(CONF_STR), .WIDE(1)) hps_io ( .clk_sys(clk_sys), @@ -349,7 +355,7 @@ hps_io #(.CONF_STR(CONF_STR), .WIDE(1)) hps_io .buttons(buttons), .status(status), - .status_menumask({using_real_cgb_bios,sgb_border_en,isGBC,cart_ready,sav_supported,|tint,gg_available}), + .status_menumask({sys_megaduck,using_real_cgb_bios,sgb_border_en,isGBC,cart_ready,sav_supported,|tint,gg_available}), .status_in({status[63:34],ss_slot,status[31:0]}), .status_set(statusUpdate), .direct_video(direct_video), @@ -445,6 +451,7 @@ wire [31:0] RTC_timestampOut; wire [47:0] RTC_savedtimeOut; wire RTC_inuse; wire rumbling; +wire [2:0] mapper_sel = status[41:39]; assign joy0_rumble = {8'd0, ((rumbling & ~status[38]) ? 8'd128 : 8'd0)}; @@ -456,6 +463,7 @@ cart_top cart ( .ce_cpu2x ( ce_cpu2x ), .speed ( speed ), .megaduck ( megaduck ), + .mapper_sel ( mapper_sel ), .cart_addr ( cart_addr ), .cart_a15 ( cart_a15 ), @@ -551,12 +559,15 @@ reg megaduck = 0; reg isGBC = 0; always @(posedge clk_sys) if(reset) begin if (cart_download) - megaduck <= (status[15:14] == 3); + megaduck <= sys_megaduck; if (md_download) - megaduck <= (status[15:14] == 0) || (status[15:14] == 3); + megaduck <= sys_auto || sys_megaduck; - if(status[15:14]) isGBC <= (status[15:14] == 2); - else if(cart_download) isGBC <= (status[15:14] == 0) && !filetype[7:6]; + if(~sys_auto) isGBC <= sys_gbc; + else if(cart_download) begin + if (!filetype[5:0]) isGBC <= isGBC_game; + else isGBC <= !filetype[7:6]; + end end wire [15:0] GB_AUDIO_L; diff --git a/files.qip b/files.qip index d13ea5d..daffe35 100644 --- a/files.qip +++ b/files.qip @@ -36,5 +36,6 @@ set_global_assignment -name VERILOG_FILE rtl/mappers/tama.v set_global_assignment -name SYSTEMVERILOG_FILE rtl/mappers/rocket.sv set_global_assignment -name VERILOG_FILE rtl/mappers/sachen.v set_global_assignment -name VERILOG_FILE rtl/mappers/megaduck.v +set_global_assignment -name VERILOG_FILE rtl/mappers/misc.v set_global_assignment -name SDC_FILE Gameboy.sdc set_global_assignment -name SYSTEMVERILOG_FILE Gameboy.sv diff --git a/rtl/cart.v b/rtl/cart.v index fa8d831..db52eb8 100644 --- a/rtl/cart.v +++ b/rtl/cart.v @@ -6,6 +6,7 @@ module cart_top ( input ce_cpu2x, input speed, input megaduck, + input [2:0] mapper_sel, input [14:0] cart_addr, input cart_a15, @@ -123,6 +124,9 @@ mappers mappers ( .tama ( tama ), .rocket ( rocket ), .sachen ( sachen), + .wisdom_tree ( wisdom_tree ), + .mani161 ( mani161 ), + .megaduck ( megaduck_en ), .isGBC_game ( isGBC_game ), @@ -199,6 +203,7 @@ wire [3:0] ram_mask = // 0 - no ram 4'b1111; // 4 - 128k 16 banks // ROM size +/* wire [8:0] rom_mask = (cart_rom_size == 0)? 9'b000000001: // 0 - 2 banks, 32k direct mapped (cart_rom_size == 1)? 9'b000000011: // 1 - 4 banks = 64k @@ -213,11 +218,14 @@ wire [8:0] rom_mask = (cart_rom_size == 83)?9'b001111111: //$53 - 80 banks = 1.2M (cart_rom_size == 84)?9'b001111111: 9'b001111111; //$54 - 96 banks = 1.5M +*/ -wire mbc1 = (cart_mbc_type == 1) || (cart_mbc_type == 2) || (cart_mbc_type == 3); +reg [8:0] rom_mask; // get mask from file size + +wire mbc1 = (mapper_sel_r == 3'd3) || (cart_mbc_type == 1) || (cart_mbc_type == 2) || (cart_mbc_type == 3); wire mbc2 = (cart_mbc_type == 5) || (cart_mbc_type == 6); //wire mmm01 = (cart_mbc_type == 11) || (cart_mbc_type == 12) || (cart_mbc_type == 13) || (cart_mbc_type == 14); -wire mbc3 = (cart_mbc_type == 15) || (cart_mbc_type == 16) || (cart_mbc_type == 17) || (cart_mbc_type == 18) || (cart_mbc_type == 19); +wire mbc3 = (mapper_sel_r == 3'd4) || (cart_mbc_type == 15) || (cart_mbc_type == 16) || (cart_mbc_type == 17) || (cart_mbc_type == 18) || (cart_mbc_type == 19); wire mbc30 = mbc3 && ( (cart_rom_size == 7) || (cart_ram_size == 5) ); //wire mbc4 = (cart_mbc_type == 21) || (cart_mbc_type == 22) || (cart_mbc_type == 23); wire mbc5 = (cart_mbc_type == 25) || (cart_mbc_type == 26) || (cart_mbc_type == 27) || (cart_mbc_type == 28) || (cart_mbc_type == 29) || (cart_mbc_type == 30); @@ -231,6 +239,9 @@ wire tama = (cart_mbc_type == 253); wire HuC3 = (cart_mbc_type == 254); wire HuC1 = (cart_mbc_type == 255); +wire wisdom_tree = (mapper_sel_r == 3'd1); +wire mani161 = (mapper_sel_r == 3'd2); + wire has_rumble = (cart_mbc_type[7:2] == 6'b0001_11); wire cart_rumbling; assign rumbling = has_rumble & cart_rumbling; @@ -252,6 +263,7 @@ wire mmm01_bank = (ioctl_addr[18:12] == 7'h78); // $78000+ wire cart_logo_match = &cart_logo_check; reg old_cart_download; +reg [2:0] mapper_sel_r; always @(posedge clk_sys) begin old_cart_download <= cart_download; @@ -262,10 +274,20 @@ always @(posedge clk_sys) begin mbc1m <= 0; mmm01 <= 0; { sachen, sachen_t1, sachen_t2 } <= 0; + mapper_sel_r <= mapper_sel; end if(cart_download & ioctl_wr) begin - if (!megaduck) begin + + rom_mask <= ioctl_addr[22:14]; + + if (megaduck) begin + cart_cgb_flag <= 0; + cart_sgb_flag <= 0; + mapper_sel_r <= 0; + if (ioctl_addr > 'h100) // Make sure there's time to reset the banks in the mapper + cart_mbc_type <= 8'd250; + end else begin if (~|ioctl_addr[24:12] || (mmm01_bank & mmm01) ) // MMM01 header is at the end of ROM case(ioctl_addr[11:0]) 12'h142: cart_cgb_flag <= ioctl_dout[15]; @@ -278,62 +300,63 @@ always @(posedge clk_sys) begin 12'h14a: { cart_old_licensee } <= ioctl_dout[15:8]; endcase - // Sachen - if (~|ioctl_addr[24:12]) begin - case(ioctl_addr[11:0]) - 12'h100: sachen_t1 <= (ioctl_dout[15:8] != 8'hC3); - 12'h140: sachen_t2 <= (ioctl_dout[ 7:0] == 8'hC3); // 0xC3 opcode is at $140 instead of $101 - 12'h150: begin /// CGB flag - if (sachen_t1 & sachen_t2) begin - sachen <= 1'b1; - cart_cgb_flag <= ioctl_dout[15]; - cart_mbc_type <= 0; - cart_sgb_flag <= 0; - cart_ram_size <= 0; - cart_rom_size <= 0; - cart_old_licensee <= 0; + // Disable other mappers when a specific mapper has been selected + if (|mapper_sel_r) begin + cart_mbc_type <= 8'd0; + mbc1m <= 0; + mmm01 <= 0; + sachen <= 0; + end else begin + // Sachen + if (~|ioctl_addr[24:12]) begin + case(ioctl_addr[11:0]) + 12'h100: sachen_t1 <= (ioctl_dout[15:8] != 8'hC3); + 12'h140: sachen_t2 <= (ioctl_dout[ 7:0] == 8'hC3); // 0xC3 opcode is at $140 instead of $101 + 12'h150: begin /// CGB flag + if (sachen_t1 & sachen_t2) begin + sachen <= 1'b1; + cart_cgb_flag <= ioctl_dout[15]; + cart_mbc_type <= 0; + cart_sgb_flag <= 0; + cart_ram_size <= 0; + cart_old_licensee <= 0; + end + end + endcase + end + + //Store cart logo data + if (ioctl_addr >= 'h104 && ioctl_addr <= 'h112) begin + cart_logo_data[cart_logo_idx] <= ioctl_dout; + cart_logo_idx <= cart_logo_idx + 1'b1; + end + + // MBC1 Multicart detect: Compare 8 words of logo data at second 256KByte bank ($40000) + // MMM01 detect: Compare the last bank every 512KByte ($78000+) + if ( mbc1m_bank | mmm01_bank ) begin + if (ioctl_addr[11:0] >= 12'h104 && ioctl_addr[11:0] <= 12'h112) begin + cart_logo_check[cart_logo_idx] <= (ioctl_dout == cart_logo_data[cart_logo_idx]); + cart_logo_idx <= cart_logo_idx + 1'b1; + if (&cart_logo_idx) begin + if (mbc1m_bank) mbc1m_check_end <= 1; + if (mmm01_bank) mmm01_check_end <= 1; end end - endcase - end - end else begin // megaduck - cart_cgb_flag <= 0; - cart_sgb_flag <= 0; - cart_rom_size <= ioctl_addr[17] ? 2'd3 : ioctl_addr[16] ? 2'd2 : ioctl_addr[15] ? 2'd1 : 2'd0; - if (ioctl_addr > 'h100) // Make sure there's time to reset the banks in the mapper - cart_mbc_type <= 8'd250; - end + end - //Store cart logo data - if (ioctl_addr >= 'h104 && ioctl_addr <= 'h112) begin - cart_logo_data[cart_logo_idx] <= ioctl_dout; - cart_logo_idx <= cart_logo_idx + 1'b1; - end + if (mbc1m_check_end) begin + mbc1m_check_end <= 0; + mbc1m <= cart_logo_match; + end - // MBC1 Multicart detect: Compare 8 words of logo data at second 256KByte bank ($40000) - // MMM01 detect: Compare the last bank every 512KByte ($78000+) - if ( mbc1m_bank | mmm01_bank ) begin - if (ioctl_addr[11:0] >= 12'h104 && ioctl_addr[11:0] <= 12'h112) begin - cart_logo_check[cart_logo_idx] <= (ioctl_dout == cart_logo_data[cart_logo_idx]); - cart_logo_idx <= cart_logo_idx + 1'b1; - if (&cart_logo_idx) begin - if (mbc1m_bank) mbc1m_check_end <= 1; - if (mmm01_bank) mmm01_check_end <= 1; + if (mmm01_check_end) begin + mmm01_check_end <= 0; + mmm01 <= cart_logo_match; + if (cart_logo_match) mbc1m <= 0; end end end end - - if (mbc1m_check_end) begin - mbc1m_check_end <= 0; - mbc1m <= cart_logo_match; - end - - if (mmm01_check_end) begin - mmm01_check_end <= 0; - mmm01 <= cart_logo_match; - if (cart_logo_match) mbc1m <= 0; - end end assign ram_size = cart_ram_size; diff --git a/rtl/mappers/mappers.v b/rtl/mappers/mappers.v index 49f79a1..9703321 100644 --- a/rtl/mappers/mappers.v +++ b/rtl/mappers/mappers.v @@ -21,6 +21,9 @@ module mappers( input tama, input rocket, input sachen, + input wisdom_tree, + input mani161, + input megaduck, input isGBC_game, @@ -94,12 +97,14 @@ tri0 RTC_inuse_b; wire ce = speed ? ce_cpu2x : ce_cpu; -wire no_mapper = ~(mbc1 | mbc2 | mbc3 | mbc5 | mbc6 | mbc7 | mmm01 | huc1 | huc3 | gb_camera | tama | rocket | sachen | megaduck); +wire no_mapper = ~(mbc1 | mbc2 | mbc3 | mbc5 | mbc6 | mbc7 | mmm01 | huc1 | huc3 | gb_camera | tama | rocket | sachen | wisdom_tree | mani161 | megaduck); +wire no_mapper_single_bank = no_mapper & ~rom_mask[1]; +wire no_mapper_multi_bank = no_mapper & rom_mask[1]; // size > 32KB wire rom_override = (rocket); wire cart_oe_override = (mbc3 | mbc7 | huc1 | huc3 | gb_camera | tama); mbc1 map_mbc1 ( - .enable ( mbc1 ), + .enable ( mbc1 | no_mapper_multi_bank ), .mbc1m ( mbc1m ), .clk_sys ( clk_sys ), @@ -590,15 +595,45 @@ megaduck map_megaduck ( .has_battery_b ( has_battery_b ) ); +// Mani 4-in-1 DMG 601 & Wisdom Tree 32KB bank mappers +misc_mapper map_misc ( + .enable ( ~reset & (wisdom_tree | mani161) ), + + .clk_sys ( clk_sys ), + .ce_cpu ( ce ), + + .mapper_sel ( mani161 ), + + .savestate_load ( savestate_load ), + .savestate_data ( savestate_data ), + .savestate_back_b ( savestate_back_b ), + + .rom_mask ( rom_mask ), + + .cart_addr ( cart_addr ), + .cart_a15 ( cart_a15 ), + + .cart_wr ( cart_wr ), + .cart_di ( cart_di ), + + .cram_di ( cram_di ), + .cram_do_b ( cram_do_b ), + .cram_addr_b ( cram_addr_b ), + + .mbc_addr_b ( mbc_addr_b ), + .ram_enabled_b ( ram_enabled_b ), + .has_battery_b ( has_battery_b ) +); + assign { cram_do } = { cram_do_b }; assign { savestate_back, savestate_back2 } = { savestate_back_b, savestate_back2_b }; assign { RTC_timestampOut, RTC_savedtimeOut, RTC_inuse } = { RTC_timestampOut_b, RTC_savedtimeOut_b, RTC_inuse_b }; assign { cram_wr_do, cram_wr } = { cram_wr_do_b, cram_wr_b }; -assign mbc_addr = no_mapper ? {8'd0, cart_addr[14:0]} : mbc_addr_b; -assign cram_addr = no_mapper ? {4'd0, cart_addr[12:0]} : cram_addr_b; -assign has_battery = no_mapper ? (cart_mbc_type == 8'h09) : has_battery_b; -assign ram_enabled = no_mapper ? has_ram : ram_enabled_b; +assign mbc_addr = no_mapper_single_bank ? {8'd0, cart_addr[14:0]} : mbc_addr_b; +assign cram_addr = no_mapper_single_bank ? {4'd0, cart_addr[12:0]} : cram_addr_b; +assign has_battery = no_mapper_single_bank ? (cart_mbc_type == 8'h09) : has_battery_b; +assign ram_enabled = no_mapper_single_bank ? has_ram : ram_enabled_b; assign rom_do = rom_override ? rom_do_b : rom_di; assign cart_oe = cart_oe_override ? cart_oe_b : ((cart_rd & ~cart_a15) | (cram_rd & ram_enabled)); diff --git a/rtl/mappers/misc.v b/rtl/mappers/misc.v new file mode 100644 index 0000000..90be454 --- /dev/null +++ b/rtl/mappers/misc.v @@ -0,0 +1,86 @@ +module misc_mapper ( + input enable, + + input clk_sys, + input ce_cpu, + + input mapper_sel, // 0: Wisdom Tree, 1: Mani DMG-601 + + input savestate_load, + input [15:0] savestate_data, + inout [15:0] savestate_back_b, + + input [8:0] rom_mask, + + input [14:0] cart_addr, + input cart_a15, + + input cart_wr, + input [7:0] cart_di, + + input [7:0] cram_di, + inout [7:0] cram_do_b, + inout [16:0] cram_addr_b, + + inout [22:0] mbc_addr_b, + inout ram_enabled_b, + inout has_battery_b +); + +wire [22:0] mbc_addr; +wire ram_enabled; +wire [7:0] cram_do; +wire [16:0] cram_addr; +wire has_battery; +wire [15:0] savestate_back; + +assign mbc_addr_b = enable ? mbc_addr : 23'hZ; +assign cram_do_b = enable ? cram_do : 8'hZ; +assign cram_addr_b = enable ? cram_addr : 17'hZ; +assign ram_enabled_b = enable ? ram_enabled : 1'hZ; +assign has_battery_b = enable ? has_battery : 1'hZ; +assign savestate_back_b = enable ? savestate_back : 16'hZ; + +// --------------------- CPU register interface ------------------ +reg [7:0] rom_bank_reg; +reg map_disable; + +assign savestate_back[ 7: 0] = rom_bank_reg; +assign savestate_back[ 8] = map_disable; +assign savestate_back[15: 9] = 0; + +always @(posedge clk_sys) begin + if(savestate_load & enable) begin + rom_bank_reg <= savestate_data[ 7: 0]; //8'd0; + map_disable <= savestate_data[ 8]; //1'b0; + end else if(~enable) begin + rom_bank_reg <= 8'd0; + map_disable <= 1'b0; + end else if(ce_cpu) begin + if (cart_wr & ~cart_a15) begin + if (mapper_sel) begin + // Mani DMG-601 + if (~map_disable) begin + rom_bank_reg <= { 5'd0, cart_di[2:0] }; + map_disable <= 1'b1; + end + end else begin + // Wisdom Tree + rom_bank_reg <= cart_addr[7:0]; + end + end + end +end + +// mask address lines to enable proper mirroring +wire [7:0] rom_bank = rom_bank_reg & rom_mask[8:1]; + +assign mbc_addr = { rom_bank, cart_addr[14:0] }; + +assign cram_do = 8'hFF; +assign cram_addr = { 4'b0000, cart_addr[12:0] }; + +assign ram_enabled = 0; +assign has_battery = 0; + +endmodule \ No newline at end of file