AppleIISd/VHDL/AppleIISd.vhd

296 lines
10 KiB
VHDL
Raw Normal View History

2017-08-27 10:21:26 +00:00
----------------------------------------------------------------------------------
-- Company: n/a
-- Engineer: A. Fachat
--
-- Create Date: 12:37:11 05/07/2011
2017-09-03 12:51:09 +00:00
-- Design Name: SPI65B
2017-08-27 10:21:26 +00:00
-- Module Name: SPI6502B - Behavioral
-- Project Name: CS/A NETUSB 2.0
-- Target Devices: CS/A NETUSB 2.0
-- Tool versions:
2017-09-03 12:51:09 +00:00
-- Description: An SPI interface for 6502-based computers (or compatible).
-- modelled after the SPI65 interface by Daryl Rictor
-- (see http://sbc.rictor.org/io/65spi.html )
-- This implementation here, however, is a complete reimplementation
-- as the ABEL language of the original implementation is not supported
-- by ISE anymore.
-- Also I added the interrupt input handling, replacing four of the
-- original SPI select outputs with four interrupt inputs
-- Also folded out the single MISO input into one input for each of the
-- four supported devices, reducing external parts count again by one.
2017-08-27 10:21:26 +00:00
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Revision 0.02 - removed spiclk and replaced with clksrc and clkcnt_is_zero combination,
2017-09-03 12:51:09 +00:00
-- to drive up SPI clock to half of input clock (and not one fourth only as before)
-- unfortunately that costed one divisor bit to fit into the CPLD
2017-08-27 10:21:26 +00:00
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity AppleIISd is
2017-09-03 12:51:09 +00:00
Port (
2017-10-08 19:48:07 +00:00
data_in : in STD_LOGIC_VECTOR (7 downto 0);
data_out : out STD_LOGIC_VECTOR (7 downto 0);
is_read : in STD_LOGIC;
2017-10-10 19:22:18 +00:00
nreset : in STD_LOGIC;
2017-09-10 12:07:23 +00:00
addr : in STD_LOGIC_VECTOR (1 downto 0);
2017-10-08 19:48:07 +00:00
phi0 : in STD_LOGIC;
2017-10-10 19:22:18 +00:00
ndev_sel : in STD_LOGIC;
2017-10-08 19:48:07 +00:00
clk : in STD_LOGIC;
miso: in std_logic;
mosi : out STD_LOGIC;
sclk : out STD_LOGIC;
nsel : out STD_LOGIC;
2017-09-10 12:07:23 +00:00
wp : in STD_LOGIC;
card : in STD_LOGIC;
2017-10-08 19:48:07 +00:00
led : out STD_LOGIC
2017-09-10 12:07:23 +00:00
);
2017-08-27 10:21:26 +00:00
constant DIV_WIDTH : integer := 3;
end AppleIISd;
architecture Behavioral of AppleIISd is
2017-09-03 12:51:09 +00:00
--------------------------
-- internal state
signal spidatain: std_logic_vector (7 downto 0);
signal spidataout: std_logic_vector (7 downto 0);
2017-08-27 10:21:26 +00:00
signal inited: std_logic; -- card initialized
2017-09-03 12:51:09 +00:00
-- spi register flags
signal tc: std_logic; -- transmission complete; cleared on spi data read
signal bsy: std_logic; -- SPI busy
signal frx: std_logic; -- fast receive mode
signal ece: std_logic; -- external clock enable; 0=phi2, 1=external clock
signal divisor: std_logic_vector(DIV_WIDTH-1 downto 0);
2017-10-09 22:41:31 +00:00
signal slavesel: std_logic := '1'; -- slave select output (0=selected)
2017-10-08 19:48:07 +00:00
signal int_miso: std_logic;
2017-09-03 12:51:09 +00:00
--------------------------
-- helper signals
2017-08-27 10:21:26 +00:00
2017-09-03 12:51:09 +00:00
-- shift engine
2017-10-09 22:41:31 +00:00
signal start_shifting: std_logic := '0'; -- shifting data
signal shifting2: std_logic := '0'; -- shifting data
2017-09-03 12:51:09 +00:00
signal shiftdone: std_logic; -- shifting data done
signal shiftcnt: std_logic_vector(3 downto 0); -- shift counter (5 bit)
-- spi clock
2017-10-05 20:57:38 +00:00
signal clksrc: std_logic; -- clock source (phi2 or clk_7m)
2017-09-10 12:07:23 +00:00
-- TODO divcnt is not used at all??
2017-10-08 19:48:07 +00:00
--signal divcnt: std_logic_vector(DIV_WIDTH-1 downto 0); -- divisor counter
2017-09-03 12:51:09 +00:00
signal shiftclk : std_logic;
2017-09-10 12:07:23 +00:00
2017-10-08 19:48:07 +00:00
begin
--led <= not (inited);
2017-10-09 21:35:52 +00:00
led <= not (bsy or not slavesel);
2017-09-03 12:51:09 +00:00
bsy <= start_shifting or shifting2;
process(start_shifting, shiftdone, shiftclk)
begin
if (rising_edge(shiftclk)) then
if (shiftdone = '1') then
shifting2 <= '0';
else
shifting2 <= start_shifting;
end if;
end if;
end process;
2017-08-27 10:21:26 +00:00
2017-10-10 19:22:18 +00:00
process(shiftcnt, nreset, shiftclk)
2017-09-03 12:51:09 +00:00
begin
2017-10-10 19:22:18 +00:00
if (nreset = '0') then
2017-09-03 12:51:09 +00:00
shiftdone <= '0';
elsif (rising_edge(shiftclk)) then
if (shiftcnt = "1111") then
shiftdone <= '1';
else
shiftdone <= '0';
end if;
end if;
end process;
2017-10-10 19:22:18 +00:00
process(nreset, shifting2, shiftcnt, shiftclk)
2017-09-03 12:51:09 +00:00
begin
2017-10-10 19:22:18 +00:00
if (nreset = '0') then
2017-09-03 12:51:09 +00:00
shiftcnt <= (others => '0');
elsif (rising_edge(shiftclk)) then
if (shifting2 = '1') then
-- count phase
shiftcnt <= shiftcnt + 1;
else
shiftcnt <= (others => '0');
end if;
end if;
end process;
2017-08-27 10:21:26 +00:00
2017-10-10 19:22:18 +00:00
inproc: process(nreset, shifting2, shiftcnt, shiftclk, spidatain, miso)
2017-09-03 12:51:09 +00:00
begin
2017-10-10 19:22:18 +00:00
if (nreset = '0') then
2017-09-03 12:51:09 +00:00
spidatain <= (others => '0');
elsif (rising_edge(shiftclk)) then
if (shifting2 = '1' and shiftcnt(0) = '1') then
-- shift in to input register
spidatain (7 downto 1) <= spidatain (6 downto 0);
spidatain (0) <= int_miso;
end if;
end if;
end process;
2017-08-27 10:21:26 +00:00
2017-10-10 19:22:18 +00:00
outproc: process(nreset, shifting2, spidataout, shiftcnt, shiftclk)
2017-09-03 12:51:09 +00:00
begin
2017-10-10 19:22:18 +00:00
if (nreset = '0') then
2017-10-08 19:48:07 +00:00
mosi <= '1';
sclk <= '0';
2017-09-03 12:51:09 +00:00
else
-- clock is sync'd
if (rising_edge(shiftclk)) then
if (shifting2='0' or shiftdone = '1') then
2017-10-08 19:48:07 +00:00
mosi <= '1';
sclk <= '0';
2017-09-03 12:51:09 +00:00
else
-- output data directly from output register
case shiftcnt(3 downto 1) is
2017-10-08 19:48:07 +00:00
when "000" => mosi <= spidataout(7);
when "001" => mosi <= spidataout(6);
when "010" => mosi <= spidataout(5);
when "011" => mosi <= spidataout(4);
when "100" => mosi <= spidataout(3);
when "101" => mosi <= spidataout(2);
when "110" => mosi <= spidataout(1);
when "111" => mosi <= spidataout(0);
when others => mosi <= '1';
2017-09-03 12:51:09 +00:00
end case;
2017-10-08 19:48:07 +00:00
sclk <= '0' xor '0' xor shiftcnt(0);
2017-09-03 12:51:09 +00:00
end if;
end if;
end if;
end process;
2017-08-27 10:21:26 +00:00
2017-09-03 12:51:09 +00:00
-- shift operation enable
2017-10-10 19:22:18 +00:00
shiften: process(nreset, ndev_sel, is_read, addr, frx, shiftdone)
2017-09-03 12:51:09 +00:00
begin
-- start shifting
2017-10-10 19:22:18 +00:00
if (nreset = '0' or shiftdone = '1') then
2017-09-03 12:51:09 +00:00
start_shifting <= '0';
2017-10-10 19:22:18 +00:00
elsif (rising_edge(ndev_sel) and addr="00" and (frx='1' or is_read='0')) then
2017-10-08 19:48:07 +00:00
-- access to register 00, either write (is_read=0) or fast receive bit set (frx)
2017-09-03 12:51:09 +00:00
-- then both types of access (write but also read)
start_shifting <= '1';
end if;
end process;
2017-08-27 10:21:26 +00:00
2017-09-03 12:51:09 +00:00
--------------------------
-- spiclk - spi clock generation
-- spiclk is still 2 times the freq. than sclk
2017-10-08 19:48:07 +00:00
clksrc <= phi0 when (ece = '0') else clk;
2017-09-03 12:51:09 +00:00
-- is a pulse signal to allow for divisor==0
--shiftclk <= clksrc when divcnt = "000000" else '0';
shiftclk <= clksrc when bsy = '1' else '0';
2017-10-10 19:22:18 +00:00
-- clkgen: process(nreset, divisor, clksrc)
2017-10-08 19:48:07 +00:00
-- begin
2017-10-10 19:22:18 +00:00
-- if (nreset = '0') then
2017-10-08 19:48:07 +00:00
-- divcnt <= divisor;
-- elsif (falling_edge(clksrc)) then
-- if (shiftclk = '1') then
-- divcnt <= divisor;
-- else
-- divcnt <= divcnt - 1;
-- end if;
-- end if;
-- end process;
2017-09-03 12:51:09 +00:00
--------------------------
-- interface section
-- inputs
2017-10-08 19:48:07 +00:00
int_miso <= (miso and not slavesel);
2017-09-03 12:51:09 +00:00
-- outputs
2017-10-08 19:48:07 +00:00
nsel <= slavesel;
2017-10-05 20:57:38 +00:00
2017-10-10 19:22:18 +00:00
tc_proc: process (ndev_sel, shiftdone)
2017-09-03 12:51:09 +00:00
begin
if (shiftdone = '1') then
tc <= '1';
2017-10-10 19:22:18 +00:00
elsif (rising_edge(ndev_sel) and addr="00") then
2017-09-10 12:07:23 +00:00
tc <= '0';
2017-09-03 12:51:09 +00:00
end if;
end process;
--------------------------
-- cpu register section
-- cpu read
2017-10-08 19:48:07 +00:00
cpu_read: process(addr, spidatain, tc, bsy, frx,
ece, divisor, slavesel, wp, card, inited)
2017-09-03 12:51:09 +00:00
begin
2017-10-08 19:48:07 +00:00
case addr is
when "00" => -- read SPI data in
data_out <= spidatain;
when "01" => -- read status register
data_out(0) <= '0';
data_out(1) <= '0';
data_out(2) <= ece;
data_out(3) <= '0';
data_out(4) <= frx;
data_out(5) <= bsy;
data_out(6) <= '0';
data_out(7) <= tc;
when "10" => -- read sclk divisor
data_out(DIV_WIDTH-1 downto 0) <= divisor;
data_out(7 downto 3) <= (others => '0');
when "11" => -- read slave select / slave interrupt state
data_out(0) <= slavesel;
data_out(4 downto 1) <= (others => '0');
data_out(5) <= wp;
data_out(6) <= card;
data_out(7) <= inited;
when others =>
data_out <= (others => '0');
end case;
2017-09-03 12:51:09 +00:00
end process;
2017-08-27 10:21:26 +00:00
2017-09-03 12:51:09 +00:00
-- cpu write
2017-10-10 19:22:18 +00:00
cpu_write: process(nreset, ndev_sel, is_read, addr, data_in, card, inited)
2017-09-03 12:51:09 +00:00
begin
2017-10-10 19:22:18 +00:00
if (nreset = '0') then
2017-09-03 12:51:09 +00:00
ece <= '0';
frx <= '0';
slavesel <= '1';
divisor <= (others => '0');
spidataout <= (others => '1');
2017-10-08 19:48:07 +00:00
inited <= '0';
2017-10-05 20:57:38 +00:00
elsif (card = '1') then
2017-10-08 19:48:07 +00:00
inited <= '0';
2017-10-10 19:22:18 +00:00
elsif (rising_edge(ndev_sel) and is_read = '0') then
2017-09-03 12:51:09 +00:00
case addr is
when "00" => -- write SPI data out (see other process above)
2017-10-08 19:48:07 +00:00
spidataout <= data_in;
2017-09-03 12:51:09 +00:00
when "01" => -- write status register
2017-10-08 19:48:07 +00:00
ece <= data_in(2);
frx <= data_in(4);
2017-10-05 20:57:38 +00:00
-- no bit 5 - 7
2017-09-03 12:51:09 +00:00
when "10" => -- write divisor
2017-10-08 19:48:07 +00:00
divisor <= data_in(DIV_WIDTH-1 downto 0);
2017-09-03 12:51:09 +00:00
when "11" => -- write slave select / slave interrupt enable
2017-10-08 19:48:07 +00:00
slavesel <= data_in(0);
2017-10-05 20:57:38 +00:00
-- no bit 1 - 6
2017-10-08 19:48:07 +00:00
inited <= data_in(7);
2017-09-10 12:07:23 +00:00
when others =>
2017-09-03 12:51:09 +00:00
end case;
end if;
end process;
2017-08-27 10:21:26 +00:00
end Behavioral;