Project

General

Profile

---------------------------------------------------------------------------
-- (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.std_logic_unsigned.ALL;
use ieee.numeric_std.ALL;
use IEEE.STD_LOGIC_MISC.all;

library work;
use work.zpupkg.all;

ENTITY zpu_glue IS
PORT
(
CLK : in std_logic;
RESET : in std_logic;
PAUSE : in std_logic;

ZPU_DI : in std_logic_vector(31 downto 0); -- response from general memory - for areas that only support 8/16 bit set top bits to 0
ZPU_ROM_DI : in std_logic_vector(31 downto 0); -- response from own program memory
ZPU_RAM_DI : in std_logic_vector(31 downto 0); -- response from own stack
ZPU_CONFIG_DI : in std_logic_vector(31 downto 0); -- response from config registers
ZPU_DO : out std_logic_vector(31 downto 0);
ZPU_ADDR_ROM_RAM : out std_logic_vector(15 downto 0); -- direct from zpu, for short paths
ZPU_ADDR_FETCH : out std_logic_vector(23 downto 0); -- clk->q, for longer paths
-- request
MEMORY_FETCH : out std_logic;
ZPU_READ_ENABLE : out std_logic;
ZPU_32BIT_WRITE_ENABLE : out std_logic; -- common case
ZPU_16BIT_WRITE_ENABLE : out std_logic; -- for sram (never happens yet!)
ZPU_8BIT_WRITE_ENABLE : out std_logic; -- for hardware regs
-- config
ZPU_CONFIG_WRITE : out std_logic;
ZPU_CONFIG_READ : out std_logic;
-- stack request
ZPU_STACK_WRITE : out std_logic_vector(3 downto 0);

-- write to ROM!!
ZPU_ROM_WREN : out std_logic;

-- response
MEMORY_READY : in std_logic
);
END zpu_glue;

architecture sticky of zpu_glue is
component ZPUMediumCore is
generic(
WORD_SIZE : integer:=32; -- 16/32 (2**wordPower)
ADDR_W : integer:=24; -- Total address space width (incl. I/O)
MEM_W : integer:=16; -- Memory (prog+data+stack) width - stack at end of memory - so end of sdram. 32K ROM, 32K RAM (MAX)
D_CARE_VAL : std_logic:='X'; -- Value used to fill the unsused bits
MULT_PIPE : boolean:=false; -- Pipeline multiplication
BINOP_PIPE : integer range 0 to 2:=0; -- Pipeline binary operations (-, =, < and <=)
ENA_LEVEL0 : boolean:=true; -- eq, loadb, neqbranch and pushspadd
ENA_LEVEL1 : boolean:=true; -- lessthan, ulessthan, mult, storeb, callpcrel and sub
ENA_LEVEL2 : boolean:=true; -- lessthanorequal, ulessthanorequal, call and poppcrel
ENA_LSHR : boolean:=true; -- lshiftright
ENA_IDLE : boolean:=false; -- Enable the enable_i input
FAST_FETCH : boolean:=true); -- Merge the st_fetch with the st_execute states
port(
clk_i : in std_logic; -- CPU Clock
reset_i : in std_logic; -- Sync Reset
enable_i : in std_logic; -- Hold the CPU (after reset)
break_o : out std_logic; -- Break instruction executed
dbg_o : out zpu_dbgo_t; -- Debug outputs (i.e. trace log)
-- Memory interface
mem_busy_i : in std_logic; -- Memory is busy
data_i : in unsigned(WORD_SIZE-1 downto 0); -- Data from mem
data_o : out unsigned(WORD_SIZE-1 downto 0); -- Data to mem
addr_o : out unsigned(ADDR_W-1 downto 0); -- Memory address
write_en_o : out std_logic; -- Memory write enable (32-bit)
read_en_o : out std_logic; -- Memory read enable (32-bit)
byte_read_o : out std_logic;
byte_write_o : out std_logic;
short_write_o: out std_logic); -- never happens
end component;
signal zpu_addr_unsigned : unsigned(23 downto 0);
signal zpu_do_unsigned : unsigned(31 downto 0);
signal ZPU_DI_unsigned : unsigned(31 downto 0);
signal zpu_break : std_logic;
signal zpu_debug : zpu_dbgo_t;
signal zpu_mem_busy : std_logic;
signal zpu_memory_fetch_pending_next : std_logic;
signal zpu_memory_fetch_pending_reg : std_logic;
signal ZPU_32bit_READ_ENABLE_temp : std_logic;
signal ZPU_8bit_READ_ENABLE_temp : std_logic;
signal ZPU_READ_temp : std_logic;
signal ZPU_32BIT_WRITE_ENABLE_temp : std_logic;
signal ZPU_16BIT_WRITE_ENABLE_temp : std_logic;
signal ZPU_8BIT_WRITE_ENABLE_temp : std_logic;
signal ZPU_WRITE_temp : std_logic;
signal ZPU_32BIT_WRITE_ENABLE_next : std_logic;
signal ZPU_16BIT_WRITE_ENABLE_next : std_logic;
signal ZPU_8BIT_WRITE_ENABLE_next : std_logic;
signal ZPU_READ_next : std_logic;
signal ZPU_32BIT_WRITE_ENABLE_reg : std_logic;
signal ZPU_16BIT_WRITE_ENABLE_reg : std_logic;
signal ZPU_8BIT_WRITE_ENABLE_reg : std_logic;
signal ZPU_READ_reg : std_logic;
signal block_mem : std_logic;
signal config_mem : std_logic;
signal special_mem : std_logic;
signal result_next : std_logic_vector(4 downto 0);
signal result_reg : std_logic_vector(4 downto 0);
constant result_external : std_logic_vector(4 downto 0) := "00000";
constant result_ram : std_logic_vector(4 downto 0) := "00001";
constant result_ram_8bit_0 : std_logic_vector(4 downto 0) := "00010";
constant result_ram_8bit_1 : std_logic_vector(4 downto 0) := "00011";
constant result_ram_8bit_2 : std_logic_vector(4 downto 0) := "00100";
constant result_ram_8bit_3 : std_logic_vector(4 downto 0) := "00101";
constant result_rom : std_logic_vector(4 downto 0) := "00110";
constant result_rom_8bit_0 : std_logic_vector(4 downto 0) := "00111";
constant result_rom_8bit_1 : std_logic_vector(4 downto 0) := "01000";
constant result_rom_8bit_2 : std_logic_vector(4 downto 0) := "01001";
constant result_rom_8bit_3 : std_logic_vector(4 downto 0) := "01010";
constant result_config : std_logic_vector(4 downto 0) := "01011";
constant result_external_special : std_logic_vector(4 downto 0) := "01100";
signal request_type : std_logic_vector(4 downto 0);
signal zpu_di_use : std_logic_vector(31 downto 0);
signal memory_access : std_logic;

-- 1 cycle delay on memory read - needed to allow running at higher clock
signal zpu_di_next : std_logic_vector(31 downto 0);
signal zpu_di_reg : std_logic_vector(31 downto 0);
signal memory_ready_next : std_logic;
signal memory_ready_reg : std_logic;
signal zpu_enable : std_logic;
signal zpu_addr_next : std_logic_vector(23 downto 0);
signal zpu_addr_reg : std_logic_vector(23 downto 0);

signal ZPU_DO_next : std_logic_vector(31 downto 0);
signal ZPU_DO_reg : std_logic_vector(31 downto 0);
begin
-- register
process(clk,reset)
begin
if (reset='1') then
zpu_memory_fetch_pending_reg <= '0';
result_reg <= result_rom;
zpu_di_reg <= (others=>'0');
zpu_do_reg <= (others=>'0');
memory_ready_reg <= '0';
zpu_addr_reg <= (others=>'0');
ZPU_32BIT_WRITE_ENABLE_reg <= '0';
ZPU_16BIT_WRITE_ENABLE_reg <= '0';
ZPU_8BIT_WRITE_ENABLE_reg <= '0';
ZPU_READ_reg <= '0';
elsif (clk'event and clk='1') then
zpu_memory_fetch_pending_reg <= zpu_memory_fetch_pending_next;
result_reg <= result_next;
zpu_di_reg <= zpu_di_next;
zpu_do_reg <= zpu_do_next;
memory_ready_reg <= memory_ready_next;
zpu_addr_reg <=zpu_addr_next;
ZPU_32BIT_WRITE_ENABLE_reg <= ZPU_32BIT_WRITE_ENABLE_next;
ZPU_16BIT_WRITE_ENABLE_reg <= ZPU_16BIT_WRITE_ENABLE_next;
ZPU_8BIT_WRITE_ENABLE_reg <= ZPU_8BIT_WRITE_ENABLE_next;
ZPU_READ_reg <= ZPU_READ_next;
end if;
end process;

-- a little glue
process(zpu_ADDR_unsigned)
begin
block_mem <= '0';
config_mem <= '0';
special_mem <= '0';
-- $00000-$0FFFF = Own ROM/RAM
-- $10000-$1FFFF = Atari
-- $20000-$2FFFF = Atari - savestate (gtia/antic/pokey have memory behind them)
-- $40000-$4FFFF = Config area
if (or_reduce(std_logic_vector(zpu_ADDR_unsigned(23 downto 21))) = '0') then -- special area
block_mem <= not(zpu_addr_unsigned(18) or zpu_addr_unsigned(17) or zpu_addr_unsigned(16));
config_mem <= zpu_addr_unsigned(18);
special_mem <= zpu_addr_unsigned(17);
end if;
end process;

ZPU_READ_TEMP <= zpu_32bit_read_enable_temp or zpu_8BIT_read_enable_temp;
ZPU_WRITE_TEMP<= zpu_32BIT_WRITE_ENABLE_temp or zpu_16BIT_WRITE_ENABLE_temp or zpu_8BIT_WRITE_ENABLE_temp;
process(zpu_addr_reg,pause,memory_ready,zpu_memory_fetch_pending_next,request_type, zpu_memory_fetch_pending_reg, memory_ready_reg, zpu_ADDR_unsigned, zpu_8bit_read_enable_temp, zpu_write_temp, result_reg, block_mem, config_mem, special_mem, memory_access,
zpu_read_reg,zpu_8BIT_WRITE_ENABLE_reg, zpu_16BIT_WRITE_ENABLE_reg, zpu_32BIT_WRITE_ENABLE_reg,
zpu_read_temp,zpu_8BIT_WRITE_ENABLE_temp, zpu_16BIT_WRITE_ENABLE_temp, zpu_32BIT_WRITE_ENABLE_temp,
zpu_do_unsigned, zpu_do_reg
)
begin
zpu_memory_fetch_pending_next <= zpu_memory_fetch_pending_reg;
result_next <= result_reg;
memory_ready_next <= memory_ready;
zpu_stACK_WRITE <= (others=>'0');
ZPU_ROM_WREN <= '0';
ZPU_config_write <= '0';
ZPU_config_read <= '0';
zpu_addr_next <= zpu_addr_reg;
zpu_do_next <= zpu_do_reg;
ZPU_MEM_BUSY <= pause;
MEMORY_ACCESS <= zpu_READ_temp or ZPU_WRITE_temp;

if (memory_access = '1') then
zpu_do_next <= std_logic_vector(zpu_do_unsigned);
end if;
memory_fetch <= zpu_memory_fetch_pending_reg;
zpu_read_next <= zpu_read_reg;
zpu_8bit_write_enable_next <= zpu_8bit_write_enable_reg;
zpu_16bit_write_enable_next <= zpu_16bit_write_enable_reg;
zpu_32bit_write_enable_next <= zpu_32bit_write_enable_reg;
request_type <= config_mem&block_mem&zpu_addr_unsigned(15)&memory_access&zpu_memory_fetch_pending_reg;
case request_type is
when "00010"|"00110" =>
zpu_memory_fetch_pending_next <= '1';
if (special_mem='0') then
result_next <= result_external;
else
result_next <= result_external_special;
end if;
ZPU_MEM_BUSY <= '1';
zpu_addr_next <= std_logic_vector(zpu_addr_unsigned);
zpu_read_next <= zpu_read_temp;
zpu_8bit_write_enable_next <= zpu_8bit_write_enable_temp;
zpu_16bit_write_enable_next <= zpu_16bit_write_enable_temp;
zpu_32bit_write_enable_next <= zpu_32bit_write_enable_temp;
when "01010" =>
if (zpu_8bit_read_enable_temp='1') then
case (zpu_addr_unsigned(1 downto 0)) is
when "00" =>
result_next <= result_rom_8bit_3;
when "01" =>
result_next <= result_rom_8bit_2;
when "10" =>
result_next <= result_rom_8bit_1;
when "11" =>
result_next <= result_rom_8bit_0;
when others =>
--nop
end case;
else
result_next <= result_rom;
end if;
ZPU_ROM_WREN <= ZPU_WRITE_TEMP;
ZPU_MEM_BUSY <= '1';
zpu_addr_next <= std_logic_vector(zpu_addr_unsigned);
when "01110" =>
if (zpu_8bit_read_enable_temp='1' or zpu_8BIT_WRITE_ENABLE_temp='1') then
case (zpu_addr_unsigned(1 downto 0)) is
when "00" =>
result_next <= result_ram_8bit_3;
ZPU_STACK_WRITE(3) <= zpu_8BIT_write_enable_temp;
when "01" =>
result_next <= result_ram_8bit_2;
ZPU_STACK_WRITE(2) <= zpu_8BIT_write_enable_temp;
when "10" =>
result_next <= result_ram_8bit_1;
ZPU_STACK_WRITE(1) <= zpu_8BIT_write_enable_temp;
when "11" =>
result_next <= result_ram_8bit_0;
ZPU_STACK_WRITE(0) <= zpu_8BIT_write_enable_temp;
when others =>
--nop
end case;
else
result_next <= result_ram;
ZPU_STACK_WRITE <= (others=>zpu_write_temp);
end if;
ZPU_MEM_BUSY <= '1';
zpu_addr_next <= std_logic_vector(zpu_addr_unsigned);
when "10110"|"10010" =>
result_next <= result_config;
ZPU_MEM_BUSY <= '1';
ZPU_config_write <= ZPU_WRITE_temp;
ZPU_config_read <= ZPU_READ_temp;
zpu_addr_next <= std_logic_vector(zpu_addr_unsigned);
when "00001"|"00011"|"00101"|"00111"|"01001"|"01011"|"01101"|"01111"|
"10001"|"10011"|"10101"|"10111"|"11001"|"11011"|"11101"|"11111"|"00X01" =>
ZPU_MEM_BUSY <= not(memory_ready_reg) or pause;
zpu_memory_fetch_pending_next <= not(memory_ready);
when others =>
-- nop
end case;
end process;

zpu_di_next <= zpu_di;
process(result_reg, zpu_di_reg, zpu_rom_di, zpu_ram_di, zpu_config_di)
begin
zpu_di_use <= (others=>'0');
case result_reg is
when result_external =>
zpu_di_use <= zpu_di_reg;
when result_external_special =>
zpu_di_use(7 downto 0) <= zpu_di_reg(15 downto 8);
when result_rom =>
zpu_di_use <= zpu_rom_DI;
when result_rom_8bit_0 =>
zpu_di_use(7 downto 0) <= zpu_rom_DI(7 downto 0);
when result_rom_8bit_1 =>
zpu_di_use(7 downto 0) <= zpu_rom_DI(15 downto 8);
when result_rom_8bit_2 =>
zpu_di_use(7 downto 0) <= zpu_rom_DI(23 downto 16);
when result_rom_8bit_3 =>
zpu_di_use(7 downto 0) <= zpu_rom_DI(31 downto 24);
when result_ram =>
zpu_di_use <= zpu_ram_DI;
when result_ram_8bit_0 =>
zpu_di_use(7 downto 0) <= zpu_ram_DI(7 downto 0);
when result_ram_8bit_1 =>
zpu_di_use(7 downto 0) <= zpu_ram_DI(15 downto 8);
when result_ram_8bit_2 =>
zpu_di_use(7 downto 0) <= zpu_ram_DI(23 downto 16);
when result_ram_8bit_3 =>
zpu_di_use(7 downto 0) <= zpu_ram_DI(31 downto 24);
when result_config =>
zpu_di_use <= zpu_config_di;
when others =>
-- nothing
end case;
end process;

-- zpu itself
--zpu_enable <= enable and not(pause);
zpu_enable <= '1'; -- does nothing useful...
myzpu: ZPUMediumCore
port map (clk_i=>clk, reset_i=>reset,enable_i=>zpu_enable,break_o=>zpu_break,dbg_o=>zpu_debug,mem_busy_i=>ZPU_MEM_BUSY,
data_i=>zpu_di_unsigned,data_o=>zpu_do_unsigned,addr_o=>zpu_addr_unsigned,write_en_o=>zpu_32bit_write_enable_temp,read_en_o=>zpu_32bit_read_enable_temp,
byte_read_o=>zpu_8bit_read_enable_temp, byte_write_o=>zpu_8bit_write_enable_temp,short_write_o=>zpu_16bit_write_enable_temp);
zpu_di_unsigned <= unsigned(zpu_di_use);
zpu_do <= zpu_do_next;
ZPU_ADDR_ROM_RAM <= zpu_addr_next(15 downto 0);
ZPU_ADDR_FETCH <= zpu_addr_reg;
zpu_read_enable <= zpu_read_reg;
zpu_8bit_write_enable <= zpu_8bit_write_enable_reg;
zpu_16bit_write_enable <= zpu_16bit_write_enable_reg;
zpu_32bit_write_enable <= zpu_32bit_write_enable_reg;

end sticky;
(4-4/8)