Add Wisdom Tree / Mani 161 mappers & mapper selection.

This commit is contained in:
paulb-nl
2022-08-06 17:33:46 +02:00
parent 69372bfd8e
commit d25e0d64e7
5 changed files with 219 additions and 63 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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));

86
rtl/mappers/misc.v Normal file
View File

@@ -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