📄 cia6526.vhd
字号:
tod_running <= '0';
end if;
end if;
end process;
-- Control TOD output latch
-- Reading the hours latches the output until
-- the 10ths of seconds are read. While latched the
-- clock continues to run in the bankground.
process(clk)
begin
if rising_edge(clk) then
if myRd = '1' then
case addr is
when X"8" => tod_latched <= '0';
when X"B" => tod_latched <= '1';
when others => null;
end case;
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Timer A and B
-- -----------------------------------------------------------------------
process(clk)
variable newTimerA : unsigned(15 downto 0);
variable nextClkTimerA : std_logic;
variable timerBInput : std_logic;
variable newTimerB : unsigned(15 downto 0);
variable nextClkTimerB : std_logic;
variable new_cra_runmode : std_logic;
variable new_crb_runmode : std_logic;
begin
if rising_edge(clk) then
loadTimerA <= '0';
loadTimerB <= '0';
new_cra_runmode := cra_runmode;
new_crb_runmode := crb_runmode;
if resetIrq then
intr_timerA <= '0';
intr_timerB <= '0';
end if;
if myWr = '1' then
case addr is
when X"4" =>
talo <= di;
when X"5" =>
tahi <= di;
if cra_start = '0' then
loadTimerA <= '1';
end if;
when X"6" =>
tblo <= di;
when X"7" =>
tbhi <= di;
if crb_start = '0' then
loadTimerB <= '1';
end if;
when X"E" =>
if cra_start = '0' then
-- Only set on rising edge
timerAToggle <= timerAToggle or di(0);
end if;
cra_start <= di(0);
new_cra_runmode := di(3);
when X"F" =>
if crb_start = '0' then
-- Only set on rising edge
timerBToggle <= timerBToggle or di(0);
end if;
crb_start <= di(0);
new_crb_runmode := di(3);
when others => null;
end case;
end if;
if reset = '1' then
new_cra_runmode := '0';
new_crb_runmode := '0';
end if;
cra_runmode <= new_cra_runmode;
crb_runmode <= new_crb_runmode;
if enable = '1' then
--
-- process timer A
--
timerAPulse <= '0';
newTimerA := timerA;
-- CNT is not emulated so don't count when inmode = 1
nextClkTimerA := cra_start and (not cra_inmode);
if clkTimerA = '1' then
newTimerA := newTimerA - 1;
end if;
if nextClkTimerA = '1'
and newTimerA = 0 then
intr_timerA <= '1';
loadTimerA <= '1';
timerAPulse <= '1';
timerAToggle <= not timerAToggle;
if (new_cra_runmode or cra_runmode) = '1' then
cra_start <= '0';
end if;
end if;
if forceTimerA = '1' then
loadTimerA <= '1';
end if;
clkTimerA <= nextClkTimerA;
timerA <= newTimerA;
--
-- process timer B
--
timerBPulse <= '0';
newTimerB := timerB;
if crb_inmode6 = '1' then
-- count timerA underflows
timerBInput := timerAPulse;
elsif crb_inmode5 = '0' then
-- count clock pulses
timerBInput := '1';
else
-- CNT is not emulated so don't count
timerBInput := '0';
end if;
nextClkTimerB := timerBInput and crb_start;
if clkTimerB = '1' then
newTimerB := newTimerB - 1;
end if;
if nextClkTimerB = '1'
and newTimerB = 0 then
intr_timerB <= '1';
loadTimerB <= '1';
timerBPulse <= '1';
timerBToggle <= not timerBToggle;
if (new_crb_runmode or crb_runmode) = '1' then
crb_start <= '0';
end if;
end if;
if forceTimerB = '1' then
loadTimerB <= '1';
end if;
clkTimerB <= nextClkTimerB;
timerB <= newTimerB;
end if;
if loadTimerA = '1' then
timerA <= tahi & talo;
clkTimerA <= '0';
end if;
if loadTimerB = '1' then
timerB <= tbhi & tblo;
clkTimerB <= '0';
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Interrupts
-- -----------------------------------------------------------------------
resetIrq <= ((myRd = '1') and (addr = X"D")) or (reset = '1');
irq_n <= not(ir);
intr_serial <= '0';
process(clk)
begin
if rising_edge(clk) then
if enable = '1' then
ir <= ir
or (intr_timerA and mask_timerA)
or (intr_timerB and mask_timerB)
or (intr_serial and mask_serial)
or (intr_flagn and mask_flagn);
end if;
if myWr = '1' then
case addr is
when X"D" =>
if di(7) ='0' then
mask_timerA <= mask_timerA and (not di(0));
mask_timerB <= mask_timerB and (not di(1));
mask_serial <= mask_serial and (not di(3));
mask_flagn <= mask_flagn and (not di(4));
else
mask_timerA <= mask_timerA or di(0);
mask_timerB <= mask_timerB or di(1);
mask_serial <= mask_serial or di(3);
mask_flagn <= mask_flagn or di(4);
end if;
when others =>
null;
end case;
end if;
if resetIrq then
ir <= '0';
end if;
if reset = '1' then
mask_timerA <= '0';
mask_timerB <= '0';
mask_serial <= '0';
mask_flagn <= '0';
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- FLAG_N input
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
prevFlag_n <= flag_n;
if (flag_n = '0') and (prevFlag_n = '1') then
intr_flagn <= '1';
end if;
if resetIrq then
intr_flagn <= '0';
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Write registers
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
-- resetIrq <= '0';
if enable = '1' then
forceTimerA <= '0';
forceTimerB <= '0';
-- cra_runmode_reg <= cra_runmode;
-- crb_runmode_reg <= crb_runmode;
end if;
if myWr = '1' then
case addr is
when X"E" =>
cra_pbon <= di(1);
cra_outmode <= di(2);
-- cra_runmode <= di(3);
forceTimerA <= di(4);
cra_inmode <= di(5);
cra_spmode <= di(6);
cra_todin <= di(7);
when X"F" =>
crb_pbon <= di(1);
crb_outmode <= di(2);
-- crb_runmode <= di(3);
forceTimerB <= di(4);
crb_inmode5 <= di(5);
crb_inmode6 <= di(6);
crb_alarm <= di(7);
when others => null;
end case;
end if;
if reset = '1' then
cra_pbon <= '0';
cra_outmode <= '0';
-- cra_runmode <= '0';
cra_inmode <= '0';
cra_spmode <= '0';
cra_todin <= '0';
crb_pbon <= '0';
crb_outmode <= '0';
-- crb_runmode <= '0';
crb_inmode5 <= '0';
crb_inmode6 <= '0';
crb_alarm <= '0';
end if;
end if;
end process;
-- -----------------------------------------------------------------------
-- Read registers
-- -----------------------------------------------------------------------
process(clk)
begin
if rising_edge(clk) then
case addr is
when X"0" => do <= ppai;
when X"1" => do <= ppbi;
when X"2" => do <= DDRA;
when X"3" => do <= DDRB;
when X"4" => do <= timera(7 downto 0);
when X"5" => do <= timera(15 downto 8);
when X"6" => do <= timerb(7 downto 0);
when X"7" => do <= timerb(15 downto 8);
when X"8" => do <= "0000" & tod_latch_10ths;
when X"9" => do <= "0" & tod_latch_secs;
when X"A" => do <= "0" & tod_latch_mins;
when X"B" => do <= tod_latch_pm & "00" & tod_latch_hrs;
when X"C" => do <= (others => '0');
when X"D" => do <= ir & "00" & intr_flagn & intr_serial & "0" & intr_timerB & intr_timerA;
when X"E" => do <= cra_todin & cra_spmode & cra_inmode & '0' & cra_runmode & cra_outmode & cra_pbon & cra_start;
when X"F" => do <= crb_alarm & crb_inmode6 & crb_inmode5 & '0' & crb_runmode & crb_outmode & crb_pbon & crb_start;
when others => do <= (others => '-');
end case;
end if;
end process;
end Behavioral;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -