-- CSG REU/REC compatible RAM expansion controller -- initial version: 2.9.2001 by Rainer Buchty (rainer@buchty.net) -- syntactically correct, but completely untested -- so use at your own risk -- -- 16MB DRAM to 64kB C64 memory DMA unit library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; package p_rec is component rec is port( phi2, dotclk: in std_logic; rst: in std_logic; dma: out std_logic; ba: in std_logic; cpu_addr: inout std_logic_vector(15 downto 0); cpu_data: inout std_logic_vector(7 downto 0); cpu_rw: inout std_logic; reu_addr: out std_logic_vector(11 downto 0); reu_data: inout std_logic_vector(7 downto 0); reu_rw: out std_logic; reu_ras, reu_cas: out std_logic; size: in std_logic; aec: inout std_logic ); end component; end package; -- -------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; entity rec is port( phi2, dotclk: in std_logic; rst: in std_logic; dma: out std_logic; ba: in std_logic; cpu_addr: inout std_logic_vector(15 downto 0); cpu_data: inout std_logic_vector(7 downto 0); cpu_rw: inout std_logic; reu_addr: out std_logic_vector(11 downto 0); reu_data: inout std_logic_vector(7 downto 0); reu_rw: out std_logic; reu_ras, reu_cas: out std_logic; size: in std_logic; aec: inout std_logic ); end entity; -- -------------------------------------------------------------------------- architecture arch_rec of rec is -- ACR and IMR signal acr: std_logic_vector(1 downto 0); signal imr: std_logic_vector(2 downto 0); -- CR signal execute, load, ff00: std_logic; signal tt: std_logic_vector(1 downto 0); -- SR signal ip, eob, fault: std_logic; constant version: std_logic_vector(3 downto 0):="0000"; -- main state machine signal state: std_logic_vector(2 downto 0); -- transfer control signal base_reu, sadr_reu: std_logic_vector(23 downto 0); signal base_c64, sadr_c64: std_logic_vector(15 downto 0); signal xfer_cnt, xfer_len: std_logic_vector(15 downto 0); -- SWAP storage signal reu_store, cpu_store: std_logic_vector(7 downto 0); -- misc signal ref_cnt: std_logic_vector(11 downto 0); -- refresh counter signal exec_s: std_logic; -- exec sampled signal ba_s: std_logic; -- ba sampled signal scnt: std_logic; -- SWAP state begin -- -------------------------------------------------------------------------- -- DMA transfer (rising edge) -- -------------------------------------------------------------------------- process(dotclk,rst) begin if rst='0' then base_reu<="000000000000000000000000"; base_c64<="0000000000000000"; xfer_cnt<="0000000000000000"; ref_cnt<="000000000000"; exec_s<='0'; ba_s<=ba; state<=(others=>'0'); scnt<='0'; -- rising edge: RAM addressing & data transfer elsif dotclk'event and dotclk='1' then ba_s<=ba; -- mute c64 lines by default cpu_addr<="ZZZZZZZZZZZZZZZZ"; cpu_data<="ZZZZZZZZ"; -- transfer control registers while idle if exec_s='0' then base_reu<=sadr_reu; base_c64<=sadr_c64; xfer_cnt<=xfer_len; exec_s<=execute; scnt<='0'; -- memory access elsif ba='1' then case state is when "000" => -- apply row addr reu_addr<=base_reu(11 downto 0); cpu_addr<=base_c64; when "001" => -- apply col addr reu_addr<=base_reu(23 downto 12); cpu_addr<=base_c64; when "010" => -- transfer data cpu_addr<=base_c64; fault<='0'; case tt is when "00" => -- C64->REU reu_data<=cpu_data; when "01" => -- REU->C64 cpu_data<=reu_data; when "10" => -- SWAP if scnt='0' then reu_store<=cpu_data; cpu_store<=reu_data; else reu_data<=reu_store; cpu_data<=cpu_store; end if; scnt<=not(scnt); when "11" => -- VERIFY if cpu_data/=reu_data then fault<='1'; end if; when others => null; end case; when "011" => -- inc addresses, dec counter xfer_cnt<=xfer_cnt-1; if acr(0)='1' then base_reu<=base_reu+1; end if; if acr(0)='1' then base_c64<=base_c64+1; end if; when "100" => -- CBR #1 reu_addr<=ref_cnt; when "101" => -- CBR #2 reu_addr<="000000000000"; when "111" => -- finish/reload ref_cnt<=ref_cnt+1; if xfer_cnt=0 then if load='1' then base_reu<=sadr_reu; base_c64<=sadr_c64; xfer_cnt<=xfer_len; end if; eob<='1'; exec_s<='0'; end if; when others => null; end case; end if; end if; end process; -- -------------------------------------------------------------------------- -- DMA transfer (falling edge) -- -------------------------------------------------------------------------- process(dotclk,rst) begin if rst='0' then base_reu<="000000000000000000000000"; base_c64<="0000000000000000"; xfer_cnt<="0000000000000000"; ref_cnt<="000000000000"; reu_ras<='1'; reu_cas<='1'; reu_rw<='1'; exec_s<='0'; ba_s<=ba; state<="000"; scnt<='0'; -- falling edge: RAM control elsif dotclk'event and dotclk='0' then -- RAM control defaults cpu_rw<='Z'; reu_rw<='1'; reu_ras<='1'; reu_cas<='1'; if exec_s='1' and ba_s<='1' then cpu_rw<='1'; state<=state+1; -- RAM control state machine case state is when "000" => -- sample row addr reu_ras<='0'; reu_cas<='1'; when "001" => -- sample col addr reu_ras<='0'; reu_cas<='0'; when "010" => -- data write reu_ras<='0'; reu_cas<='0'; case tt is when "00" => -- C64->REU reu_rw<='0'; when "01" => -- REU->C64 cpu_rw<='0'; when "10" => -- SWAP if scnt='1' then cpu_rw<='0'; reu_rw<='0'; end if; when others => null; end case; when "011" => -- end of transfer reu_ras<='1'; reu_cas<='0'; when "100" => -- CBR #1 reu_ras<='1'; reu_cas<='0'; when "101" => -- CBR #2 reu_ras<='0'; reu_cas<='0'; when others => reu_ras<='1'; reu_cas<='1'; end case; end if; end if; end process; -- -------------------------------------------------------------------------- -- external access to REU registers -- -------------------------------------------------------------------------- reg_access: process(phi2,rst) variable reg_addr: std_logic_vector(3 downto 0); begin if rst='0' then execute<='0'; load<='0'; ff00<='0'; sadr_c64<="0000000000000000"; sadr_reu<="000000000000000000000000"; xfer_len<="0000000000000000"; imr<="000"; acr<="00"; elsif (phi2'event and phi2='1') then reg_addr:=cpu_addr(3 downto 0); -- clear execute when finished if exec_s='1' and execute='1' then execute<='0'; -- auto-execute on ff00 access elsif load='1' and cpu_addr="1111111100000000" then execute<='1'; -- normal access elsif cpu_rw='0' then case reg_addr is when "0001" => -- CR execute<=cpu_data(7); load<=cpu_data(5); ff00<=cpu_data(4); tt<=cpu_data(1 downto 0); when "0010" => -- c64 start address sadr_c64(15 downto 8)<=cpu_data; when "0011" => sadr_c64( 7 downto 0)<=cpu_data; when "0100" => -- reu start address sadr_reu(23 downto 16)<=cpu_data; when "0101" => sadr_reu(15 downto 8)<=cpu_data; when "0110" => sadr_reu( 7 downto 0)<=cpu_data; when "0111" => -- transfer length xfer_len(15 downto 8)<=cpu_data; when "1000" => xfer_len( 7 downto 0)<=cpu_data; when "1001" => -- IMR imr<=cpu_data(7 downto 5); when "1010" => -- ACR acr<=cpu_data(7 downto 6); when others => null; end case; elsif cpu_rw='1' then case reg_addr is when "0000" => -- SR cpu_data<=ip & eob & fault & size & version; when "0001" => -- CR cpu_data<=execute & '1' & load & ff00 & "11" & tt; when "0010" => -- c64 start address cpu_data<=sadr_c64(15 downto 8); when "0011" => cpu_data<=sadr_c64( 7 downto 0); when "0100" => -- reu start address cpu_data<=sadr_reu(23 downto 16); when "0101" => cpu_data<=sadr_reu(15 downto 8); when "0110" => cpu_data<=sadr_reu( 7 downto 0); when "0111" => -- transfer length cpu_data<=xfer_len(15 downto 8); when "1000" => cpu_data<=xfer_len( 7 downto 0); when "1001" => -- IMR cpu_data<=imr & "11111"; when "1010" => -- ACR cpu_data<=acr & "111111"; when others => null; end case; end if; end if; end process; end architecture;