---------------------------------------------------------------------------------- -- Inital version 1.0 for xc9572xl-vq64 -- Engineer: Mario Prato -- Create Date: 10:07:18 11/22/2012 -- -- Modified for Altera EPM3128ATC100-10 -- Modified for Altera EPM7128STC100-7 -- Engineer: valerium -- Design Name: divmmc ver. 1.1 -- Redesign Date: 02:54:18 10/05/2021 -- -- Module Name: divmmc - Behavioral -- Project Name: divmmc -- Target Devices: EPM3128ATC100-10 -- Target Devices: EPM7128STC100-7 -- Tool versions: Quartus II 13.0SP1 -- Description: zx spectrum mmc sd interface ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity divmmc is Port ( -- z80 cpu signals A : in std_logic_vector (15 downto 0); D : inout std_logic_vector (7 downto 0); iorq : in std_logic; IORQGE : out STD_LOGIC; mreq : in std_logic; wr : in std_logic; rd : in std_logic; m1 : in std_logic; reset : in std_logic; clock : in std_logic; -- Z80 Clock from ula chip (must be negated from edge connector signal) -- ram/rom signals romcs : out STD_LOGIC; -- 1 -> page out spectrum rom romoe : out STD_LOGIC; -- eeprom oe pin romwr : out STD_LOGIC; -- eeprom wr pin ramoe : out STD_LOGIC; -- ram oe pin ramwr : out STD_LOGIC; -- ram wr pin bankout : out STD_LOGIC_VECTOR (5 downto 0); --ram bank no. -- spi interface card : out std_logic_vector(1 downto 0) :="11"; -- Cards CS spi_clock : out std_logic :='1'; -- card clock spi_dataout : out std_logic :='1'; -- card data in spi_datain : in std_logic :='1'; -- card data out -- various poweron : in STD_LOGIC; -- low pulse on poweron eprom : in STD_LOGIC; -- eprom jumper mapcondout : out std_logic -- hi when divmmc mem paged in ); end divmmc; -- ============================================================================================================ architecture Behavioral of divmmc is signal address : std_logic_vector(7 downto 0) ; signal zxmmcio : std_logic; signal divideio : std_logic; signal bank : std_logic_vector (5 downto 0) := "000000"; signal mapterm : std_logic := '0'; signal mapcond : std_logic := '0'; signal conmem : std_logic := '0'; signal mapram : std_logic := '0'; signal automap : std_logic := '0'; signal map3DXX : std_logic; signal map1F00 : std_logic; signal bank3 : std_logic; -- Transmission states type transStates is ( IDLE, -- Wait for a WR or RD request on port 0xEB SAMPLE, -- As there is an I/O request, prepare the transmission; sample the CPU databus if required TRANSMIT); -- Transmission (SEND or RECEIVE) signal transState : transStates := IDLE; -- Transmission state (initially IDLE) signal TState : unsigned(3 downto 0) := (others => '0'); -- Counts the T-States during transmission signal fromSDByte : std_logic_vector(7 downto 0) := (others => '1'); -- Byte received from SD signal toSDByte : std_logic_vector(7 downto 0) := (others => '1'); -- Byte to send to SD signal toCPUByte : std_logic_vector(7 downto 0) := (others => '1'); -- Byte seen by the CPU after a byte read -- dichiarazioni constanti constant divide_control_port : std_logic_vector(7 downto 0) := x"E3"; -- port %11100011 constant zxmmc_control_port : std_logic_vector(7 downto 0) := x"E7"; -- era la porta 31 nella zxmmc+ constant zxmmc_spi_port : std_logic_vector(7 downto 0) := x"EB"; -- era la porta 63 nella zxmmc+ attribute PWR_MODE: string; attribute FAST: string; attribute BUFG: string; -- ============================================================================================================ begin address <= A(7 downto 0); bank3 <= '1' when bank ="000011" else '0'; IORQGE <= '1' when (address = divide_control_port) OR (address = zxmmc_control_port) OR (address = zxmmc_spi_port) else 'Z'; -- IORQGE for exUSSR clone's on NemoBUS -- (SL60, SL62 socked, like ISA slot in x386 machines) -- Need Hi-Z or VCC pinOut state (VCC=Blocked all ports in ZX mainboard) -- ROM read write signals romoe <= rd or A(15) or A(14) or A(13) or (not conmem and mapram) or (not conmem and not automap) or (not conmem and eprom); -- 5 OR Act.level=0; rd=0; A[15..13]=0; eprom=in_Pin; romcs <= '1' when ((automap and not eprom) or (automap and mapram) or conmem )='1' else '0' ; -- RDR NemoBUS -- 3 OR Act.level=0; conmem=; inv.eprom=in_Pin; romwr <= '0' when wr ='0' and a(13)='0' and a(14)='0' and a(15)='0' and eprom='1' and conmem='1' else '1'; -- 6 AND Act.level=0; inv.pin; A[15..13]=0; wr=0; eprom=1; conmem=Q_DFF; -- RAM read write signals ramoe <= rd or A(15) or A(14) or ( not A(13) and not mapram) or ( not A(13) and conmem) or (not conmem and not automap) or (not conmem and eprom and not mapram); ramwr <= wr or A(15) or A(14) or not a(13) or (not conmem and mapram and bank3 ) or (not conmem and not automap) or (not conmem and eprom and not mapram); -- -- Divide Automapping logic mapterm <= '1' when A(15 downto 0) = x"0000" or A(15 downto 0) = x"0008" or A(15 downto 0) = x"0038" or A(15 downto 0) = x"0066" or A(15 downto 0) = x"04c6" or A(15 downto 0) = x"0562" else '0'; map3DXX <= '1' when A(15 downto 8) = "00111101" else '0'; -- mappa 3D00 - 3DFF map1F00 <= '0' when A(15 downto 3) = "0001111111111" else '1'; -- 1ff8 - 1fff -- ============================================================================================================ process(mreq) begin if falling_edge(mreq) then if m1='0' then mapcond <= mapterm or map3DXX or (mapcond and map1F00); automap <= mapcond or map3DXX; end if; end if; end process; mapcondout <= mapcond; -- Q_DFF_mapcond=Pin_out; -- divide control port divideio <='0' when iorq='0' and wr='0' and M1='1' and address = divide_control_port else '1'; --divideio=CLK_DFF's -- 4 AND m1=1; iorq=0; wr=0; A[7..0]=hE3 adr. -- ============================================================================================================ process(divideio,poweron) begin -- if poweron ='0' then -- originally by M.Prato if poweron ='0' or reset = '0' then -- patch by valerium bank <= "000000"; mapram <= '0'; conmem <= '0'; elsif rising_edge(divideio) then bank(5 downto 0) <= D(5 downto 0); mapram <= D(6) or mapram; conmem <= D(7); end if; end process; -- ============================================================================================================ -- ram banks bankout(0) <= bank(0) or not A(13); -- Bank = 8kB bankout(1) <= bank(1) or not A(13); bankout(2) <= bank(2) and A(13); bankout(3) <= bank(3) and A(13); bankout(4) <= bank(4) and A(13); bankout(5) <= bank(5) and A(13); -- SD CS signal management zxmmcio <= '0' when address = zxmmc_control_port and iorq='0' and m1='1' and wr ='0' else '1'; process(reset, zxmmcio) begin if reset = '0' then card(0) <= '1'; -- Master SD VCC= no active card(1) <= '1'; -- Slave SD elsif rising_edge(zxmmcio) then card(0) <= D(0); -- Master SD card(1) <= D(1); -- Slave SD end if; end process; -- ============================================================================================================ -- spi transmission/reception -- Update transmission state process(clock, reset) begin if reset = '0' then transState <= IDLE; TState <= (others => '0'); fromSDByte <= (others => '1'); toSDByte <= (others => '1'); toCPUByte <= (others => '1'); elsif falling_edge(clock) then case transState is when IDLE => -- Intercept a new transmission request (port 0x3F) if address = zxmmc_spi_port and iorq='0' and m1='1' then -- If there is a transmission request, prepare to SAMPLE the databus transState <= SAMPLE; end if; when SAMPLE => if wr = '0' then -- If it is a SEND request, sample the CPU data bus toSDByte <= D; end if; transState <= TRANSMIT; -- then start the transmission when TRANSMIT => TState <= TState + 1; if TState < 15 then if TState(0) = '1' then toSDByte <= toSDByte(6 downto 0)&'1'; fromSDByte <= fromSDByte(6 downto 0)& spi_datain; end if; else if TState = 15 then -- transmission is completed; intercept if there is a new transmission request if address = zxmmc_spi_port and iorq='0' and m1='1'and wr='0' then toSDByte <= D; transState <= TRANSMIT; else -- else we'll go in IDLE state. transState <= IDLE; -- TState <= "0000"; end if; toCPUByte <= fromSDByte(6 downto 0)& spi_datain; end if; end if; when OTHERS => null; end case; end if; -- SPI SD Card pins SPI_clock <= TState(0); spi_dataout <= toSDByte(7); end process; D <= toCPUByte when (address = zxmmc_spi_port) and (iorq = '0') and (rd = '0') and m1='1' else "ZZZZZZZZ"; -- ============================================================================================================ end Behavioral;