mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-06 16:14:42 +00:00
[C64] Update CIA to Rayne's version
This commit is contained in:
@@ -156,7 +156,7 @@ set_global_assignment -name RESERVE_DCLK_AFTER_CONFIGURATION "USE AS REGULAR IO"
|
||||
set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO"
|
||||
set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS"
|
||||
set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON
|
||||
set_global_assignment -name FITTER_EFFORT "STANDARD FIT"
|
||||
set_global_assignment -name FITTER_EFFORT "AUTO FIT"
|
||||
|
||||
# Assembler Assignments
|
||||
# =====================
|
||||
@@ -337,7 +337,8 @@ set_global_assignment -name VHDL_FILE rtl/fpga64_rgbcolor.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/fpga64_keyboard_matrix_mark_mcdougall.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/fpga64_bustiming.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/fpga64_buslogic_roms_mmu.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/cia6526.vhd
|
||||
set_global_assignment -name VERILOG_FILE rtl/mos6526.v
|
||||
set_global_assignment -name VHDL_FILE rtl/mos6526.vhd
|
||||
set_global_assignment -name VHDL_FILE rtl/cpu_6510.vhd
|
||||
set_global_assignment -name VERILOG_FILE rtl/cartridge.v
|
||||
set_global_assignment -name VHDL_FILE rtl/rom_c64_chargen.vhd
|
||||
|
||||
@@ -1,753 +0,0 @@
|
||||
-- -----------------------------------------------------------------------
|
||||
--
|
||||
-- FPGA 64
|
||||
--
|
||||
-- A fully functional commodore 64 implementation in a single FPGA
|
||||
--
|
||||
-- -----------------------------------------------------------------------
|
||||
-- Peter Wendrich (pwsoft@syntiac.com)
|
||||
-- http://www.syntiac.com/fpga64.html
|
||||
-- -----------------------------------------------------------------------
|
||||
--
|
||||
-- 6526 Complex Interface Adapter
|
||||
--
|
||||
-- rev 1 - june17 / TOD alarms
|
||||
-- -----------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.ALL;
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
|
||||
entity cia6526 is
|
||||
generic (
|
||||
todEnabled : std_logic := '1'
|
||||
);
|
||||
port (
|
||||
clk: in std_logic;
|
||||
todClk: in std_logic;
|
||||
reset: in std_logic;
|
||||
enable: in std_logic;
|
||||
cs: in std_logic;
|
||||
we: in std_logic; -- Write strobe
|
||||
rd: in std_logic; -- Read strobe
|
||||
|
||||
addr: in unsigned(3 downto 0);
|
||||
di: in unsigned(7 downto 0);
|
||||
do: out unsigned(7 downto 0);
|
||||
|
||||
ppai: in unsigned(7 downto 0);
|
||||
ppao: out unsigned(7 downto 0);
|
||||
ppad: out unsigned(7 downto 0);
|
||||
|
||||
ppbi: in unsigned(7 downto 0);
|
||||
ppbo: out unsigned(7 downto 0);
|
||||
ppbd: out unsigned(7 downto 0);
|
||||
|
||||
flag_n: in std_logic;
|
||||
|
||||
irq_n: out std_logic
|
||||
);
|
||||
end cia6526;
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
|
||||
architecture Behavioral of cia6526 is
|
||||
-- IO ports
|
||||
signal pra: unsigned(7 downto 0);
|
||||
signal prb: unsigned(7 downto 0);
|
||||
signal ddra: unsigned(7 downto 0);
|
||||
signal ddrb: unsigned(7 downto 0);
|
||||
|
||||
-- Timer to IO ports
|
||||
signal timerAPulse : std_logic;
|
||||
signal timerAToggle : std_logic;
|
||||
signal timerBPulse : std_logic;
|
||||
signal timerBToggle : std_logic;
|
||||
|
||||
-- Timer A reload registers
|
||||
signal talo: unsigned(7 downto 0) := (others => '1');
|
||||
signal tahi: unsigned(7 downto 0) := (others => '1');
|
||||
|
||||
-- Timer B reload registers
|
||||
signal tblo: unsigned(7 downto 0) := (others => '1');
|
||||
signal tbhi: unsigned(7 downto 0) := (others => '1');
|
||||
|
||||
-- Timer A and B internal registers
|
||||
signal timerA : unsigned(15 downto 0);
|
||||
signal forceTimerA : std_logic;
|
||||
signal loadTimerA : std_logic;
|
||||
signal nextClkTimerA : std_logic;
|
||||
signal clkTimerA : std_logic; -- internal timer clock
|
||||
|
||||
signal timerB: unsigned(15 downto 0);
|
||||
signal forceTimerB : std_logic;
|
||||
signal loadTimerB : std_logic;
|
||||
signal nextClkTimerB : std_logic;
|
||||
signal clkTimerB : std_logic; -- internal timer clock
|
||||
|
||||
-- Config register A
|
||||
signal cra_start : std_logic;
|
||||
signal cra_pbon : std_logic;
|
||||
signal cra_outmode : std_logic;
|
||||
signal cra_runmode : std_logic;
|
||||
signal cra_runmode_reg : std_logic;
|
||||
signal cra_inmode : std_logic;
|
||||
signal cra_spmode : std_logic;
|
||||
signal cra_todin : std_logic;
|
||||
|
||||
-- Config register B
|
||||
signal crb_start : std_logic;
|
||||
signal crb_pbon : std_logic;
|
||||
signal crb_outmode : std_logic;
|
||||
signal crb_runmode : std_logic;
|
||||
signal crb_runmode_reg : std_logic;
|
||||
signal crb_inmode5 : std_logic;
|
||||
signal crb_inmode6 : std_logic;
|
||||
signal crb_alarm : std_logic;
|
||||
|
||||
-- TOD 50/60 hz clock
|
||||
signal todTick : std_logic;
|
||||
signal oldTodClk : std_logic;
|
||||
signal tod_clkcnt: unsigned(2 downto 0);
|
||||
|
||||
-- TOD counters
|
||||
signal tod_running: std_logic;
|
||||
signal tod_10ths: unsigned(3 downto 0);
|
||||
signal tod_secs: unsigned(6 downto 0);
|
||||
signal tod_mins: unsigned(6 downto 0);
|
||||
signal tod_hrs: unsigned(7 downto 0);
|
||||
signal tod_pm: std_logic;
|
||||
|
||||
-- TOD latches
|
||||
signal tod_latched: std_logic;
|
||||
signal tod_latch_10ths: unsigned(3 downto 0);
|
||||
signal tod_latch_secs: unsigned(6 downto 0);
|
||||
signal tod_latch_mins: unsigned(6 downto 0);
|
||||
signal tod_latch_hrs: unsigned(7 downto 0);
|
||||
constant tod_latch_pm: std_logic := '0';
|
||||
|
||||
-- TOD alarms - LCA
|
||||
signal tod_10ths_alarm: unsigned(3 downto 0);
|
||||
signal tod_secs_alarm: unsigned(6 downto 0);
|
||||
signal tod_mins_alarm: unsigned(6 downto 0);
|
||||
signal tod_hrs_alarm: unsigned(7 downto 0);
|
||||
signal tod_pm_alarm: std_logic;
|
||||
|
||||
-- Interrupt processing
|
||||
signal resetIrq : boolean;
|
||||
signal intr_flagn : std_logic;
|
||||
signal intr_serial : std_logic;
|
||||
signal intr_alarm : std_logic; -- LCA
|
||||
signal intr_timerA : std_logic;
|
||||
signal intr_timerB : std_logic;
|
||||
signal mask_timerA : std_logic;
|
||||
signal mask_timerB : std_logic;
|
||||
signal mask_alarm : std_logic; -- LCA
|
||||
signal mask_serial : std_logic;
|
||||
signal mask_flagn : std_logic;
|
||||
signal ir: std_logic;
|
||||
|
||||
signal prevFlag_n: std_logic;
|
||||
|
||||
signal myWr : std_logic;
|
||||
signal myRd : std_logic;
|
||||
begin
|
||||
-- -----------------------------------------------------------------------
|
||||
-- chip-select signals
|
||||
-- -----------------------------------------------------------------------
|
||||
myWr <= cs and we;
|
||||
myRd <= cs and rd;
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
-- I/O ports
|
||||
-- -----------------------------------------------------------------------
|
||||
-- Port A
|
||||
process(pra, ddra)
|
||||
begin
|
||||
ppad <= ddra;
|
||||
ppao <= pra or (not ddra);
|
||||
end process;
|
||||
|
||||
-- Port B
|
||||
process(prb, ddrb, cra_pbon, cra_outmode, crb_pbon, crb_outmode, timerAPulse, timerAToggle, timerBPulse, timerBToggle)
|
||||
begin
|
||||
ppbd <= ddrb;
|
||||
ppbo <= prb or (not ddrb);
|
||||
if cra_pbon = '1' then
|
||||
ppbo(6) <= timerAPulse;
|
||||
if cra_outmode = '1' then
|
||||
ppbo(6) <= timerAToggle;
|
||||
end if;
|
||||
end if;
|
||||
if crb_pbon = '1' then
|
||||
ppbo(7) <= timerBPulse;
|
||||
if crb_outmode = '1' then
|
||||
ppbo(7) <= timerBToggle;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- I/O port registers
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if myWr = '1' then
|
||||
case addr is
|
||||
when X"0" => pra <= di;
|
||||
when X"1" => prb <= di;
|
||||
when X"2" => ddra <= di;
|
||||
when X"3" => ddrb <= di;
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
if reset = '1' then
|
||||
pra <= (others => '0');
|
||||
prb <= (others => '0');
|
||||
ddra <= (others => '0');
|
||||
ddrb <= (others => '0');
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
-- TOD - time of day
|
||||
-- -----------------------------------------------------------------------
|
||||
process(clk)
|
||||
begin
|
||||
-- Process rising edge on the todClk.
|
||||
-- There is a prescaler of 5 or 6 to get 10ths of seconds from
|
||||
-- 50 Hz or 60 Hz line frequency.
|
||||
--
|
||||
-- Output is a 'todTick' signal synchronished with enable signal (@ 1Mhz).
|
||||
if rising_edge(clk) then
|
||||
if todEnabled = '1' then
|
||||
if enable = '1' then
|
||||
todTick <= '0';
|
||||
end if;
|
||||
|
||||
if todClk = '1' and oldTodClk = '0' then
|
||||
-- Divide by 5 or 6 dependng on 50/60 Hz flag.
|
||||
if tod_clkcnt /= "000" then
|
||||
tod_clkcnt <= tod_clkcnt - 1;
|
||||
else
|
||||
todTick <= tod_running;
|
||||
tod_clkcnt <= "101"; -- 60 Hz
|
||||
if cra_todin = '1' then
|
||||
tod_clkcnt <= "100"; -- 50 Hz
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
oldTodClk <= todClk;
|
||||
else
|
||||
todTick <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
process(clk)
|
||||
variable new_10ths : unsigned(3 downto 0);
|
||||
variable new_secsL : unsigned(3 downto 0);
|
||||
variable new_secsH : unsigned(2 downto 0);
|
||||
variable new_minsL : unsigned(3 downto 0);
|
||||
variable new_minsH : unsigned(2 downto 0);
|
||||
variable new_hrsL : unsigned(3 downto 0);
|
||||
variable new_hrsH : std_logic;
|
||||
variable new_hrs_byte : unsigned(7 downto 0); -- LCA am/pm and hours
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
new_10ths := tod_10ths;
|
||||
new_secsL := tod_secs(3 downto 0);
|
||||
new_secsH := tod_secs(6 downto 4);
|
||||
new_minsL := tod_mins(3 downto 0);
|
||||
new_minsH := tod_mins(6 downto 4);
|
||||
-- new_hrsL := tod_hrs(3 downto 0);
|
||||
-- new_hrsH := tod_hrs(4);
|
||||
new_hrs_byte := tod_hrs (7 downto 0); -- LCA am/pm and hours
|
||||
-- new_hrs_byte := new_hrsH & new_hrsL;
|
||||
|
||||
if enable = '1'
|
||||
and todTick = '1' then
|
||||
if new_10ths /= "1001" then
|
||||
new_10ths := new_10ths + 1;
|
||||
else
|
||||
new_10ths := "0000";
|
||||
if new_secsL /= "1001" then
|
||||
new_secsL := new_secsL + 1;
|
||||
else
|
||||
new_secsL := "0000";
|
||||
if new_secsH /= "101" then
|
||||
new_secsH := new_secsH + 1;
|
||||
else
|
||||
new_secsH := "000";
|
||||
if new_minsL /= "1001" then
|
||||
new_minsL := new_minsL + 1;
|
||||
else
|
||||
new_minsL := "0000";
|
||||
if new_minsH /= "101" then
|
||||
new_minsH := new_minsH + 1;
|
||||
else
|
||||
new_minsH := "000";
|
||||
-- hrs were missing jun17 LCA
|
||||
-- I mean completely absent from code :) !!!!!!
|
||||
-- case to lookup then handles oddities in others
|
||||
-- retarded am/pm flag flip madness handled at register load below (REG B)
|
||||
|
||||
case tod_hrs is -- case state to set hours and am/pm
|
||||
when "00010010" =>
|
||||
new_hrs_byte := "00000001"; -- 1 am set
|
||||
when "00000001" =>
|
||||
new_hrs_byte := "00000010";
|
||||
when "00000010" =>
|
||||
new_hrs_byte := "00000011";
|
||||
when "00000011" =>
|
||||
new_hrs_byte := "00000100";
|
||||
when "00000100" =>
|
||||
new_hrs_byte := "00000101";
|
||||
when "00000101" =>
|
||||
new_hrs_byte := "00000110";
|
||||
when "00000110" =>
|
||||
new_hrs_byte := "00000111";
|
||||
when "00000111" =>
|
||||
new_hrs_byte := "00001000";
|
||||
when "00001000" =>
|
||||
new_hrs_byte := "00001001";
|
||||
when "00001001" =>
|
||||
new_hrs_byte := "00010000";
|
||||
when "00010000" =>
|
||||
new_hrs_byte := "00010001"; -- 11am set
|
||||
when "00010001" =>
|
||||
new_hrs_byte := "10010010"; -- 12pm set
|
||||
when "10010010" =>
|
||||
new_hrs_byte := "10000001"; -- 1 pm set
|
||||
|
||||
when "10000001" =>
|
||||
new_hrs_byte := "10000010";
|
||||
when "10000010" =>
|
||||
new_hrs_byte := "10000011";
|
||||
when "10000011" =>
|
||||
new_hrs_byte := "10000100";
|
||||
when "10000100" =>
|
||||
new_hrs_byte := "10000101";
|
||||
when "10000101" =>
|
||||
new_hrs_byte := "10000110";
|
||||
when "10000110" =>
|
||||
new_hrs_byte := "10000111";
|
||||
when "10000111" =>
|
||||
new_hrs_byte := "10001000";
|
||||
when "10001000" =>
|
||||
new_hrs_byte := "10001001";
|
||||
when "10001001" =>
|
||||
new_hrs_byte := "10010000"; -- 10pm set
|
||||
when "10010000" =>
|
||||
new_hrs_byte := "10010001"; -- 11pm set
|
||||
when "10010001" =>
|
||||
new_hrs_byte := "00010010"; -- 12am set (midnight)
|
||||
when others =>
|
||||
new_hrs_byte (3 downto 0) := new_hrs_byte (3 downto 0) + 1;
|
||||
--null;
|
||||
end case;
|
||||
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if myWr = '1' then
|
||||
if crb_alarm = '0' then
|
||||
case addr is
|
||||
when X"8" =>
|
||||
new_10ths := di(3 downto 0);
|
||||
tod_running <= '1';
|
||||
when X"9" =>
|
||||
new_secsL := di(3 downto 0);
|
||||
new_secsH := di(6 downto 4);
|
||||
when X"A" =>
|
||||
new_minsL := di(3 downto 0);
|
||||
new_minsH := di(6 downto 4);
|
||||
when X"B" =>
|
||||
new_hrs_byte := di(7) & "00" & di(4 downto 0); -- LCA
|
||||
tod_running <= '0';
|
||||
if di(7 downto 0) = "10010010" or di(7 downto 0) = "00010010" then -- super bodge because cbm flips am/pm flag at 12 am or pm (its retarded!!!!!)
|
||||
new_hrs_byte(7) := not new_hrs_byte(7); -- This P.O.S. now mimics real commodore 64 !!!!! LCA
|
||||
end if;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
else -- TOD ALARM UPDATE
|
||||
case addr is
|
||||
when X"8" =>
|
||||
tod_10ths_alarm <= di(3 downto 0);
|
||||
when X"9" =>
|
||||
tod_secs_alarm <= di(6 downto 0);
|
||||
when X"A" =>
|
||||
tod_mins_alarm <= di(6 downto 0);
|
||||
when X"B" =>
|
||||
-- tod_hrs_alarm <= di(4 downto 0);
|
||||
-- tod_pm_alarm <= di(7);
|
||||
tod_hrs_alarm <= di(7) & "00" & di(4 downto 0); -- LCA
|
||||
if di(7 downto 0) = "10010010" or di(7 downto 0) = "00010010" then -- super bodge because cbm flips am/pm flag at 12 am or pm (its retarded!!!!!)
|
||||
tod_hrs_alarm(7) <= not tod_hrs_alarm(7); -- This P.O.S. now mimics real commodore 64 !!!!! LCA
|
||||
end if;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Update state
|
||||
tod_10ths <= new_10ths;
|
||||
tod_secs <= new_secsH & new_secsL;
|
||||
tod_mins <= new_minsH & new_minsL;
|
||||
tod_hrs <= new_hrs_byte; -- LCA
|
||||
|
||||
if tod_latched = '0' then
|
||||
tod_latch_10ths <= new_10ths;
|
||||
tod_latch_secs <= new_secsH & new_secsL;
|
||||
tod_latch_mins <= new_minsH & new_minsL;
|
||||
tod_latch_hrs <= new_hrs_byte; -- LCA
|
||||
end if;
|
||||
|
||||
-- TOD ALARM test for match - LCA
|
||||
if (tod_10ths = tod_10ths_alarm) and
|
||||
(tod_secs = tod_secs_alarm) and
|
||||
(tod_mins = tod_mins_alarm) and
|
||||
(tod_hrs = tod_hrs_alarm) and
|
||||
(crb_alarm = '1') then
|
||||
intr_alarm <= '1' ;
|
||||
end if;
|
||||
|
||||
if reset = '1' then
|
||||
tod_running <= '0';
|
||||
tod_10ths_alarm <= "0000" ;
|
||||
tod_secs_alarm <= "0000000" ;
|
||||
tod_mins_alarm <= "0000000" ;
|
||||
tod_hrs_alarm <= "00000000" ;
|
||||
tod_pm_alarm <= '0' ;
|
||||
end if;
|
||||
|
||||
if resetIrq then
|
||||
intr_alarm <= '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 timerAInput : std_logic;
|
||||
variable timerBInput : std_logic;
|
||||
variable newTimerB : unsigned(15 downto 0);
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
loadTimerA <= '0';
|
||||
loadTimerB <= '0';
|
||||
|
||||
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);
|
||||
cra_runmode_reg <= 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);
|
||||
crb_runmode_reg <= di(3);
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
|
||||
if reset = '1' then
|
||||
cra_runmode_reg <= '0';
|
||||
crb_runmode_reg <= '0';
|
||||
end if;
|
||||
|
||||
|
||||
if enable = '1' then
|
||||
|
||||
cra_runmode <= cra_runmode_reg;
|
||||
crb_runmode <= crb_runmode_reg;
|
||||
--
|
||||
-- process timer A
|
||||
--
|
||||
timerAPulse <= '0';
|
||||
newTimerA := timerA;
|
||||
|
||||
-- CNT is not emulated so don't count when inmode = 1
|
||||
timerAInput := not cra_inmode;
|
||||
|
||||
nextClkTimerA <= timerAInput and cra_start;
|
||||
clkTimerA <= nextClkTimerA;
|
||||
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 (cra_runmode_reg or cra_runmode) = '1' then
|
||||
cra_start <= '0';
|
||||
end if;
|
||||
end if;
|
||||
if forceTimerA = '1' then
|
||||
loadTimerA <= '1';
|
||||
end if;
|
||||
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;
|
||||
clkTimerB <= nextClkTimerB;
|
||||
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 (crb_runmode_reg or crb_runmode) = '1' then
|
||||
crb_start <= '0';
|
||||
end if;
|
||||
end if;
|
||||
if forceTimerB = '1' then
|
||||
loadTimerB <= '1';
|
||||
end if;
|
||||
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_alarm and mask_alarm)
|
||||
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_alarm <= mask_alarm and (not di(2)); -- LCA
|
||||
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_alarm <= mask_alarm or di(2); -- LCA
|
||||
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_alarm <= '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"B" => do <= tod_latch_hrs; -- LCA
|
||||
when X"C" => do <= (others => '0');
|
||||
when X"D" => do <= ir & "00" & intr_flagn & intr_serial & intr_alarm & 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;
|
||||
@@ -29,6 +29,7 @@ use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.std_logic_unsigned.ALL;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
use work.mos6526.all;
|
||||
-- -----------------------------------------------------------------------
|
||||
|
||||
entity fpga64_sid_iec is
|
||||
@@ -367,12 +368,13 @@ begin
|
||||
when CYCLE_VIC2 =>
|
||||
enableVic <= '1';
|
||||
when CYCLE_CPUE =>
|
||||
enableCia <= '1';
|
||||
enableVic <= '1';
|
||||
if baLoc = '1'
|
||||
or cpuWe = '1' then
|
||||
enableCpu <= '1';
|
||||
end if;
|
||||
when CYCLE_CPUF =>
|
||||
enableCia <= '1';
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
@@ -615,52 +617,56 @@ div1m: process(clk32) -- this process devides 32 MHz to 1MHz (for the SID)
|
||||
-- -----------------------------------------------------------------------
|
||||
-- CIAs
|
||||
-- -----------------------------------------------------------------------
|
||||
cia1: entity work.cia6526
|
||||
cia1: mos6526
|
||||
port map (
|
||||
clk => clk32,
|
||||
todClk => vicVSync,
|
||||
reset => reset,
|
||||
enable => enableCia,
|
||||
cs => cs_cia1,
|
||||
we => pulseWrIo,
|
||||
rd => pulseRd,
|
||||
phi2 => enableCia,
|
||||
res_n => not reset,
|
||||
cs_n => not cs_cia1,
|
||||
rw => not cpuWe,
|
||||
|
||||
addr => cpuAddr(3 downto 0),
|
||||
di => cpuDo,
|
||||
do => cia1Do,
|
||||
rs => std_logic_vector(cpuAddr)(3 downto 0),
|
||||
db_in => std_logic_vector(cpuDo),
|
||||
unsigned(db_out) => cia1Do,
|
||||
|
||||
ppai => cia1_pai,
|
||||
ppao => cia1_pao,
|
||||
ppbi => cia1_pbi,
|
||||
ppbo => cia1_pbo,
|
||||
pa_in => std_logic_vector(cia1_pai),
|
||||
unsigned(pa_out) => cia1_pao,
|
||||
pb_in => std_logic_vector(cia1_pbi),
|
||||
unsigned(pb_out) => cia1_pbo,
|
||||
|
||||
flag_n => '1',
|
||||
flag_n => '1',
|
||||
sp_in => '1',
|
||||
cnt_in => '1',
|
||||
|
||||
irq_n => irq_cia1
|
||||
pc_n => open,
|
||||
tod => vicVSync,
|
||||
irq_n => irq_cia1
|
||||
);
|
||||
|
||||
cia2: entity work.cia6526
|
||||
cia2: mos6526
|
||||
port map (
|
||||
clk => clk32,
|
||||
todClk => vicVSync,
|
||||
reset => reset,
|
||||
enable => enableCia,
|
||||
cs => cs_cia2,
|
||||
we => pulseWrIo,
|
||||
rd => pulseRd,
|
||||
phi2 => enableCia,
|
||||
res_n => not reset,
|
||||
cs_n => not cs_cia2,
|
||||
rw => not cpuWe,
|
||||
|
||||
addr => cpuAddr(3 downto 0),
|
||||
di => cpuDo,
|
||||
do => cia2Do,
|
||||
rs => std_logic_vector(cpuAddr)(3 downto 0),
|
||||
db_in => std_logic_vector(cpuDo),
|
||||
unsigned(db_out) => cia2Do,
|
||||
|
||||
ppai => cia2_pai,
|
||||
ppao => cia2_pao,
|
||||
ppbi => cia2_pbi,
|
||||
ppbo => cia2_pbo,
|
||||
pa_in => std_logic_vector(cia2_pai),
|
||||
unsigned(pa_out) => cia2_pao,
|
||||
pb_in => std_logic_vector(cia2_pbi),
|
||||
unsigned(pb_out) => cia2_pbo,
|
||||
|
||||
flag_n => '1',
|
||||
flag_n => '1',
|
||||
sp_in => '1',
|
||||
cnt_in => '1',
|
||||
|
||||
irq_n => irq_cia2
|
||||
pc_n => open,
|
||||
tod => vicVSync,
|
||||
irq_n => irq_cia2
|
||||
);
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
|
||||
439
cores/c64/rtl/mos6526.v
Normal file
439
cores/c64/rtl/mos6526.v
Normal file
@@ -0,0 +1,439 @@
|
||||
module mos6526 (
|
||||
input wire clk,
|
||||
input wire phi2,
|
||||
input wire res_n,
|
||||
input wire cs_n,
|
||||
input wire rw,
|
||||
|
||||
input wire [3:0] rs,
|
||||
input wire [7:0] db_in,
|
||||
output reg [7:0] db_out,
|
||||
|
||||
input wire [7:0] pa_in,
|
||||
output reg [7:0] pa_out,
|
||||
input wire [7:0] pb_in,
|
||||
output reg [7:0] pb_out,
|
||||
|
||||
input wire flag_n,
|
||||
output reg pc_n,
|
||||
|
||||
input wire tod,
|
||||
|
||||
input wire sp_in,
|
||||
output reg sp_out,
|
||||
|
||||
input wire cnt_in,
|
||||
output reg cnt_out,
|
||||
|
||||
output reg irq_n
|
||||
);
|
||||
|
||||
// Internal Registers
|
||||
reg [7:0] pra;
|
||||
reg [7:0] prb;
|
||||
reg [7:0] ddra;
|
||||
reg [7:0] ddrb;
|
||||
|
||||
reg [7:0] ta_lo;
|
||||
reg [7:0] ta_hi;
|
||||
reg [7:0] tb_lo;
|
||||
reg [7:0] tb_hi;
|
||||
|
||||
reg [3:0] tod_10ths;
|
||||
reg [6:0] tod_sec;
|
||||
reg [6:0] tod_min;
|
||||
reg [5:0] tod_hr;
|
||||
|
||||
reg [7:0] sdr;
|
||||
reg [4:0] icr;
|
||||
reg [7:0] cra;
|
||||
reg [7:0] crb;
|
||||
|
||||
// Internal Signals
|
||||
reg flag_n_prev;
|
||||
|
||||
reg [15:0] timer_a;
|
||||
reg [ 1:0] timer_a_out;
|
||||
reg [15:0] timer_b;
|
||||
reg [ 1:0] timer_b_out;
|
||||
|
||||
reg tod_prev;
|
||||
reg tod_run;
|
||||
reg [ 2:0] tod_count;
|
||||
reg tod_tick;
|
||||
reg [23:0] tod_alarm;
|
||||
reg tod_alarm_reg;
|
||||
reg [23:0] tod_latch;
|
||||
reg tod_latched;
|
||||
|
||||
reg sp_pending;
|
||||
reg sp_received;
|
||||
reg sp_transmit;
|
||||
reg [ 7:0] sp_shiftreg;
|
||||
|
||||
reg cnt_in_prev;
|
||||
reg cnt_out_prev;
|
||||
reg [ 2:0] cnt_pulsecnt;
|
||||
|
||||
reg [ 4:0] int_data;
|
||||
reg [ 1:0] int_reset;
|
||||
|
||||
// Register Decoding
|
||||
always @(posedge clk) begin
|
||||
if (!res_n) db_out <= 8'h00;
|
||||
else if (!cs_n && rw)
|
||||
case (rs)
|
||||
4'h0: db_out <= pa_in;
|
||||
4'h1: db_out <= pb_in;
|
||||
4'h2: db_out <= ddra;
|
||||
4'h3: db_out <= ddrb;
|
||||
4'h4: db_out <= timer_a[ 7:0];
|
||||
4'h5: db_out <= timer_a[15:8];
|
||||
4'h6: db_out <= timer_b[ 7:0];
|
||||
4'h7: db_out <= timer_b[15:8];
|
||||
4'h8: db_out <= tod_latched ?
|
||||
{4'h0, tod_latch[3:0]} : {4'h0, tod_10ths};
|
||||
4'h9: db_out <= tod_latched ?
|
||||
{1'b0, tod_latch[10:4]} : {1'b0, tod_sec};
|
||||
4'ha: db_out <= tod_latched ?
|
||||
{1'b0, tod_latch[17:11]} : {1'b0, tod_min};
|
||||
4'hb: db_out <= tod_latched ?
|
||||
{tod_latch[23], 2'h0, tod_latch[22:18]} :
|
||||
{tod_hr[5], 2'h0, tod_hr[4:0]};
|
||||
4'hc: db_out <= sdr;
|
||||
4'hd: db_out <= {~irq_n, 2'b00, int_data};
|
||||
4'he: db_out <= {cra[7:5], 1'b0, cra[3:0]};
|
||||
4'hf: db_out <= {crb[7:5], 1'b0, crb[3:0]};
|
||||
endcase
|
||||
end
|
||||
|
||||
// Port A Output
|
||||
always @(posedge clk) begin
|
||||
if (!res_n) begin
|
||||
pra <= 8'h00;
|
||||
ddra <= 8'h00;
|
||||
end
|
||||
else if (!cs_n && !rw)
|
||||
case (rs)
|
||||
4'h0: pra <= db_in;
|
||||
4'h2: ddra <= db_in;
|
||||
default: begin
|
||||
pra <= pra;
|
||||
ddra <= ddra;
|
||||
end
|
||||
endcase
|
||||
if (phi2) pa_out <= pra | ~ddra;
|
||||
end
|
||||
|
||||
// Port B Output
|
||||
always @(posedge clk) begin
|
||||
if (!res_n) begin
|
||||
prb <= 8'h00;
|
||||
ddrb <= 8'h00;
|
||||
end
|
||||
else if (!cs_n && !rw)
|
||||
case (rs)
|
||||
4'h1: prb <= db_in;
|
||||
4'h3: ddrb <= db_in;
|
||||
default: begin
|
||||
prb <= prb;
|
||||
ddrb <= ddrb;
|
||||
end
|
||||
endcase
|
||||
if (phi2) begin
|
||||
pb_out[7] <= crb[1] ? crb[2] ? timer_b_out[1] | ~ddrb[7] :
|
||||
timer_b_out[0] | ~ddrb[7] : prb[7] | ~ddrb[7];
|
||||
pb_out[6] <= cra[1] ? cra[2] ? timer_a_out[1] | ~ddrb[6] :
|
||||
timer_a_out[0] | ~ddrb[7] : prb[6] | ~ddrb[6];
|
||||
pb_out[5:0] <= prb[5:0] | ~ddrb[5:0];
|
||||
end
|
||||
end
|
||||
|
||||
// FLAG Input
|
||||
always @(posedge clk) begin
|
||||
if (!res_n || int_reset[1]) int_data[4] <= 1'b0;
|
||||
else if (!flag_n && flag_n_prev) int_data[4] <= 1'b1;
|
||||
if (phi2) flag_n_prev <= flag_n;
|
||||
end
|
||||
|
||||
// Port Control Output
|
||||
always @(posedge clk) begin
|
||||
if (!cs_n && rs == 4'h1) pc_n <= 1'b0;
|
||||
else pc_n <= phi2 ? 1'b1 : pc_n;
|
||||
end
|
||||
|
||||
// Timer A
|
||||
always @(posedge clk) begin
|
||||
if (!res_n) begin
|
||||
ta_lo <= 8'hff;
|
||||
ta_hi <= 8'hff;
|
||||
cra <= 8'h00;
|
||||
timer_a <= 16'h0000;
|
||||
timer_a_out[1] <= 1'b0;
|
||||
int_data[0] <= 1'b0;
|
||||
end
|
||||
else if (!cs_n && !rw)
|
||||
case (rs)
|
||||
4'h4: ta_lo <= db_in;
|
||||
4'h5: ta_hi <= db_in;
|
||||
4'he: begin
|
||||
cra <= db_in;
|
||||
timer_a_out[1] <= timer_a_out[1] | db_in[0];
|
||||
end
|
||||
default: begin
|
||||
ta_lo <= ta_lo;
|
||||
ta_hi <= ta_hi;
|
||||
cra <= cra;
|
||||
timer_a_out[1] <= timer_a_out[1];
|
||||
end
|
||||
endcase
|
||||
timer_a_out[0] <= phi2 ? 1'b0 : timer_a_out[0];
|
||||
if (phi2 && cra[0] && !cra[4]) begin
|
||||
if (!cra[5]) timer_a <= timer_a - 1'b1;
|
||||
else timer_a <= (cnt_in && !cnt_in_prev) ? timer_a - 1'b1 : timer_a;
|
||||
if (!timer_a) begin
|
||||
cra[0] <= ~cra[3];
|
||||
int_data[0] <= 1'b1;
|
||||
timer_a <= {ta_hi, ta_lo};
|
||||
timer_a_out <= {~timer_a_out[1], 1'b1};
|
||||
end
|
||||
end
|
||||
if ((phi2 && cra[4]) || (!cra[0] && !cs_n && !rw && rs == 4'h5)) begin
|
||||
cra[4] <= 1'b0;
|
||||
timer_a <= {ta_hi, ta_lo};
|
||||
end
|
||||
if (int_reset[1]) int_data[0] <= 1'b0;
|
||||
end
|
||||
|
||||
// Timer B
|
||||
always @(posedge clk) begin
|
||||
if (!res_n) begin
|
||||
tb_lo <= 8'hff;
|
||||
tb_hi <= 8'hff;
|
||||
crb <= 8'h00;
|
||||
timer_b <= 16'h0000;
|
||||
timer_b_out[1] <= 1'b0;
|
||||
int_data[1] <= 1'b0;
|
||||
end
|
||||
else if (!cs_n && !rw)
|
||||
case (rs)
|
||||
4'h6: tb_lo <= db_in;
|
||||
4'h7: tb_hi <= db_in;
|
||||
4'hf: begin
|
||||
crb <= db_in;
|
||||
timer_b_out[1] <= timer_b_out[1] | db_in[0];
|
||||
end
|
||||
default: begin
|
||||
tb_lo <= tb_lo;
|
||||
tb_hi <= tb_hi;
|
||||
crb <= crb;
|
||||
timer_b_out[1] <= timer_b_out[1];
|
||||
end
|
||||
endcase
|
||||
timer_b_out[0] <= phi2 ? 1'b0 : timer_b_out[0];
|
||||
if (phi2 && crb[0] && !crb[4]) begin
|
||||
case (crb[6:5])
|
||||
2'b00: timer_b <= timer_b - 1'b1;
|
||||
2'b01: timer_b <= (cnt_in && !cnt_in_prev) ? timer_b - 1'b1 : timer_b;
|
||||
2'b10: timer_b <= timer_a_out[0] ? timer_b - 1'b1 : timer_b;
|
||||
2'b11: timer_b <= (timer_a_out[0] && cnt_in) ? timer_b - 1'b1 : timer_b;
|
||||
endcase
|
||||
if (!timer_b) begin
|
||||
crb[0] <= ~crb[3];
|
||||
int_data[1] <= 1'b1;
|
||||
timer_b <= {tb_hi, tb_lo};
|
||||
timer_b_out <= {~timer_b_out[1], 1'b1};
|
||||
end
|
||||
end
|
||||
if ((phi2 && crb[4]) || (!crb[0] && !cs_n && !rw && rs == 4'h7)) begin
|
||||
crb[4] <= 1'b0;
|
||||
timer_b <= {tb_hi, tb_lo};
|
||||
end
|
||||
if (int_reset[1]) int_data[1] <= 1'b0;
|
||||
end
|
||||
|
||||
// Time of Day
|
||||
always @(posedge clk) begin
|
||||
if (!res_n) begin
|
||||
tod_10ths <= 4'h0;
|
||||
tod_sec <= 7'h00;
|
||||
tod_min <= 7'h00;
|
||||
tod_hr <= 6'h01;
|
||||
tod_run <= 1'b0;
|
||||
tod_alarm <= 24'h000000;
|
||||
tod_latch <= 24'h000000;
|
||||
tod_latched <= 1'b0;
|
||||
int_data[2] <= 1'b0;
|
||||
end
|
||||
else if (!cs_n && !rw)
|
||||
case (rs)
|
||||
4'h8: if (crb[7]) tod_alarm[3:0] <= db_in[3:0];
|
||||
else tod_10ths <= db_in[3:0];
|
||||
4'h9: if (crb[7]) tod_alarm[10:4] <= db_in[6:0];
|
||||
else tod_sec <= db_in[6:0];
|
||||
4'ha: if (crb[7]) tod_alarm[17:11] <= db_in[6:0];
|
||||
else tod_min <= db_in[6:0];
|
||||
4'hb: if (crb[7]) tod_alarm[23:18] <= {db_in[7], db_in[4:0]};
|
||||
else tod_hr <= {db_in[7], db_in[4:0]};
|
||||
default: begin
|
||||
tod_10ths <= tod_10ths;
|
||||
tod_sec <= tod_sec;
|
||||
tod_min <= tod_min;
|
||||
tod_hr <= tod_hr;
|
||||
tod_alarm <= tod_alarm;
|
||||
end
|
||||
endcase
|
||||
if (!cs_n)
|
||||
if (rs == 4'h8)
|
||||
if (!rw) tod_run <= !crb[7] ? 1'b1 : tod_run;
|
||||
else begin
|
||||
tod_latched <= 1'b0;
|
||||
tod_latch <= 24'h000000;
|
||||
end
|
||||
else if (rs == 4'hb)
|
||||
if (!rw) tod_run <= !crb[7] ? 1'b0 : tod_run;
|
||||
else begin
|
||||
tod_latched <= 1'b1;
|
||||
tod_latch <= {tod_hr, tod_min, tod_sec, tod_10ths};
|
||||
end
|
||||
tod_prev <= tod;
|
||||
tod_tick <= 1'b0;
|
||||
if (tod_run) begin
|
||||
tod_count <= (tod && !tod_prev) ? tod_count + 1'b1 : tod_count;
|
||||
if ((cra[7] && tod_count == 3'h5) || tod_count == 3'h6) begin
|
||||
tod_tick <= 1'b1;
|
||||
tod_count <= 3'h0;
|
||||
end
|
||||
if (tod_tick) begin
|
||||
tod_10ths <= (tod_10ths == 4'h9) ? 1'b0 : tod_10ths + 1'b1;
|
||||
if (tod_10ths == 4'h9) begin
|
||||
tod_sec[3:0] <= tod_sec[3:0] + 1'b1;
|
||||
if (tod_sec[3:0] == 4'h9) begin
|
||||
tod_sec[3:0] <= 4'h0;
|
||||
tod_sec[6:4] <= tod_sec[6:4] + 1'b1;
|
||||
end
|
||||
if (tod_sec == 7'h59) begin
|
||||
tod_sec[6:4] <= 3'h0;
|
||||
tod_min[3:0] <= tod_min[3:0] + 1'b1;
|
||||
end
|
||||
if (tod_min[3:0] == 4'h9 && tod_sec == 7'h59) begin
|
||||
tod_min[3:0] <= 4'h0;
|
||||
tod_min[6:4] <= tod_min[6:4] + 1'b1;
|
||||
end
|
||||
if (tod_min == 7'h59 && tod_sec == 7'h59) begin
|
||||
tod_min[6:4] <= 3'h0;
|
||||
tod_hr[3:0] <= tod_hr[3:0] + 1'b1;
|
||||
end
|
||||
if (tod_hr[3:0] == 4'h9 && tod_min == 7'h59 && tod_sec == 7'h59) begin
|
||||
tod_hr[3:0] <= 4'h0;
|
||||
tod_hr[4] <= tod_hr[4] + 1'b1;
|
||||
end
|
||||
if (tod_min == 7'h59 && tod_sec == 7'h59)
|
||||
if (tod_hr[4:0] == 5'h11)
|
||||
if (!tod_hr[5]) begin
|
||||
tod_hr[5] <= ~tod_hr[5];
|
||||
tod_hr[3:0] <= tod_hr[3:0] + 1'b1;
|
||||
end
|
||||
else begin
|
||||
tod_hr[5] <= ~tod_hr[5];
|
||||
tod_hr[4:0] <= 5'h00;
|
||||
end
|
||||
else if (tod_hr[4:0] == 5'h12) tod_hr[4:0] <= 5'h01;
|
||||
end
|
||||
end
|
||||
end
|
||||
else tod_count <= 3'h0;
|
||||
if ({tod_hr, tod_min, tod_sec, tod_10ths} == tod_alarm) begin
|
||||
tod_alarm_reg <= 1'b1;
|
||||
int_data[2] <= !tod_alarm_reg ? 1'b1 : int_data[2];
|
||||
end
|
||||
else tod_alarm_reg <= 1'b0;
|
||||
if (int_reset[1]) int_data[2] <= 1'b0;
|
||||
end
|
||||
|
||||
// Serial Port Input/Output
|
||||
always @(posedge clk) begin
|
||||
if (!res_n) begin
|
||||
sdr <= 8'h00;
|
||||
sp_out <= 1'b0;
|
||||
sp_pending <= 1'b0;
|
||||
sp_received <= 1'b0;
|
||||
sp_transmit <= 1'b0;
|
||||
sp_shiftreg <= 8'h00;
|
||||
int_data[3] <= 1'b0;
|
||||
end
|
||||
else if (!cs_n && !rw)
|
||||
case (rs)
|
||||
4'hc: sdr <= db_in;
|
||||
default: sdr <= sdr;
|
||||
endcase
|
||||
if (!cra[6]) begin
|
||||
if (sp_received) begin
|
||||
sdr <= sp_shiftreg;
|
||||
int_data[3] <= 1'b1;
|
||||
sp_received <= 1'b0;
|
||||
sp_shiftreg <= 8'h00;
|
||||
end
|
||||
else if (cnt_in && !cnt_in_prev) begin
|
||||
sp_shiftreg <= {sp_shiftreg[6:0], sp_in};
|
||||
sp_received <= (cnt_pulsecnt == 3'h7) ? 1'b1 : sp_received;
|
||||
end
|
||||
end
|
||||
else if (cra[6] && !cra[3] && cra[0]) begin
|
||||
if (!cs_n && !rw && rs == 8'hc) sp_pending <= 1'b1;
|
||||
if (sp_pending && !sp_transmit) begin
|
||||
sp_pending <= 1'b0;
|
||||
sp_transmit <= 1'b1;
|
||||
sp_shiftreg <= sdr;
|
||||
end
|
||||
else if (!cnt_out && cnt_out_prev) begin
|
||||
if (cnt_pulsecnt == 3'h7) begin
|
||||
int_data[3] <= 1'b1;
|
||||
sp_transmit <= 1'b0;
|
||||
end
|
||||
sp_out <= sp_shiftreg[7];
|
||||
sp_shiftreg <= {sp_shiftreg[6:0], 1'b0};
|
||||
end
|
||||
end
|
||||
if (int_reset[1]) int_data[3] <= 1'b0;
|
||||
end
|
||||
|
||||
// CNT Input/Output
|
||||
always @(posedge clk) begin
|
||||
if (!res_n) begin
|
||||
cnt_out <= 1'b1;
|
||||
cnt_out_prev <= 1'b1;
|
||||
cnt_pulsecnt <= 3'h0;
|
||||
end
|
||||
else if (phi2) begin
|
||||
cnt_in_prev <= cnt_in;
|
||||
cnt_out_prev <= cnt_out;
|
||||
end
|
||||
if (!cra[6] && cnt_in && !cnt_in_prev) cnt_pulsecnt <= cnt_pulsecnt + 1'b1;
|
||||
else if (cra[6] && !cra[3] && cra[0]) begin
|
||||
if (sp_transmit) begin
|
||||
cnt_out <= timer_a_out[0] ? ~cnt_out : cnt_out;
|
||||
if (!cnt_out && cnt_out_prev) cnt_pulsecnt <= cnt_pulsecnt + 1'b1;
|
||||
end
|
||||
else cnt_out <= timer_a_out[0] ? 1'b1 : cnt_out;
|
||||
end
|
||||
end
|
||||
|
||||
// Interrupt Control
|
||||
always @(posedge clk) begin
|
||||
if (!res_n) begin
|
||||
icr <= 5'h00;
|
||||
irq_n <= 1'b1;
|
||||
int_reset <= 2'b00;
|
||||
end
|
||||
else if (!cs_n && !rw)
|
||||
case (rs)
|
||||
4'hd: icr <= db_in[7] ? icr | db_in[4:0] : icr & ~db_in[4:0];
|
||||
default: icr <= icr;
|
||||
endcase
|
||||
else irq_n <= irq_n ? ~|(icr & int_data) : int_reset[1] ? 1'b1 : irq_n;
|
||||
if (!cs_n && rw && rs == 4'hd) int_reset <= 2'b01;
|
||||
else if (int_reset) int_reset <= {int_reset[0], 1'b0};
|
||||
end
|
||||
|
||||
endmodule
|
||||
29
cores/c64/rtl/mos6526.vhd
Normal file
29
cores/c64/rtl/mos6526.vhd
Normal file
@@ -0,0 +1,29 @@
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
|
||||
package mos6526 is
|
||||
component mos6526
|
||||
PORT (
|
||||
clk : in std_logic;
|
||||
phi2 : in std_logic;
|
||||
res_n : in std_logic;
|
||||
cs_n : in std_logic;
|
||||
rw : in std_logic; -- '1' - read, '0' - write
|
||||
rs : in std_logic_vector(3 downto 0);
|
||||
db_in : in std_logic_vector(7 downto 0);
|
||||
db_out : out std_logic_vector(7 downto 0);
|
||||
pa_in : in std_logic_vector(7 downto 0);
|
||||
pa_out : out std_logic_vector(7 downto 0);
|
||||
pb_in : in std_logic_vector(7 downto 0);
|
||||
pb_out : out std_logic_vector(7 downto 0);
|
||||
flag_n : in std_logic;
|
||||
pc_n : out std_logic;
|
||||
tod : in std_logic;
|
||||
sp_in : in std_logic;
|
||||
sp_out : out std_logic;
|
||||
cnt_in : in std_logic;
|
||||
cnt_out : out std_logic;
|
||||
irq_n : out std_logic
|
||||
);
|
||||
end component;
|
||||
end package;
|
||||
Reference in New Issue
Block a user