280 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			VHDL
		
	
	
	
	
	
			
		
		
	
	
			280 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			VHDL
		
	
	
	
	
	
| ----------------------------------------------------------------------------------
 | |
| -- 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;
 | |
| 
 |