Project

General

Profile

----------------------------------------------------------------------------------
-- FreezerLogic.vhd - Freezer logic
--
-- Copyright (C) 2011-2012 Matthias Reichl <hias@horus.com>
--
-- 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;

(28-28/63)