From d17f5b97f0cd8928bdafbdb5fdffa7267aa4473a Mon Sep 17 00:00:00 2001 From: Fabricio Breve Date: Fri, 1 May 2026 04:12:50 -0300 Subject: [PATCH] Add Meka mapper 11 and Dahjee Type A expansion (#184) * Clear bk_pending when download starts Add explicit check to clear bk_pending on the transition into downloading (~old_downloading & downloading). This prevents a lingering backup-pending flag when a new download begins while preserving the existing logic that sets bk_pending on bk_ena && ~OSD_STATUS && bk_save_write and clears it when bk_state is active. Change applied in SMS.sv. * Add Meka mapper 11 and Dahjee Type A expansion Introduce support for MEKA mapper 11 and Dahjee Type A expansion. New Master System games supported: - FA Tetris (Korea) (Unl) - Flashpoint (Korea) (Unl) New SG-1000 games supported: - Rally-X (Taiwan) (Chinese Logo) (Unl) - Rally-X (Taiwan) (English Logo) (Unl) - Road Fighter (Taiwan) (Chinese Logo) (Unl) - Road Fighter (Taiwan) (English Logo) (Unl) Also add CRC-based for 4 PAK All Action (Australia) (Unl). Changes include: - Added signals: mapper_4pak_crc, mapper_linear, mapper_sega_locked, mapper_dahjee_a. - Implemented CRC matches for several carts (linear/MEKA type 11 and Dahjee Type A), and set mapper_4pak via CRC (0x73ED) at reset instead of purely write-based auto-detect. - Added mapper_linear branch: linear ROM addressing for specific 32KB games. - Added mapper_sega_locked mode to keep Sega mapper path but block bank writes for 48KB dahjee_typeb games (works around FPGA boot/logo issues). - Added mapper_dahjee_a: supports linear ROM with 8KB RAM at 0x2000-0x3FFF; adjusted nvram addressing and read paths so that that area reads/writes use the nvram block. - Updated rom_RD gating and I/O/data mux logic to account for Dahjee Type A and linear mapper cases. - Updated rom_a_i generation to include sc3000_en, mapper_linear, and mapper_dahjee_a linear-addressing behavior. - Minor comment and formatting clarifications around mapper selection and OSD mapper lock/force behavior. These changes enable proper behavior for several regional/unlabeled cartridges and fix boot issues on physical FPGA targets by selecting the correct mapping path and protecting bank registers when required. --------- Co-authored-by: Fabricio Breve <7475908+fbreve@users.noreply.github.com> --- SMS.sv | 4 ++- rtl/system.vhd | 82 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 73 insertions(+), 13 deletions(-) diff --git a/SMS.sv b/SMS.sv index 1c49178..c7bbd27 100644 --- a/SMS.sv +++ b/SMS.sv @@ -1235,7 +1235,9 @@ wire bk_save_write = nvram_we; reg bk_pending; always @(posedge clk_sys) begin - if (bk_ena && ~OSD_STATUS && bk_save_write) + if (~old_downloading & downloading) + bk_pending <= 1'b0; + else if (bk_ena && ~OSD_STATUS && bk_save_write) bk_pending <= 1'b1; else if (bk_state) bk_pending <= 1'b0; diff --git a/rtl/system.vhd b/rtl/system.vhd index 842a680..d08530d 100644 --- a/rtl/system.vhd +++ b/rtl/system.vhd @@ -265,6 +265,7 @@ architecture Behavioral of system is -- 4-PAK All Action mapper signals (HES 4 PAK All Action) -- References: MAME sega8_4pak_device (src/devices/bus/sega8/rom.cpp) signal mapper_4pak : std_logic := '0'; + signal mapper_4pak_crc : std_logic; -- 4-PAK CRC match (0x73ED) signal pak4_reg0 : std_logic_vector(7 downto 0) := "00000000"; -- written at $3FFE signal pak4_reg2 : std_logic_vector(7 downto 0) := "00000000"; -- written at $BFFF @@ -285,6 +286,9 @@ architecture Behavioral of system is signal mapper_zemina_crc : std_logic; -- '1' for other Zemina CRC matches - plain Zemina signal mapper_castle : std_logic := '0'; -- The Castle (Japan): 32KB RAM at 0x8000-0xFFFF signal mapper_wonderkid : std_logic; -- Wonder Kid [Proto]: Codemasters-style 16KB, all banks init 0 + signal mapper_linear : std_logic; -- No mapper, linear ROM up to 48KB (MEKA type 11) + signal mapper_sega_locked : std_logic := '0'; -- Sega mapper path + all bank writes blocked (for 48KB dahjee_typeb games) + signal mapper_dahjee_a : std_logic; -- Dahjee Type A: linear ROM + 8KB RAM at 0x2000-0x3FFF signal reset_n_prev : std_logic := '0'; -- for synchronous rising-edge detection of RESET_n signal bootloader_n_prev : std_logic := '1'; -- for rising-edge detection of bootloader_n (BIOS->cart handoff) @@ -674,6 +678,7 @@ port map( nvram_a <= "0000" & A(10 downto 0) when sc3000_en = '1' and sc_cart_ram = "01" else '0' & A(13 downto 0) when sc3000_en = '1' and sc_cart_ram = "10" else A(14 downto 0) when (sc3000_en = '1' and sc_cart_ram = "11") or mapper_castle = '1' else + "00" & A(12 downto 0) when mapper_dahjee_a = '1' else (nvram_p and not A(14)) & A(13 downto 0); nvram_we <= nvram_WR; nvram_d <= D_in; @@ -778,9 +783,11 @@ port map( or (A(15 downto 14)="11" and nvram_ex = '1') or (A(15 downto 13)="101" and nvram_cme = '1')) or sc_cart_ram_low='1' - or sc_cart_ram_high='1') else '0'; + or sc_cart_ram_high='1' + or (mapper_dahjee_a='1' and A(15 downto 13)="001")) else '0'; rom_RD <= not RD_n when MREQ_n='0' and A(15 downto 14)/="11" and sc_multicart_upper='0' - and not (mapper_castle='1' and A(15)='1') else '0'; + and not (mapper_castle='1' and A(15)='1') + and not (mapper_dahjee_a='1' and A(15 downto 13)="001") else '0'; color <= vdp2_color when (vdp2_y1='1' and systeme='1' and vdp_enables(1)='0') else vdp_color when vdp_enables(0)='0' else x"000"; process (clk_sys) @@ -841,7 +848,7 @@ port map( process (IORQ_n,A,vdp_D_out,vdp2_D_out,io_D_out,irom_D_out,ram_D_out,nvram_D_out, nvram_ex,nvram_e,nvram_cme,gg,det_D,fm_ena,bootloader_n,systeme,io_upper_port,io_gg_data_port, - sc_cart_ram_rd,sc_multicart_open) + sc_cart_ram_rd,sc_multicart_open,mapper_dahjee_a) begin if IORQ_n='0' then if A(7 downto 0)=x"F2" and fm_ena = '1' and systeme='0' then @@ -872,6 +879,9 @@ port map( D_out <= nvram_D_out; elsif A(15 downto 14)="10" and nvram_e = '1' then D_out <= nvram_D_out; + elsif mapper_dahjee_a = '1' and A(15 downto 13) = "001" then + -- Dahjee Type A: RAM at 0x2000-0x3FFF reads from nvram block + D_out <= nvram_D_out; else D_out <= irom_D_out; end if; @@ -943,6 +953,9 @@ port map( if RESET_n = '1' and reset_n_prev = '0' then if mapper_nemesis_auto = '1' then nem_bank0 <= std_logic_vector(unsigned(rom_size_pages) - 1); + elsif mapper_4pak_crc = '1' then + -- Enable 4-PAK only for known CRC instead of write-based auto-detect. + mapper_4pak <= '1'; elsif mapper_wonderkid = '1' then -- All slots start at page 0; pre-lock to prevent 4-PAK misdetection bank1 <= "00000000"; @@ -956,8 +969,8 @@ port map( last_read_addr <= A; -- gyurco anti-ldir patch end if; - if systeme = '1' or sc3000_en = '1' or mapper_castle = '1' then - -- no System E, SC-3000, or Castle (32KB RAM) mappers + if systeme = '1' or sc3000_en = '1' or mapper_castle = '1' or mapper_linear = '1' or mapper_dahjee_a = '1' or mapper_sega_locked = '1' then + -- no System E, SC-3000, Castle (32KB RAM), linear, Dahjee Type A, or Sega-locked mappers elsif mapper_4pak = '1' then -- 4-PAK All Action mapper (per MAME sega8_4pak_device): -- $3FFE: reg0=D; bank0=D; bank2=(reg0[5:4]+reg2) @@ -1000,7 +1013,7 @@ port map( pak4_reg0 <= D_in; pak4_reg2 <= "00000000"; bank0 <= D_in; - bank1 <= "00000001"; -- will be set by first $7FFF write + bank1 <= "00000001"; bank2 <= std_logic_vector( ("00" & unsigned(D_in(5 downto 4)) & "0000") + to_unsigned(0, 8)); -- reg2=0 initially @@ -1091,6 +1104,50 @@ port map( -- CRC16-CCITT of last 8KB block: 0x8613 mapper_wonderkid <= '1' when rom_crc16_run = x"8613" else '0'; + -- MEKA mapper type 11: no mapper, linear ROM (MAME dahjee_typeb). + -- Pure linear ROM with system RAM at 0xC000-0xFFFF, no banking. + -- mapper_linear uses A[15:13] directly for rom_a_i (bypasses all bank registers). + -- Works correctly for these 32KB games on the physical FPGA. + -- 48KB dahjee_typeb games that need bank-write protection but NOT the mapper_linear + -- rom_a_i branch are handled separately by mapper_sega_locked (see below). + -- CRC16 of last 8KB block: + -- FA Tetris (Korea) (Unl) 0x890A [linear, 32KB] + -- Flashpoint (Korea) (Unl) 0x4742 [linear, 32KB] + -- Rally-X (Taiwan) (English Logo) (Unl) 0x8D9A [dahjee_typeb, 32KB] + -- Road Fighter (Taiwan) (English Logo) (Unl) 0x24BE [dahjee_typeb, 32KB] + mapper_linear <= '1' when ( + rom_crc16_run = x"890A" or -- FA Tetris (Korea) + rom_crc16_run = x"4742" or -- Flashpoint (Korea) + rom_crc16_run = x"8D9A" or -- Rally-X (English Logo) + rom_crc16_run = x"24BE" -- Road Fighter (English Logo) + ) else '0'; + + -- 48KB dahjee_typeb games: Sega mapper code path (bank registers 0,1,2 never updated) + -- with ALL mapper register writes blocked to prevent bank corruption. + -- These must NOT use the mapper_linear branch of rom_a_i: that path (using A[15:13] + -- directly from the combinational address bus) fails to boot on the physical Cyclone V + -- FPGA due to different routing/timing vs the Sega mapper's registered-bank path. + -- Keeping them on the Sega mapper path (same SDRAM addresses for banks 0,1,2 on 48KB) + -- while blocking all write detection fixes both the boot failure and the logo loop. + mapper_sega_locked <= '0'; + + -- Dahjee Type A expansion: linear ROM + 8KB RAM at 0x2000-0x3FFF. + -- MSX conversions published by DahJee/Jumbo that require the Type A + -- RAM expansion cart (which adds 9KB total: 8KB at 0x2000-0x3FFF + + -- 1KB at 0xC000 merged with the system WRAM). + -- (MAME devices: sega8_dahjee_typea_device) + -- CRC16 of last 8KB block: + -- Rally-X (Taiwan) (Chinese Logo) (Unl) 0xD6ED [32KB] (confirmed working) + -- Road Fighter (Taiwan) (Chinese Logo) (Unl) 0x7B1C [32KB] (confirmed working) + mapper_dahjee_a <= '1' when ( + rom_crc16_run = x"D6ED" or -- Rally-X (Taiwan) (Chinese Logo) + rom_crc16_run = x"7B1C" -- Road Fighter (Taiwan) (Chinese Logo) + ) else '0'; + + -- 4-PAK All Action (Australia) (Unl) + -- CRC16-CCITT of last 8KB block: 0x73ED + mapper_4pak_crc <= '1' when rom_crc16_run = x"73ED" else '0'; + -- Nemesis I (0xEE05): Zemina banking with $0000-$1FFF = last 8KB page at startup mapper_nemesis_auto <= '1' when rom_crc16_run = x"EE05" else '0'; -- Plain Zemina (nem_bank0=0): Nemesis II (0x9136), F-1 Spirit (0x599E), @@ -1101,14 +1158,15 @@ port map( rom_crc16_run = x"880E") else '0'; -- Active for any Zemina-family mapper. - -- mapper_zemina_force (OSD Zemina) overrides auto-detection. - -- mapper_lock (OSD Sega) disables all auto-detection but NOT the force. + -- mapper_zemina_force (OSD): user explicitly selected Zemina mapper. + -- mapper_lock (OSD): user explicitly selected Sega mapper, disables all auto-detection. + -- Both are mutually exclusive (same 2-bit OSD status field). use_zem <= mapper_zemina_force or (not mapper_lock and (mapper_msx or mapper_zemina_det or mapper_nemesis_auto or mapper_zemina_crc)); rom_a_i(12 downto 0) <= A(12 downto 0); - process (A,bank0,bank1,bank2,bank3,use_zem,nem_bank0,mapper_4pak,mapper_codies,systeme,sc3000_en,sc_multicart_en,sc_multicart_page,rom_bank,bootloader_n) + process (A,bank0,bank1,bank2,bank3,use_zem,nem_bank0,mapper_4pak,mapper_codies,systeme,sc3000_en,sc_multicart_en,sc_multicart_page,rom_bank,bootloader_n,mapper_linear,mapper_dahjee_a) begin if systeme = '1' then case A(15 downto 14) is @@ -1120,9 +1178,9 @@ port map( elsif sc_multicart_en = '1' then rom_a_i(21 downto 15) <= sc_multicart_page; rom_a_i(14 downto 13) <= A(14 downto 13); - elsif sc3000_en = '1' then - -- SC-3000 cartridges are linear, unbanked images in the $0000-$BFFF space. - -- Keep the full CPU address so 32K BASIC/Music carts don't mirror every 16K. + elsif sc3000_en = '1' or mapper_linear = '1' or mapper_dahjee_a = '1' then + -- SC-3000, no-mapper (MEKA type 11), and Dahjee Type A cartridges: linear, unbanked. + -- Keep the full CPU address so ROM pages don't mirror. rom_a_i(21 downto 16) <= (others=>'0'); rom_a_i(15 downto 13) <= A(15 downto 13); -- Zemina/Nemesis mapper is suppressed while the BIOS is running (bootloader_n='0').