---------------------------------------------------------------------------------- -- FreezerLogic.vhd - Freezer logic -- -- Copyright (C) 2011-2012 Matthias Reichl -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU Lesser General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.NUMERIC_STD.ALL; library work; entity FreezerLogic is Port ( clk: in std_logic; clk_enable: in std_logic; cpu_cycle: in std_logic; a: in std_logic_vector(15 downto 0); d_in: in std_logic_vector(7 downto 0); rw: in std_logic; reset_n: in std_logic; activate_n: in std_logic; dualpokey_n: in std_logic; --output: out mem_output disable_atari: out boolean; access_type: out std_logic_vector(1 downto 0); access_address: out std_logic_vector(16 downto 0); d_out: out std_logic_vector(7 downto 0); request: in std_logic; request_complete: out std_logic; state_out: out std_logic_vector ); end FreezerLogic; architecture RTL of FreezerLogic is constant access_type_none: std_logic_vector(1 downto 0) := "00"; constant access_type_data: std_logic_vector(1 downto 0) := "01"; constant access_type_ram: std_logic_vector(1 downto 0) := "10"; constant access_type_rom: std_logic_vector(1 downto 0) := "11"; signal ram_bank: std_logic_vector(16 downto 12); signal rom_bank: std_logic_vector(15 downto 13); constant freezer_def_rom_bank: std_logic_vector(15 downto 13) := "100"; constant freezer_def_ram_bank: std_logic_vector(16 downto 12) := "11111"; subtype state_type is std_logic_vector(2 downto 0); constant state_disabled: state_type := "000"; constant state_half_enabled: state_type := "001"; constant state_startup: state_type := "010"; constant state_enabled: state_type := "100"; constant state_temporary_disabled: state_type := "101"; signal state: state_type := state_disabled; signal vector_access: boolean; signal vector_a2: std_logic; signal use_status_as_ram_address: boolean; type mem_output is record adr: std_logic_vector(16 downto 0); ram_access: boolean; rom_access: boolean; disable_atari: boolean; dout: std_logic_vector(7 downto 0); dout_enable: boolean; shadow_enable: boolean; end record; signal output: mem_output; signal bram_adr: std_logic_vector(6 downto 0); signal bram_data_out: std_logic_vector(7 downto 0); signal bram_we: std_logic; signal bram_request: std_logic; signal bram_request_complete: std_logic; begin vector_access <= (a(15 downto 3) = "1111111111111") and (rw='1'); state_out <= state; state_machine: process(clk) begin if (rising_edge(clk)) then if (reset_n = '0') then state <= state_disabled; else if (clk_enable = '1' and cpu_cycle='1') then case state is when state_disabled => if vector_access and (activate_n = '0') and (a(0) = '0') then state <= state_half_enabled; vector_a2 <= a(2); end if; when state_half_enabled => if vector_access and (activate_n = '0') and (a(0) = '1') then state <= state_startup; else state <= state_disabled; end if; when state_startup => if (a(15 downto 4) = x"D72") then state <= state_enabled; end if; when state_enabled => if (a(15 downto 4) = x"D70") then if (rw = '1') then state <= state_disabled; else state <= state_temporary_disabled; end if; end if; when state_temporary_disabled => if (a(15 downto 4) = x"D70") then if (rw = '1') then state <= state_disabled; else state <= state_enabled; end if; end if; when others => state <= state_disabled; end case; end if; end if; end if; end process state_machine; set_status_ram_address: process(clk) begin if (rising_edge(clk)) then if (clk_enable = '1') then if (state = state_disabled) then use_status_as_ram_address <= false; else if (a(15 downto 4) = x"D71") then use_status_as_ram_address <= (rw = '1'); end if; end if; end if; end if; end process set_status_ram_address; banksel: process(clk) begin if (rising_edge(clk)) then if (clk_enable = '1') then if (state = state_disabled) then ram_bank <= (others => '0'); rom_bank <= freezer_def_rom_bank; else -- D740-D77F if (a(15 downto 6) = "1101011101") then rom_bank <= a(2 downto 0); end if; -- D780-D79F if (a(15 downto 5) = "11010111100") then ram_bank <= a(4 downto 0); end if; end if; end if; end if; end process banksel; access_freezer: process(a, rw, state, vector_access, ram_bank, rom_bank, vector_a2, use_status_as_ram_address, dualpokey_n) begin output.adr <= (others => '0'); output.ram_access <= false; output.rom_access <= false; output.disable_atari <= false; output.dout <= (others => '1'); output.dout_enable <= false; output.shadow_enable <= false; case state is when state_disabled | state_half_enabled => -- shadow writes to D0xx, D2xx, D4xx if (rw = '0') then case a(15 downto 8) is when x"D0" | x"D2" | x"D3" | x"D4" => output.shadow_enable <= true; output.adr(16 downto 8) <= freezer_def_ram_bank & a(11 downto 8); -- GTIA/D000 needs 32 bytes, others 16 bytes -- in dualpokey mode also shadow D2xx with 32 bytes if (a(10 downto 8) = "000") or (dualpokey_n = '0' and a(10 downto 8) = "010") then output.adr(4 downto 0) <= a(4 downto 0); else output.adr(3 downto 0) <= a(3 downto 0); end if; when others => null; end case; end if; if (state = state_half_enabled) and (vector_access) and (a(0) = '1') then -- re-route interrupt vectors to NOP slide page output.dout <= x"21"; output.dout_enable <= true; output.disable_atari <= true; end if; when state_startup | state_enabled => if (state = state_startup) and (vector_access) and (a(0) = '1') then -- re-route interrupt vectors to RTI slide page output.dout <= x"20"; output.dout_enable <= true; output.disable_atari <= true; end if; -- 0000-1FFF: RAM (0000-0FFF fixed, 1000-1FFF switchable) if (a(15 downto 13) = "000") then output.ram_access <= true; output.disable_atari <= true; if (a(12) = '0') then output.adr(16 downto 12) <= freezer_def_ram_bank; else output.adr(16 downto 12) <= ram_bank; end if; output.adr(11 downto 0) <= a(11 downto 0); if (use_status_as_ram_address) then output.adr(4) <= vector_a2; output.adr(5) <= not dualpokey_n; end if; end if; -- 2000-3FFF: switched ROM bank if (a(15 downto 13) = "001") then if (rw = '1') then output.rom_access <= true; end if; output.disable_atari <= true; output.adr <= "0" & rom_bank & a(12 downto 0); end if; -- D7xx freezer control, disable Atari memory if (a(15 downto 8) = x"D7") then output.disable_atari <= true; end if; when state_temporary_disabled => -- D7xx freezer control, disable Atari memory if (a(15 downto 8) = x"D7") then output.disable_atari <= true; end if; when others => null; end case; end process access_freezer; memory_glue: process(output, rw, bram_data_out, request, bram_request_complete) begin disable_atari <= output.disable_atari; access_type <= access_type_none; access_address <= output.adr; request_complete <= '0'; d_out <= (others => '1'); bram_adr <= (others => '0'); bram_we <= '0'; bram_request <= '0'; if (output.shadow_enable) then bram_adr <= output.adr(9)&(output.adr(8) or output.adr(10))&output.adr(4 downto 0); bram_we <= '1'; elsif (output.dout_enable) then access_type <= access_type_data; d_out <= output.dout; request_complete <= request; elsif (output.rom_access) then access_type <= access_type_rom; elsif (output.ram_access) then access_type <= access_type_ram; -- map shadow ram access to blockram if (output.adr(16 downto 12) = freezer_def_ram_bank) and (output.adr(7 downto 5) = "000") then case output.adr(11 downto 8) is when x"0" | x"2" | x"3" | x"4" => access_type <= access_type_data; bram_adr <= output.adr(9)&(output.adr(8) or output.adr(10))&output.adr(4 downto 0); bram_we <= request and not rw; bram_request <= request; request_complete <= bram_request_complete; d_out <= bram_data_out; when others => null; end case; end if; end if; end process memory_glue; process(clk, reset_n) begin if rising_edge(clk) then if (reset_n = '0') then bram_request_complete <= '0'; else bram_request_complete <= bram_request; end if; end if; end process; freezer_bram: entity work.generic_ram_infer generic map ( ADDRESS_WIDTH => 7, SPACE => 128, DATA_WIDTH =>8 ) PORT MAP(clock => clk, address => bram_adr, data => d_in, we => bram_we, q => bram_data_out ); end RTL;