«
Previous
|
Next
»
Revision 1
Added by markw over 11 years ago
common/a8core/address_decoder.vhdl | ||
---|---|---|
---------------------------------------------------------------------------
|
||
-- (c) 2013 mark watson
|
||
-- I am happy for anyone to use this for non-commercial use.
|
||
-- If my vhdl files are used commercially or otherwise sold,
|
||
-- please contact me for explicit permission at scrameta (gmail).
|
||
-- This applies for source and binary form and derived works.
|
||
---------------------------------------------------------------------------
|
||
LIBRARY ieee;
|
||
USE ieee.std_logic_1164.all;
|
||
use ieee.numeric_std.all;
|
||
use IEEE.STD_LOGIC_MISC.all;
|
||
|
||
|
||
ENTITY address_decoder IS
|
||
PORT
|
||
(
|
||
CLK : IN STD_LOGIC;
|
||
|
||
-- bus masters - either CPU or antic
|
||
-- antic has priority and is slected when ANTIC_FETCH high
|
||
CPU_ADDR : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
|
||
CPU_FETCH : in std_logic;
|
||
CPU_WRITE_N : IN STD_LOGIC;
|
||
CPU_WRITE_DATA : in std_logic_vector(7 downto 0);
|
||
|
||
ANTIC_ADDR : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
|
||
ANTIC_FETCH : IN STD_LOGIC;
|
||
antic_refresh : in std_logic; -- use for sdram refresh (sdram needs more, but this is a start)
|
||
|
||
ZPU_ADDR : in std_logic_vector(23 downto 0);
|
||
ZPU_FETCH : in std_logic;
|
||
ZPU_READ_ENABLE : in std_logic;
|
||
ZPU_32BIT_WRITE_ENABLE : in std_logic; -- common case
|
||
ZPU_16BIT_WRITE_ENABLE : in std_logic; -- for sram
|
||
ZPU_8BIT_WRITE_ENABLE : in std_logic; -- for hardware regs
|
||
ZPU_WRITE_DATA : in std_logic_vector(31 downto 0);
|
||
|
||
-- sources of data
|
||
ROM_DATA : IN STD_LOGIC_VECTOR(7 downto 0); -- flash rom
|
||
GTIA_DATA : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
CACHE_GTIA_DATA : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
POKEY_DATA : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
CACHE_POKEY_DATA : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
POKEY2_DATA : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
CACHE_POKEY2_DATA : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
ANTIC_DATA : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
CACHE_ANTIC_DATA : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
PIA_DATA : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
RAM_DATA : IN STD_LOGIC_VECTOR(15 downto 0);
|
||
CART_ROM_DATA : in std_logic_Vector(7 downto 0);
|
||
|
||
-- completion flags
|
||
RAM_REQUEST_COMPLETE : IN STD_LOGIC;
|
||
ROM_REQUEST_COMPLETE : IN STD_LOGIC;
|
||
CART_REQUEST_COMPLETE : IN STD_LOGIC;
|
||
|
||
-- configuration options
|
||
PORTB : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
|
||
reset_n : in std_logic;
|
||
|
||
rom_select : in std_logic_vector(5 downto 0);
|
||
cart_select : in std_logic_vector(6 downto 0);
|
||
cart_activate : in std_logic;
|
||
|
||
ram_select : in std_logic_vector(2 downto 0);
|
||
|
||
CART_RD4 : in std_logic;
|
||
CART_RD5 : in std_logic;
|
||
|
||
use_sdram : in std_logic;
|
||
|
||
-- Memory read mux output
|
||
MEMORY_DATA : OUT STD_LOGIC_VECTOR(31 downto 0);
|
||
|
||
-- Flash and internal RAM take 2 cycles to access. SRAM takes 1 cycle.
|
||
-- Allow us to say we're not ready for a cycle
|
||
MEMORY_READY_ANTIC : OUT STD_LOGIC;
|
||
MEMORY_READY_ZPU : OUT STD_LOGIC;
|
||
MEMORY_READY_CPU : out std_logic;
|
||
|
||
-- Each chip does not have whole address bus, so several are addressed at once
|
||
-- For reads not an issue, but for writes we need to only write to a single place!
|
||
-- these all take 1 cycle, so fine to leave device selected in general
|
||
GTIA_WR_ENABLE : OUT STD_LOGIC;
|
||
POKEY_WR_ENABLE : OUT STD_LOGIC;
|
||
POKEY2_WR_ENABLE : OUT STD_LOGIC;
|
||
ANTIC_WR_ENABLE : OUT STD_LOGIC;
|
||
PIA_WR_ENABLE : OUT STD_LOGIC;
|
||
PIA_RD_ENABLE : OUT STD_LOGIC; -- ... except PIA takes action on reads!
|
||
RAM_WR_ENABLE : OUT STD_LOGIC;
|
||
PBI_WR_ENABLE : OUT STD_LOGIC;
|
||
D6_WR_ENABLE : OUT STD_LOGIC;
|
||
|
||
-- ROM and RAM have extended address busses to allow for bank switching etc.
|
||
ROM_ADDR : OUT STD_LOGIC_VECTOR(21 downto 0);
|
||
RAM_ADDR : OUT STD_LOGIC_VECTOR(18 downto 0);
|
||
PBI_ADDR : out std_logic_vector(15 downto 0);
|
||
|
||
RAM_REQUEST : out std_logic;
|
||
ROM_REQUEST : out std_logic;
|
||
CART_REQUEST : out std_logic;
|
||
|
||
CART_S4_n : out std_logic;
|
||
CART_S5_n : out std_logic;
|
||
CART_CCTL_n : out std_logic;
|
||
|
||
-- width of access
|
||
WIDTH_8bit_ACCESS : out std_logic;
|
||
WIDTH_16bit_ACCESS : out std_logic;
|
||
WIDTH_32bit_ACCESS : out std_logic;
|
||
|
||
-- interface as though SRAM - this module can take care of caching/write combining etc etc. For first cut... nothing. TODO: What extra info would help me here?
|
||
SDRAM_ADDR : out std_logic_vector(22 downto 0); -- 1 extra bit for byte alignment
|
||
SDRAM_READ_EN : out std_logic; -- if no reads pending may be a good time to do a refresh
|
||
SDRAM_WRITE_EN : out std_logic;
|
||
--SDRAM_REQUEST : out std_logic; -- Toggle this to issue a new request
|
||
SDRAM_REQUEST : out std_logic; -- Usual pattern
|
||
SDRAM_REFRESH : out std_logic;
|
||
|
||
--SDRAM_REPLY : in std_logic; -- This matches the request once complete
|
||
SDRAM_REQUEST_COMPLETE : in std_logic;
|
||
SDRAM_DATA : in std_logic_vector(31 downto 0);
|
||
|
||
WRITE_DATA : out std_logic_vector(31 downto 0)
|
||
);
|
||
|
||
END address_decoder;
|
||
|
||
ARCHITECTURE vhdl OF address_decoder IS
|
||
signal ADDR_next : std_logic_vector(23 downto 0);
|
||
signal ADDR_reg : std_logic_vector(23 downto 0);
|
||
|
||
signal DATA_WRITE_next : std_logic_vector(31 downto 0);
|
||
signal DATA_WRITE_reg : std_logic_vector(31 downto 0);
|
||
|
||
signal width_8bit_next : std_logic;
|
||
signal width_16bit_next : std_logic;
|
||
signal width_32bit_next : std_logic;
|
||
signal write_enable_next : std_logic;
|
||
|
||
signal width_8bit_reg : std_logic;
|
||
signal width_16bit_reg : std_logic;
|
||
signal width_32bit_reg : std_logic;
|
||
signal write_enable_reg : std_logic;
|
||
|
||
signal request_complete : std_logic;
|
||
signal notify_antic : std_logic;
|
||
signal notify_zpu : std_logic;
|
||
signal notify_cpu : std_logic;
|
||
signal start_request : std_logic;
|
||
|
||
signal extended_access_addr : std_logic;
|
||
signal extended_access_cpu_or_antic : std_logic;
|
||
signal extended_access_antic : std_logic;
|
||
signal extended_access_cpu: std_logic; -- 130XE and compy shop switch antic seperately
|
||
|
||
signal extended_access_either: std_logic; -- RAMBO switches both together using CPU bit
|
||
|
||
signal extended_self_test : std_logic;
|
||
signal extended_bank : std_logic_vector(8 downto 0); -- ONLY "000" - "103" valid...
|
||
|
||
-- even though we have 3 targets (flash, ram, rom) and 3 masters, only allow access to one a a time - simpler.
|
||
signal state_next : std_logic_vector(1 downto 0);
|
||
signal state_reg : std_logic_vector(1 downto 0);
|
||
constant state_idle : std_logic_vector(1 downto 0) := "00";
|
||
constant state_waiting_cpu : std_logic_vector(1 downto 0) := "01";
|
||
constant state_waiting_zpu : std_logic_vector(1 downto 0) := "10";
|
||
constant state_waiting_antic : std_logic_vector(1 downto 0) := "11";
|
||
|
||
signal ram_chip_select : std_logic;
|
||
signal sdram_chip_select : std_logic;
|
||
|
||
-- signal sdram_request_next : std_logic;
|
||
-- signal sdram_request_reg : std_logic;
|
||
-- signal SDRAM_REQUEST_COMPLETE : std_logic;
|
||
|
||
signal fetch_priority : std_logic_vector(2 downto 0);
|
||
|
||
signal fetch_wait_next : std_logic_vector(8 downto 0);
|
||
signal fetch_wait_reg : std_logic_vector(8 downto 0);
|
||
|
||
signal rom_in_ram : std_logic;
|
||
|
||
signal antic_fetch_real_next : std_logic;
|
||
signal antic_fetch_real_reg : std_logic;
|
||
signal cpu_fetch_real_next : std_logic;
|
||
signal cpu_fetch_real_reg : std_logic;
|
||
|
||
signal SDRAM_CART_ADDR : std_logic_vector(22 downto 0);
|
||
signal SDRAM_BASIC_ROM_ADDR : std_logic_vector(22 downto 0);
|
||
signal SDRAM_OS_ROM_ADDR : std_logic_vector(22 downto 0);
|
||
|
||
signal sdram_only_bank : std_logic;
|
||
|
||
BEGIN
|
||
-- register
|
||
process(clk,reset_n)
|
||
begin
|
||
if (reset_n='0') then
|
||
addr_reg <= (others=>'0');
|
||
state_reg <= state_idle;
|
||
width_8bit_reg <= '0';
|
||
width_16bit_reg <= '0';
|
||
width_32bit_reg <= '0';
|
||
write_enable_reg <= '0';
|
||
data_write_reg <= (others=> '0');
|
||
--sdram_request_reg <= '0';
|
||
fetch_wait_reg <= (others=>'0');
|
||
|
||
cpu_fetch_real_reg <= '0';
|
||
antic_fetch_real_reg <= '0';
|
||
elsif (clk'event and clk='1') then
|
||
addr_reg <= addr_next;
|
||
state_reg <= state_next;
|
||
width_8bit_reg <= width_8bit_next;
|
||
width_16bit_reg <= width_16bit_next;
|
||
width_32bit_reg <= width_32bit_next;
|
||
write_enable_reg <= write_enable_next;
|
||
data_write_reg <= data_WRITE_next;
|
||
--sdram_request_reg <= sdram_request_next;
|
||
fetch_wait_reg <= fetch_wait_next;
|
||
|
||
cpu_fetch_real_reg <= cpu_fetch_real_next;
|
||
antic_fetch_real_reg <= antic_fetch_real_next;
|
||
end if;
|
||
end process;
|
||
|
||
-- ANTIC FETCH
|
||
|
||
-- concept
|
||
-- bus master sends request - antic or cpu
|
||
-- antic has priority
|
||
-- cpu may be idle
|
||
-- once request complete MEMORY_READY is set
|
||
-- if request interrupted then results are LOST - memory ready not set until priority request satisfied
|
||
|
||
-- so
|
||
-- memory_ready <= device_ready;
|
||
|
||
-- problem
|
||
-- request -> device access -> interrupt -> device finishes -> ignored? -> device access
|
||
|
||
-- state machine
|
||
|
||
-- state machine impl
|
||
fetch_priority <= ANTIC_FETCH&ZPU_FETCH&CPU_FETCH;
|
||
process(fetch_wait_reg, state_reg, addr_reg, data_write_reg, width_8bit_reg, width_16bit_reg, width_32bit_reg, write_enable_reg, fetch_priority, antic_addr, zpu_addr, cpu_addr, request_complete, zpu_8bit_write_enable,zpu_16bit_write_enable,zpu_32bit_write_enable,zpu_read_enable, cpu_write_n, CPU_WRITE_DATA, ZPU_WRITE_DATA, antic_fetch_real_reg, cpu_fetch_real_reg)
|
||
begin
|
||
start_request <= '0';
|
||
notify_antic <= '0';
|
||
notify_cpu <= '0';
|
||
notify_zpu <= '0';
|
||
state_next <= state_reg;
|
||
fetch_wait_next <= std_logic_vector(unsigned(fetch_wait_reg) +1);
|
||
|
||
addr_next <= addr_reg;
|
||
data_WRITE_next <= data_WRITE_reg;
|
||
width_8bit_next <= width_8bit_reg;
|
||
width_16bit_next <= width_16bit_reg;
|
||
width_32bit_next <= width_32bit_reg;
|
||
write_enable_next <= write_enable_reg;
|
||
|
||
antic_fetch_real_next <= antic_fetch_real_reg;
|
||
cpu_fetch_real_next <= cpu_fetch_real_reg;
|
||
|
||
case state_reg is
|
||
when state_idle =>
|
||
fetch_wait_next <= (others=>'0');
|
||
write_enable_next <= '0';
|
||
width_8bit_next <= '0';
|
||
width_16bit_next <= '0';
|
||
width_32bit_next <= '0';
|
||
data_WRITE_next <= (others => '0');
|
||
addr_next <= zpu_ADDR(23 downto 16)&cpu_ADDR(15 downto 0);
|
||
|
||
case fetch_priority is
|
||
when "100"|"101"|"110"|"111" => -- antic wins
|
||
start_request <= '1';
|
||
addr_next <= "00000000"&antic_ADDR;
|
||
width_8bit_next <= '1';
|
||
if (request_complete = '1') then
|
||
notify_antic <= '1';
|
||
else
|
||
state_next <= state_waiting_antic;
|
||
end if;
|
||
antic_fetch_real_next <= '1';
|
||
when "010"|"011" => -- zpu wins (zpu usually accesses own ROM memory - this is NOT a zpu_fetch)
|
||
start_request <= '1';
|
||
addr_next <= zpu_ADDR;
|
||
data_WRITE_next <= zpu_wRITE_DATA;
|
||
|
||
width_8bit_next <= zpu_8BIT_WRITE_ENABLE or (zpu_READ_ENABLE and (zpu_addr(0) or zpu_addr(1)));
|
||
width_16bit_next <= zpu_16BIT_WRITE_ENABLE;
|
||
width_32bit_next <= zpu_32BIT_WRITE_ENABLE or (zpu_READ_ENABLE and not(zpu_addr(0) or zpu_addr(1))); -- narrower devices just return 8 bits on read
|
||
|
||
write_enable_next <= not(zpu_READ_ENABLE);
|
||
|
||
if (request_complete = '1') then
|
||
notify_zpu <= '1';
|
||
else
|
||
state_next <= state_waiting_zpu;
|
||
end if;
|
||
when "001" => -- 6502 wins
|
||
start_request <= '1';
|
||
addr_next <= "00000000"&cpu_ADDR;
|
||
data_WRITE_next(7 downto 0) <= cpu_WRITE_DATA;
|
||
width_8bit_next <= '1';
|
||
write_enable_next <= not(cpu_WRITE_N);
|
||
if (request_complete = '1') then
|
||
notify_cpu <= '1';
|
||
else
|
||
state_next <= state_waiting_cpu;
|
||
end if;
|
||
cpu_fetch_real_next <= '1';
|
||
when "000" =>
|
||
-- no requests
|
||
when others =>
|
||
-- nop
|
||
end case;
|
||
when state_waiting_antic =>
|
||
if (request_complete = '1') then
|
||
notify_antic <= '1';
|
||
state_next <= state_idle;
|
||
end if;
|
||
when state_waiting_zpu =>
|
||
if (request_complete = '1') then
|
||
notify_zpu <= '1';
|
||
state_next <= state_idle;
|
||
end if;
|
||
when state_waiting_cpu =>
|
||
if (request_complete = '1') then
|
||
notify_cpu <= '1';
|
||
state_next <= state_idle;
|
||
end if;
|
||
when others =>
|
||
-- NOP
|
||
end case;
|
||
end process;
|
||
|
||
-- output
|
||
MEMORY_READY_ANTIC <= notify_antic;
|
||
MEMORY_READY_ZPU <= notify_zpu;
|
||
MEMORY_READY_CPU <= notify_cpu;
|
||
|
||
RAM_REQUEST <= ram_chip_select;
|
||
|
||
SDRAM_REQUEST <= sdram_chip_select;
|
||
--SDRAM_REQUEST <= sdram_request_next;
|
||
SDRAM_REFRESH <= '0'; --fetch_wait_reg(7); -- TODO, BROKEN! antic_refresh;
|
||
SDRAM_READ_EN <= not(write_enable_next);
|
||
SDRAM_WRITE_EN <= write_enable_next;
|
||
|
||
WIDTH_8bit_ACCESS <= width_8bit_next;
|
||
WIDTH_16bit_ACCESS <= width_16bit_next;
|
||
WIDTH_32bit_ACCESS <= width_32bit_next;
|
||
|
||
WRITE_DATA <= DATA_WRITE_next;
|
||
|
||
-- a little sdram glue - move to sdram wrapper? TODO
|
||
--SDRAM_REQUEST_COMPLETE <= (SDRAM_REPLY xnor sdram_request_reg) and not(start_request);
|
||
--sdram_request_next <= sdram_request_reg xor sdram_chip_select;
|
||
|
||
-- Calculate which memory area to use
|
||
extended_access_addr <= addr_next(14) and not(addr_next(15)); --0x4000 to 0x7fff
|
||
extended_access_cpu_or_antic <= extended_access_antic or extended_access_cpu;
|
||
extended_access_antic <= (extended_access_addr and antic_fetch_real_next and not(portb(5)));
|
||
extended_access_cpu <= (extended_access_addr and cpu_fetch_real_next and not(portb(4)));
|
||
extended_access_either <= extended_access_addr and not(portb(4));
|
||
sdram_only_bank <= or_reduce(extended_bank(8 downto 5));
|
||
|
||
process(extended_access_cpu_or_antic,extended_access_either,extended_access_addr,addr_next,ram_select,portb)
|
||
begin
|
||
extended_bank <= "0000000"&addr_next(15 downto 14);
|
||
extended_self_test <= '1';
|
||
|
||
case ram_select is
|
||
when "000" => -- 64k
|
||
-- default
|
||
when "001" => -- 128k
|
||
if (extended_access_cpu_or_antic='1') then
|
||
extended_bank(2 downto 0) <= '1'&portb(3 downto 2);
|
||
end if;
|
||
when "010" => -- 320k compy shop
|
||
if (extended_access_cpu_or_antic='1') then
|
||
extended_bank(4 downto 0) <= '1'&portb(7 downto 6)&portb(3 downto 2);
|
||
extended_self_test <= '0';
|
||
end if;
|
||
when "011" => -- 320k rambo
|
||
if (extended_access_either='1')then
|
||
extended_bank(4 downto 0) <= '1'&portb(6 downto 5)&portb(3 downto 2);
|
||
end if;
|
||
when "100" => -- 576k compy shop
|
||
if (extended_access_cpu_or_antic='1') then
|
||
extended_bank(4 downto 0) <= portb(7 downto 6)&portb(3 downto 1);
|
||
extended_bank(5) <= not(or_reduce(portb(7 downto 6)&portb(3)));
|
||
extended_self_test <= '0';
|
||
end if;
|
||
when "101" => -- 576k rambo
|
||
if (extended_access_either='1') then
|
||
extended_bank(4 downto 0) <= portb(6 downto 5)&portb(3 downto 1);
|
||
extended_bank(5) <= not(or_reduce(portb(6 downto 5)&portb(3)));
|
||
end if;
|
||
when "110" => -- 1088k rambo
|
||
if (extended_access_either='1') then
|
||
extended_bank(5 downto 0) <= portb(7 downto 5)&portb(3 downto 1);
|
||
extended_bank(6) <= not(or_reduce(portb(7 downto 5)&portb(3)));
|
||
extended_self_test <= '0';
|
||
end if;
|
||
when "111" => -- 4MB!
|
||
if (extended_access_addr='1') then
|
||
extended_bank(7 downto 0) <= portb(7 downto 0);
|
||
extended_bank(8) <= not(or_reduce(portb(7 downto 2)));
|
||
extended_self_test <= and_reduce(portb(6 downto 4)); -- which means self-test is in the middle of half the banks - euuugh, oh well!
|
||
end if;
|
||
when others =>
|
||
-- TODO - portc!
|
||
end case;
|
||
end process;
|
||
|
||
|
||
-- SRAM memory map (512k)
|
||
-- base 64k RAM - banks 0-3 "000 0000 1111 1111 1111 1111" (TOP)
|
||
-- to 512k RAM - banks 4-31 "000 0111 1111 1111 1111 1111" (TOP)
|
||
-- SDRAM memory map (8MB)
|
||
-- base 64k RAM - banks 0-3 "000 0000 1111 1111 1111 1111" (TOP)
|
||
-- to 512k RAM - banks 4-31 "000 0111 1111 1111 1111 1111" (TOP)
|
||
-- to 4MB RAM - banks 32-255 "011 1111 1111 1111 1111 1111" (TOP)
|
||
-- +64k - banks 256-259"100 0000 0000 1111 1111 1111" (TOP)
|
||
-- SCRATCH - 4MB+64k-5MB
|
||
-- CARTS - "101 YYYY YYY0 0000 0000 0000" (BOT) - 2MB! 8kb banks
|
||
SDRAM_CART_ADDR <= "101"&cart_select& "0000000000000";
|
||
-- BASIC/OS ROM - "111 XXXX XX00 0000 0000 0000" (BOT) (BASIC IN SLOT 0!), 2nd to last 512K
|
||
SDRAM_BASIC_ROM_ADDR <= "111"&"000000" &"00000000000000";
|
||
SDRAM_OS_ROM_ADDR <= "111"&rom_select &"00000000000000";
|
||
-- SYSTEM - "111 1000 0000 0000 0000 0000" (BOT) - LAST 512K
|
||
|
||
process(
|
||
-- address and writing absolutely points us at a device
|
||
ADDR_next,WRITE_enable_next,
|
||
|
||
-- except for these additional special address bits
|
||
portb,
|
||
antic_fetch,
|
||
rom_select,
|
||
ram_select,cart_rd4,cart_rd5,
|
||
use_sdram,
|
||
|
||
-- input data from n sources
|
||
GTIA_DATA,POKEY_DATA,POKEY2_DATA,PIA_DATA,ANTIC_DATA,CART_ROM_DATA,ROM_DATA,RAM_DATA,SDRAM_DATA,
|
||
CACHE_GTIA_DATA,CACHE_POKEY_DATA,CACHE_POKEY2_DATA,CACHE_ANTIC_DATA,
|
||
|
||
-- input data from n sources complete?
|
||
-- hardware regs take 1 cycle, so always complete
|
||
ram_request_complete,sdram_request_complete,rom_request_complete,cart_request_complete,
|
||
|
||
-- on new access this is set - we must select the appropriate device - for this cycle only
|
||
start_request,
|
||
|
||
rom_in_ram,
|
||
|
||
-- SDRAM base addresses
|
||
extended_self_test,extended_bank,sdram_only_bank,
|
||
SDRAM_BASIC_ROM_ADDR,SDRAM_CART_ADDR,SDRAM_OS_ROM_ADDR
|
||
|
||
)
|
||
begin
|
||
MEMORY_DATA <= (others => '1');
|
||
|
||
ROM_ADDR <= (others=>'0');
|
||
RAM_ADDR <= addr_next(18 downto 0);
|
||
SDRAM_ADDR <= addr_next(22 downto 0);
|
||
|
||
PBI_ADDR <= ADDR_next(15 downto 0);
|
||
|
||
request_complete <= '0';
|
||
|
||
GTIA_WR_ENABLE <= '0';
|
||
POKEY_WR_ENABLE <= '0';
|
||
POKEY2_WR_ENABLE <= '0';
|
||
ANTIC_WR_ENABLE <= '0';
|
||
PIA_WR_ENABLE <= '0';
|
||
PIA_RD_ENABLE <= '0';
|
||
PBI_WR_ENABLE <= '0';
|
||
D6_WR_ENABLE <= '0';
|
||
|
||
RAM_WR_ENABLE <= write_enable_next;
|
||
SDRAM_WRITE_EN <= write_enable_next;
|
||
|
||
CART_S4_n <= '1';
|
||
CART_S5_n <= '1';
|
||
CART_CCTL_n <= '1';
|
||
|
||
rom_request <= '0';
|
||
cart_request <= '0';
|
||
|
||
ram_chip_select <= '0';
|
||
sdram_chip_select <= '0';
|
||
|
||
rom_in_ram <= '1';
|
||
|
||
-- if (addr_next(23 downto 17) = "0000000" ) then -- bit 16 left out on purpose, so the Atari 64k is available as 64k-128k for zpu. The zpu has rom at 0-64k...
|
||
if (or_reduce(addr_next(23 downto 18)) = '0' ) then -- bit 16,17 left out on purpose, so the Atari 64k is available as 64k-128k for zpu. The zpu has rom at 0-64k...
|
||
|
||
SDRAM_ADDR(13 downto 0) <= addr_next(13 downto 0);
|
||
SDRAM_ADDR(22 downto 14) <= extended_bank;
|
||
RAM_ADDR(13 downto 0) <= addr_next(13 downto 0);
|
||
RAM_ADDR(18 downto 14) <= extended_bank(4 downto 0);
|
||
|
||
if ((use_sdram or sdram_only_bank)='1') then
|
||
MEMORY_DATA(7 downto 0) <= SDRAM_DATA(7 downto 0);
|
||
sdram_chip_select <= start_request;
|
||
request_complete <= sdram_request_COMPLETE;
|
||
else
|
||
MEMORY_DATA(7 downto 0) <= RAM_DATA(7 downto 0);
|
||
ram_chip_select <= start_request;
|
||
request_complete <= ram_request_COMPLETE;
|
||
end if;
|
||
|
||
case addr_next(15 downto 8) is
|
||
-- GTIA
|
||
when X"D0" =>
|
||
GTIA_WR_ENABLE <= write_enable_next;
|
||
MEMORY_DATA(7 downto 0) <= GTIA_DATA;
|
||
MEMORY_DATA(15 downto 8) <= CACHE_GTIA_DATA;
|
||
request_complete <= '1';
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
|
||
-- POKEY
|
||
when X"D2" =>
|
||
if (addr_next(4) = '0') then
|
||
POKEY_WR_ENABLE <= write_enable_next;
|
||
MEMORY_DATA(7 downto 0) <= POKEY_DATA;
|
||
MEMORY_DATA(15 downto 8) <= CACHE_POKEY_DATA;
|
||
else
|
||
POKEY2_WR_ENABLE <= write_enable_next;
|
||
MEMORY_DATA(7 downto 0) <= POKEY2_DATA;
|
||
MEMORY_DATA(15 downto 8) <= CACHE_POKEY2_DATA;
|
||
end if;
|
||
request_complete <= '1';
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
|
||
-- PIA
|
||
when X"D3" =>
|
||
PIA_WR_ENABLE <= write_enable_next;
|
||
PIA_RD_ENABLE <= '1';
|
||
MEMORY_DATA(7 downto 0) <= PIA_DATA;
|
||
request_complete <= '1';
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
|
||
-- ANTIC
|
||
when X"D4" =>
|
||
ANTIC_WR_ENABLE <= write_enable_next;
|
||
MEMORY_DATA(7 downto 0) <= ANTIC_DATA;
|
||
MEMORY_DATA(15 downto 8) <= CACHE_ANTIC_DATA;
|
||
request_complete <= '1';
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
|
||
-- CART_CONFIG -- TODO - wait for n cycles (for now non-turbo mode should work?)
|
||
when X"D5" =>
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
if ((CART_RD4 or CART_RD5) = '1') then
|
||
PBI_WR_ENABLE <= write_enable_next;
|
||
MEMORY_DATA(7 downto 0) <= CART_ROM_DATA;
|
||
cart_request <= start_request;
|
||
CART_CCTL_n <= '0';
|
||
request_complete <= CART_REQUEST_COMPLETE;
|
||
else
|
||
MEMORY_DATA(7 downto 0) <= X"FF";
|
||
request_complete <= '1';
|
||
end if;
|
||
|
||
when X"D6" =>
|
||
D6_WR_ENABLE <= write_enable_next;
|
||
-- TODO - should this still have RAM with covox here?
|
||
|
||
-- SELF TEST ROM 0x5000->0x57ff and XE RAM
|
||
when
|
||
X"50"|X"51"|X"52"|X"53"|X"54"|X"55"|X"56"|X"57" =>
|
||
|
||
if (portb(7) = '0' and portb(0) = '1' and extended_self_test = '1') then
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
|
||
if (rom_in_ram = '1') then
|
||
MEMORY_DATA(7 downto 0) <= SDRAM_DATA(7 downto 0);
|
||
else
|
||
MEMORY_DATA(7 downto 0) <= ROM_DATA;
|
||
end if;
|
||
|
||
if (write_enable_next = '1') then
|
||
request_complete <= '1';
|
||
else
|
||
if (rom_in_ram = '1') then
|
||
request_complete <= sdram_request_COMPLETE;
|
||
sdram_chip_select <= start_request;
|
||
else
|
||
request_complete <= rom_request_COMPLETE;
|
||
rom_request <= start_request;
|
||
end if;
|
||
end if;
|
||
--ROM_ADDR <= "000000"&"00010"&ADDR(10 downto 0); -- x01000 based 2k (i.e. self test is 4k in - usually under hardware regs)
|
||
SDRAM_ADDR <= SDRAM_OS_ROM_ADDR;
|
||
SDRAM_ADDR(13 downto 0) <= "010"&ADDR_next(10 downto 0);
|
||
ROM_ADDR <= "000000"&"00"&"010"&ADDR_next(10 downto 0); -- x01000 based 2k
|
||
end if;
|
||
|
||
-- 0x80 cart
|
||
when
|
||
X"80"|X"81"|X"82"|X"83"|X"84"|X"85"|X"86"|X"87"|X"88"|X"89"|X"8A"|X"8B"|X"8C"|X"8D"|X"8E"|X"8F"
|
||
|X"90"|X"91"|X"92"|X"93"|X"94"|X"95"|X"96"|X"97"|X"98"|X"99"|X"9A"|X"9B"|X"9C"|X"9D"|X"9E"|X"9F" =>
|
||
|
||
if (cart_rd4 = '1') then
|
||
MEMORY_DATA(7 downto 0) <= CART_ROM_DATA;
|
||
rom_request <= start_request;
|
||
CART_S4_n <= '0';
|
||
request_complete <= CART_REQUEST_COMPLETE;
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
end if;
|
||
|
||
-- 0xa0 cart (BASIC ROM 0xa000 - 0xbfff (8k))
|
||
when
|
||
X"A0"|X"A1"|X"A2"|X"A3"|X"A4"|X"A5"|X"A6"|X"A7"|X"A8"|X"A9"|X"AA"|X"AB"|X"AC"|X"AD"|X"AE"|X"AF"
|
||
|X"B0"|X"B1"|X"B2"|X"B3"|X"B4"|X"B5"|X"B6"|X"B7"|X"B8"|X"B9"|X"BA"|X"BB"|X"BC"|X"BD"|X"BE"|X"BF" =>
|
||
|
||
if (cart_rd5 = '1') then
|
||
MEMORY_DATA(7 downto 0) <= CART_ROM_DATA;
|
||
cart_request <= start_request;
|
||
CART_S5_n <= '0';
|
||
request_complete <= CART_REQUEST_COMPLETE;
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
else
|
||
if (portb(1) = '0') then
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
--request_complete <= ROM_REQUEST_COMPLETE;
|
||
--MEMORY_DATA(7 downto 0) <= ROM_DATA;
|
||
--rom_request <= start_request;
|
||
if (rom_in_ram = '1') then
|
||
MEMORY_DATA(7 downto 0) <= SDRAM_DATA(7 downto 0);
|
||
else
|
||
MEMORY_DATA(7 downto 0) <= ROM_DATA;
|
||
end if;
|
||
if (write_enable_next = '1') then
|
||
request_complete <= '1';
|
||
else
|
||
if (rom_in_ram = '1') then
|
||
request_complete <= sdram_request_COMPLETE;
|
||
sdram_chip_select <= start_request;
|
||
else
|
||
request_complete <= rom_request_COMPLETE;
|
||
rom_request <= start_request;
|
||
end if;
|
||
end if;
|
||
|
||
ROM_ADDR <= "000000"&"110"&ADDR_next(12 downto 0); -- x0C000 based 8k
|
||
SDRAM_ADDR <= SDRAM_BASIC_ROM_ADDR;
|
||
SDRAM_ADDR(12 downto 0) <= ADDR_next(12 downto 0); -- x0C000 based 8k
|
||
end if;
|
||
end if;
|
||
|
||
-- OS ROM 0xc00->0xcff
|
||
-- OS ROM d800->0xfff
|
||
when
|
||
X"C0"|X"C1"|X"C2"|X"C3"|X"C4"|X"C5"|X"C6"|X"C7"|X"C8"|X"C9"|X"CA"|X"CB"|X"CC"|X"CD"|X"CE"|X"CF"
|
||
|X"D8"|X"D9"|X"DA"|X"DB"|X"DC"|X"DD"|X"DE"|X"DF"
|
||
|X"E0"|X"E1"|X"E2"|X"E3"|X"E4"|X"E5"|X"E6"|X"E7"|X"E8"|X"E9"|X"EA"|X"EB"|X"EC"|X"ED"|X"EE"|X"EF"
|
||
|X"F0"|X"F1"|X"F2"|X"F3"|X"F4"|X"F5"|X"F6"|X"F7"|X"F8"|X"F9"|X"FA"|X"FB"|X"FC"|X"FD"|X"FE"|X"FF" =>
|
||
|
||
if (portb(0) = '1') then
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
--request_complete <= ROM_REQUEST_COMPLETE;
|
||
--MEMORY_DATA(7 downto 0) <= ROM_DATA;
|
||
--rom_request <= start_request;
|
||
if (rom_in_ram = '1') then
|
||
MEMORY_DATA(7 downto 0) <= SDRAM_DATA(7 downto 0);
|
||
else
|
||
MEMORY_DATA(7 downto 0) <= ROM_DATA;
|
||
end if;
|
||
if (write_enable_next = '1') then
|
||
request_complete <= '1';
|
||
else
|
||
if (rom_in_ram = '1') then
|
||
request_complete <= sdram_request_COMPLETE;
|
||
sdram_chip_select <= start_request;
|
||
else
|
||
request_complete <= rom_request_COMPLETE;
|
||
rom_request <= start_request;
|
||
end if;
|
||
end if;
|
||
|
||
ROM_ADDR <= "000000"&"00"&ADDR_next(13 downto 0); -- x00000 based 16k
|
||
SDRAM_ADDR <= SDRAM_OS_ROM_ADDR;
|
||
SDRAM_ADDR(13 downto 0) <= ADDR_next(13 downto 0);
|
||
end if;
|
||
|
||
when others =>
|
||
end case;
|
||
else
|
||
sdram_chip_select <= '0';
|
||
ram_chip_select <= '0';
|
||
case addr_next(23 downto 21) is
|
||
when "000" =>
|
||
-- internal area for zpu, never happens!
|
||
when "001" => -- sram, 512K
|
||
MEMORY_DATA(15 downto 0) <= RAM_DATA;
|
||
ram_chip_select <= start_request;
|
||
request_complete <= ram_request_COMPLETE;
|
||
RAM_ADDR <= addr_next(18 downto 0);
|
||
|
||
when "010"|"011" => -- flash rom, 4MB
|
||
request_complete <= ROM_REQUEST_COMPLETE;
|
||
MEMORY_DATA(7 downto 0) <= ROM_DATA;
|
||
rom_request <= start_request;
|
||
ROM_ADDR <= addr_next(21 downto 0);
|
||
|
||
when "100"|"101"|"110"|"111" => -- sdram, 8MB
|
||
MEMORY_DATA <= SDRAM_DATA;
|
||
sdram_chip_select <= start_request;
|
||
request_complete <= sdram_request_COMPLETE;
|
||
SDRAM_ADDR <= addr_next(22 downto 0);
|
||
when others =>
|
||
-- NOP
|
||
end case;
|
||
end if;
|
||
|
||
-- case addr_next(15 downto 0) is
|
||
-- when X"FFFC" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"00";
|
||
-- when X"FFFD" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"06";
|
||
-- when X"0600" => --JSR 0610
|
||
-- MEMORY_DATA(7 downto 0) <= X"20";
|
||
-- when X"0601" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"10";
|
||
-- when X"0602" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"06";
|
||
-- when X"0603" => --JMP
|
||
-- MEMORY_DATA(7 downto 0) <= X"4C";
|
||
-- when X"0604" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"00";
|
||
-- when X"0605" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"06";
|
||
-- when X"0610" => --LDA RANDOM, STA 0x10, LDA 0x10, RTS
|
||
-- MEMORY_DATA(7 downto 0) <= X"AD";
|
||
-- when X"0611" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"0A";
|
||
-- when X"0612" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"D2";
|
||
-- when X"0613" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"85";
|
||
-- when X"0614" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"10";
|
||
-- when X"0615" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"44";
|
||
-- when X"0616" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"10";
|
||
-- when X"0617" =>
|
||
-- MEMORY_DATA(7 downto 0) <= X"60";
|
||
-- when others =>
|
||
-- end case;
|
||
|
||
end process;
|
||
END vhdl;
|
common/a8core/synchronizer.vhdl | ||
---|---|---|
---------------------------------------------------------------------------
|
||
-- (c) 2013 mark watson
|
||
-- I am happy for anyone to use this for non-commercial use.
|
||
-- If my vhdl files are used commercially or otherwise sold,
|
||
-- please contact me for explicit permission at scrameta (gmail).
|
||
-- This applies for source and binary form and derived works.
|
||
---------------------------------------------------------------------------
|
||
LIBRARY ieee;
|
||
USE ieee.std_logic_1164.all;
|
||
use ieee.numeric_std.all;
|
||
|
||
ENTITY synchronizer IS
|
||
PORT
|
||
(
|
||
CLK : IN STD_LOGIC;
|
||
RAW : IN STD_LOGIC;
|
||
SYNC : OUT STD_LOGIC
|
||
);
|
||
END synchronizer;
|
||
|
||
ARCHITECTURE vhdl OF synchronizer IS
|
||
signal ff_next : std_logic_vector(2 downto 0);
|
||
signal ff_reg : std_logic_vector(2 downto 0);
|
||
begin
|
||
-- register
|
||
process(clk)
|
||
begin
|
||
if (clk'event and clk='1') then
|
||
ff_reg <= ff_next;
|
||
end if;
|
||
end process;
|
||
|
||
ff_next <= RAW&ff_reg(2 downto 1);
|
||
|
||
SYNC <= ff_reg(0);
|
||
|
||
end vhdl;
|
||
|
||
|
common/components/hq_dac.v | ||
---|---|---|
`timescale 1ns / 1ps
|
||
|
||
// This module is a third order delta/sigma modulator
|
||
// It uses no multiply only shifts by 1, 2 or 13
|
||
// There are only 7 adders used, it takes around 110 LUTs
|
||
module hq_dac
|
||
(
|
||
input reset,
|
||
input clk,
|
||
input clk_ena,
|
||
input [19:0] pcm_in,
|
||
output reg dac_out
|
||
);
|
||
|
||
// ======================================
|
||
// ============== Stage #1 ==============
|
||
// ======================================
|
||
wire [23:0] w_data_in_p0;
|
||
wire [23:0] w_data_err_p0;
|
||
wire [23:0] w_data_int_p0;
|
||
reg [23:0] r_data_fwd_p1;
|
||
|
||
// PCM input extended to 24 bits
|
||
assign w_data_in_p0 = { {4{pcm_in[19]}}, pcm_in };
|
||
|
||
// Error between the input and the quantizer output
|
||
assign w_data_err_p0 = w_data_in_p0 - w_data_qt_p2;
|
||
|
||
// First integrator adder
|
||
assign w_data_int_p0 = { {3{w_data_err_p0[23]}}, w_data_err_p0[22:2] } // Divide by 4
|
||
+ r_data_fwd_p1;
|
||
|
||
// First integrator forward delay
|
||
always @(posedge reset or posedge clk)
|
||
if (reset)
|
||
r_data_fwd_p1 <= 24'd0;
|
||
else if (clk_ena)
|
||
r_data_fwd_p1 <= w_data_int_p0;
|
||
|
||
// ======================================
|
||
// ============== Stage #2 ==============
|
||
// ======================================
|
||
wire [23:0] w_data_fb1_p1;
|
||
wire [23:0] w_data_fb2_p1;
|
||
wire [23:0] w_data_lpf_p1;
|
||
reg [23:0] r_data_lpf_p2;
|
||
|
||
// Feedback from the quantizer output
|
||
assign w_data_fb1_p1 = { {3{r_data_fwd_p1[23]}}, r_data_fwd_p1[22:2] } // Divide by 4
|
||
- { {3{w_data_qt_p2[23]}}, w_data_qt_p2[22:2] }; // Divide by 4
|
||
|
||
// Feedback from the third stage
|
||
assign w_data_fb2_p1 = w_data_fb1_p1
|
||
- { {14{r_data_fwd_p2[23]}}, r_data_fwd_p2[22:13] }; // Divide by 8192
|
||
|
||
// Low pass filter
|
||
assign w_data_lpf_p1 = w_data_fb2_p1 + r_data_lpf_p2;
|
||
|
||
// Low pass filter feedback delay
|
||
always @(posedge reset or posedge clk)
|
||
if (reset)
|
||
r_data_lpf_p2 <= 24'd0;
|
||
else if (clk_ena)
|
||
r_data_lpf_p2 <= w_data_lpf_p1;
|
||
|
||
// ======================================
|
||
// ============== Stage #3 ==============
|
||
// ======================================
|
||
wire [23:0] w_data_fb3_p1;
|
||
wire [23:0] w_data_int_p1;
|
||
reg [23:0] r_data_fwd_p2;
|
||
|
||
// Feedback from the quantizer output
|
||
assign w_data_fb3_p1 = { {2{w_data_lpf_p1[23]}}, w_data_lpf_p1[22:1] } // Divide by 2
|
||
- { {2{w_data_qt_p2[23]}}, w_data_qt_p2[22:1] }; // Divide by 2
|
||
|
||
// Second integrator adder
|
||
assign w_data_int_p1 = w_data_fb3_p1 + r_data_fwd_p2;
|
||
|
||
// Second integrator forward delay
|
||
always @(posedge reset or posedge clk)
|
||
if (reset)
|
||
r_data_fwd_p2 <= 24'd0;
|
||
else if (clk_ena)
|
||
r_data_fwd_p2 <= w_data_int_p1;
|
||
|
||
// =====================================
|
||
// ========== 1-bit quantizer ==========
|
||
// =====================================
|
||
wire [23:0] w_data_qt_p2;
|
||
|
||
assign w_data_qt_p2 = (r_data_fwd_p2[23]) ? 24'hF00000 : 24'h100000;
|
||
|
||
always @(posedge reset or posedge clk)
|
||
if (reset)
|
||
dac_out <= 1'b0;
|
||
else if (clk_ena)
|
||
dac_out <= ~r_data_fwd_p2[23];
|
||
|
||
endmodule
|
common/components/scandoubler.vhdl | ||
---|---|---|
---------------------------------------------------------------------------
|
||
-- (c) 2013 mark watson
|
||
-- I am happy for anyone to use this for non-commercial use.
|
||
-- If my vhdl files are used commercially or otherwise sold,
|
||
-- please contact me for explicit permission at scrameta (gmail).
|
||
-- This applies for source and binary form and derived works.
|
||
---------------------------------------------------------------------------
|
||
LIBRARY ieee;
|
||
USE ieee.std_logic_1164.all;
|
||
use ieee.numeric_std.all;
|
||
|
||
ENTITY scandoubler IS
|
||
PORT
|
||
(
|
||
CLK : IN STD_LOGIC;
|
||
RESET_N : IN STD_LOGIC;
|
||
|
||
VGA : IN STD_LOGIC;
|
||
COMPOSITE_ON_HSYNC : in std_logic;
|
||
|
||
colour_enable : in std_logic;
|
||
doubled_enable : in std_logic;
|
||
|
||
-- GTIA interface
|
||
colour_in : in std_logic_vector(7 downto 0);
|
||
vsync_in : in std_logic;
|
||
hsync_in : in std_logic;
|
||
|
||
-- TO TV...
|
||
R : OUT STD_LOGIC_vector(3 downto 0);
|
||
G : OUT STD_LOGIC_vector(3 downto 0);
|
||
B : OUT STD_LOGIC_vector(3 downto 0);
|
||
|
||
VSYNC : out std_logic;
|
||
HSYNC : out std_logic
|
||
);
|
||
END scandoubler;
|
||
|
||
ARCHITECTURE vhdl OF scandoubler IS
|
||
|
||
COMPONENT gtia_palette IS
|
||
PORT
|
||
(
|
||
ATARI_COLOUR : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
|
||
R_next : OUT STD_LOGIC_VECTOR(7 downto 0);
|
||
G_next : OUT STD_LOGIC_VECTOR(7 downto 0);
|
||
B_next : OUT STD_LOGIC_VECTOR(7 downto 0)
|
||
);
|
||
END component;
|
||
|
||
-- component reg_file IS
|
||
-- generic
|
||
-- (
|
||
-- BYTES : natural := 1;
|
||
-- WIDTH : natural := 1
|
||
-- );
|
||
-- PORT
|
||
-- (
|
||
-- CLK : IN STD_LOGIC;
|
||
-- ADDR : IN STD_LOGIC_VECTOR(width-1 DOWNTO 0);
|
||
-- DATA_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
|
||
-- WR_EN : IN STD_LOGIC;
|
||
--
|
||
-- DATA_OUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
|
||
-- );
|
||
-- END component;
|
||
|
||
component scandouble_ram_infer IS
|
||
PORT
|
||
(
|
||
clock: IN std_logic;
|
||
data: IN std_logic_vector (7 DOWNTO 0);
|
||
address: IN integer RANGE 0 to 1824;
|
||
we: IN std_logic;
|
||
q: OUT std_logic_vector (7 DOWNTO 0)
|
||
);
|
||
END component;
|
||
|
||
component delay_line IS
|
||
generic(COUNT : natural := 1);
|
||
PORT
|
||
(
|
||
CLK : IN STD_LOGIC;
|
||
SYNC_RESET : IN STD_LOGIC;
|
||
DATA_IN : IN STD_LOGIC;
|
||
ENABLE : IN STD_LOGIC; -- i.e. shift on this clock
|
||
RESET_N : IN STD_LOGIC;
|
||
|
||
DATA_OUT : OUT STD_LOGIC
|
||
);
|
||
END component;
|
||
|
||
signal colour_next : std_logic_vector(7 downto 0);
|
||
signal colour_reg : std_logic_vector(7 downto 0);
|
||
|
||
signal vsync_next : std_logic;
|
||
signal vsync_reg : std_logic;
|
||
|
||
signal hsync_next : std_logic;
|
||
signal hsync_reg : std_logic;
|
||
|
||
signal r_next : std_logic_vector(7 downto 0);
|
||
signal g_next : std_logic_vector(7 downto 0);
|
||
signal b_next : std_logic_vector(7 downto 0);
|
||
signal r_reg : std_logic_vector(7 downto 0);
|
||
signal g_reg : std_logic_vector(7 downto 0);
|
||
signal b_reg : std_logic_vector(7 downto 0);
|
||
|
||
signal linea_address : std_logic_vector(10 downto 0);
|
||
signal linea_write_enable : std_logic;
|
||
signal linea_out : std_logic_vector(7 downto 0);
|
||
|
||
signal lineb_address : std_logic_vector(10 downto 0);
|
||
signal lineb_write_enable : std_logic;
|
||
signal lineb_out : std_logic_vector(7 downto 0);
|
||
|
||
signal input_address_next : std_logic_vector(10 downto 0);
|
||
signal input_address_reg : std_logic_vector(10 downto 0);
|
||
|
||
signal output_address_next : std_logic_vector(10 downto 0);
|
||
signal output_address_reg : std_logic_vector(10 downto 0);
|
||
|
||
signal buffer_select_next : std_logic;
|
||
signal buffer_select_reg : std_logic;
|
||
|
||
signal hsync_in_reg : std_logic;
|
||
|
||
signal vga_hsync_next : std_logic;
|
||
signal vga_hsync_reg : std_logic;
|
||
signal vga_hsync_start : std_logic;
|
||
signal vga_hsync_end : std_logic;
|
||
|
||
begin
|
||
-- register
|
||
process(clk,reset_n)
|
||
begin
|
||
if (reset_n = '0') then
|
||
r_reg <= (others=>'0');
|
||
g_reg <= (others=>'0');
|
||
b_reg <= (others=>'0');
|
||
colour_reg <= (others=>'0');
|
||
hsync_reg <= '0';
|
||
vsync_reg <= '0';
|
||
|
||
input_address_reg <= (others=>'0');
|
||
output_address_reg <= (others=>'0');
|
||
|
||
buffer_select_reg <= '0';
|
||
|
||
vga_hsync_reg <= '0';
|
||
elsif (clk'event and clk='1') then
|
||
r_reg <= r_next;
|
||
g_reg <= g_next;
|
||
b_reg <= b_next;
|
||
colour_reg <= colour_next;
|
||
hsync_reg <= hsync_next;
|
||
vsync_reg <= vsync_next;
|
||
|
||
input_address_reg <= input_address_next;
|
||
output_address_reg <= output_address_next;
|
||
|
||
buffer_select_reg <= buffer_select_next;
|
||
|
||
hsync_in_reg <= hsync_in;
|
||
|
||
vga_hsync_reg <= vga_hsync_next;
|
||
end if;
|
||
end process;
|
||
|
||
-- TODO - these should use FPGA RAM - at present about 50% of FPGA is taken by these!!!
|
||
-- linea : reg_file
|
||
--generic map (BYTES=>456,WIDTH=>9)
|
||
--port map (clk=>clk,addr=>linea_address,wr_en=>linea_write_enable,data_in=>colour_in,data_out=>linea_out);
|
||
|
||
--lineb : reg_file
|
||
-- generic map (BYTES=>456,WIDTH=>9)
|
||
-- port map (clk=>clk,addr=>lineb_address,wr_en=>lineb_write_enable,data_in=>colour_in,data_out=>lineb_out);
|
||
|
||
linea : scandouble_ram_infer
|
||
port map (clock=>clk,address=>to_integer(unsigned(linea_address)),we=>linea_write_enable,data=>colour_in,q=>linea_out);
|
||
|
||
lineb : scandouble_ram_infer
|
||
port map (clock=>clk,address=>to_integer(unsigned(lineb_address)),we=>lineb_write_enable,data=>colour_in,q=>lineb_out);
|
||
|
||
-- capture
|
||
process(input_address_reg,colour_enable,hsync_in,hsync_in_reg,buffer_select_reg)
|
||
begin
|
||
input_address_next <= input_address_reg;
|
||
buffer_select_next <= buffer_select_reg;
|
||
|
||
linea_write_enable <= '0';
|
||
lineb_write_enable <= '0';
|
||
|
||
if (colour_enable = '1') then
|
||
input_address_next <= std_logic_vector(unsigned(input_address_reg)+1);
|
||
linea_write_enable <= buffer_select_reg;
|
||
lineb_write_enable <= not(buffer_select_reg);
|
||
end if;
|
||
|
||
if (hsync_in = '1' and hsync_in_reg = '0') then
|
||
input_address_next <= (others=>'0');
|
||
buffer_select_next <= not(buffer_select_reg);
|
||
end if;
|
||
end process;
|
||
|
||
-- output
|
||
process(vga_hsync_reg,vga_hsync_end,output_address_reg,doubled_enable)
|
||
begin
|
||
output_address_next <= output_address_reg;
|
||
vga_hsync_start<='0';
|
||
vga_hsync_next <= vga_hsync_reg;
|
||
|
||
if (doubled_enable = '1') then
|
||
output_address_next <= std_logic_vector(unsigned(output_address_reg)+1);
|
||
|
||
if (output_address_reg = "111"&X"1F") then
|
||
output_address_next <= (others=>'0');
|
||
vga_hsync_start <= '1';
|
||
vga_hsync_next <= '1';
|
||
end if;
|
||
end if;
|
||
|
||
if (vga_hsync_end = '1') then
|
||
vga_hsync_next <= '0';
|
||
end if;
|
||
end process;
|
||
|
||
linea_address <= input_address_reg when buffer_select_reg='1' else output_address_reg;
|
||
lineb_address <= input_address_reg when buffer_select_reg='0' else output_address_reg;
|
||
|
||
hsync_delay : delay_line
|
||
generic map (COUNT=>128)
|
||
port map(clk=>clk,sync_reset=>'0',data_in=>vga_hsync_start,enable=>doubled_enable,reset_n=>reset_n,data_out=>vga_hsync_end);
|
||
|
||
-- display
|
||
process(colour_reg,vsync_reg,vga_hsync_reg,hsync_reg,colour_in,vsync_in,hsync_in,colour_enable,doubled_enable,vga,composite_on_hsync,buffer_select_reg,linea_out,lineb_out)
|
||
begin
|
||
colour_next <= colour_reg;
|
||
vsync_next <= vsync_reg;
|
||
hsync_next <= hsync_reg;
|
||
|
||
if (vga = '0') then
|
||
-- non-vga mode - pass through
|
||
colour_next <= colour_in;
|
||
vsync_next <= not(vsync_in);
|
||
--hsync_next <= not(hsync_in or vsync_in);
|
||
if (composite_on_hsync = '1') then
|
||
hsync_next <= not(hsync_in xor vsync_in);
|
||
else
|
||
hsync_next <= not(hsync_in);
|
||
end if;
|
||
else
|
||
-- vga mode, store all inputs - then play back!
|
||
if (buffer_select_reg = '0') then
|
||
colour_next <= linea_out; -- todo, smoothly increase/decrease...
|
||
else
|
||
colour_next <= lineb_out;
|
||
end if;
|
||
|
||
vsync_next <= not(vsync_in);
|
||
--hsync_next <= not(vga_hsync_reg);
|
||
if (composite_on_hsync = '1') then
|
||
hsync_next <= not(vga_hsync_reg xor vsync_in);
|
||
else
|
||
hsync_next <= not(vga_hsync_reg);
|
||
end if;
|
||
end if;
|
||
end process;
|
||
|
||
-- colour palette
|
||
-- Color Value Color Value
|
||
--Black 0, 0 Medium blue 8, 128
|
||
--Rust 1, 16 Dark blue 9, 144
|
||
--Red-orange 2, 32 Blue-grey 10, 160
|
||
--Dark orange 3, 48 Olive green 11, 176
|
||
--Red 4, 64 Medium green 12, 192
|
||
--Dk lavender 5, 80 Dark green 13, 208
|
||
--Cobalt blue 6, 96 Orange-green 14, 224
|
||
--Ultramarine 7, 112 Orange 15, 240
|
||
|
||
-- from altirra
|
||
palette1 : entity work.gtia_palette(altirra)
|
||
port map (ATARI_COLOUR=>colour_reg, R_next=>R_next, G_next=>G_next, B_next=>B_next);
|
||
|
||
-- from lao
|
||
-- palette2 : entity work.gtia_palette(laoo)
|
||
-- port map (ATARI_COLOUR=>COLOUR, R_next=>R_next, G_next=>G_next, B_next=>B_next);
|
||
|
||
-- output
|
||
-- TODO - for DE2, output full 8 bits
|
||
R <= R_reg(7 downto 4);
|
||
G <= G_reg(7 downto 4);
|
||
B <= B_reg(7 downto 4);
|
||
|
||
vsync<=vsync_reg;
|
||
hsync<=hsync_reg;
|
||
|
||
end vhdl;
|
||
|
||
|
common/a8core/pokey_keyboard_scanner.vhdl | ||
---|---|---|
---------------------------------------------------------------------------
|
||
-- (c) 2013 mark watson
|
||
-- I am happy for anyone to use this for non-commercial use.
|
||
-- If my vhdl files are used commercially or otherwise sold,
|
||
-- please contact me for explicit permission at scrameta (gmail).
|
||
-- This applies for source and binary form and derived works.
|
||
---------------------------------------------------------------------------
|
||
LIBRARY ieee;
|
||
USE ieee.std_logic_1164.all;
|
||
use ieee.numeric_std.all;
|
||
|
||
entity pokey_keyboard_scanner is
|
||
port
|
||
(
|
||
clk : in std_logic;
|
||
reset_n : in std_logic;
|
||
|
||
enable : in std_logic; -- typically hsync or equiv timing
|
||
keyboard_response : in std_logic_vector(1 downto 0);
|
||
debounce_disable : in std_logic;
|
||
scan_enable : in std_logic;
|
||
|
||
keyboard_scan : out std_logic_vector(5 downto 0);
|
||
|
||
shift_pressed : out std_logic;
|
||
control_pressed : out std_logic;
|
||
break_pressed : out std_logic;
|
||
key_held : out std_logic;
|
||
keycode : out std_logic_vector(5 downto 0);
|
||
other_key_irq : out std_logic
|
||
);
|
||
end pokey_keyboard_scanner;
|
||
|
||
architecture vhdl of pokey_keyboard_scanner is
|
||
signal bincnt_next : std_logic_vector(5 downto 0);
|
||
signal bincnt_reg : std_logic_vector(5 downto 0);
|
||
|
||
signal break_pressed_next : std_logic;
|
||
signal break_pressed_reg : std_logic;
|
||
|
||
signal shift_pressed_next : std_logic;
|
||
signal shift_pressed_reg : std_logic;
|
||
|
||
signal control_pressed_next : std_logic;
|
||
signal control_pressed_reg : std_logic;
|
||
|
||
signal compare_latch_next : std_logic_vector(5 downto 0);
|
||
signal compare_latch_reg : std_logic_vector(5 downto 0);
|
||
|
||
signal keycode_latch_next : std_logic_vector(5 downto 0);
|
||
signal keycode_latch_reg : std_logic_vector(5 downto 0);
|
||
|
||
signal irq_next : std_logic;
|
||
signal irq_reg : std_logic;
|
||
|
||
signal key_held_next : std_logic;
|
||
signal key_held_reg : std_logic;
|
||
|
||
signal my_key : std_logic;
|
||
|
||
signal state_next : std_logic_vector(1 downto 0);
|
||
signal state_reg : std_logic_vector(1 downto 0);
|
||
constant state_wait_key : std_logic_vector(1 downto 0) := "00";
|
||
constant state_key_bounce : std_logic_vector(1 downto 0) := "01";
|
||
constant state_valid_key : std_logic_vector(1 downto 0) := "10";
|
||
constant state_key_debounce : std_logic_vector(1 downto 0) := "11";
|
||
begin
|
||
|
||
-- register
|
||
process(clk,reset_n)
|
||
begin
|
||
if (reset_n = '0') then
|
||
bincnt_reg <= (others=>'0');
|
||
break_pressed_reg <= '0';
|
||
shift_pressed_reg <= '0';
|
||
control_pressed_reg <= '0';
|
||
compare_latch_reg <= (others=>'0');
|
||
keycode_latch_reg <= (others=>'1');
|
||
key_held_reg <= '0';
|
||
state_reg <= state_wait_key;
|
||
irq_reg <= '0';
|
||
elsif (clk'event and clk = '1') then
|
||
bincnt_reg <= bincnt_next;
|
||
state_reg <= state_next;
|
||
break_pressed_reg <= break_pressed_next;
|
||
shift_pressed_reg <= shift_pressed_next;
|
||
control_pressed_reg <= control_pressed_next;
|
||
compare_latch_reg <= compare_latch_next;
|
||
keycode_latch_reg <= keycode_latch_next;
|
||
key_held_reg <= key_held_next;
|
||
state_reg <= state_next;
|
||
irq_reg <= irq_next;
|
||
end if;
|
||
end process;
|
||
|
||
process (enable, keyboard_response, scan_enable, key_held_reg, my_key, state_reg,bincnt_reg, compare_latch_reg, break_pressed_reg, shift_pressed_reg, control_pressed_reg, keycode_latch_reg, debounce_disable)
|
||
begin
|
||
bincnt_next <= bincnt_reg;
|
||
state_next <= state_reg;
|
||
compare_latch_next <= compare_latch_reg;
|
||
irq_next <= '0';
|
||
break_pressed_next <= break_pressed_reg;
|
||
shift_pressed_next <= shift_pressed_reg;
|
||
control_pressed_next <= control_pressed_reg;
|
||
keycode_latch_next <= keycode_latch_reg;
|
||
key_held_next <= key_held_reg;
|
||
|
||
my_key <= '0';
|
||
if (bincnt_reg = compare_latch_reg or debounce_disable='1') then
|
||
my_key <= '1';
|
||
end if;
|
||
|
||
if (enable = '1' and scan_enable='1') then
|
||
bincnt_next <= std_logic_vector(unsigned(bincnt_reg) + 1); -- check another key
|
||
|
||
key_held_next<= '0';
|
||
|
||
case state_reg is
|
||
when state_wait_key =>
|
||
if (keyboard_response(0) = '0') then -- detected key press
|
||
state_next <= state_key_bounce;
|
||
compare_latch_next <= bincnt_reg;
|
||
end if;
|
||
|
||
when state_key_bounce =>
|
||
if (keyboard_response(0) = '0') then -- detected key press
|
||
if (my_key = '1') then -- same key
|
||
keycode_latch_next <= compare_latch_reg;
|
||
irq_next <= '1';
|
||
key_held_next<= '1';
|
||
state_next <= state_valid_key;
|
||
else -- different key (multiple keys pressed)
|
||
state_next <= state_wait_key;
|
||
end if;
|
||
else -- key not pressed
|
||
if (my_key = '1') then -- same key, no longer pressed
|
||
state_next <= state_wait_key;
|
||
end if;
|
||
end if;
|
||
|
||
when state_valid_key =>
|
||
key_held_next<= '1';
|
||
if (my_key = '1') then -- only response to my key
|
||
if (keyboard_response(0) = '1') then -- no longer pressed
|
||
state_next <= state_key_debounce;
|
||
end if;
|
||
end if;
|
||
|
||
when state_key_debounce =>
|
||
if (my_key = '1') then
|
||
state_next <= state_wait_key;
|
||
end if;
|
||
|
||
when others=>
|
||
state_next <= state_wait_key;
|
||
end case;
|
||
|
||
if (bincnt_reg(3 downto 0) = "0000") then
|
||
case bincnt_reg(5 downto 4) is
|
||
when "11" =>
|
||
break_pressed_next <= not(keyboard_response(1)); --0x30
|
||
when "01" =>
|
||
shift_pressed_next <= not(keyboard_response(1)); --0x10
|
||
when "00" =>
|
||
control_pressed_next <= not(keyboard_response(1)); -- 0x00
|
||
when others =>
|
||
--
|
||
end case;
|
||
end if;
|
||
end if;
|
||
end process;
|
||
|
||
-- outputs
|
||
keyboard_scan <= not(bincnt_reg);
|
||
|
||
key_held <= key_held_reg;
|
||
keycode <= keycode_latch_reg;
|
||
break_pressed <= break_pressed_reg;
|
||
shift_pressed <= shift_pressed_reg;
|
||
control_pressed <= control_pressed_reg;
|
||
other_key_irq <= irq_reg;
|
||
end vhdl;
|
common/a8core/pokey_noise_filter.vhdl | ||
---|---|---|
---------------------------------------------------------------------------
|
||
-- (c) 2013 mark watson
|
||
-- I am happy for anyone to use this for non-commercial use.
|
||
-- If my vhdl files are used commercially or otherwise sold,
|
||
-- please contact me for explicit permission at scrameta (gmail).
|
||
-- This applies for source and binary form and derived works.
|
||
---------------------------------------------------------------------------
|
||
LIBRARY ieee;
|
||
USE ieee.std_logic_1164.all;
|
||
use ieee.numeric_std.all;
|
||
|
||
ENTITY pokey_noise_filter IS
|
||
PORT
|
||
(
|
||
NOISE_SELECT : IN STD_LOGIC_VECTOR(2 downto 0);
|
||
|
||
PULSE_IN : IN STD_LOGIC;
|
||
|
||
NOISE_4 : IN STD_LOGIC;
|
||
NOISE_5 : IN STD_LOGIC;
|
||
NOISE_LARGE : IN STD_LOGIC;
|
||
|
||
PULSE_OUT : OUT STD_LOGIC
|
||
);
|
||
END pokey_noise_filter;
|
||
|
||
ARCHITECTURE vhdl OF pokey_noise_filter IS
|
||
signal pulse_noise_a : std_logic;
|
||
signal pulse_noise_b : std_logic;
|
||
BEGIN
|
||
process(pulse_in, noise_4, noise_5, noise_large, pulse_noise_a, pulse_noise_b, noise_select)
|
||
begin
|
||
pulse_noise_a <= noise_large;
|
||
pulse_noise_b <= noise_5 and pulse_in;
|
||
|
||
if (NOISE_SELECT(1) = '1') then
|
||
pulse_noise_a <= noise_4;
|
||
end if;
|
||
|
||
if (NOISE_SELECT(2) = '1') then
|
||
pulse_noise_b <= pulse_in;
|
||
end if;
|
||
|
||
PULSE_OUT <= pulse_noise_a and pulse_noise_b;
|
||
|
||
if (NOISE_SELECT(0) = '1') then
|
||
PULSE_OUT <= pulse_noise_b;
|
||
end if;
|
||
end process;
|
||
end vhdl;
|
common/a8core/poly_4.vhdl | ||
---|---|---|
---------------------------------------------------------------------------
|
||
-- (c) 2013 mark watson
|
||
-- I am happy for anyone to use this for non-commercial use.
|
||
-- If my vhdl files are used commercially or otherwise sold,
|
||
-- please contact me for explicit permission at scrameta (gmail).
|
||
-- This applies for source and binary form and derived works.
|
||
---------------------------------------------------------------------------
|
||
LIBRARY ieee;
|
||
USE ieee.std_logic_1164.all;
|
||
use ieee.numeric_std.all;
|
||
|
||
ENTITY poly_4 IS
|
||
PORT
|
||
(
|
||
CLK : IN STD_LOGIC;
|
||
RESET_N : IN STD_LOGIC;
|
||
ENABLE : IN STD_LOGIC;
|
||
INIT : IN STD_LOGIC;
|
||
|
||
BIT_OUT : OUT STD_LOGIC
|
||
);
|
Also available in: Unified diff
Current unmerged vhdl for my Atari800 core and start at merging them into one tree with a common core