1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-17 16:43:22 +00:00
2019-07-22 23:42:05 +02:00

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;