mirror of
https://github.com/MiSTer-devel/BBCMicro_MiSTer.git
synced 2026-05-24 03:02:58 +00:00
Use cycle accurate VIA module.
This commit is contained in:
@@ -24,7 +24,7 @@ set_global_assignment -name VHDL_FILE rtl/sn76489/sn76489_attenuator.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/R65Cx2.vhd
|
||||
set_global_assignment -name QIP_FILE rtl/t65/t65.qip
|
||||
set_global_assignment -name VHDL_FILE rtl/upd7002.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/m6522.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/via6522.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/rtc.vhd
|
||||
set_global_assignment -name VERILOG_FILE rtl/rtc_chip.v
|
||||
set_global_assignment -name VHDL_FILE rtl/saa5050.vhd
|
||||
|
||||
@@ -234,7 +234,7 @@ signal ttxt_hblank : std_logic;
|
||||
|
||||
-- System VIA signals
|
||||
signal sys_via_do : std_logic_vector(7 downto 0);
|
||||
signal sys_via_irq_n : std_logic;
|
||||
signal sys_via_irq : std_logic;
|
||||
signal sys_via_ca1_in : std_logic := '0';
|
||||
signal sys_via_ca2_in : std_logic := '0';
|
||||
signal sys_via_pa_in : std_logic_vector(7 downto 0);
|
||||
@@ -247,22 +247,22 @@ signal sys_via_do_r : std_logic_vector (7 downto 0);
|
||||
|
||||
-- User VIA signals
|
||||
signal user_via_do : std_logic_vector(7 downto 0);
|
||||
signal user_via_irq_n : std_logic;
|
||||
signal user_via_irq : std_logic;
|
||||
signal user_via_ca1_in : std_logic := '0';
|
||||
signal user_via_pa_in : std_logic_vector(7 downto 0);
|
||||
signal user_via_pa_out : std_logic_vector(7 downto 0);
|
||||
signal user_via_cb1_in : std_logic := '0';
|
||||
signal user_via_cb1_out : std_logic;
|
||||
signal user_via_cb1_oe_n: std_logic;
|
||||
signal user_via_cb1_oe : std_logic;
|
||||
signal user_via_cb2_in : std_logic := '0';
|
||||
signal user_via_pb_in : std_logic_vector(7 downto 0);
|
||||
signal user_via_pb_out : std_logic_vector(7 downto 0);
|
||||
signal user_via_pb_oe_n : std_logic_vector(7 downto 0);
|
||||
signal user_via_pb_oe : std_logic_vector(7 downto 0);
|
||||
signal user_via_do_r : std_logic_vector (7 downto 0);
|
||||
|
||||
-- Mouse VIA signals
|
||||
signal mouse_via_do : std_logic_vector(7 downto 0);
|
||||
signal mouse_via_irq_n : std_logic;
|
||||
signal mouse_via_irq : std_logic;
|
||||
signal mouse_via_pa_in : std_logic_vector(7 downto 0);
|
||||
signal mouse_via_pa_out : std_logic_vector(7 downto 0);
|
||||
signal mouse_via_cb1_in : std_logic := '0';
|
||||
@@ -476,103 +476,75 @@ begin
|
||||
);
|
||||
|
||||
-- System VIA
|
||||
system_via : entity work.m6522 port map (
|
||||
cpu_a(3 downto 0),
|
||||
cpu_do,
|
||||
sys_via_do,
|
||||
open,
|
||||
cpu_r_nw,
|
||||
sys_via_enable,
|
||||
'0', -- nCS2
|
||||
sys_via_irq_n,
|
||||
sys_via_ca1_in,
|
||||
sys_via_ca2_in,
|
||||
open,
|
||||
open,
|
||||
sys_via_pa_in,
|
||||
sys_via_pa_out,
|
||||
open,
|
||||
sys_via_cb1_in,
|
||||
open,
|
||||
open,
|
||||
sys_via_cb2_in,
|
||||
open,
|
||||
open,
|
||||
sys_via_pb_in,
|
||||
sys_via_pb_out,
|
||||
open,
|
||||
mhz1_clken,
|
||||
reset_n,
|
||||
mhz4_clken,
|
||||
clock_32
|
||||
);
|
||||
|
||||
-- User VIA
|
||||
user_via : entity work.m6522 port map (
|
||||
cpu_a(3 downto 0),
|
||||
cpu_do,
|
||||
user_via_do,
|
||||
open,
|
||||
cpu_r_nw,
|
||||
user_via_enable,
|
||||
'0', -- nCS2
|
||||
user_via_irq_n,
|
||||
user_via_ca1_in,
|
||||
'0',
|
||||
open,
|
||||
open,
|
||||
user_via_pa_in,
|
||||
user_via_pa_out,
|
||||
open,
|
||||
user_via_cb1_in,
|
||||
user_via_cb1_out,
|
||||
user_via_cb1_oe_n,
|
||||
user_via_cb2_in,
|
||||
open,
|
||||
open,
|
||||
user_via_pb_in,
|
||||
user_via_pb_out,
|
||||
user_via_pb_oe_n,
|
||||
mhz1_clken,
|
||||
reset_n,
|
||||
mhz4_clken,
|
||||
clock_32
|
||||
);
|
||||
system_via: work.via6522 port map (
|
||||
clock => clock_32,
|
||||
rising => mhz2_clken and mhz1_clken,
|
||||
falling => mhz2_clken and not mhz1_clken,
|
||||
reset => not reset_n,
|
||||
addr => cpu_a(3 downto 0),
|
||||
wen => sys_via_enable and not cpu_r_nw,
|
||||
ren => sys_via_enable and cpu_r_nw,
|
||||
data_in => cpu_do,
|
||||
data_out => sys_via_do,
|
||||
port_a_i => sys_via_pa_in,
|
||||
port_a_o => sys_via_pa_out,
|
||||
port_b_i => sys_via_pb_in,
|
||||
port_b_o => sys_via_pb_out,
|
||||
ca1_i => sys_via_ca1_in,
|
||||
ca2_i => sys_via_ca2_in,
|
||||
cb1_i => sys_via_cb1_in,
|
||||
cb2_i => sys_via_cb2_in,
|
||||
irq => sys_via_irq
|
||||
);
|
||||
|
||||
user_via : work.via6522 port map (
|
||||
clock => clock_32,
|
||||
rising => mhz2_clken and mhz1_clken,
|
||||
falling => mhz2_clken and not mhz1_clken,
|
||||
reset => not reset_n,
|
||||
addr => cpu_a(3 downto 0),
|
||||
wen => user_via_enable and not cpu_r_nw,
|
||||
ren => user_via_enable and cpu_r_nw,
|
||||
data_in => cpu_do,
|
||||
data_out => user_via_do,
|
||||
port_a_i => user_via_pa_in,
|
||||
port_a_o => user_via_pa_out,
|
||||
port_b_i => user_via_pb_in,
|
||||
port_b_o => user_via_pb_out,
|
||||
port_b_t => user_via_pb_oe,
|
||||
ca1_i => user_via_ca1_in,
|
||||
ca2_i => '0',
|
||||
cb1_i => user_via_cb1_in,
|
||||
cb1_o => user_via_cb1_out,
|
||||
cb1_t => user_via_cb1_oe,
|
||||
cb2_i => user_via_cb2_in,
|
||||
irq => user_via_irq
|
||||
);
|
||||
|
||||
-- Second VIA
|
||||
-- If this is included, it becomes the via at FE60 and the user via (above)
|
||||
-- is re-addressed to FE80
|
||||
GenMouse: if IncludeAMXMouse generate
|
||||
mouse_via : entity work.m6522 port map (
|
||||
cpu_a(3 downto 0),
|
||||
cpu_do,
|
||||
mouse_via_do,
|
||||
open,
|
||||
cpu_r_nw,
|
||||
mouse_via_enable,
|
||||
'0', -- nCS2
|
||||
mouse_via_irq_n,
|
||||
'0',
|
||||
'0',
|
||||
open,
|
||||
open,
|
||||
mouse_via_pa_in,
|
||||
mouse_via_pa_out,
|
||||
open,
|
||||
mouse_via_cb1_in,
|
||||
open,
|
||||
open,
|
||||
mouse_via_cb2_in,
|
||||
open,
|
||||
open,
|
||||
mouse_via_pb_in,
|
||||
open,
|
||||
open,
|
||||
mhz1_clken,
|
||||
reset_n,
|
||||
mhz4_clken,
|
||||
clock_32
|
||||
);
|
||||
mouse_via: work.via6522 port map (
|
||||
clock => clock_32,
|
||||
rising => mhz2_clken and mhz1_clken,
|
||||
falling => mhz2_clken and not mhz1_clken,
|
||||
reset => not reset_n,
|
||||
addr => cpu_a(3 downto 0),
|
||||
wen => mouse_via_enable and not cpu_r_nw,
|
||||
ren => mouse_via_enable and cpu_r_nw,
|
||||
data_in => cpu_do,
|
||||
data_out => mouse_via_do,
|
||||
port_a_i => mouse_via_pa_in,
|
||||
port_a_o => mouse_via_pa_out,
|
||||
port_b_i => mouse_via_pb_in,
|
||||
ca1_i => '0',
|
||||
ca2_i => '0',
|
||||
cb1_i => mouse_via_cb1_in,
|
||||
cb2_i => mouse_via_cb2_in,
|
||||
irq => mouse_via_irq
|
||||
);
|
||||
|
||||
-- BBC Micro User Port (Mouse use)
|
||||
-- 2 - CB1 - X Axis
|
||||
-- 6 - D0 - X Dir
|
||||
@@ -600,7 +572,7 @@ begin
|
||||
end generate;
|
||||
GenNotMouse: if not IncludeAMXMouse generate
|
||||
mouse_via_do <= x"FE";
|
||||
mouse_via_irq_n <= '1';
|
||||
mouse_via_irq <= '0';
|
||||
end generate;
|
||||
|
||||
-- PS/2 Keyboard
|
||||
@@ -1037,8 +1009,8 @@ begin
|
||||
"11111111" when io_fred = '1' or io_jim = '1' else
|
||||
(others => '0'); -- un-decoded locations are pulled down by RP1
|
||||
|
||||
cpu_irq_n <= not ((not sys_via_irq_n) or (not user_via_irq_n) or (not mouse_via_irq_n) or acc_irr) when m128_mode = '1' else
|
||||
not ((not sys_via_irq_n) or (not user_via_irq_n) or (not mouse_via_irq_n));
|
||||
cpu_irq_n <= not (sys_via_irq or user_via_irq or mouse_via_irq or acc_irr) when m128_mode = '1' else
|
||||
not (sys_via_irq or user_via_irq or mouse_via_irq);
|
||||
|
||||
-- Synchronous outputs to External Memory
|
||||
|
||||
@@ -1253,15 +1225,15 @@ begin
|
||||
-- MMBEEB
|
||||
|
||||
-- SDCLK is driven from either PB1 or CB1 depending on the SR Mode
|
||||
sdclk_int <= user_via_pb_out(1) when user_via_pb_oe_n(1) = '0' else
|
||||
user_via_cb1_out when user_via_cb1_oe_n = '0' else
|
||||
sdclk_int <= user_via_pb_out(1) when user_via_pb_oe(1) = '1' else
|
||||
user_via_cb1_out when user_via_cb1_oe = '1' else
|
||||
'1';
|
||||
|
||||
SDCLK <= sdclk_int;
|
||||
user_via_cb1_in <= sdclk_int;
|
||||
|
||||
-- SDMOSI is always driven from PB0
|
||||
SDMOSI <= user_via_pb_out(0) when user_via_pb_oe_n(0) = '0' else
|
||||
SDMOSI <= user_via_pb_out(0) when user_via_pb_oe(0) = '1' else
|
||||
'1';
|
||||
|
||||
-- SDMISO is always read from CB2
|
||||
|
||||
1019
rtl/m6522.vhd
1019
rtl/m6522.vhd
File diff suppressed because it is too large
Load Diff
706
rtl/via6522.vhd
Normal file
706
rtl/via6522.vhd
Normal file
@@ -0,0 +1,706 @@
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- (C) COPYRIGHT 2007-2017, Gideon's Logic Architectures
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-- Title : VIA 6522
|
||||
-------------------------------------------------------------------------------
|
||||
-- Author : Gideon Zweijtzer <gideon.zweijtzer@gmail.com>
|
||||
-------------------------------------------------------------------------------
|
||||
-- Description: This module implements the 6522 VIA chip.
|
||||
-- Please note: A LOT OF REVERSE ENGINEERING has been done to
|
||||
-- make this module as accurate as it is now. Please do not copy
|
||||
-- (use in your own projects) without written permission of the
|
||||
-- author.
|
||||
-------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.std_logic_arith.all;
|
||||
use ieee.std_logic_unsigned.all;
|
||||
|
||||
entity via6522 is
|
||||
port (
|
||||
clock : in std_logic;
|
||||
rising : in std_logic;
|
||||
falling : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
addr : in std_logic_vector(3 downto 0);
|
||||
wen : in std_logic;
|
||||
ren : in std_logic;
|
||||
data_in : in std_logic_vector(7 downto 0);
|
||||
data_out : out std_logic_vector(7 downto 0);
|
||||
|
||||
phi2_ref : out std_logic;
|
||||
|
||||
-- pio --
|
||||
port_a_o : out std_logic_vector(7 downto 0);
|
||||
port_a_t : out std_logic_vector(7 downto 0);
|
||||
port_a_i : in std_logic_vector(7 downto 0);
|
||||
|
||||
port_b_o : out std_logic_vector(7 downto 0);
|
||||
port_b_t : out std_logic_vector(7 downto 0);
|
||||
port_b_i : in std_logic_vector(7 downto 0);
|
||||
|
||||
-- handshake pins
|
||||
ca1_i : in std_logic;
|
||||
|
||||
ca2_o : out std_logic;
|
||||
ca2_i : in std_logic;
|
||||
ca2_t : out std_logic;
|
||||
|
||||
cb1_o : out std_logic;
|
||||
cb1_i : in std_logic;
|
||||
cb1_t : out std_logic;
|
||||
|
||||
cb2_o : out std_logic;
|
||||
cb2_i : in std_logic;
|
||||
cb2_t : out std_logic;
|
||||
|
||||
irq : out std_logic );
|
||||
|
||||
end via6522;
|
||||
|
||||
architecture Gideon of via6522 is
|
||||
|
||||
type pio_t is
|
||||
record
|
||||
pra : std_logic_vector(7 downto 0);
|
||||
ddra : std_logic_vector(7 downto 0);
|
||||
prb : std_logic_vector(7 downto 0);
|
||||
ddrb : std_logic_vector(7 downto 0);
|
||||
end record;
|
||||
|
||||
constant pio_default : pio_t := (others => (others => '0'));
|
||||
constant latch_reset_pattern : std_logic_vector(15 downto 0) := X"5550";
|
||||
|
||||
signal last_data : std_logic_vector(7 downto 0) := X"55";
|
||||
|
||||
signal pio_i : pio_t;
|
||||
signal port_a_c : std_logic_vector(7 downto 0) := (others => '0');
|
||||
signal port_b_c : std_logic_vector(7 downto 0) := (others => '0');
|
||||
|
||||
signal irq_mask : std_logic_vector(6 downto 0) := (others => '0');
|
||||
signal irq_flags : std_logic_vector(6 downto 0) := (others => '0');
|
||||
signal irq_events : std_logic_vector(6 downto 0) := (others => '0');
|
||||
signal irq_out : std_logic;
|
||||
|
||||
signal timer_a_latch : std_logic_vector(15 downto 0) := latch_reset_pattern;
|
||||
signal timer_b_latch : std_logic_vector(15 downto 0) := latch_reset_pattern;
|
||||
signal timer_a_count : std_logic_vector(15 downto 0) := latch_reset_pattern;
|
||||
signal timer_b_count : std_logic_vector(15 downto 0) := latch_reset_pattern;
|
||||
signal timer_a_out : std_logic;
|
||||
signal timer_b_tick : std_logic;
|
||||
|
||||
signal acr, pcr : std_logic_vector(7 downto 0) := X"00";
|
||||
signal shift_reg : std_logic_vector(7 downto 0) := X"00";
|
||||
signal serport_en : std_logic;
|
||||
signal ser_cb2_o : std_logic;
|
||||
signal hs_cb2_o : std_logic;
|
||||
signal cb1_t_int : std_logic;
|
||||
signal cb1_o_int : std_logic;
|
||||
signal cb2_t_int : std_logic;
|
||||
signal cb2_o_int : std_logic;
|
||||
|
||||
alias ca2_event : std_logic is irq_events(0);
|
||||
alias ca1_event : std_logic is irq_events(1);
|
||||
alias serial_event : std_logic is irq_events(2);
|
||||
alias cb2_event : std_logic is irq_events(3);
|
||||
alias cb1_event : std_logic is irq_events(4);
|
||||
alias timer_b_event : std_logic is irq_events(5);
|
||||
alias timer_a_event : std_logic is irq_events(6);
|
||||
|
||||
alias ca2_flag : std_logic is irq_flags(0);
|
||||
alias ca1_flag : std_logic is irq_flags(1);
|
||||
alias serial_flag : std_logic is irq_flags(2);
|
||||
alias cb2_flag : std_logic is irq_flags(3);
|
||||
alias cb1_flag : std_logic is irq_flags(4);
|
||||
alias timer_b_flag : std_logic is irq_flags(5);
|
||||
alias timer_a_flag : std_logic is irq_flags(6);
|
||||
|
||||
alias tmr_a_output_en : std_logic is acr(7);
|
||||
alias tmr_a_freerun : std_logic is acr(6);
|
||||
alias tmr_b_count_mode : std_logic is acr(5);
|
||||
alias shift_dir : std_logic is acr(4);
|
||||
alias shift_clk_sel : std_logic_vector(1 downto 0) is acr(3 downto 2);
|
||||
alias shift_mode_control : std_logic_vector(2 downto 0) is acr(4 downto 2);
|
||||
alias pb_latch_en : std_logic is acr(1);
|
||||
alias pa_latch_en : std_logic is acr(0);
|
||||
|
||||
alias cb2_is_output : std_logic is pcr(7);
|
||||
alias cb2_edge_select : std_logic is pcr(6); -- for when CB2 is input
|
||||
alias cb2_no_irq_clr : std_logic is pcr(5); -- for when CB2 is input
|
||||
alias cb2_out_mode : std_logic_vector(1 downto 0) is pcr(6 downto 5);
|
||||
alias cb1_edge_select : std_logic is pcr(4);
|
||||
|
||||
alias ca2_is_output : std_logic is pcr(3);
|
||||
alias ca2_edge_select : std_logic is pcr(2); -- for when CA2 is input
|
||||
alias ca2_no_irq_clr : std_logic is pcr(1); -- for when CA2 is input
|
||||
alias ca2_out_mode : std_logic_vector(1 downto 0) is pcr(2 downto 1);
|
||||
alias ca1_edge_select : std_logic is pcr(0);
|
||||
|
||||
signal ira, irb : std_logic_vector(7 downto 0) := (others => '0');
|
||||
|
||||
signal write_t1c_l : std_logic;
|
||||
signal write_t1c_h : std_logic;
|
||||
signal write_t2c_h : std_logic;
|
||||
|
||||
signal ca1_c, ca2_c : std_logic;
|
||||
signal cb1_c, cb2_c : std_logic;
|
||||
signal ca1_d, ca2_d : std_logic;
|
||||
signal cb1_d, cb2_d : std_logic;
|
||||
|
||||
signal ca2_handshake_o : std_logic;
|
||||
signal ca2_pulse_o : std_logic;
|
||||
signal cb2_handshake_o : std_logic;
|
||||
signal cb2_pulse_o : std_logic;
|
||||
signal shift_active : std_logic;
|
||||
begin
|
||||
irq <= irq_out;
|
||||
|
||||
write_t1c_l <= '1' when (addr = X"4" or addr = x"6") and wen='1' and falling = '1' else '0';
|
||||
write_t1c_h <= '1' when addr = X"5" and wen='1' and falling = '1' else '0';
|
||||
write_t2c_h <= '1' when addr = X"9" and wen='1' and falling = '1' else '0';
|
||||
|
||||
ca1_event <= (ca1_c xor ca1_d) and (ca1_d xor ca1_edge_select);
|
||||
ca2_event <= (ca2_c xor ca2_d) and (ca2_d xor ca2_edge_select);
|
||||
cb1_event <= (cb1_c xor cb1_d) and (cb1_d xor cb1_edge_select);
|
||||
cb2_event <= (cb2_c xor cb2_d) and (cb2_d xor cb2_edge_select);
|
||||
|
||||
ca2_t <= ca2_is_output;
|
||||
cb2_t_int <= cb2_is_output when serport_en='0' else shift_dir;
|
||||
cb2_o_int <= hs_cb2_o when serport_en='0' else ser_cb2_o;
|
||||
|
||||
cb1_t <= cb1_t_int;
|
||||
cb1_o <= cb1_o_int;
|
||||
cb2_t <= cb2_t_int;
|
||||
cb2_o <= cb2_o_int;
|
||||
|
||||
with ca2_out_mode select ca2_o <=
|
||||
ca2_handshake_o when "00",
|
||||
ca2_pulse_o when "01",
|
||||
'0' when "10",
|
||||
'1' when others;
|
||||
|
||||
with cb2_out_mode select hs_cb2_o <=
|
||||
cb2_handshake_o when "00",
|
||||
cb2_pulse_o when "01",
|
||||
'0' when "10",
|
||||
'1' when others;
|
||||
|
||||
process(irq_flags, irq_mask)
|
||||
begin
|
||||
if (irq_flags and irq_mask) = "0000000" then
|
||||
irq_out <= '0';
|
||||
else
|
||||
irq_out <= '1';
|
||||
end if;
|
||||
end process;
|
||||
|
||||
process(clock)
|
||||
begin
|
||||
if rising_edge(clock) then
|
||||
if rising = '1' then
|
||||
phi2_ref <= '1';
|
||||
elsif falling = '1' then
|
||||
phi2_ref <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
process(clock)
|
||||
begin
|
||||
if rising_edge(clock) then
|
||||
-- CA1/CA2/CB1/CB2 edge detect flipflops
|
||||
ca1_c <= To_X01(ca1_i);
|
||||
ca2_c <= To_X01(ca2_i);
|
||||
if cb1_t_int = '0' then
|
||||
cb1_c <= To_X01(cb1_i);
|
||||
else
|
||||
cb1_c <= cb1_o_int;
|
||||
end if;
|
||||
if cb2_t_int = '0' then
|
||||
cb2_c <= To_X01(cb2_i);
|
||||
else
|
||||
cb2_c <= cb2_o_int;
|
||||
end if;
|
||||
|
||||
ca1_d <= ca1_c;
|
||||
ca2_d <= ca2_c;
|
||||
cb1_d <= cb1_c;
|
||||
cb2_d <= cb2_c;
|
||||
|
||||
-- input registers
|
||||
port_a_c <= port_a_i;
|
||||
port_b_c <= port_b_i;
|
||||
|
||||
-- input latch emulation
|
||||
if pa_latch_en = '0' or ca1_event = '1' then
|
||||
ira <= port_a_c;
|
||||
end if;
|
||||
|
||||
if pb_latch_en = '0' or cb1_event = '1' then
|
||||
irb <= port_b_c;
|
||||
end if;
|
||||
|
||||
-- CA2 logic
|
||||
if ca1_event = '1' then
|
||||
ca2_handshake_o <= '1';
|
||||
elsif (ren = '1' or wen = '1') and addr = X"1" and falling = '1' then
|
||||
ca2_handshake_o <= '0';
|
||||
end if;
|
||||
|
||||
if falling = '1' then
|
||||
if (ren = '1' or wen = '1') and addr = X"1" then
|
||||
ca2_pulse_o <= '0';
|
||||
else
|
||||
ca2_pulse_o <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- CB2 logic
|
||||
if cb1_event = '1' then
|
||||
cb2_handshake_o <= '1';
|
||||
elsif (ren = '1' or wen = '1') and addr = X"0" and falling = '1' then
|
||||
cb2_handshake_o <= '0';
|
||||
end if;
|
||||
|
||||
if falling = '1' then
|
||||
if (ren = '1' or wen = '1') and addr = X"0" then
|
||||
cb2_pulse_o <= '0';
|
||||
else
|
||||
cb2_pulse_o <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Interrupt logic
|
||||
irq_flags <= irq_flags or irq_events;
|
||||
|
||||
-- Writes --
|
||||
if wen='1' and falling = '1' then
|
||||
last_data <= data_in;
|
||||
case addr is
|
||||
when X"0" => -- ORB
|
||||
pio_i.prb <= data_in;
|
||||
if cb2_no_irq_clr='0' then
|
||||
cb2_flag <= '0';
|
||||
end if;
|
||||
cb1_flag <= '0';
|
||||
|
||||
when X"1" => -- ORA
|
||||
pio_i.pra <= data_in;
|
||||
if ca2_no_irq_clr='0' then
|
||||
ca2_flag <= '0';
|
||||
end if;
|
||||
ca1_flag <= '0';
|
||||
|
||||
when X"2" => -- DDRB
|
||||
pio_i.ddrb <= data_in;
|
||||
|
||||
when X"3" => -- DDRA
|
||||
pio_i.ddra <= data_in;
|
||||
|
||||
when X"4" => -- TA LO counter (write=latch)
|
||||
timer_a_latch(7 downto 0) <= data_in;
|
||||
|
||||
when X"5" => -- TA HI counter
|
||||
timer_a_latch(15 downto 8) <= data_in;
|
||||
timer_a_flag <= '0';
|
||||
|
||||
when X"6" => -- TA LO latch
|
||||
timer_a_latch(7 downto 0) <= data_in;
|
||||
|
||||
when X"7" => -- TA HI latch
|
||||
timer_a_latch(15 downto 8) <= data_in;
|
||||
timer_a_flag <= '0';
|
||||
|
||||
when X"8" => -- TB LO latch
|
||||
timer_b_latch(7 downto 0) <= data_in;
|
||||
|
||||
when X"9" => -- TB HI counter
|
||||
timer_b_flag <= '0';
|
||||
|
||||
when X"A" => -- Serial port
|
||||
serial_flag <= '0';
|
||||
|
||||
when X"B" => -- ACR (Auxiliary Control Register)
|
||||
acr <= data_in;
|
||||
|
||||
when X"C" => -- PCR (Peripheral Control Register)
|
||||
pcr <= data_in;
|
||||
|
||||
when X"D" => -- IFR
|
||||
irq_flags <= irq_flags and not data_in(6 downto 0);
|
||||
|
||||
when X"E" => -- IER
|
||||
if data_in(7)='1' then -- set
|
||||
irq_mask <= irq_mask or data_in(6 downto 0);
|
||||
else -- clear
|
||||
irq_mask <= irq_mask and not data_in(6 downto 0);
|
||||
end if;
|
||||
|
||||
when X"F" => -- ORA no handshake
|
||||
pio_i.pra <= data_in;
|
||||
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end if;
|
||||
|
||||
-- Reads - Output only --
|
||||
data_out <= X"00";
|
||||
case addr is
|
||||
when X"0" => -- ORB
|
||||
--Port B reads its own output register for pins set to output.
|
||||
data_out <= (pio_i.prb and pio_i.ddrb) or (irb and not pio_i.ddrb);
|
||||
if tmr_a_output_en='1' then
|
||||
data_out(7) <= timer_a_out;
|
||||
end if;
|
||||
when X"1" => -- ORA
|
||||
data_out <= ira;
|
||||
when X"2" => -- DDRB
|
||||
data_out <= pio_i.ddrb;
|
||||
when X"3" => -- DDRA
|
||||
data_out <= pio_i.ddra;
|
||||
when X"4" => -- TA LO counter
|
||||
data_out <= timer_a_count(7 downto 0);
|
||||
when X"5" => -- TA HI counter
|
||||
data_out <= timer_a_count(15 downto 8);
|
||||
when X"6" => -- TA LO latch
|
||||
data_out <= timer_a_latch(7 downto 0);
|
||||
when X"7" => -- TA HI latch
|
||||
data_out <= timer_a_latch(15 downto 8);
|
||||
when X"8" => -- TA LO counter
|
||||
data_out <= timer_b_count(7 downto 0);
|
||||
when X"9" => -- TA HI counter
|
||||
data_out <= timer_b_count(15 downto 8);
|
||||
when X"A" => -- SR
|
||||
data_out <= shift_reg;
|
||||
when X"B" => -- ACR
|
||||
data_out <= acr;
|
||||
when X"C" => -- PCR
|
||||
data_out <= pcr;
|
||||
when X"D" => -- IFR
|
||||
data_out <= irq_out & irq_flags;
|
||||
when X"E" => -- IER
|
||||
data_out <= '0' & irq_mask;
|
||||
when X"F" => -- ORA
|
||||
data_out <= ira;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
|
||||
-- Read actions --
|
||||
if ren = '1' and falling = '1' then
|
||||
case addr is
|
||||
when X"0" => -- ORB
|
||||
if cb2_no_irq_clr='0' then
|
||||
cb2_flag <= '0';
|
||||
end if;
|
||||
cb1_flag <= '0';
|
||||
|
||||
when X"1" => -- ORA
|
||||
if ca2_no_irq_clr='0' then
|
||||
ca2_flag <= '0';
|
||||
end if;
|
||||
ca1_flag <= '0';
|
||||
|
||||
when X"4" => -- TA LO counter
|
||||
timer_a_flag <= '0';
|
||||
|
||||
when X"8" => -- TB LO counter
|
||||
timer_b_flag <= '0';
|
||||
|
||||
when X"A" => -- SR
|
||||
serial_flag <= '0';
|
||||
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end if;
|
||||
|
||||
if reset='1' then
|
||||
pio_i <= pio_default;
|
||||
irq_mask <= (others => '0');
|
||||
irq_flags <= (others => '0');
|
||||
acr <= (others => '0');
|
||||
pcr <= (others => '0');
|
||||
ca2_handshake_o <= '1';
|
||||
ca2_pulse_o <= '1';
|
||||
cb2_handshake_o <= '1';
|
||||
cb2_pulse_o <= '1';
|
||||
timer_a_latch <= latch_reset_pattern;
|
||||
timer_b_latch <= latch_reset_pattern;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- PIO Out select --
|
||||
port_a_o <= pio_i.pra;
|
||||
port_b_o(6 downto 0) <= pio_i.prb(6 downto 0);
|
||||
port_b_o(7) <= pio_i.prb(7) when tmr_a_output_en='0' else timer_a_out;
|
||||
|
||||
port_a_t <= pio_i.ddra;
|
||||
port_b_t(6 downto 0) <= pio_i.ddrb(6 downto 0);
|
||||
port_b_t(7) <= pio_i.ddrb(7) or tmr_a_output_en;
|
||||
|
||||
|
||||
-- Timer A
|
||||
tmr_a: block
|
||||
signal timer_a_reload : std_logic;
|
||||
signal timer_a_toggle : std_logic;
|
||||
signal timer_a_may_interrupt : std_logic;
|
||||
begin
|
||||
process(clock)
|
||||
begin
|
||||
if rising_edge(clock) then
|
||||
if falling = '1' then
|
||||
-- always count, or load
|
||||
|
||||
if timer_a_reload = '1' then
|
||||
timer_a_count <= timer_a_latch;
|
||||
if write_t1c_l = '1' then
|
||||
timer_a_count(7 downto 0) <= data_in;
|
||||
end if;
|
||||
timer_a_reload <= '0';
|
||||
timer_a_may_interrupt <= timer_a_may_interrupt and tmr_a_freerun;
|
||||
else
|
||||
if timer_a_count = X"0000" then
|
||||
-- generate an event if we were triggered
|
||||
timer_a_reload <= '1';
|
||||
end if;
|
||||
--Timer coutinues to count in both free run and one shot.
|
||||
timer_a_count <= timer_a_count - X"0001";
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if rising = '1' then
|
||||
if timer_a_event = '1' and tmr_a_output_en = '1' then
|
||||
timer_a_toggle <= not timer_a_toggle;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if write_t1c_h = '1' then
|
||||
timer_a_may_interrupt <= '1';
|
||||
timer_a_toggle <= not tmr_a_output_en;
|
||||
timer_a_count <= data_in & timer_a_latch(7 downto 0);
|
||||
timer_a_reload <= '0';
|
||||
end if;
|
||||
|
||||
if reset='1' then
|
||||
timer_a_may_interrupt <= '0';
|
||||
timer_a_toggle <= '1';
|
||||
timer_a_count <= latch_reset_pattern;
|
||||
timer_a_reload <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
timer_a_out <= timer_a_toggle;
|
||||
timer_a_event <= rising and timer_a_reload and timer_a_may_interrupt;
|
||||
|
||||
end block tmr_a;
|
||||
|
||||
-- Timer B
|
||||
tmr_b: block
|
||||
signal timer_b_reload_lo : std_logic;
|
||||
signal timer_b_oneshot_trig : std_logic;
|
||||
signal timer_b_timeout : std_logic;
|
||||
signal pb6_c, pb6_d : std_logic;
|
||||
begin
|
||||
process(clock)
|
||||
variable timer_b_decrement : std_logic;
|
||||
begin
|
||||
if rising_edge(clock) then
|
||||
timer_b_decrement := '0';
|
||||
|
||||
if rising = '1' then
|
||||
pb6_c <= To_X01(port_b_i(6));
|
||||
pb6_d <= pb6_c;
|
||||
end if;
|
||||
|
||||
if falling = '1' then
|
||||
timer_b_timeout <= '0';
|
||||
timer_b_tick <= '0';
|
||||
|
||||
if tmr_b_count_mode = '1' then
|
||||
if (pb6_d='1' and pb6_c='0') then
|
||||
timer_b_decrement := '1';
|
||||
end if;
|
||||
else -- one shot or used for shift register
|
||||
timer_b_decrement := '1';
|
||||
end if;
|
||||
|
||||
if timer_b_decrement = '1' then
|
||||
if timer_b_count = X"0000" then
|
||||
if timer_b_oneshot_trig = '1' then
|
||||
timer_b_oneshot_trig <= '0';
|
||||
timer_b_timeout <= '1';
|
||||
end if;
|
||||
end if;
|
||||
if timer_b_count(7 downto 0) = X"00" then
|
||||
case shift_mode_control is
|
||||
when "001" | "101" | "100" =>
|
||||
timer_b_reload_lo <= '1';
|
||||
timer_b_tick <= '1';
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end if;
|
||||
timer_b_count <= timer_b_count - X"0001";
|
||||
end if;
|
||||
if timer_b_reload_lo = '1' then
|
||||
timer_b_count(7 downto 0) <= timer_b_latch(7 downto 0);
|
||||
timer_b_reload_lo <= '0';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if write_t2c_h = '1' then
|
||||
timer_b_count <= data_in & timer_b_latch(7 downto 0);
|
||||
timer_b_oneshot_trig <= '1';
|
||||
end if;
|
||||
|
||||
if reset='1' then
|
||||
timer_b_count <= latch_reset_pattern;
|
||||
timer_b_reload_lo <= '0';
|
||||
timer_b_oneshot_trig <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
timer_b_event <= rising and timer_b_timeout;
|
||||
|
||||
end block tmr_b;
|
||||
|
||||
ser: block
|
||||
signal trigger_serial: std_logic;
|
||||
signal shift_clock_d : std_logic;
|
||||
signal shift_clock : std_logic;
|
||||
signal shift_tick_r : std_logic;
|
||||
signal shift_tick_f : std_logic;
|
||||
signal shift_timer_tick : std_logic;
|
||||
signal cb2_c : std_logic := '0';
|
||||
signal bit_cnt : integer range 0 to 7;
|
||||
signal shift_pulse : std_logic;
|
||||
begin
|
||||
process(shift_active, timer_b_tick, shift_clk_sel, shift_clock, shift_clock_d, shift_timer_tick)
|
||||
begin
|
||||
case shift_clk_sel is
|
||||
when "10" =>
|
||||
shift_pulse <= '1';
|
||||
|
||||
when "00"|"01" =>
|
||||
shift_pulse <= shift_timer_tick;
|
||||
|
||||
when others =>
|
||||
shift_pulse <= shift_clock and not shift_clock_d;
|
||||
|
||||
end case;
|
||||
|
||||
if shift_active = '0' then
|
||||
-- Mode 0 still loads the shift register to external pulse (MMBEEB SD-Card interface uses this)
|
||||
if shift_mode_control = "000" then
|
||||
shift_pulse <= shift_clock and not shift_clock_d;
|
||||
else
|
||||
shift_pulse <= '0';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end process;
|
||||
|
||||
|
||||
process(clock)
|
||||
begin
|
||||
if rising_edge(clock) then
|
||||
|
||||
cb2_c <= To_X01(cb2_i);
|
||||
|
||||
if rising = '1' then
|
||||
|
||||
if shift_active='0' then
|
||||
if shift_mode_control = "000" then
|
||||
shift_clock <= To_X01(cb1_i);
|
||||
else
|
||||
shift_clock <= '1';
|
||||
end if;
|
||||
elsif shift_clk_sel = "11" then
|
||||
shift_clock <= To_X01(cb1_i);
|
||||
elsif shift_pulse = '1' then
|
||||
shift_clock <= not shift_clock;
|
||||
end if;
|
||||
|
||||
shift_clock_d <= shift_clock;
|
||||
|
||||
end if;
|
||||
|
||||
if falling = '1' then
|
||||
shift_timer_tick <= timer_b_tick;
|
||||
end if;
|
||||
|
||||
if reset = '1' then
|
||||
shift_clock <= '1';
|
||||
shift_clock_d <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cb1_t_int <= '0' when shift_clk_sel="11" else serport_en;
|
||||
cb1_o_int <= shift_clock_d;
|
||||
ser_cb2_o <= shift_reg(7);
|
||||
|
||||
serport_en <= shift_dir or shift_clk_sel(1) or shift_clk_sel(0);
|
||||
trigger_serial <= '1' when (ren='1' or wen='1') and addr=x"A" else '0';
|
||||
shift_tick_r <= not shift_clock_d and shift_clock;
|
||||
shift_tick_f <= shift_clock_d and not shift_clock;
|
||||
|
||||
process(clock)
|
||||
begin
|
||||
if rising_edge(clock) then
|
||||
if reset = '1' then
|
||||
shift_reg <= X"FF";
|
||||
elsif falling = '1' then
|
||||
if wen = '1' and addr = X"A" then
|
||||
shift_reg <= data_in;
|
||||
elsif shift_dir='1' and shift_tick_f = '1' then -- output
|
||||
shift_reg <= shift_reg(6 downto 0) & shift_reg(7);
|
||||
elsif shift_dir='0' and shift_tick_r = '1' then -- input
|
||||
shift_reg <= shift_reg(6 downto 0) & cb2_c;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- tell people that we're ready!
|
||||
serial_event <= shift_tick_r and not shift_active and rising and serport_en;
|
||||
|
||||
process(clock)
|
||||
begin
|
||||
if rising_edge(clock) then
|
||||
if falling = '1' then
|
||||
if shift_active = '0' and shift_mode_control /= "000" then
|
||||
if trigger_serial = '1' then
|
||||
bit_cnt <= 7;
|
||||
shift_active <= '1';
|
||||
end if;
|
||||
else -- we're active
|
||||
if shift_clk_sel = "00" then
|
||||
shift_active <= shift_dir; -- when '1' we're active, but for mode 000 we go inactive.
|
||||
elsif shift_pulse = '1' and shift_clock = '1' then
|
||||
if bit_cnt = 0 then
|
||||
shift_active <= '0';
|
||||
else
|
||||
bit_cnt <= bit_cnt - 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if reset='1' then
|
||||
shift_active <= '0';
|
||||
bit_cnt <= 0;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end block ser;
|
||||
end Gideon;
|
||||
Reference in New Issue
Block a user