From e9130e7b045ab45061bb3a6063e9efdd1d6f4f29 Mon Sep 17 00:00:00 2001 From: Fabricio Breve <7475908+fbreve@users.noreply.github.com> Date: Wed, 29 Apr 2026 11:23:49 -0300 Subject: [PATCH 1/2] Add The Castle mapper (32KB RAM) support Introduce mapper_castle signal and CRC detection (CRC16-CCITT 0xEF38) for The Castle (Japan) SG-1000 cartridge. Treat The Castle as a 32KB cart with 32KB RAM at 0x8000-0xFFFF by updating sc_cart_ram_32k/sc_cart_ram_low, nvram addressing, and ROM read gating (prevent ROM reads when Castle RAM is mapped into the upper half). Also exclude the Castle mapper from System E / SC-3000 mapper handling and add explanatory comments. --- rtl/system.vhd | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/rtl/system.vhd b/rtl/system.vhd index ece8792..f02f34b 100644 --- a/rtl/system.vhd +++ b/rtl/system.vhd @@ -280,6 +280,7 @@ architecture Behavioral of system is -- Nemesis II+ (other CRCs): plain Zemina banking ($0000-$1FFF = page 0), no special startup page signal mapper_nemesis_auto : std_logic; -- '1' for Nemesis I (CRC 0xEE05) - needs last-page boot 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 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) @@ -643,8 +644,8 @@ port map( io_sc_legacy_port <= '1' when (A(7 downto 0)=x"DE" or A(7 downto 0)=x"DF") and palettemode='1' and gg='0' and systeme='0' else '0'; io_sc_mc_port <= '1' when A(7 downto 5)="111" and sc_multicart_en='1' and gg='0' and systeme='0' else '0'; - sc_cart_ram_32k <= '1' when sc3000_en='1' and sc_cart_ram="11" else '0'; - sc_cart_ram_low <= '1' when sc3000_en='1' and sc_cart_ram/="00" and A(15 downto 14)="10" else '0'; + sc_cart_ram_32k <= '1' when (sc3000_en='1' and sc_cart_ram="11") or mapper_castle='1' else '0'; + sc_cart_ram_low <= '1' when ((sc3000_en='1' and sc_cart_ram/="00") or mapper_castle='1') and A(15 downto 14)="10" else '0'; sc_cart_ram_high <= '1' when sc_cart_ram_32k='1' and A(15 downto 14)="11" else '0'; sc_cart_ram_rd <= sc_cart_ram_low or sc_cart_ram_high; sc_multicart_upper <= '1' when sc_multicart_en='1' and A(15)='1' else '0'; @@ -662,7 +663,7 @@ port map( -- 11=32KB total (32KB cart overlaying the internal 2KB window). 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" else + A(14 downto 0) when (sc3000_en = '1' and sc_cart_ram = "11") or mapper_castle = '1' else (nvram_p and not A(14)) & A(13 downto 0); nvram_we <= nvram_WR; nvram_d <= D_in; @@ -768,7 +769,8 @@ port map( or (A(15 downto 13)="101" and nvram_cme = '1')) or sc_cart_ram_low='1' or sc_cart_ram_high='1') else '0'; - rom_RD <= not RD_n when MREQ_n='0' and A(15 downto 14)/="11" and sc_multicart_upper='0' 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'; 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) @@ -939,8 +941,8 @@ port map( last_read_addr <= A; -- gyurco anti-ldir patch end if; - if systeme = '1' or sc3000_en = '1' then - -- no System E or SC-3000 mappers + if systeme = '1' or sc3000_en = '1' or mapper_castle = '1' then + -- no System E, SC-3000, or Castle (32KB RAM) 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) @@ -1063,6 +1065,10 @@ port map( end if; end process; + -- The Castle (Japan) [SG-1000]: 32KB ROM, 32KB RAM at 0x8000-0xFFFF + -- CRC16-CCITT of last 8KB block: 0xEF38 + mapper_castle <= '1' when rom_crc16_run = x"EF38" 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), From e6dadb754b4a2224020f7242605ad1bd528cb23e Mon Sep 17 00:00:00 2001 From: Fabricio Breve <7475908+fbreve@users.noreply.github.com> Date: Wed, 29 Apr 2026 12:09:18 -0300 Subject: [PATCH 2/2] Add Wonder Kid mapper detection and init rtl/system.vhd: add support for the Wonder Kid [Proto] mapper (Codemasters-style 16KB). Introduces signal mapper_wonderkid and CRC detection (0x8613). Prevents MSX mapper selection when Wonder Kid is detected, and on RESET_n rising initializes banks to page 0 and pre-locks mapper B to avoid 4-PAK misdetection. Includes explanatory comments for the new mapper behavior. --- rtl/system.vhd | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/rtl/system.vhd b/rtl/system.vhd index f02f34b..14af297 100644 --- a/rtl/system.vhd +++ b/rtl/system.vhd @@ -281,6 +281,7 @@ architecture Behavioral of system is signal mapper_nemesis_auto : std_logic; -- '1' for Nemesis I (CRC 0xEE05) - needs last-page boot 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 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) @@ -879,7 +880,7 @@ port map( mapper_msx <= '0' ; else if rising_edge(clk_sys) then - if bootloader_n='1' and sc3000_en='0' and not mapper_msx_lock then + if bootloader_n='1' and sc3000_en='0' and mapper_wonderkid='0' and not mapper_msx_lock then if MREQ_n='0' then -- in this state, A is stable but not D_out if A=x"0000" then @@ -933,6 +934,11 @@ 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_wonderkid = '1' then + -- All slots start at page 0; pre-lock to prevent 4-PAK misdetection + bank1 <= "00000000"; + bank2 <= "00000000"; + lock_mapper_B <= '1'; end if; end if; reset_n_prev <= RESET_n; @@ -1069,6 +1075,13 @@ port map( -- CRC16-CCITT of last 8KB block: 0xEF38 mapper_castle <= '1' when rom_crc16_run = x"EF38" else '0'; + -- Wonder Kid [Proto] [SMS-GG]: MAPPER_MSX_Generic16_8000 + -- Codemasters-style 16KB banking, register at $8000, all slots init at page 0. + -- ROM starts with 0x41 0x42 which would normally trigger MSX/Zemina mapper; + -- suppressed here by CRC. Banks initialised to 0/0/0 at RESET_n rise. + -- CRC16-CCITT of last 8KB block: 0x8613 + mapper_wonderkid <= '1' when rom_crc16_run = x"8613" 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),