1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-05-06 00:04:10 +00:00
Files
Gehstock.Mist_FPGA/Console_MiST/ChannelF_MiST/rtl/f8_psu.vhd
2022-07-02 07:45:05 +02:00

510 lines
15 KiB
VHDL

--------------------------------------------------------------------------------
-- Fairchild F8 F351 PSU
--------------------------------------------------------------------------------
-- DO 8/2020
--------------------------------------------------------------------------------
-- With help from MAME F8 model
-- - 1kB ROM
-- - 2 8bits IO port
-- - Programmable timer
-- - Interrupts
-- MASK OPTIONS
-- - 1k ROM
-- - 6bits page select
-- - 6bits IO port address select
-- - 16bits interrupt address vector
-- - IO port output option
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
USE std.textio.ALL;
LIBRARY work;
USE work.base_pack.ALL;
USE work.f8_pack.ALL;
ENTITY f8_psu IS
GENERIC (
PAGE : uv6;
IOPAGE : uv6;
IVEC : uv16;
ROM : arr_uv8(0 TO 1023)
);
PORT (
dw : IN uv8; -- Data Write
dr : OUT uv8; -- Data Read
dv : OUT std_logic;
romc : IN uv5;
tick : IN std_logic; -- 1/8 or 1/12 cycle length
phase : IN uint4;
ext_int : IN std_logic;
int_req : OUT std_logic;
pri_o : OUT std_logic;
pri_i : IN std_logic;
po_a : OUT uv8; -- IO port A
pi_a : IN uv8;
po_b : OUT uv8; -- IO port B
pi_b : IN uv8;
load_a : IN uv10;
load_d : IN uv8;
load_wr : IN std_logic;
clk : IN std_logic;
ce : IN std_logic;
reset_na : IN std_logic;
pc0o : OUT uv16;
pc1o : OUT uv16;
dc0o : OUT uv16
);
END ENTITY f8_psu;
ARCHITECTURE rtl OF f8_psu IS
SIGNAL dc0,dc1 : uv16;
SIGNAL pc0,pc1 : uv16;
SIGNAL mem : arr_uv8(0 TO 1023) :=ROM;
SIGNAL mem_a : uv16;
SIGNAL mem_dr,mem_dw : uv8;
SIGNAL io_wr,io_rd : std_logic;
SIGNAL io_port,io_dr,io_dw : uv8;
SIGNAL po_a_l,po_b_l : uv8;
SIGNAL tim : uv8;
SIGNAL tdiv : uint5;
SIGNAL icr : uv2;
SIGNAL ext_int_d,tim_int_d,tim_int : std_logic;
SIGNAL inta,inta_set,inta_clr : std_logic;
SIGNAL int_req_l : std_logic;
BEGIN
mem_a<=dc0 WHEN romc="00010" OR romc="00101" ELSE pc0;
----------------------------------------------------------
-- ROMC BUS
PROCESS(clk,reset_na) IS
FUNCTION pchk(A : uv16) RETURN std_logic IS
BEGIN
RETURN to_std_logic(A(15 DOWNTO 10)=PAGE);
END FUNCTION;
BEGIN
IF rising_edge(clk) THEN
IF ce='1' THEN
--dv<='0';
inta_clr<='0';
IF phase=2 THEN
dv<='0';
END IF;
io_wr<='0';
CASE romc IS
WHEN "00000" =>
-- S,L : Instruction fetch. The device whose address space includes
-- the content of the PC0 register must place on the data bus
-- the op code addressed by PC0. Then all devices increment
-- the contents of PC0.
IF phase=2 THEN
dr <= mem_dr;
dv <= pchk(pc0);
END IF;
IF phase=6 THEN
pc0<= pc0 + 1;
END IF;
WHEN "00001" =>
-- L : The device whose address space includes the contents of
-- the PC0 register must place on the data bus the contents of
-- the memory location addressed by PC0. Then all devices add the
-- 8-bit value on the data bus, as a signed binary number, to PC0.
IF phase=2 THEN
dr <= mem_dr;
dv <= pchk(pc0);
END IF;
IF phase=6 THEN
pc0<= pc0 + sext(dw,16);
END IF;
WHEN "00010" =>
-- L : The device whose DC0 addresses a memory word within the
-- address space of that device must place on the data bus the
-- contents of the memory location addressed by
-- DC0. Then all devices increment DC0.
IF phase=2 THEN
dr <= mem_dr;
dv <= pchk(dc0);
END IF;
IF phase=6 THEN
dc0<= dc0 + 1;
END IF;
WHEN "00011" =>
-- L,S : Similar to 00, except that it is used for Immediate Operand
-- fetches (using PC0) instead of instruction fetches.
IF phase=2 THEN
dr <= mem_dr;
dv <= pchk(pc0);
END IF;
IF phase=6 THEN
pc0<= pc0 + 1;
io_port<=dw;
END IF;
WHEN "00100" =>
-- S : Copy the contents of PC1 into PC0.
IF phase=6 THEN
pc0<= pc1;
END IF;
WHEN "00101" =>
-- L : Store the data bus contents into the memory
-- location pointed to by DC0. Increment DC0.
-- <ROM ! NO WRITE>
--mem_a<=dc0;
--IF phase=4 AND pchk(dc0)='1' THEN
-- mem_wr<='1';
--END IF;
--IF phase=6 THEN
-- dc0<=dc0 + 1;
--END IF;
WHEN "00110" =>
-- L : Place the high order byte of DC0 on the data bus.
IF phase=2 THEN
dr <=dc0(15 DOWNTO 8);
dv <='1';
END IF;
WHEN "00111" =>
-- L : Place the high order byte of PC1 on the data bus.
IF phase=2 THEN
dr <=pc1(15 DOWNTO 8);
dv <='1';
END IF;
WHEN "01000" =>
-- L : All devices copy the contents of PC0 into PC1. The CPU
-- outputs zero on the data bus in this ROMC state. Load the
-- data bus into both halves of PC0 thus clearing the register.
IF phase=6 THEN
pc1<=pc0;
pc0<=x"0000";
END IF;
WHEN "01001" =>
-- The device whose address space includes the contents of the DC0
-- register must place the low order byte of DC0 onto the data bus.
IF phase=2 THEN
dr <=dc0(7 DOWNTO 0);
dv <=pchk(dc0);
END IF;
WHEN "01010" =>
-- L : All devices add the 8-bit value on the data bus, treated
-- as a signed binary number, to the Data Counter.
IF phase=6 THEN
dc0<=dc0 + sext(dw,16);
END IF;
WHEN "01011" =>
-- L : The device whose address space includes the value in PC1
-- must place the low order byte of PC1 on the data bus.
IF phase=2 THEN
dr <=pc1(7 DOWNTO 0);
dv <=pchk(pc1);
END IF;
WHEN "01100" =>
-- L : The device whose address space includes the contents of
-- the PC0 register must place the contents of the memory word
-- addressed by PC0 onto the data bus. Then all devices move the
-- value which has just been placed on the data bus into the low
-- order byte of PC0.
IF phase=2 THEN
dr <= mem_dr;
dv <= pchk(pc0);
END IF;
IF phase=6 THEN
pc0(7 DOWNTO 0)<= dw;
END IF;
WHEN "01101" =>
-- S : All devices store in PC1 the current contents of PC0,
-- incremented by 1. PC0 is unaltered.
pc1 <= pc0 +1;
WHEN "01110" =>
-- L : The device whose address space includes the contents of
-- PC0 must place the contents of the word addressed by PC0
-- onto the data bus. The value on the data bus is then
-- moved to the low order byte of DC0 by all devices
IF phase=2 THEN
dr <= mem_dr;
dv <= pchk(pc0);
END IF;
IF phase=6 THEN
dc0(7 DOWNTO 0)<= dw;
END IF;
WHEN "01111" =>
-- L : The interrupting device with highest priority must place
-- the low order byte of the interrupt vector on the data bus.
-- All devices must copy the contents of PC0 into PC1.
-- All devices must move the contents of the data bus into
-- the low order byte of PC0.
IF phase=2 THEN
dr <=IVEC(7 DOWNTO 0);
dv <=int_req_l;
END IF;
IF phase=6 THEN
pc1 <= pc0;
pc0(7 DOWNTO 0) <= dw;
END IF;
WHEN "10000" =>
-- L : Inhibit any modification to the interrupt priority logic.
-- <TODO>
WHEN "10001" =>
-- L : The device whose memory space includes the contents of
-- PC0 must place the contents of the addressed memory word
-- on the data bus. All devices must then move the contents
-- of the data bus to the upper byte of DC0.
IF phase=2 THEN
dr <=mem_dr;
dv <=pchk(pc0);
END IF;
IF phase=6 THEN
dc0(15 DOWNTO 8)<=dw;
END IF;
WHEN "10010" =>
-- L : All devices copy the contents of PC0 into PC1. All
-- devices then move the contents of the data bus into
-- the low order byte of PC0.
IF phase=6 THEN
pc1<=pc0;
pc0(7 DOWNTO 0)<=dw;
END IF;
WHEN "10011" =>
-- L : The interrupting device with highest priority must move
-- the high order half of the interrupt vector onto the data bus.
-- All devices must move the contents of the data bus into the
-- high order byte of PC0. The interrupting device will request
-- its interrupt circuitry (so that it is no longer requesting CPU
-- servicing and can respond to another interrupt).
IF phase=2 THEN
dr <=IVEC(15 DOWNTO 8);
dv <=int_req_l;
END IF;
IF phase=6 THEN
pc0(15 DOWNTO 8) <= dw;
inta_clr<=int_req_l;
END IF;
WHEN "10100" =>
-- L : All devices move the contents of the data bus into the
-- high order byte of PC0.
IF phase=6 THEN
pc0(15 DOWNTO 8)<=dw;
END IF;
WHEN "10101" =>
-- L : All devices move contents of the data bus into the
-- high order byte of PC1.
IF phase=6 THEN
pc1(15 DOWNTO 8)<=dw;
END IF;
WHEN "10110" =>
-- L : All devices move the contents of the data bus into the
-- high order byte of DC0.
IF phase=6 THEN
dc0(15 DOWNTO 8)<=dw;
END IF;
WHEN "10111" =>
-- L : All devices move the contents of the data bus into the
-- low order byte of PC0.
IF phase=6 THEN
pc0(7 DOWNTO 0)<=dw;
END IF;
WHEN "11000" =>
-- L : All devices move contents of the data bus into the low
-- order byte of PC1.
IF phase=6 THEN
pc1(7 DOWNTO 0)<=dw;
END IF;
WHEN "11001" =>
-- L : All devices move contents of the data bus into the low
-- order byte of DC0.
IF phase=6 THEN
dc0(7 DOWNTO 0)<=dw;
END IF;
WHEN "11010" =>
-- L : During the prior cycle an I/O port timer or interrupt
-- control register was addressed, The device containing
-- the addressed port must move the current contents of
-- the data bus into the addressed port.
IF phase=6 THEN
io_dw<=dw;
io_wr<=to_std_logic(io_port(7 DOWNTO 2)=IOPAGE);
END IF;
WHEN "11011" =>
-- L : During the prior cycle the data bus specified the
-- address of an I/O port. The device containing the
-- addressed I/O port must place the contents of the I/O
-- port on the data bus. (Note that the contents of timer
-- and interrupt control retgisters cannot be read back onto
-- the data bus.)
IF phase=2 THEN
io_rd<=to_std_logic(io_port(7 DOWNTO 2)=IOPAGE);
dr<=io_dr;
dv<=to_std_logic(io_port(7 DOWNTO 2)=IOPAGE);
END IF;
WHEN "11100" =>
-- L/S : None. Before IO port access
IF phase=6 THEN
io_port<=dw;
END IF;
WHEN "11101" =>
-- S : Devices with DC0 and DC1 registers must switch registers.
-- Devices without a DC1 register perform no operation.
--IF phase=6 THEN
-- dc0<=dc1;
-- dc1<=dc0;
--END IF;
WHEN "11110" =>
-- L : The device whose address space includes the contents of
-- PC0 must place the low order byte of PC0 onto the data bus.
IF phase=2 THEN
dr <=pc0(7 DOWNTO 0);
dv <=pchk(pc0);
END IF;
WHEN "11111" =>
-- L : The device whose address space includes the contents of
-- PC0 must place the high order byte of PC0 on the data bus.
IF phase=2 THEN
dr <=pc0(15 DOWNTO 8);
dv <=pchk(pc0);
END IF;
WHEN OTHERS =>
NULL;
END CASE;
IF reset_na='0' THEN
pc0<=x"0000";
pc1<=x"0000";
dc0<=x"0000";
END IF;
END IF;
END IF;
END PROCESS;
----------------------------------------------------------
-- ROM READ
PROCESS(clk) IS
BEGIN
IF rising_edge(clk) THEN
IF ce='1' THEN
mem_dr<=mem(to_integer(mem_a(9 DOWNTO 0)));
END IF;
IF load_wr='1' THEN
mem(to_integer(load_a))<=load_d;
END IF;
END IF;
END PROCESS;
----------------------------------------------------------
-- IO PORTS
po_a<=po_a_l;
po_b<=po_b_l;
int_req<=int_req_l;
PROCESS(clk,reset_na) IS
BEGIN
IF rising_edge(clk) THEN
IF ce='1' THEN
-------------------------------
-- LFSR TIMER
tdiv<=(tdiv+1) MOD 32;
IF tdiv=0 THEN
tim(0)<=(tim(3) XOR tim(4)) XNOR (tim(5) XOR tim(7));
tim(7 DOWNTO 1)<=tim(6 DOWNTO 0);
END IF;
tim_int<=to_std_logic(tim=x"FE");
tim_int_d<=tim_int;
-- Interrupts
ext_int_d<=ext_int;
inta_set<=(NOT ext_int_d AND ext_int AND to_std_logic(icr="01")) OR
(NOT tim_int_d AND tim_int AND to_std_logic(icr="11"));
inta <=(inta OR inta_set) AND NOT inta_clr;
int_req_l<=inta AND pri_i;
pri_o<=pri_i AND NOT inta;
-------------------------------
CASE io_port(1 DOWNTO 0) IS
WHEN "00" => -- IO PORT A READ
io_dr<=pi_a AND po_a_l;
WHEN "01" => -- IO PORT B READ
io_dr<=pi_b AND po_b_l;
WHEN "10" => -- Interrupt control bits
io_dr<=x"00"; -- <TBD>
WHEN OTHERS => -- Timer
io_dr<=x"00"; -- <TBD>
END CASE;
IF io_wr='1' THEN
CASE io_port(1 DOWNTO 0) IS
WHEN "00" => po_a_l<=io_dw;
WHEN "01" => po_b_l<=io_dw;
WHEN "10" => tim<=io_dw;
WHEN OTHERS => icr<=io_dw(1 DOWNTO 0);
END CASE;
END IF;
IF reset_na='0' THEN
po_a_l<=x"00";
po_b_l<=x"00";
END IF;
-------------------------------
END IF;
END IF;
END PROCESS;
pc0o<=pc0;
pc1o<=pc1;
dc0o<=dc0;
END ARCHITECTURE rtl;