mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-01-18 09:02:08 +00:00
220 lines
7.6 KiB
VHDL
220 lines
7.6 KiB
VHDL
------------------------------------------------------------------------------
|
|
-- Project : Red Zombie
|
|
------------------------------------------------------------------------------
|
|
-- File : redzombie.vhd
|
|
-- Author : fpgakuechle
|
|
-- Company : hobbyist
|
|
-- Created : 2012-12
|
|
-- Last update: 2013-04-02
|
|
-- Lizenz : GNU General Public License (http://www.gnu.de/documents/gpl.de.html)
|
|
------------------------------------------------------------------------------
|
|
-- Description:
|
|
--parallel io unit
|
|
--Zilog Z80 PIO - U855
|
|
------------------------------------------------------------------------------
|
|
--Status: UNDER CONSTRUCTION: 2013-03-03
|
|
--missing: IRQ-control
|
|
--control register/data path under test now
|
|
--last change: fixed: mixed up mask and mode register; add single bit mode
|
|
-- fixed: outputs *_rdy at single bit mode
|
|
------------------------------------------------------------------------------
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
|
|
entity pio is
|
|
port(
|
|
clk : in std_logic;
|
|
ce_ni : in std_logic;
|
|
IOREQn_i : in std_logic;
|
|
data_o : out std_logic_vector(7 downto 0);
|
|
data_i : in std_logic_vector(7 downto 0);
|
|
RD_n : in std_logic;
|
|
M1_n : in std_logic;
|
|
|
|
sel_b_nA : in std_logic;
|
|
sel_c_nD : in std_logic;
|
|
--
|
|
IRQEna_i : in std_logic;
|
|
IRQEna_o : out std_logic;
|
|
|
|
INTn_o : out std_logic;
|
|
|
|
astb_n : in std_logic; --Data strobe in, is able to generate IREQ
|
|
ardy_n : out std_logic; --
|
|
porta_o : out std_logic_vector(7 downto 0);
|
|
porta_i : in std_logic_vector(7 downto 0);
|
|
|
|
bstb_n : in std_logic;
|
|
brdy_n : out std_logic;
|
|
portb_o : out std_logic_vector(7 downto 0);
|
|
portb_i : in std_logic_vector(7 downto 0));
|
|
end entity pio;
|
|
|
|
architecture behave of pio is
|
|
signal ctrl_selected : boolean;
|
|
signal data_selected : boolean;
|
|
|
|
type T_ALL_REGS_INDEX is (
|
|
IRQ_VEC, MODE, PORTDIR, IRQ_CTRL, MASK, ERR);
|
|
type T_PORT_INDEX is (PORT_A, PORT_B);
|
|
|
|
subtype T_REG is std_logic_vector(7 downto 0);
|
|
type T_ALL_REGS is array (T_ALL_REGS_INDEX) of T_REG;
|
|
|
|
signal reg_index : T_ALL_REGS_INDEX;
|
|
|
|
type T_2P_SL is array (T_PORT_INDEX'left to T_PORT_INDEX'right) of std_logic;
|
|
type T_2P_REG_7b is array (T_PORT_INDEX) of std_logic_vector(7 downto 1);
|
|
type T_2P_REG_8b is array (T_PORT_INDEX) of std_logic_vector(7 downto 0);
|
|
type T_2P_REG_2b is array (T_PORT_INDEX) of std_logic_vector(7 downto 6);
|
|
|
|
--default mode: Byte - Out
|
|
signal mode_reg : T_2P_REG_2b := (others => "01");
|
|
signal portdir_reg : T_2P_REG_8b := (others => x"00");
|
|
signal mask_reg : T_2P_REG_8b := (others => x"00");
|
|
signal irq_vec_reg : T_2P_REG_7b := (others => "0000000");
|
|
|
|
signal irq_ctrl_reg : std_logic_vector(7 downto 4) := (others => '0');
|
|
signal err_reg : std_logic_vector(7 downto 0) := (others => '0');
|
|
|
|
signal wr_dir_reg_q : boolean := false;
|
|
signal wr_mask_reg_q : boolean := false;
|
|
|
|
signal data_oq : std_logic_vector(7 downto 0);
|
|
signal port_sel : T_PORT_INDEX;
|
|
--ports as vectors
|
|
signal port_indata : T_2P_REG_8b;
|
|
signal port_outdata : T_2P_REG_8b;
|
|
--ports regs
|
|
signal port_indata_reg : T_2P_REG_8b;
|
|
signal port_outdata_reg : T_2P_REG_8b;
|
|
|
|
signal strb_in : T_2P_SL;
|
|
signal rdy_out : T_2P_SL;
|
|
|
|
begin
|
|
port_sel <= PORT_B when sel_b_nA = '1' else
|
|
PORT_A;
|
|
|
|
strb_in(PORT_A) <= astb_n;
|
|
strb_in(PORT_B) <= bstb_n;
|
|
|
|
ardy_n <= rdy_out(PORT_A);
|
|
brdy_n <= rdy_out(PORT_B);
|
|
|
|
port_indata(PORT_A) <= porta_i;
|
|
port_indata(PORT_B) <= portb_i;
|
|
|
|
porta_o <= port_outdata(PORT_A);
|
|
portb_o <= port_outdata(PORT_B);
|
|
|
|
--built enables for control register
|
|
process(data_i(3 downto 0), wr_dir_reg_q, wr_mask_reg_q) is
|
|
begin
|
|
if wr_dir_reg_q then
|
|
reg_index <= PORTDIR;
|
|
elsif wr_mask_reg_q then
|
|
reg_index <= MASK;
|
|
elsif data_i(0) = '0' then
|
|
reg_index <= IRQ_VEC;
|
|
elsif data_i(3 downto 0) = x"F" then
|
|
reg_index <= MODE;
|
|
elsif data_i(3 downto 0) = x"7" then
|
|
reg_index <= IRQ_CTRL;
|
|
else
|
|
reg_index <= ERR;
|
|
end if;
|
|
end process;
|
|
|
|
ctrl_selected <= ce_ni = '0' and IOREQn_i = '0' and sel_c_nD = '1'; --access controlregs
|
|
data_selected <= ce_ni = '0' and IOREQn_i = '0' and sel_c_nD = '0'; --access ports
|
|
|
|
--read/write control register
|
|
process(clk)
|
|
begin
|
|
if falling_edge(clk) then
|
|
if ctrl_selected then
|
|
if rd_n = '1' then
|
|
wr_dir_reg_q <= false;
|
|
wr_mask_reg_q <= false;
|
|
--write control reg
|
|
case reg_index is
|
|
when IRQ_VEC => irq_vec_reg(port_sel) <= data_i(7 downto 1);
|
|
when MODE => mode_reg(port_sel) <= data_i(7 downto 6);
|
|
if data_i(7 downto 6) = "11" then
|
|
wr_dir_reg_q <= true;
|
|
end if;
|
|
|
|
when PORTDIR => portdir_reg(port_sel) <= data_i(7 downto 0);
|
|
when IRQ_CTRL => irq_ctrl_reg <= data_i(7 downto 4);
|
|
if data_i(4) = '1' then
|
|
wr_mask_reg_q <= true;
|
|
end if;
|
|
when MASK => mask_reg(port_sel) <= data_i(7 downto 0);
|
|
when ERR => err_reg <= data_i(7 downto 0);
|
|
when others => err_reg <= data_i(7 downto 0);
|
|
end case;
|
|
else
|
|
--read control reg ?How to select control register while reading?
|
|
case reg_index is
|
|
when IRQ_VEC => data_oq <= irq_vec_reg(port_sel) & '0';
|
|
when MODE => data_oq <= mode_reg(port_sel) & "000000";
|
|
when PORTDIR => data_oq <= portdir_reg(port_sel);
|
|
when IRQ_CTRL => data_oq <= irq_ctrl_reg & x"0";
|
|
|
|
when MASK => data_oq <= mask_reg(port_sel);
|
|
when ERR => data_oq <= err_reg;
|
|
when others => data_oq <= x"00";
|
|
end case;
|
|
end if;
|
|
--port_regs <> CPU
|
|
elsif data_selected then
|
|
if rd_n = '0' then
|
|
data_oq <= port_indata_reg(port_sel);
|
|
else
|
|
port_outdata_reg(port_sel) <= data_i;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
g_portCPU : for pchan in T_PORT_INDEX generate
|
|
--real port access
|
|
process(clk)
|
|
begin
|
|
if falling_edge(clk) then
|
|
if mode_reg(pchan) = "00" then --output mode
|
|
port_outdata(pchan) <= port_outdata_reg(pchan);
|
|
elsif mode_reg(pchan) = "01" then --input mode
|
|
port_indata_reg(pchan) <= port_indata(pchan);
|
|
elsif mode_reg(pchan) = "10" then --bidir
|
|
for i in 0 to 7 loop --strb contrl mot implemented yet
|
|
if portdir_reg(pchan)(i) = '0' then --output
|
|
port_outdata(pchan)(i) <= port_outdata_reg(pchan)(i);
|
|
else
|
|
port_indata_reg(pchan)(i) <= port_indata(pchan)(i);
|
|
end if;
|
|
end loop;
|
|
elsif mode_reg(pchan) = "11" then --bit mode
|
|
for i in 0 to 7 loop
|
|
if portdir_reg(pchan)(i) = '0' then --output port
|
|
port_outdata(pchan)(i) <= port_outdata_reg(pchan)(i);
|
|
else --input port
|
|
port_indata_reg(pchan)(i) <= port_indata(pchan)(i);
|
|
end if;
|
|
end loop;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
end generate g_portCPU;
|
|
data_o <= data_oq;
|
|
--unused output yet
|
|
|
|
IRQEna_o <= '1';
|
|
INTn_o <= '1';
|
|
|
|
rdy_out(PORT_A) <= '0' when mode_reg(PORT_A) = "11" else '1'; --other modes
|
|
--not implemented
|
|
rdy_out(PORT_B) <= '0' when mode_reg(PORT_B) = "11" and mode_reg(PORT_A) /= "10" else '1';
|
|
end architecture;
|