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.numeric_std.all;

-- Problem - UART on the DE1 does not have all pins connected. Need to use...

ENTITY pokey IS
GENERIC
(
CUSTOM_KEYBOARD_SCAN : integer := 0 -- drive from hsync-like if 0, otherwise custom increment signal
);
PORT
(
CLK : IN STD_LOGIC;
ENABLE_179 :in std_logic;
ADDR : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
DATA_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
WR_EN : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
-- keyboard interface
keyboard_scan_enable : in std_logic := '0';
keyboard_scan : out std_logic_vector(5 downto 0);
keyboard_response : in std_logic_vector(1 downto 0);
-- pots - go high as capacitor charges
POT_IN : in std_logic_vector(7 downto 0);
-- sio interface
SIO_IN1 : IN std_logic;
SIO_IN2 : IN std_logic;
SIO_IN3 : IN std_logic;
DATA_OUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
CHANNEL_0_OUT : OUT STD_LOGIC_VECTOR(3 downto 0);
CHANNEL_1_OUT : OUT STD_LOGIC_VECTOR(3 downto 0);
CHANNEL_2_OUT : OUT STD_LOGIC_VECTOR(3 downto 0);
CHANNEL_3_OUT : OUT STD_LOGIC_VECTOR(3 downto 0);
IRQ_N_OUT : OUT std_logic;
SIO_OUT1 : OUT std_logic;
SIO_OUT2 : OUT std_logic;
SIO_OUT3 : OUT std_logic;
SIO_CLOCKIN_IN : IN std_logic := '1';
SIO_CLOCKIN_OUT : OUT std_logic;
SIO_CLOCKIN_OE : OUT std_logic;
SIO_CLOCKOUT : OUT std_logic;
POT_RESET : out std_logic
);
END pokey;

ARCHITECTURE vhdl OF pokey IS
component synchronizer IS
PORT
(
CLK : IN STD_LOGIC;
RAW : IN STD_LOGIC;
SYNC : OUT STD_LOGIC
);
END component;

component syncreset_enable_divider IS
generic(COUNT : natural := 1; RESETCOUNT : natural := 0);
PORT
(
CLK : IN STD_LOGIC;
syncreset : in std_logic;
reset_n : in std_logic;
ENABLE_IN : IN STD_LOGIC;
ENABLE_OUT : OUT STD_LOGIC
);
END component;
component pokey_poly_17_9 IS
PORT
(
CLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
ENABLE : IN STD_LOGIC;
SELECT_9_17 : IN STD_LOGIC; -- 9 high, 17 low
INIT : IN STD_LOGIC;
BIT_OUT : OUT STD_LOGIC;
RAND_OUT : OUT std_logic_vector(7 downto 0)
);
END component;
component pokey_poly_5 IS
PORT
(
CLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
ENABLE : IN STD_LOGIC;
INIT : IN STD_LOGIC;
BIT_OUT : OUT STD_LOGIC
);
END component;
component pokey_poly_4 IS
PORT
(
CLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
ENABLE : IN STD_LOGIC;
INIT : IN STD_LOGIC;
BIT_OUT : OUT STD_LOGIC
);
END component;
component pokey_countdown_timer IS
generic(UNDERFLOW_DELAY : natural := 3);
PORT
(
CLK : IN STD_LOGIC;
ENABLE : IN STD_LOGIC;
ENABLE_UNDERFLOW : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
WR_EN : IN STD_LOGIC;
DATA_IN : IN STD_LOGIC_VECTOR(7 downto 0);

DATA_OUT : OUT STD_LOGIC
);
END component;
component pokey_noise_filter IS
PORT
(
CLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;

NOISE_SELECT : IN STD_LOGIC_VECTOR(2 downto 0);
PULSE_IN : IN STD_LOGIC;

NOISE_4 : IN STD_LOGIC;
NOISE_5 : IN STD_LOGIC;
NOISE_LARGE : IN STD_LOGIC;

SYNC_RESET : IN STD_LOGIC;
PULSE_OUT : OUT STD_LOGIC
);
END component;
COMPONENT complete_address_decoder IS
generic (width : natural := 1);
PORT
(
addr_in : in std_logic_vector(width-1 downto 0);
addr_decoded : out std_logic_vector((2**width)-1 downto 0)
);
END component;
component delay_line IS
generic(COUNT : natural := 1);
PORT
(
CLK : IN STD_LOGIC;
SYNC_RESET : IN STD_LOGIC;
DATA_IN : IN STD_LOGIC;
ENABLE : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
DATA_OUT : OUT STD_LOGIC
);
END component;

component latch_delay_line IS
generic(COUNT : natural := 1);
PORT
(
CLK : IN STD_LOGIC;
SYNC_RESET : IN STD_LOGIC;
DATA_IN : IN STD_LOGIC;
ENABLE : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
DATA_OUT : OUT STD_LOGIC
);
END component;
component pokey_keyboard_scanner is
port
(
clk : in std_logic;
reset_n : in std_logic;
enable : in std_logic; -- typically hsync or equiv timing
keyboard_response : in std_logic_vector(1 downto 0);
debounce_disable : in std_logic;
scan_enable : in std_logic;
keyboard_scan : out std_logic_vector(5 downto 0);
key_held : out std_logic;
shift_held : out std_logic;
keycode : out std_logic_vector(7 downto 0);
other_key_irq : out std_logic;
break_irq : out std_logic
);
end component;
--signal enable_179 : std_logic;
signal enable_64 : std_logic;
signal enable_15 : std_logic;

signal audf0_reg : std_logic_vector(7 downto 0);
signal audc0_reg : std_logic_vector(7 downto 0);
signal audf1_reg : std_logic_vector(7 downto 0);
signal audc1_reg : std_logic_vector(7 downto 0);
signal audf2_reg : std_logic_vector(7 downto 0);
signal audc2_reg : std_logic_vector(7 downto 0);
signal audf3_reg : std_logic_vector(7 downto 0);
signal audc3_reg : std_logic_vector(7 downto 0);
signal audctl_reg : std_logic_vector(7 downto 0);
signal audf0_next : std_logic_vector(7 downto 0);
signal audc0_next : std_logic_vector(7 downto 0);
signal audf1_next : std_logic_vector(7 downto 0);
signal audc1_next : std_logic_vector(7 downto 0);
signal audf2_next : std_logic_vector(7 downto 0);
signal audc2_next : std_logic_vector(7 downto 0);
signal audf3_next : std_logic_vector(7 downto 0);
signal audc3_next : std_logic_vector(7 downto 0);
signal audctl_next : std_logic_vector(7 downto 0);

signal audf0_pulse : std_logic;
signal audf1_pulse : std_logic;
signal audf2_pulse : std_logic;
signal audf3_pulse : std_logic;
signal audf0_reload : std_logic;
signal audf1_reload : std_logic;
signal audf2_reload : std_logic;
signal audf3_reload : std_logic;
signal stimer_write : std_logic;
signal stimer_write_delayed : std_logic;
signal audf0_pulse_noise : std_logic;
signal audf1_pulse_noise : std_logic;
signal audf2_pulse_noise : std_logic;
signal audf3_pulse_noise : std_logic;
signal audf0_enable : std_logic;
signal audf1_enable : std_logic;
signal audf2_enable : std_logic;
signal audf3_enable : std_logic;
signal chan0_output_next : std_logic;
signal chan1_output_next : std_logic;
signal chan2_output_next : std_logic;
signal chan3_output_next : std_logic;
signal chan0_output_reg : std_logic;
signal chan1_output_reg : std_logic;
signal chan2_output_reg : std_logic;
signal chan3_output_reg : std_logic;

signal chan0_output_del_next : std_logic;
signal chan1_output_del_next : std_logic;
signal chan0_output_del_reg : std_logic;
signal chan1_output_del_reg : std_logic;
signal highpass0_next : std_logic;
signal highpass1_next : std_logic;
signal highpass0_reg : std_logic;
signal highpass1_reg : std_logic;
signal volume_channel_0_next : std_logic_vector(3 downto 0);
signal volume_channel_1_next : std_logic_vector(3 downto 0);
signal volume_channel_2_next : std_logic_vector(3 downto 0);
signal volume_channel_3_next : std_logic_vector(3 downto 0);
signal volume_channel_0_reg : std_logic_vector(3 downto 0);
signal volume_channel_1_reg : std_logic_vector(3 downto 0);
signal volume_channel_2_reg : std_logic_vector(3 downto 0);
signal volume_channel_3_reg : std_logic_vector(3 downto 0);
signal addr_decoded : std_logic_vector(15 downto 0);
signal noise_4 : std_logic;
signal noise_5 : std_logic;
signal noise_large : std_logic;
signal noise_4_next : std_logic_vector(2 downto 0);
signal noise_4_reg : std_logic_vector(2 downto 0);
signal noise_5_next : std_logic_vector(2 downto 0);
signal noise_5_reg : std_logic_vector(2 downto 0);
signal noise_large_next : std_logic_vector(2 downto 0);
signal noise_large_reg : std_logic_vector(2 downto 0);

signal rand_out : std_logic_vector(7 downto 0); -- snoop part of the shift reg
signal initmode : std_logic;
signal irqen_next : std_logic_vector(7 downto 0);
signal irqen_reg : std_logic_vector(7 downto 0);

signal irqst_next : std_logic_vector(7 downto 0);
signal irqst_reg : std_logic_vector(7 downto 0);
signal irq_n_next : std_logic;
signal irq_n_reg : std_logic; -- for output
-- serial ports!
signal serial_ip_ready_interrupt : std_logic;
signal serial_ip_framing_next : std_logic;
signal serial_ip_framing_reg : std_logic;
signal serial_ip_overrun_next : std_logic;
signal serial_ip_overrun_reg : std_logic;
signal serial_op_needed_interrupt : std_logic;
signal skctl_next : std_logic_vector(7 downto 0);
signal skctl_reg : std_logic_vector(7 downto 0);
signal serin_shift_next : std_logic_vector(9 downto 0);
signal serin_shift_reg : std_logic_vector(9 downto 0);
signal serin_next : std_logic_vector(7 downto 0);
signal serin_reg : std_logic_vector(7 downto 0);
signal serin_bitcount_next : std_logic_vector(3 downto 0);
signal serin_bitcount_reg : std_logic_vector(3 downto 0);
signal sio_in1_reg : std_logic;
signal sio_in2_reg : std_logic;
signal sio_in3_reg : std_logic;
signal sio_in_next : std_logic;
signal sio_in_reg : std_logic;
signal sio_out_next : std_logic;
signal sio_out_reg : std_logic;
signal serial_out_next : std_logic;
signal serial_out_reg : std_logic;
signal serout_shift_next : std_logic_vector(9 downto 0);
signal serout_shift_reg : std_logic_vector(9 downto 0);
signal serout_holding_full_next : std_logic;
signal serout_holding_full_reg : std_logic;
signal serout_holding_next : std_logic_vector(7 downto 0);
signal serout_holding_reg : std_logic_vector(7 downto 0);
signal serout_holding_load : std_logic;

signal serout_bitcount_next : std_logic_vector(3 downto 0);
signal serout_bitcount_reg : std_logic_vector(3 downto 0);
signal serout_active_next : std_logic;
signal serout_active_reg : std_logic;
signal serial_reset : std_logic;
signal serout_sync_reset : std_logic;
signal skrest_write : std_logic;
signal serout_enable : std_logic;
signal serout_enable_delayed : std_logic;
signal serin_enable : std_logic;
signal async_serial_reset : std_logic;
signal waiting_for_start_bit : std_logic;
signal serin_clock_next : std_logic;
signal serin_clock_reg : std_logic;
signal serin_clock_last_next : std_logic;
signal serin_clock_last_reg : std_logic;

signal serout_clock_next : std_logic;
signal serout_clock_reg : std_logic;
signal serout_clock_last_next : std_logic;
signal serout_clock_last_reg : std_logic;
signal twotone_reset : std_logic;
signal twotone_reset_delayed : std_logic;
signal twotone_next : std_logic;
signal twotone_reg : std_logic;
signal clock_next : std_logic;
signal clock_reg : std_logic;
signal clock_sync_next : std_logic;
signal clock_sync_reg : std_logic;
signal clock_input : std_logic;
-- keyboard
signal keyboard_overrun_next : std_logic;
signal keyboard_overrun_reg : std_logic;
signal shift_held : std_logic;
signal break_irq : std_logic;
signal key_held : std_logic;
signal other_key_irq : std_logic;
signal kbcode : std_logic_vector(7 downto 0);
-- pots
signal pot0_next : std_logic_vector(7 downto 0);
signal pot0_reg : std_logic_vector(7 downto 0);
signal pot1_next : std_logic_vector(7 downto 0);
signal pot1_reg : std_logic_vector(7 downto 0);
signal pot2_next : std_logic_vector(7 downto 0);
signal pot2_reg : std_logic_vector(7 downto 0);
signal pot3_next : std_logic_vector(7 downto 0);
signal pot3_reg : std_logic_vector(7 downto 0);
signal pot4_next : std_logic_vector(7 downto 0);
signal pot4_reg : std_logic_vector(7 downto 0);
signal pot5_next : std_logic_vector(7 downto 0);
signal pot5_reg : std_logic_vector(7 downto 0);
signal pot6_next : std_logic_vector(7 downto 0);
signal pot6_reg : std_logic_vector(7 downto 0);
signal pot7_next : std_logic_vector(7 downto 0);
signal pot7_reg : std_logic_vector(7 downto 0);

signal allpot_next : std_logic_vector(7 downto 0);
signal allpot_reg : std_logic_vector(7 downto 0);
signal pot_counter_next : std_logic_vector(7 downto 0);
signal pot_counter_reg : std_logic_vector(7 downto 0);
signal potgo_write : std_logic;
signal pot_reset_next : std_logic;
signal pot_reset_reg : std_logic;
BEGIN
-- register
process(clk,reset_n)
begin
if (reset_n = '0') then
-- FIXME - Pokey does not have RESET - instead this is caused by 'init' sequence
audf0_reg <= X"00";
audc0_reg <= X"00";
audf1_reg <= X"00";
audc1_reg <= X"00";
audf2_reg <= X"00";
audc2_reg <= X"00";
audf3_reg <= X"00";
audc3_reg <= X"00";
audctl_reg <= X"00";
irqen_reg <= X"00";
irqst_reg <= X"FF";
irq_n_reg <= '1';
skctl_reg <= X"00";
highpass0_reg <= '0';
highpass1_reg <= '0';
chan0_output_reg <= '0';
chan1_output_reg <= '0';
chan2_output_reg <= '0';
chan3_output_reg <= '0';

chan0_output_del_reg <= '0';
chan1_output_del_reg <= '0';

volume_channel_0_reg <= (others=>'0');
volume_channel_1_reg <= (others=>'0');
volume_channel_2_reg <= (others=>'0');
volume_channel_3_reg <= (others=>'0');
serin_reg <= (others=>'0');
serin_shift_reg <= (others=>'0');
serin_bitcount_reg <= (others=>'0');
serout_shift_reg <= (others=>'0');
serout_holding_reg <= (others=>'0');
serout_holding_full_reg <= '0';
serout_active_reg <= '0';
sio_out_reg <= '1';
serial_out_reg <= '1';
serial_ip_framing_reg <= '0';
serial_ip_overrun_reg <= '0';
clock_reg <= '0';
clock_sync_reg <= '0';
keyboard_overrun_reg <= '0';
serin_clock_reg <= '0';
serin_clock_last_reg <= '0';
serout_clock_reg <= '0';
serout_clock_last_reg <= '0';
twotone_reg <= '0';
sio_in_reg <= '0';
pot0_reg <= (others=>'0');
pot1_reg <= (others=>'0');
pot2_reg <= (others=>'0');
pot3_reg <= (others=>'0');
pot4_reg <= (others=>'0');
pot5_reg <= (others=>'0');
pot6_reg <= (others=>'0');
pot7_reg <= (others=>'0');

allpot_reg <= (others=>'1');
pot_counter_reg <= (others=>'0');
pot_reset_reg <= '1';

noise_4_reg <= (others=>'0');
noise_5_reg <= (others=>'0');
noise_large_reg <= (others=>'0');
elsif (clk'event and clk='1') then
audf0_reg <= audf0_next;
audc0_reg <= audc0_next;
audf1_reg <= audf1_next;
audc1_reg <= audc1_next;
audf2_reg <= audf2_next;
audc2_reg <= audc2_next;
audf3_reg <= audf3_next;
audc3_reg <= audc3_next;
audctl_reg <= audctl_next;
irqen_reg <= irqen_next;
irqst_reg <= irqst_next;
irq_n_reg <= irq_n_next;
skctl_reg <= skctl_next;
highpass0_reg <= highpass0_next;
highpass1_reg <= highpass1_next;
chan0_output_reg <= chan0_output_next;
chan1_output_reg <= chan1_output_next;
chan2_output_reg <= chan2_output_next;
chan3_output_reg <= chan3_output_next;

chan0_output_del_reg <= chan0_output_del_next;
chan1_output_del_reg <= chan1_output_del_next;
volume_channel_0_reg<= volume_channel_0_next;
volume_channel_1_reg<= volume_channel_1_next;
volume_channel_2_reg<= volume_channel_2_next;
volume_channel_3_reg<= volume_channel_3_next;
serin_reg <= serin_next;
serin_shift_reg <= serin_shift_next;
serin_bitcount_reg <= serin_bitcount_next;
serout_shift_reg <= serout_shift_next;
serout_bitcount_reg <= serout_bitcount_next;
serout_holding_reg<=serout_holding_next;
serout_holding_full_reg<=serout_holding_full_next;
serout_active_reg <= serout_active_next;
sio_out_reg <= sio_out_next;
serial_out_reg <= serial_out_next;
serial_ip_framing_reg <= serial_ip_framing_next;
serial_ip_overrun_reg <= serial_ip_overrun_next;
clock_reg <= clock_next;
clock_sync_reg <= clock_sync_next;
keyboard_overrun_reg <= keyboard_overrun_next;
serin_clock_reg <= serin_clock_next;
serin_clock_last_reg <= serin_clock_last_next;
serout_clock_reg <= serout_clock_next;
serout_clock_last_reg <= serout_clock_last_next;
twotone_reg <= twotone_next;
sio_in_reg <= sio_in_next;
pot0_reg <= pot0_next;
pot1_reg <= pot1_next;
pot2_reg <= pot2_next;
pot3_reg <= pot3_next;
pot4_reg <= pot4_next;
pot5_reg <= pot5_next;
pot6_reg <= pot6_next;
pot7_reg <= pot7_next;

allpot_reg <= allpot_next;
pot_counter_reg <= pot_counter_next;
pot_reset_reg <= pot_reset_next;

noise_4_reg <= noise_4_next;
noise_5_reg <= noise_5_next;
noise_large_reg <= noise_large_next;
end if;
end process;
-- decode address
decode_addr1 : complete_address_decoder
generic map(width=>4)
port map (addr_in=>addr, addr_decoded=>addr_decoded);
-- clock selection
process(enable_64,enable_15,enable_179,audctl_reg,audf0_pulse,audf2_pulse)
begin
audf0_enable <= enable_64;
audf1_enable <= enable_64;
audf2_enable <= enable_64;
audf3_enable <= enable_64;
if (audctl_reg(0) = '1') then
audf0_enable <= enable_15;
audf1_enable <= enable_15;
audf2_enable <= enable_15;
audf3_enable <= enable_15;
end if;

if (audctl_reg(6) = '1') then
audf0_enable <= enable_179;
end if;
if (audctl_reg(5) = '1') then
audf2_enable <= enable_179;
end if;
if(audctl_reg(4) = '1') then
audf1_enable <= audf0_pulse;
end if;
if(audctl_reg(3) = '1') then
audf3_enable <= audf2_pulse;
end if;
end process;
-- Instantiate timers
timer0 : pokey_countdown_timer
generic map (UNDERFLOW_DELAY=>3)
port map(clk=>clk,enable=>audf0_enable,enable_underflow=>enable_179,reset_n=>reset_n,wr_en=>audf0_reload,data_in=>audf0_next,DATA_OUT=>audf0_pulse);
timer1 : pokey_countdown_timer
generic map (UNDERFLOW_DELAY=>3)
port map(clk=>clk,enable=>audf1_enable,enable_underflow=>enable_179,reset_n=>reset_n,wr_en=>audf1_reload,data_in=>audf1_next,DATA_OUT=>audf1_pulse);
timer2 : pokey_countdown_timer
generic map (UNDERFLOW_DELAY=>3)
port map(clk=>clk,enable=>audf2_enable,enable_underflow=>enable_179,reset_n=>reset_n,wr_en=>audf2_reload,data_in=>audf2_next,DATA_OUT=>audf2_pulse);
timer3 : pokey_countdown_timer
generic map (UNDERFLOW_DELAY=>3)
port map(clk=>clk,enable=>audf3_enable,enable_underflow=>enable_179,reset_n=>reset_n,wr_en=>audf3_reload,data_in=>audf3_next,DATA_OUT=>audf3_pulse);
-- Timer reloading
process (audctl_reg, audf0_pulse, audf1_pulse, audf2_pulse, audf3_pulse, stimer_write_delayed, async_serial_reset, twotone_reset_delayed)
begin
audf0_reload <= ((not(audctl_reg(4)) and audf0_pulse)) or (audctl_reg(4) and audf1_pulse) or stimer_write_delayed or twotone_reset_delayed;
audf1_reload <= audf1_pulse or stimer_write_delayed or twotone_reset_delayed;
audf2_reload <= ((not(audctl_reg(3)) and audf2_pulse)) or (audctl_reg(3) and audf3_pulse) or stimer_write_delayed or async_serial_reset;
audf3_reload <= audf3_pulse or stimer_write_delayed or async_serial_reset;
end process;

twotone_del : latch_delay_line
generic map (count=>2)
port map (clk=>clk, sync_reset=>'0',data_in=>twotone_reset, enable=>enable_179, reset_n=>reset_n, data_out=>twotone_reset_delayed);
-- twotone_reset_delayed <= twotone_reset;
-- Writes to registers
process(data_in,wr_en,addr_decoded,audf0_reg,audc0_reg,audf1_reg,audc1_reg,audf2_reg,audc2_reg,audf3_reg,audc3_reg,audf0_enable,audf1_enable,audf2_enable,audf3_enable,audctl_reg, irqen_reg, skctl_reg, serout_holding_reg)
begin
audf0_next <= audf0_reg;
audc0_next <= audc0_reg;
audf1_next <= audf1_reg;
audc1_next <= audc1_reg;
audf2_next <= audf2_reg;
audc2_next <= audc2_reg;
audf3_next <= audf3_reg;
audc3_next <= audc3_reg;
audctl_next <= audctl_reg;
irqen_next <= irqen_reg;
skctl_next <= skctl_reg;
stimer_write <= '0';
serout_holding_load <= '0';
serout_holding_next <= serout_holding_reg;
serial_reset <= '0';
skrest_write <= '0';
potgo_write <= '0';
if (wr_en = '1') then
if(addr_decoded(0) = '1') then
audf0_next <= data_in;
end if;
if(addr_decoded(1) = '1') then
audc0_next <= data_in;
end if;
if(addr_decoded(2) = '1') then
audf1_next <= data_in;
end if;

if(addr_decoded(3) = '1') then
audc1_next <= data_in;
end if;
if(addr_decoded(4) = '1') then
audf2_next <= data_in;
end if;

if(addr_decoded(5) = '1') then
audc2_next <= data_in;
end if;
if(addr_decoded(6) = '1') then
audf3_next <= data_in;
end if;

if(addr_decoded(7) = '1') then
audc3_next <= data_in;
end if;
if(addr_decoded(8) = '1') then
audctl_next <= data_in;
end if;
if (addr_decoded(9) = '1') then --STIMER
stimer_write <= '1';
end if;
if (addr_decoded(10) = '1') then -- skrest - resets the serial input problems - overflow etc
skrest_write <= '1';
end if;

if (addr_decoded(11) = '1') then -- POTGO - start POT scan
potgo_write <= '1';
end if;
if (addr_decoded(13) = '1') then --SEROUT
serout_holding_next <= data_in;
serout_holding_load <= '1';
end if;
if (addr_decoded(14) = '1') then --IRQEN
irqen_next <= data_in;
end if;

if (addr_decoded(15) = '1') then --SKCTL
skctl_next <= data_in;
if (data_in(6 downto 4)="000") then
serial_reset <= '1';
end if;
end if;
end if;
end process;
-- Read from registers
process(addr_decoded,kbcode,RAND_OUT,IRQST_REG,key_held,shift_held,sio_in_reg,serin_reg,keyboard_overrun_reg, serial_ip_framing_reg, serial_ip_overrun_reg, waiting_for_start_bit, pot_in, pot0_reg, pot1_reg, pot2_reg, pot3_reg, pot4_reg, pot5_reg, pot6_reg, pot7_reg, allpot_reg)
begin
data_out <= X"FF";

if(addr_decoded(0) = '1') then --POT0
data_out <= pot0_reg;
end if;

if(addr_decoded(1) = '1') then --POT1
data_out <= pot1_reg;
end if;

if(addr_decoded(2) = '1') then --POT2
data_out <= pot2_reg;
end if;

if(addr_decoded(3) = '1') then --POT3
data_out <= pot3_reg;
end if;
if(addr_decoded(4) = '1') then --POT4
data_out <= pot4_reg;
end if;

if(addr_decoded(5) = '1') then --POT5
data_out <= pot5_reg;
end if;

if(addr_decoded(6) = '1') then --POT6
data_out <= pot6_reg;
end if;

if(addr_decoded(7) = '1') then --POT7
data_out <= pot7_reg;
end if;

if(addr_decoded(8) = '1') then --ALLPOT
data_out <= allpot_reg;
end if;
if(addr_decoded(9) = '1') then --KBCODE
data_out <= kbcode;
end if;
if(addr_decoded(10) = '1') then -- RANDOM
data_out <= RAND_OUT;
end if;

if (addr_decoded(13) = '1') then --SERIN
data_out <= serin_reg;
end if;
if (addr_decoded(14) = '1') then --IRQST - bits set to low when irq
data_out <= IRQST_REG;
--break_irq_n & other_key_irq_n & serial_ip_irq_n & serial_op_irq_n & serial_trans_irq_n & timer3_irq_n & timer_1_irq_n & timer_0_irq_n
end if;

if (addr_decoded(15) = '1') then --SKSTAT
data_out <= not(serial_ip_framing_reg)&not(keyboard_overrun_reg)&not(serial_ip_overrun_reg)&sio_in_reg&not(shift_held)&not(key_held)&waiting_for_start_bit&"1";
end if;
end process;
-- Fire interrupts
process (irqen_reg, irqst_reg, audf0_pulse, audf1_pulse, audf3_pulse, other_key_irq, serial_ip_ready_interrupt, serout_active_reg, serial_op_needed_interrupt, break_irq)
begin
-- clear interrupts
irqst_next <= irqst_reg or not(irqen_reg);
irq_n_next <= '0';

if ((irqst_reg or "0000"&not(irqen_reg(3))&"000") = X"FF") then
irq_n_next <= '1';
end if;
-- set interrupts
if (audf0_pulse = '1') then
irqst_next(0) <= not(irqen_reg(0));
end if;

if (audf1_pulse = '1') then
irqst_next(1) <= not(irqen_reg(1));
end if;

if (audf3_pulse = '1') then
irqst_next(2) <= not(irqen_reg(2));
end if;
if (other_key_irq = '1') then
irqst_next(6) <= not(irqen_reg(6));
end if;
if (break_irq = '1') then
irqst_next(7) <= not(irqen_reg(7));
end if;
if (serial_ip_ready_interrupt = '1') then
irqst_next(5) <= not(irqen_reg(5));
end if;
irqst_next(3) <= serout_active_reg;
if (serial_op_needed_interrupt = '1') then
irqst_next(4) <= not(irqen_reg(4));
end if;
end process;
-- Instantiate delay for stimer reload_request
stimer_delay : latch_delay_line
generic map (count=>3)
port map (clk=>clk, sync_reset=>'0',data_in=>stimer_write, enable=>enable_179, reset_n=>reset_n, data_out=>stimer_write_delayed);
--stimer_write_delayed <= stimer_write;
-- Instantiate audio noise filters
pokey_noise_filter0 : pokey_noise_filter
port map(clk=>clk,reset_n=>reset_n,noise_select=>audc0_reg(7 downto 5),pulse_in=>audf0_pulse,pulse_out=>audf0_pulse_noise,noise_4=>noise_4,noise_5=>noise_5,noise_large=>noise_large, sync_reset=>stimer_write_delayed);
pokey_noise_filter1 : pokey_noise_filter
port map(clk=>clk,reset_n=>reset_n,noise_select=>audc1_reg(7 downto 5),pulse_in=>audf1_pulse,pulse_out=>audf1_pulse_noise,noise_4=>noise_4_reg(0),noise_5=>noise_5_reg(0),noise_large=>noise_large_reg(0), sync_reset=>stimer_write_delayed);
pokey_noise_filter2 : pokey_noise_filter
port map(clk=>clk,reset_n=>reset_n,noise_select=>audc2_reg(7 downto 5),pulse_in=>audf2_pulse,pulse_out=>audf2_pulse_noise,noise_4=>noise_4_reg(1),noise_5=>noise_5_reg(1),noise_large=>noise_large_reg(1), sync_reset=>stimer_write_delayed);
pokey_noise_filter3 : pokey_noise_filter
port map(clk=>clk,reset_n=>reset_n,noise_select=>audc3_reg(7 downto 5),pulse_in=>audf3_pulse,pulse_out=>audf3_pulse_noise,noise_4=>noise_4_reg(2),noise_5=>noise_5_reg(2),noise_large=>noise_large_reg(2), sync_reset=>stimer_write_delayed);
-- Audio output stage
-- (toggling now handled in the noise filter - the subtlety on when to toggle and when to sample is important)
chan0_output_next <= audf0_pulse_noise;
chan1_output_next <= audf1_pulse_noise;
chan2_output_next <= audf2_pulse_noise;
chan3_output_next <= audf3_pulse_noise;
-- High pass filters
process(audctl_reg,audf2_pulse,audf3_pulse,chan0_output_reg, chan1_output_reg, chan2_output_reg, chan3_output_reg, highpass0_reg, highpass1_reg)
begin
highpass0_next <= highpass0_reg;
highpass1_next <= highpass1_reg;
if (audctl_reg(2) = '1') then
if (audf2_pulse = '1') then
highpass0_next <= chan0_output_reg;
end if;
else
highpass0_next <= '1';
end if;
if (audctl_reg(1) = '1') then
if (audf3_pulse = '1') then
highpass1_next <= chan1_output_reg;
end if;
else
highpass1_next <= '1';
end if;
end process;

process(chan0_output_reg,chan1_output_reg,chan0_output_del_reg,chan1_output_del_reg,enable_179)
begin
chan0_output_del_next <= chan0_output_del_reg;
chan1_output_del_next <= chan1_output_del_reg;

if (enable_179 = '1') then
chan0_output_del_next <= chan0_output_reg;
chan1_output_del_next <= chan1_output_reg;
end if;
end process;
-- Instantiate key pokey clocks
-- ~1.79MHz - from 25MHz/14
-- ~64KHz - from 1.79MHz/28
-- ~15KHz - from 1.79MHz/114
--enable_179_div : enable_divider
-- generic map (COUNT=>14)
-- port map(clk=>clk,reset_n=>reset_n,enable_in=>'1',enable_out=>enable_179);
-- resetcount 6/33
enable_64_div : syncreset_enable_divider
generic map (COUNT=>28,RESETCOUNT=>6) -- 28-22
port map(clk=>clk,syncreset=>initmode,reset_n=>reset_n,enable_in=>enable_179,enable_out=>enable_64);
enable_15_div : syncreset_enable_divider
generic map (COUNT=>114,RESETCOUNT=>33) -- 114-81
port map(clk=>clk,syncreset=>initmode,reset_n=>reset_n,enable_in=>enable_179,enable_out=>enable_15);
-- Instantiate pokey noise circuits (lfsr)
initmode <= skctl_next(1) nor skctl_next(0);
poly_17_19_lfsr : pokey_poly_17_9
port map(clk=>clk,reset_n=>reset_n,init=>initmode,enable=>enable_179,select_9_17=>audctl_reg(7),bit_out=>noise_large,rand_out=>rand_out);
poly_5_lfsr : pokey_poly_5
port map(clk=>clk,reset_n=>reset_n,init=>initmode,enable=>enable_179,bit_out=>noise_5);
poly_4_lfsr : pokey_poly_4
port map(clk=>clk,reset_n=>reset_n,init=>initmode,enable=>enable_179,bit_out=>noise_4);

-- Delay between feeding noise between channels
process(noise_large_reg, noise_5_reg, noise_4_reg, noise_large, noise_5, noise_4, enable_179)
begin
noise_large_next <= noise_large_reg;
noise_5_next <= noise_5_reg;
noise_4_next <= noise_4_reg;

if (enable_179='1') then
noise_large_next <= noise_large_reg(1 downto 0)&noise_large;
noise_5_next <= noise_5_reg(1 downto 0)&noise_5;
noise_4_next <= noise_4_reg(1 downto 0)&noise_4;
end if;
end process;
--AUDIO_LEFT <= "000"&count_reg(15 downto 3);
process(chan0_output_del_reg, chan1_output_del_reg, chan2_output_reg, chan3_output_reg, audc0_reg, audc1_reg, audc2_reg, audc3_reg, highpass0_reg, highpass1_reg)
begin
volume_channel_0_next <= "0000";
volume_channel_1_next <= "0000";
volume_channel_2_next <= "0000";
volume_channel_3_next <= "0000";
if (((chan0_output_del_reg xor highpass0_reg) or audc0_reg(4)) = '1') then
volume_channel_0_next <= audc0_reg(3 downto 0);
end if;
if (((chan1_output_del_reg xor highpass1_reg) or audc1_reg(4)) = '1') then
volume_channel_1_next <= audc1_reg(3 downto 0);
end if;
if ((chan2_output_reg or audc2_reg(4)) = '1') then
volume_channel_2_next <= audc2_reg(3 downto 0);
end if;
if ((chan3_output_reg or audc3_reg(4)) = '1') then
volume_channel_3_next <= audc3_reg(3 downto 0);
end if;
end process;
-- serial port output
-- urghhh (TODO: If timers are cleared with stimer_write, some clocks are still triggering. This workaround fixes the acid test. Investigate the proper fix)
serout_sync_reset <= serial_reset or stimer_write_delayed;
serout_clock_delay : delay_line
generic map (count=>2)
port map (clk=>clk, sync_reset=>serout_sync_reset,data_in=>serout_enable, enable=>enable_179, reset_n=>reset_n, data_out=>serout_enable_delayed);
process(serout_enable_delayed, skctl_reg, serout_active_reg, serout_clock_last_reg,serout_clock_reg, serout_holding_load, serout_holding_reg, serout_holding_full_reg, serout_shift_reg, serout_bitcount_reg, serial_out_reg, twotone_reg, audf0_pulse, audf1_pulse, serial_reset)
begin
serout_clock_next <= serout_clock_reg;
serout_clock_last_next <= serout_clock_reg;
serout_shift_next <= serout_shift_reg;
serout_bitcount_next <= serout_bitcount_reg;
serout_holding_full_next <= serout_holding_full_reg;
serout_active_next <= serout_active_reg;
serial_out_next <= serial_out_reg; -- output from shift reg (if unchanged)
sio_out_next <= serial_out_reg;
-- two tone output
twotone_next <= twotone_reg;
twotone_reset <= '0';
if ((audf1_pulse or (audf0_pulse and serial_out_reg)) = '1') then
twotone_next <= not(twotone_reg);
twotone_reset <= skctl_reg(3);
end if;
if (skctl_reg(3) = '1') then
sio_out_next <= twotone_reg;
end if;
serial_op_needed_interrupt <= '0';
-- generate clock from enable signals
if (serout_enable_delayed = '1') then
serout_clock_next <= not(serout_clock_reg);
end if;
-- output bits over sio
if (serout_clock_last_reg = '0' and serout_clock_reg = '1') then
serout_shift_next <= '0'&serout_shift_reg(9 downto 1); -- next
serial_out_next <= serout_shift_reg(1) or not(serout_active_reg); -- i.e. next serout_shift_reg(0)
-- reload
if (serout_bitcount_reg = X"0") then
if (serout_holding_full_reg='1') then -- unless, more to send in holding reg?
serout_bitcount_next <= X"9"; -- 10 bits to send, 9 more after this
serout_shift_next <= '1'&serout_holding_reg&'0';
serial_out_next <= '0'; -- start bit (serout_shift_reg(0) after this cycle)
serout_holding_full_next <= '0';
serial_op_needed_interrupt <= '1'; -- more data please!
serout_active_next <= '1';
else
serout_active_next <= '0';
serial_out_next <= '1'; -- remove blip!
end if;
else
serout_bitcount_next <= std_logic_vector(unsigned(serout_bitcount_reg)-1);
end if;
end if;

-- force break
if (skctl_reg(7) = '1') then
serial_out_next <= '0';
end if;
-- register to load has been written too, update our state to reflect that it is full
if (serout_holding_load = '1') then
serout_holding_full_next <= '1';
end if;
if (serial_reset = '1') then
twotone_next <= '0';
serout_bitcount_next <= (others=>'0');
serout_shift_next <= (others=>'0');
serout_holding_full_next <= '0';
serout_clock_next <= '0';
serout_clock_last_next <= '0';
serout_active_next <= '0';
end if;
end process;
-- serial port input
sio_in1_synchronizer : synchronizer
port map (clk=>clk, raw=>sio_in1, sync=>sio_in1_reg);
sio_in2_synchronizer : synchronizer
port map (clk=>clk, raw=>sio_in2, sync=>sio_in2_reg);
sio_in3_synchronizer : synchronizer
port map (clk=>clk, raw=>sio_in3, sync=>sio_in3_reg);
sio_in_next <= sio_in1_reg and sio_in2_reg and sio_in3_reg;
waiting_for_start_bit <= '1' when serin_bitcount_reg = X"9" else '0';
process(serin_enable,serin_clock_last_reg,serin_clock_reg, sio_in_reg, serin_reg,serin_shift_reg, serin_bitcount_reg, serial_ip_overrun_reg, serial_ip_framing_reg, skrest_write, irqst_reg, skctl_reg, waiting_for_start_bit, serial_reset)
begin
serin_clock_next <= serin_clock_reg;
serin_clock_last_next <= serin_clock_reg;
serin_shift_next <= serin_shift_reg;
serin_bitcount_next <= serin_bitcount_reg;
serin_next <= serin_reg;
serial_ip_overrun_next <= serial_ip_overrun_reg;
serial_ip_framing_next <= serial_ip_framing_reg;
serial_ip_ready_interrupt <= '0';
async_serial_reset <= '0';
-- generate clock from enable signals
if (serin_enable = '1') then
serin_clock_next <= not(serin_clock_reg);
end if;
-- resync clock on receipt of start bit
if ((skctl_reg(4) and sio_in_reg and waiting_for_start_bit)= '1') then
async_serial_reset <= '1';
serin_clock_next <= '1';
end if;
-- receive bits into shift reg
if (serin_clock_last_reg='1' and serin_clock_reg='0') then -- failing edge
if (((waiting_for_start_bit and not(sio_in_reg)) or not(waiting_for_start_bit))='1') then
serin_shift_next <= sio_in_reg&serin_shift_reg(9 downto 1);
if (serin_bitcount_reg = X"0") then -- full byte
serin_next <= serin_shift_reg(9 downto 2); -- not shifted yet
serin_bitcount_next <= X"9"; -- next... no disable for serial input, always happening.
-- irq to alert new data avilable
serial_ip_ready_interrupt <= '1';
-- flag up overrun
if (irqst_reg(5) = '0') then -- if interrupt bit not cleared yet...
serial_ip_overrun_next <= '1';
end if;
-- flag up framing problem (stop bit is 1 - pull from sio since reg not yet shifted)
if (sio_in_reg='0') then
serial_ip_framing_next <= '1';
end if;
else
serin_bitcount_next <= std_logic_vector(unsigned(serin_bitcount_reg)-1);
end if;
end if;
end if;
if (skrest_write = '1') then
serial_ip_overrun_next <= '0';
serial_ip_framing_next <= '0';
end if;
if (serial_reset = '1') then
serin_clock_next <= '0';
serin_bitcount_next <= X"9"; -- i.e. waiting for start bit
serin_shift_next <= (others=>'0');
end if;
end process;
-- serial clocks
process(sio_clockin_in,skctl_reg,clock_reg,clock_sync_reg,audf1_pulse,audf2_pulse,audf3_pulse)
begin
clock_next <= sio_clockin_in;
clock_sync_next <= clock_reg;
serout_enable <= '0';
serin_enable <= '0';
clock_input <= '1'; -- when output, outputs channel 4
case skctl_reg(6 downto 4) is
when "000" =>
serin_enable <= not(clock_sync_reg) and clock_reg;
serout_enable <= not(clock_sync_reg) and clock_reg;
when "001" =>
serin_enable <= audf3_pulse;
serout_enable <= not(clock_sync_reg) and clock_reg;
when "010" =>
serin_enable <= audf3_pulse;
serout_enable <= audf3_pulse;
clock_input <= '0';
when "011" =>
serin_enable <= audf3_pulse;
serout_enable <= audf3_pulse;
when "100" =>
serin_enable <= not(clock_sync_reg) and clock_reg;
serout_enable <= audf3_pulse;
when "101" =>
serin_enable <= audf3_pulse;
serout_enable <= audf3_pulse;
when "110" =>
serin_enable <= audf3_pulse;
serout_enable <= audf1_pulse;
clock_input <= '0';
when "111" =>
serin_enable <= audf3_pulse;
serout_enable <= audf1_pulse;
when others =>
-- nop
end case;
end process;
-- keyboard overrun (i.e. second key pressed before interrupt cleared)
process(other_key_irq,keyboard_overrun_reg,skrest_write,irqst_reg)
begin
keyboard_overrun_next <= keyboard_overrun_reg;
if (other_key_irq='1' and irqst_reg(6)='0') then
keyboard_overrun_next <= '1';
end if;
if (skrest_write = '1') then
keyboard_overrun_next <= '0';
end if;
end process;
-- keyboard scan
gen_custom_scan : if custom_keyboard_scan=1 generate
pokey_keyboard_scanner1 : pokey_keyboard_scanner
port map (clk=>clk, reset_n=>reset_n, enable=>keyboard_scan_enable, keyboard_response=>keyboard_response, debounce_disable=>not(skctl_reg(0)), scan_enable=>skctl_reg(1), keyboard_scan=>keyboard_scan, key_held=>key_held, shift_held=>shift_held, keycode=>kbcode, other_key_irq=>other_key_irq, break_irq=>break_irq);
end generate;

gen_normal_scan : if custom_keyboard_scan=0 generate
pokey_keyboard_scanner1 : pokey_keyboard_scanner
port map (clk=>clk, reset_n=>reset_n, enable=>enable_15, keyboard_response=>keyboard_response, debounce_disable=>not(skctl_reg(0)), scan_enable=>skctl_reg(1), keyboard_scan=>keyboard_scan, key_held=>key_held, shift_held=>shift_held, keycode=>kbcode, other_key_irq=>other_key_irq, break_irq=>break_irq);
end generate;

-- POT scan
process(potgo_write, pot_reset_reg, pot_counter_reg, pot_in, enable_15, enable_179, skctl_reg, pot0_reg, pot1_reg, pot2_reg, pot3_reg, pot4_reg, pot5_reg, pot6_reg, pot7_reg, allpot_reg)
begin
pot0_next <= pot0_reg;
pot1_next <= pot1_reg;
pot2_next <= pot2_reg;
pot3_next <= pot3_reg;
pot4_next <= pot4_reg;
pot5_next <= pot5_reg;
pot6_next <= pot6_reg;
pot7_next <= pot7_reg;

allpot_next <= allpot_reg;
pot_reset_next <= pot_reset_reg;
pot_counter_next <= pot_counter_reg;
if (((enable_15 and not(skctl_reg(2))) or (enable_179 and skctl_reg(2))) = '1') then
pot_counter_next <= std_logic_vector(unsigned(pot_counter_reg) + 1);
if (pot_counter_reg = X"E4") then
pot_reset_next <= '1'; -- turn on pot dump transistors
allpot_next <= (others=>'0');
end if;
if (pot_reset_reg = '0') then
if (pot_in(0) = '0') then -- pot now high, latch
pot0_next <= pot_counter_reg;
end if;
if (pot_in(1) = '0') then -- pot now high, latch
pot1_next <= pot_counter_reg;
end if;
if (pot_in(2) = '0') then -- pot now high, latch
pot2_next <= pot_counter_reg;
end if;
if (pot_in(3) = '0') then -- pot now high, latch
pot3_next <= pot_counter_reg;
end if;
if (pot_in(4) = '0') then -- pot now high, latch
pot4_next <= pot_counter_reg;
end if;
if (pot_in(5) = '0') then -- pot now high, latch
pot5_next <= pot_counter_reg;
end if;
if (pot_in(6) = '0') then -- pot now high, latch
pot6_next <= pot_counter_reg;
end if;
if (pot_in(7) = '0') then -- pot now high, latch
pot7_next <= pot_counter_reg;
end if;

allpot_next <= allpot_reg and not(pot_in);
end if;
end if;
if (potgo_write = '1') then
pot_counter_next <= (others=>'0');
pot_reset_next <= '0'; -- turn off pot dump transistors, so they start to get charged
allpot_next <= (others=>'1');
end if;
end process;
-- Outputs
irq_n_out <= irq_n_reg;
CHANNEL_0_OUT <= volume_channel_0_reg;
CHANNEL_1_OUT <= volume_channel_1_reg;
CHANNEL_2_OUT <= volume_channel_2_reg;
CHANNEL_3_OUT <= volume_channel_3_reg;
sio_out1 <= sio_out_reg;
sio_out2 <= sio_out_reg;
sio_out3 <= sio_out_reg;
sio_clockout <= serout_clock_reg;
sio_clockin_oe <= not(clock_input);
sio_clockin_out <= serin_clock_reg;
pot_reset <= pot_reset_reg;
END vhdl;


(13-13/30)