mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-05 23:54:41 +00:00
C16: update 1541 to the latest version from Dar
Also get rid of the double spi->sdcard transfer, and use MiST's block IO with the help of Sorgelig's thin wrapper.
This commit is contained in:
395
cores/c16/c1541/c1541_logic.vhd
Normal file
395
cores/c16/c1541/c1541_logic.vhd
Normal file
@@ -0,0 +1,395 @@
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
--use work.platform_pkg.all;
|
||||
--use work.project_pkg.all;
|
||||
|
||||
--
|
||||
-- Model 1541B
|
||||
--
|
||||
|
||||
entity c1541_logic is
|
||||
generic
|
||||
(
|
||||
DEVICE_SELECT : std_logic_vector(1 downto 0)
|
||||
);
|
||||
port
|
||||
(
|
||||
clk_32M : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
-- serial bus
|
||||
sb_data_oe : out std_logic;
|
||||
sb_data_in : in std_logic;
|
||||
sb_clk_oe : out std_logic;
|
||||
sb_clk_in : in std_logic;
|
||||
sb_atn_oe : out std_logic;
|
||||
sb_atn_in : in std_logic;
|
||||
|
||||
-- drive-side interface
|
||||
ds : in std_logic_vector(1 downto 0); -- device select
|
||||
di : in std_logic_vector(7 downto 0); -- disk read data
|
||||
do : out std_logic_vector(7 downto 0); -- disk data to write
|
||||
mode : out std_logic; -- read/write
|
||||
stp : out std_logic_vector(1 downto 0); -- stepper motor control
|
||||
mtr : out std_logic; -- stepper motor on/off
|
||||
freq : out std_logic_vector(1 downto 0); -- motor frequency
|
||||
sync_n : in std_logic; -- reading SYNC bytes
|
||||
byte_n : in std_logic; -- byte ready
|
||||
wps_n : in std_logic; -- write-protect sense
|
||||
tr00_sense_n : in std_logic; -- track 0 sense (unused?)
|
||||
act : out std_logic; -- activity LED
|
||||
|
||||
dbg_adr_fetch : out std_logic_vector(15 downto 0); -- dbg DAR
|
||||
dbg_cpu_irq : out std_logic -- dbg DAR
|
||||
);
|
||||
end c1541_logic;
|
||||
|
||||
architecture SYN of c1541_logic is
|
||||
|
||||
-- clocks, reset
|
||||
signal reset_n : std_logic;
|
||||
signal clk_4M_en : std_logic;
|
||||
signal p2_h : std_logic;
|
||||
signal clk_1M_pulse : std_logic;
|
||||
|
||||
-- cpu signals
|
||||
signal cpu_a : std_logic_vector(23 downto 0);
|
||||
signal cpu_di : std_logic_vector(7 downto 0);
|
||||
signal cpu_do : std_logic_vector(7 downto 0);
|
||||
signal cpu_rw_n : std_logic;
|
||||
signal cpu_irq_n : std_logic;
|
||||
signal cpu_so_n : std_logic;
|
||||
signal cpu_sync : std_logic; -- DAR
|
||||
|
||||
-- rom signals
|
||||
signal rom_cs : std_logic;
|
||||
signal rom_do : std_logic_vector(cpu_di'range);
|
||||
|
||||
-- ram signals
|
||||
signal ram_cs : std_logic;
|
||||
signal ram_wr : std_logic;
|
||||
signal ram_do : std_logic_vector(cpu_di'range);
|
||||
|
||||
-- UC1 (VIA6522) signals
|
||||
signal uc1_do : std_logic_vector(7 downto 0);
|
||||
signal uc1_do_oe_n : std_logic;
|
||||
signal uc1_cs1 : std_logic;
|
||||
signal uc1_cs2_n : std_logic;
|
||||
signal uc1_irq_n : std_logic;
|
||||
signal uc1_ca1_i : std_logic;
|
||||
signal uc1_pa_i : std_logic_vector(7 downto 0);
|
||||
signal uc1_pb_i : std_logic_vector(7 downto 0);
|
||||
signal uc1_pb_o : std_logic_vector(7 downto 0);
|
||||
signal uc1_pb_oe_n : std_logic_vector(7 downto 0);
|
||||
|
||||
-- UC3 (VIA6522) signals
|
||||
signal uc3_do : std_logic_vector(7 downto 0);
|
||||
signal uc3_do_oe_n : std_logic;
|
||||
signal uc3_cs1 : std_logic;
|
||||
signal uc3_cs2_n : std_logic;
|
||||
signal uc3_irq_n : std_logic;
|
||||
signal uc3_ca1_i : std_logic;
|
||||
signal uc3_ca2_o : std_logic;
|
||||
signal uc3_ca2_oe_n : std_logic;
|
||||
signal uc3_pa_i : std_logic_vector(7 downto 0);
|
||||
signal uc3_pa_o : std_logic_vector(7 downto 0);
|
||||
signal uc3_cb2_o : std_logic;
|
||||
signal uc3_cb2_oe_n : std_logic;
|
||||
signal uc3_pa_oe_n : std_logic_vector(7 downto 0);
|
||||
signal uc3_pb_i : std_logic_vector(7 downto 0);
|
||||
signal uc3_pb_o : std_logic_vector(7 downto 0);
|
||||
signal uc3_pb_oe_n : std_logic_vector(7 downto 0);
|
||||
|
||||
-- internal signals
|
||||
signal atna : std_logic; -- ATN ACK - input gate array
|
||||
signal atn : std_logic; -- attention
|
||||
signal soe : std_logic; -- set overflow enable
|
||||
|
||||
begin
|
||||
|
||||
reset_n <= not reset;
|
||||
|
||||
process (clk_32M, reset)
|
||||
variable count : std_logic_vector(8 downto 0) := (others => '0');
|
||||
alias hcnt : std_logic_vector(1 downto 0) is count(4 downto 3);
|
||||
begin
|
||||
if rising_edge(clk_32M) then
|
||||
-- generate 1MHz pulse
|
||||
clk_1M_pulse <= '0';
|
||||
--if count(4 downto 0) = "00111" then
|
||||
if count(4 downto 0) = "01000" then
|
||||
clk_1M_pulse <= '1';
|
||||
end if;
|
||||
if count = "000100000" then -- DAR divide by 33 (otherwise real c64 miss EOI acknowledge)
|
||||
count := (others => '0'); -- DAR
|
||||
else -- DAR
|
||||
count := std_logic_vector(unsigned(count) + 1);
|
||||
end if; -- DAR
|
||||
end if;
|
||||
p2_h <= not hcnt(1);
|
||||
|
||||
-- for original m6522 design that requires a real clock
|
||||
-- clk_4M_en <= not count(2);
|
||||
|
||||
-- for version 002 with clock enable
|
||||
if count(2 downto 0) = "111" then
|
||||
clk_4M_en <= '1';
|
||||
else
|
||||
clk_4M_en <= '0';
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- decode logic
|
||||
-- RAM $0000-$07FF (2KB)
|
||||
ram_cs <= '1' when STD_MATCH(cpu_a(15 downto 0), "00000-----------") else '0';
|
||||
-- UC1 (VIA6522) $1800-$180F
|
||||
uc1_cs2_n <= '0' when STD_MATCH(cpu_a(15 downto 0), "000110000000----") else '1';
|
||||
-- UC3 (VIA6522) $1C00-$1C0F
|
||||
uc3_cs2_n <= '0' when STD_MATCH(cpu_a(15 downto 0), "000111000000----") else '1';
|
||||
-- ROM $C000-$FFFF (16KB)
|
||||
rom_cs <= '1' when STD_MATCH(cpu_a(15 downto 0), "11--------------") else '0';
|
||||
|
||||
-- qualified write signals
|
||||
ram_wr <= '1' when ram_cs = '1' and cpu_rw_n = '0' else '0';
|
||||
|
||||
--
|
||||
-- hook up UC1 ports
|
||||
--
|
||||
|
||||
uc1_cs1 <= cpu_a(11);
|
||||
--uc1_cs2_n: see decode logic above
|
||||
-- CA1
|
||||
--uc1_ca1_i <= not sb_atn_in; -- DAR comment : synched with clk_4M_en see below
|
||||
-- PA
|
||||
uc1_pa_i(0) <= tr00_sense_n;
|
||||
uc1_pa_i(7 downto 1) <= (others => '0'); -- NC
|
||||
-- PB
|
||||
uc1_pb_i(0) <= '1' when sb_data_in = '0' else
|
||||
'1' when (uc1_pb_o(1) = '1' and uc1_pb_oe_n(1) = '0') else -- DAR comment : external OR wired
|
||||
'1' when atn = '1' else -- DAR comment : external OR wired
|
||||
'0';
|
||||
sb_data_oe <= '1' when (uc1_pb_o(1) = '1' and uc1_pb_oe_n(1) = '0') else
|
||||
'1' when atn = '1' else
|
||||
'0';
|
||||
uc1_pb_i(2) <= '1' when sb_clk_in = '0' else
|
||||
'1' when (uc1_pb_o(3) = '1' and uc1_pb_oe_n(3) = '0') else -- DAR comment : external OR wired
|
||||
'0';
|
||||
sb_clk_oe <= '1' when (uc1_pb_o(3) = '1' and uc1_pb_oe_n(3) = '0') else '0';
|
||||
|
||||
atna <= uc1_pb_o(4); -- when uc1_pc_oe = '1'
|
||||
uc1_pb_i(6 downto 5) <= DEVICE_SELECT xor ds; -- allows override
|
||||
uc1_pb_i(7) <= not sb_atn_in;
|
||||
|
||||
--
|
||||
-- hook up UC3 ports
|
||||
--
|
||||
|
||||
uc3_cs1 <= cpu_a(11);
|
||||
--uc3_cs2_n: see decode logic above
|
||||
-- CA1
|
||||
uc3_ca1_i <= cpu_so_n; -- byte ready gated with soe
|
||||
-- CA2
|
||||
soe <= uc3_ca2_o or uc3_ca2_oe_n;
|
||||
-- PA
|
||||
uc3_pa_i <= di;
|
||||
do <= uc3_pa_o or uc3_pa_oe_n;
|
||||
-- CB2
|
||||
mode <= uc3_cb2_o or uc3_cb2_oe_n;
|
||||
-- PB
|
||||
stp(1) <= uc3_pb_o(0) or uc3_pb_oe_n(0);
|
||||
stp(0) <= uc3_pb_o(1) or uc3_pb_oe_n(1);
|
||||
mtr <= uc3_pb_o(2) or uc3_pb_oe_n(2);
|
||||
act <= uc3_pb_o(3) or uc3_pb_oe_n(3);
|
||||
freq <= uc3_pb_o(6 downto 5) or uc3_pb_oe_n(6 downto 5);
|
||||
uc3_pb_i <= sync_n & "11" & wps_n & "1111";
|
||||
|
||||
--
|
||||
-- CPU connections
|
||||
--
|
||||
cpu_di <= rom_do when rom_cs = '1' else
|
||||
ram_do when ram_cs = '1' else
|
||||
uc1_do when (uc1_cs1 = '1' and uc1_cs2_n = '0') else
|
||||
uc3_do when (uc3_cs1 = '1' and uc3_cs2_n = '0') else
|
||||
(others => '1');
|
||||
cpu_irq_n <= uc1_irq_n and uc3_irq_n;
|
||||
cpu_so_n <= byte_n or not soe;
|
||||
|
||||
-- internal connections
|
||||
atn <= atna xor (not sb_atn_in);
|
||||
|
||||
-- external connections
|
||||
-- ATN never driven by the 1541
|
||||
sb_atn_oe <= '0';
|
||||
|
||||
|
||||
-- DAR
|
||||
process (clk_32M)
|
||||
begin
|
||||
if rising_edge(clk_32M) then
|
||||
if clk_4M_en = '1' then
|
||||
uc1_ca1_i <= not sb_atn_in; -- DAR sample external atn to ensure not missing edge within VIA
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
process (clk_32M, cpu_sync)
|
||||
begin
|
||||
if rising_edge(clk_32M) then
|
||||
if cpu_sync = '1' then
|
||||
dbg_adr_fetch <= cpu_a(15 downto 0);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
dbg_cpu_irq <= cpu_irq_n;
|
||||
-- DAR
|
||||
|
||||
cpu_inst : entity work.T65
|
||||
port map
|
||||
(
|
||||
Mode => "00", -- 6502
|
||||
Res_n => reset_n,
|
||||
Enable => clk_1M_pulse,
|
||||
Clk => clk_32M,
|
||||
Rdy => '1',
|
||||
Abort_n => '1',
|
||||
IRQ_n => cpu_irq_n,
|
||||
NMI_n => '1',
|
||||
SO_n => cpu_so_n,
|
||||
R_W_n => cpu_rw_n,
|
||||
Sync => cpu_sync, -- open -- DAR
|
||||
EF => open,
|
||||
MF => open,
|
||||
XF => open,
|
||||
ML_n => open,
|
||||
VP_n => open,
|
||||
VDA => open,
|
||||
VPA => open,
|
||||
A => cpu_a,
|
||||
DI => cpu_di,
|
||||
DO => cpu_do
|
||||
);
|
||||
|
||||
rom_inst : entity work.sprom
|
||||
generic map
|
||||
(
|
||||
-- init_file => "../roms/JiffyDOS_C1541.hex", -- DAR tested OK
|
||||
-- init_file => "../roms/25196802.hex",
|
||||
-- init_file => "../roms/25196801.hex",
|
||||
init_file => "../roms/325302-1_901229-03.hex",
|
||||
-- init_file => "../roms/1541_c000_01_and_e000_06aa.hex", -- DAR tested OK
|
||||
|
||||
|
||||
numwords_a => 16384,
|
||||
widthad_a => 14
|
||||
)
|
||||
port map
|
||||
(
|
||||
clock => clk_32M,
|
||||
address => cpu_a(13 downto 0),
|
||||
q => rom_do
|
||||
);
|
||||
|
||||
ram_inst : entity work.spram
|
||||
generic map
|
||||
(
|
||||
numwords_a => 2048,
|
||||
widthad_a => 11
|
||||
)
|
||||
port map
|
||||
(
|
||||
clock => clk_32M,
|
||||
address => cpu_a(10 downto 0),
|
||||
wren => ram_wr,
|
||||
data => cpu_do,
|
||||
q => ram_do
|
||||
);
|
||||
|
||||
uc1_via6522_inst : entity work.M6522
|
||||
port map
|
||||
(
|
||||
I_RS => cpu_a(3 downto 0),
|
||||
I_DATA => cpu_do,
|
||||
O_DATA => uc1_do,
|
||||
O_DATA_OE_L => uc1_do_oe_n,
|
||||
|
||||
I_RW_L => cpu_rw_n,
|
||||
I_CS1 => uc1_cs1,
|
||||
I_CS2_L => uc1_cs2_n,
|
||||
|
||||
O_IRQ_L => uc1_irq_n,
|
||||
|
||||
-- port a
|
||||
I_CA1 => uc1_ca1_i,
|
||||
I_CA2 => '0',
|
||||
O_CA2 => open,
|
||||
O_CA2_OE_L => open,
|
||||
|
||||
I_PA => uc1_pa_i,
|
||||
O_PA => open,
|
||||
O_PA_OE_L => open,
|
||||
|
||||
-- port b
|
||||
I_CB1 => '0',
|
||||
O_CB1 => open,
|
||||
O_CB1_OE_L => open,
|
||||
|
||||
I_CB2 => '0',
|
||||
O_CB2 => open,
|
||||
O_CB2_OE_L => open,
|
||||
|
||||
I_PB => uc1_pb_i,
|
||||
O_PB => uc1_pb_o,
|
||||
O_PB_OE_L => uc1_pb_oe_n,
|
||||
|
||||
RESET_L => reset_n,
|
||||
CLK => clk_32M,
|
||||
I_P2_H => p2_h, -- high for phase 2 clock ____----__
|
||||
ENA_4 => clk_4M_en -- 4x system clock (4HZ) _-_-_-_-_-
|
||||
);
|
||||
|
||||
uc3_via6522_inst : entity work.M6522
|
||||
port map
|
||||
(
|
||||
I_RS => cpu_a(3 downto 0),
|
||||
I_DATA => cpu_do,
|
||||
O_DATA => uc3_do,
|
||||
O_DATA_OE_L => uc3_do_oe_n,
|
||||
|
||||
I_RW_L => cpu_rw_n,
|
||||
I_CS1 => cpu_a(11),
|
||||
I_CS2_L => uc3_cs2_n,
|
||||
|
||||
O_IRQ_L => uc3_irq_n,
|
||||
|
||||
-- port a
|
||||
I_CA1 => uc3_ca1_i,
|
||||
I_CA2 => '0',
|
||||
O_CA2 => uc3_ca2_o,
|
||||
O_CA2_OE_L => uc3_ca2_oe_n,
|
||||
|
||||
I_PA => uc3_pa_i,
|
||||
O_PA => uc3_pa_o,
|
||||
O_PA_OE_L => uc3_pa_oe_n,
|
||||
|
||||
-- port b
|
||||
I_CB1 => '0',
|
||||
O_CB1 => open,
|
||||
O_CB1_OE_L => open,
|
||||
|
||||
I_CB2 => '0',
|
||||
O_CB2 => uc3_cb2_o,
|
||||
O_CB2_OE_L => uc3_cb2_oe_n,
|
||||
|
||||
I_PB => uc3_pb_i,
|
||||
O_PB => uc3_pb_o,
|
||||
O_PB_OE_L => uc3_pb_oe_n,
|
||||
|
||||
RESET_L => reset_n,
|
||||
CLK => clk_32M,
|
||||
I_P2_H => p2_h, -- high for phase 2 clock ____----__
|
||||
ENA_4 => clk_4M_en -- 4x system clock (4HZ) _-_-_-_-_-
|
||||
);
|
||||
|
||||
end SYN;
|
||||
372
cores/c16/c1541/c1541_sd.vhd
Normal file
372
cores/c16/c1541/c1541_sd.vhd
Normal file
@@ -0,0 +1,372 @@
|
||||
---------------------------------------------------------------------------------
|
||||
-- Commodore 1541 to SD card (read/write) by Dar (darfpga@aol.fr) 24-May-2017
|
||||
-- http://darfpga.blogspot.fr
|
||||
--
|
||||
-- c1541_sd reads D64 data from raw SD card, produces GCR data, feeds c1541_logic
|
||||
-- Raw SD data : each D64 image must start on 256KB boundaries
|
||||
-- disk_num allow to select D64 image
|
||||
--
|
||||
-- c1541_logic from : Mark McDougall
|
||||
-- spi_controller from : Michel Stempin, Stephen A. Edwards
|
||||
-- via6522 from : Arnim Laeuger, Mark McDougall, MikeJ
|
||||
-- T65 from : Daniel Wallner, MikeJ, ehenciak
|
||||
--
|
||||
-- c1541_logic modified for : slow down CPU (EOI ack missed by real c64)
|
||||
-- : remove iec internal OR wired
|
||||
-- : synched atn_in (sometime no IRQ with real c64)
|
||||
-- spi_controller modified for : sector start and size adapted + busy signal
|
||||
-- via6522 modified for : no modification
|
||||
--
|
||||
--
|
||||
-- Input clk 32MHz and 18MHz (18MHz could be replaced with 32/2 if needed)
|
||||
--
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.std_logic_unsigned.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity c1541_sd is
|
||||
port(
|
||||
clk32 : in std_logic;
|
||||
-- clk_spi_ctrlr : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
disk_num : in std_logic_vector(9 downto 0);
|
||||
disk_change : in std_logic;
|
||||
|
||||
iec_atn_i : in std_logic;
|
||||
iec_data_i : in std_logic;
|
||||
iec_clk_i : in std_logic;
|
||||
|
||||
iec_atn_o : out std_logic;
|
||||
iec_data_o : out std_logic;
|
||||
iec_clk_o : out std_logic;
|
||||
|
||||
sd_lba : out std_logic_vector(31 downto 0);
|
||||
sd_rd : out std_logic;
|
||||
sd_wr : out std_logic;
|
||||
sd_ack : in std_logic;
|
||||
|
||||
sd_buff_addr : in std_logic_vector(8 downto 0);
|
||||
sd_buff_dout : in std_logic_vector(7 downto 0);
|
||||
sd_buff_din : out std_logic_vector(7 downto 0);
|
||||
sd_buff_wr : in std_logic;
|
||||
|
||||
dbg_track_num_dbl : out std_logic_vector(6 downto 0);
|
||||
dbg_sd_busy : out std_logic;
|
||||
dbg_sd_state : out std_logic_vector(7 downto 0);
|
||||
dbg_read_sector : out std_logic_vector(4 downto 0);
|
||||
dbg_mtr : out std_logic;
|
||||
dbg_act : out std_logic
|
||||
);
|
||||
end c1541_sd;
|
||||
|
||||
architecture struct of c1541_sd is
|
||||
|
||||
signal spi_ram_addr : std_logic_vector(12 downto 0);
|
||||
signal spi_ram_di : std_logic_vector( 7 downto 0);
|
||||
signal spi_ram_we : std_logic;
|
||||
|
||||
signal ram_addr : std_logic_vector(12 downto 0);
|
||||
signal ram_di : std_logic_vector( 7 downto 0);
|
||||
signal ram_do : std_logic_vector( 7 downto 0);
|
||||
signal ram_we : std_logic;
|
||||
|
||||
signal floppy_ram_addr : std_logic_vector(12 downto 0);
|
||||
signal floppy_ram_di : std_logic_vector( 7 downto 0);
|
||||
signal floppy_ram_we : std_logic;
|
||||
|
||||
signal c1541_logic_din : std_logic_vector(7 downto 0); -- data read
|
||||
signal c1541_logic_dout : std_logic_vector(7 downto 0); -- data to write
|
||||
signal mode : std_logic; -- read/write
|
||||
signal mode_r : std_logic; -- read/write
|
||||
signal stp : std_logic_vector(1 downto 0); -- stepper motor control
|
||||
signal stp_r : std_logic_vector(1 downto 0); -- stepper motor control
|
||||
signal mtr : std_logic ; -- stepper motor on/off
|
||||
--signal mtr_r : std_logic ; -- stepper motor on/off
|
||||
signal freq : std_logic_vector(1 downto 0); -- motor (gcr_bit) frequency
|
||||
signal sync_n : std_logic; -- reading SYNC bytes
|
||||
signal byte_n : std_logic; -- byte ready
|
||||
signal act : std_logic; -- activity LED
|
||||
signal act_r : std_logic; -- activity LED
|
||||
|
||||
signal track_num_dbl : std_logic_vector(6 downto 0);
|
||||
signal new_track_num_dbl : std_logic_vector(6 downto 0);
|
||||
signal sd_busy : std_logic;
|
||||
|
||||
type byte_array is array(0 to 8191) of std_logic_vector(7 downto 0);
|
||||
signal track_buffer : byte_array;
|
||||
|
||||
signal save_track : std_logic;
|
||||
signal track_modified : std_logic;
|
||||
signal sector_offset : std_logic;
|
||||
signal save_track_stage : std_logic_vector(3 downto 0);
|
||||
|
||||
signal dbg_sector : std_logic_vector(4 downto 0);
|
||||
signal dbg_adr_fetch : std_logic_vector(15 downto 0);
|
||||
|
||||
component mist_sd_card port
|
||||
(
|
||||
sd_lba : out std_logic_vector(31 downto 0);
|
||||
sd_rd : out std_logic;
|
||||
sd_wr : out std_logic;
|
||||
sd_ack : in std_logic;
|
||||
|
||||
sd_buff_addr : in std_logic_vector(8 downto 0);
|
||||
sd_buff_dout : in std_logic_vector(7 downto 0);
|
||||
sd_buff_din : out std_logic_vector(7 downto 0);
|
||||
sd_buff_wr : in std_logic;
|
||||
|
||||
ram_addr : out std_logic_vector(12 downto 0);
|
||||
ram_di : out std_logic_vector(7 downto 0);
|
||||
ram_do : in std_logic_vector(7 downto 0);
|
||||
ram_we : out std_logic;
|
||||
sector_offset : out std_logic; -- 0 : sector 0 is at ram adr 0, 1 : sector 0 is at ram adr 256
|
||||
|
||||
save_track : in std_logic;
|
||||
change : in std_logic; -- Force reload as disk may have changed
|
||||
track : in std_logic_vector(5 downto 0); -- Track number (0-34)
|
||||
busy : out std_logic;
|
||||
|
||||
clk : in std_logic; -- System clock
|
||||
reset : in std_logic
|
||||
);
|
||||
end component mist_sd_card;
|
||||
|
||||
begin
|
||||
|
||||
c1541 : entity work.c1541_logic
|
||||
generic map
|
||||
(
|
||||
DEVICE_SELECT => "00"
|
||||
)
|
||||
port map
|
||||
(
|
||||
clk_32M => clk32,
|
||||
reset => reset,
|
||||
|
||||
-- serial bus
|
||||
sb_data_oe => iec_data_o,
|
||||
sb_clk_oe => iec_clk_o,
|
||||
sb_atn_oe => iec_atn_o,
|
||||
|
||||
sb_data_in => not iec_data_i,
|
||||
sb_clk_in => not iec_clk_i,
|
||||
sb_atn_in => not iec_atn_i,
|
||||
|
||||
-- drive-side interface
|
||||
ds => "00", -- device select
|
||||
di => c1541_logic_din, -- data read
|
||||
do => c1541_logic_dout, -- data to write
|
||||
mode => mode, -- read/write
|
||||
stp => stp, -- stepper motor control
|
||||
mtr => mtr, -- motor on/off
|
||||
freq => freq, -- motor frequency
|
||||
sync_n => sync_n, -- reading SYNC bytes
|
||||
byte_n => byte_n, -- byte ready
|
||||
wps_n => '1', -- write-protect sense (0 = protected)
|
||||
tr00_sense_n => '1', -- track 0 sense (unused?)
|
||||
act => act, -- activity LED
|
||||
|
||||
dbg_adr_fetch => dbg_adr_fetch,
|
||||
dbg_cpu_irq => open
|
||||
);
|
||||
|
||||
floppy : entity work.gcr_floppy
|
||||
port map
|
||||
(
|
||||
clk32 => clk32,
|
||||
|
||||
c1541_logic_din => c1541_logic_din, -- data read
|
||||
c1541_logic_dout => c1541_logic_dout, -- data to write
|
||||
|
||||
mode => mode, -- read/write
|
||||
-- stp => stp, -- stepper motor control
|
||||
mtr => mtr, -- stepper motor on/off
|
||||
-- freq => freq, -- motor (gcr_bit) frequency
|
||||
sync_n => sync_n, -- reading SYNC bytes
|
||||
byte_n => byte_n, -- byte ready
|
||||
|
||||
track_num => new_track_num_dbl(6 downto 1),
|
||||
|
||||
ram_addr => floppy_ram_addr,
|
||||
ram_do => ram_do,
|
||||
ram_di => floppy_ram_di,
|
||||
ram_we => floppy_ram_we,
|
||||
ram_ready => not sd_busy,
|
||||
|
||||
dbg_sector => dbg_sector
|
||||
);
|
||||
|
||||
-- mist_sd_card replaces work.spi_controller
|
||||
sd: mist_sd_card
|
||||
port map
|
||||
(
|
||||
clk => clk32,
|
||||
reset => reset,
|
||||
|
||||
ram_addr => spi_ram_addr, -- out unsigned(13 downto 0);
|
||||
ram_di => spi_ram_di, -- out unsigned(7 downto 0);
|
||||
ram_do => ram_do, -- in unsigned(7 downto 0);
|
||||
ram_we => spi_ram_we,
|
||||
|
||||
track => new_track_num_dbl(6 downto 1),
|
||||
-- disk_num => disk_num,
|
||||
busy => sd_busy,
|
||||
save_track => save_track,
|
||||
sector_offset => sector_offset,
|
||||
change => disk_change,
|
||||
|
||||
sd_buff_addr => sd_buff_addr,
|
||||
sd_buff_dout => sd_buff_dout,
|
||||
sd_buff_din => sd_buff_din,
|
||||
sd_buff_wr => sd_buff_wr,
|
||||
|
||||
sd_lba => sd_lba,
|
||||
sd_rd => sd_rd,
|
||||
sd_wr => sd_wr,
|
||||
sd_ack => sd_ack
|
||||
);
|
||||
|
||||
--sd_spi : entity work.spi_controller
|
||||
--port map
|
||||
--(
|
||||
-- cs_n => sd_cs_n, --: out std_logic; -- MMC chip select
|
||||
-- mosi => sd_mosi, --: out std_logic; -- Data to card (master out slave in)
|
||||
-- miso => sd_miso, --: in std_logic; -- Data from card (master in slave out)
|
||||
-- sclk => sd_sclk, --: out std_logic; -- Card clock
|
||||
-- bus_available => bus_available,
|
||||
--
|
||||
-- ram_addr => spi_ram_addr, -- out unsigned(13 downto 0);
|
||||
-- ram_di => spi_ram_di, -- out unsigned(7 downto 0);
|
||||
-- ram_do => ram_do, -- in unsigned(7 downto 0);
|
||||
-- ram_we => spi_ram_we,
|
||||
--
|
||||
-- track_num => new_track_num_dbl(6 downto 1),
|
||||
-- disk_num => disk_num,
|
||||
-- busy => sd_busy,
|
||||
-- save_track => save_track,
|
||||
-- sector_offset => sector_offset,
|
||||
--
|
||||
-- clk => clk_spi_ctrlr,
|
||||
-- reset => reset,
|
||||
--
|
||||
-- dbg_state => dbg_sd_state
|
||||
--);
|
||||
|
||||
process (clk32)
|
||||
begin
|
||||
if rising_edge(clk32) then
|
||||
stp_r <= stp;
|
||||
act_r <= act;
|
||||
mode_r <= mode;
|
||||
if reset = '1' then
|
||||
track_num_dbl <= "0100100";--"0000010";
|
||||
track_modified <= '0';
|
||||
save_track_stage <= X"0";
|
||||
else
|
||||
if mtr = '1' then
|
||||
if( (stp_r = "00" and stp = "10")
|
||||
or (stp_r = "10" and stp = "01")
|
||||
or (stp_r = "01" and stp = "11")
|
||||
or (stp_r = "11" and stp = "00")) then
|
||||
if track_num_dbl < "1010000" then
|
||||
track_num_dbl <= track_num_dbl + '1';
|
||||
if track_modified = '1' then
|
||||
if save_track_stage = X"0" then
|
||||
save_track_stage <= X"1";
|
||||
end if;
|
||||
else
|
||||
new_track_num_dbl <= track_num_dbl + '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if( (stp_r = "00" and stp = "11")
|
||||
or (stp_r = "10" and stp = "00")
|
||||
or (stp_r = "01" and stp = "10")
|
||||
or (stp_r = "11" and stp = "01")) then
|
||||
if track_num_dbl > "0000001" then
|
||||
track_num_dbl <= track_num_dbl - '1';
|
||||
if track_modified = '1' then
|
||||
if save_track_stage = X"0" then
|
||||
save_track_stage <= X"1";
|
||||
end if;
|
||||
else
|
||||
new_track_num_dbl <= track_num_dbl - '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if mode_r = '0' and mode = '1' then -- leaving write mode
|
||||
track_modified <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if act = '0' and act_r = '1' then -- stopping activity
|
||||
if track_modified = '1' and save_track_stage = X"0" then
|
||||
save_track_stage <= X"1";
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- save track state machine
|
||||
case save_track_stage is
|
||||
when X"0" =>
|
||||
new_track_num_dbl <= track_num_dbl;
|
||||
when X"1" =>
|
||||
save_track <= '1';
|
||||
if sd_busy = '1' then
|
||||
save_track_stage <= X"2";
|
||||
end if;
|
||||
when X"2" =>
|
||||
save_track_stage <= X"3";
|
||||
when X"3" =>
|
||||
save_track_stage <= X"4";
|
||||
when X"4" =>
|
||||
save_track <= '0'; -- must released save_track for spi_controler
|
||||
if sd_busy = '0' then
|
||||
save_track_stage <= X"5";
|
||||
end if;
|
||||
when X"5" =>
|
||||
track_modified <= '0';
|
||||
save_track_stage <= X"0";
|
||||
when others =>
|
||||
save_track_stage <= X"0";
|
||||
end case;
|
||||
|
||||
end if; -- reset
|
||||
end if; -- rising edge clock
|
||||
end process;
|
||||
|
||||
|
||||
process(clk32)
|
||||
begin
|
||||
if falling_edge(clk32) then
|
||||
if ram_we = '1' then
|
||||
track_buffer(to_integer(unsigned(ram_addr))) <= ram_di;
|
||||
end if;
|
||||
ram_do <= track_buffer(to_integer(unsigned(ram_addr)));
|
||||
end if;
|
||||
end process;
|
||||
|
||||
ram_addr <= spi_ram_addr when sd_busy = '1' else floppy_ram_addr + ("000"§or_offset&X"00");
|
||||
ram_we <= spi_ram_we when sd_busy = '1' else floppy_ram_we;
|
||||
ram_di <= spi_ram_di when sd_busy = '1' else floppy_ram_di;
|
||||
|
||||
process (clk32)
|
||||
begin
|
||||
if rising_edge(clk32) then
|
||||
if dbg_adr_fetch = X"F4D7" then
|
||||
dbg_read_sector <= dbg_sector;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
dbg_sd_busy <= sd_busy;
|
||||
dbg_track_num_dbl <= new_track_num_dbl;
|
||||
dbg_mtr <= mtr;
|
||||
dbg_act <= act;
|
||||
|
||||
end struct;
|
||||
311
cores/c16/c1541/c1541_sd.vhd.bak
Normal file
311
cores/c16/c1541/c1541_sd.vhd.bak
Normal file
@@ -0,0 +1,311 @@
|
||||
---------------------------------------------------------------------------------
|
||||
-- Commodore 1541 to SD card (read/write) by Dar (darfpga@aol.fr) 24-May-2017
|
||||
-- http://darfpga.blogspot.fr
|
||||
--
|
||||
-- c1541_sd reads D64 data from raw SD card, produces GCR data, feeds c1541_logic
|
||||
-- Raw SD data : each D64 image must start on 256KB boundaries
|
||||
-- disk_num allow to select D64 image
|
||||
--
|
||||
-- c1541_logic from : Mark McDougall
|
||||
-- spi_controller from : Michel Stempin, Stephen A. Edwards
|
||||
-- via6522 from : Arnim Laeuger, Mark McDougall, MikeJ
|
||||
-- T65 from : Daniel Wallner, MikeJ, ehenciak
|
||||
--
|
||||
-- c1541_logic modified for : slow down CPU (EOI ack missed by real c64)
|
||||
-- : remove iec internal OR wired
|
||||
-- : synched atn_in (sometime no IRQ with real c64)
|
||||
-- spi_controller modified for : sector start and size adapted + busy signal
|
||||
-- via6522 modified for : no modification
|
||||
--
|
||||
--
|
||||
-- Input clk 32MHz and 18MHz (18MHz could be replaced with 32/2 if needed)
|
||||
--
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.std_logic_unsigned.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity c1541_sd is
|
||||
port(
|
||||
clk32 : in std_logic;
|
||||
clk_spi_ctrlr : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
disk_num : in std_logic_vector(9 downto 0);
|
||||
|
||||
iec_atn_i : in std_logic;
|
||||
iec_data_i : in std_logic;
|
||||
iec_clk_i : in std_logic;
|
||||
|
||||
iec_atn_o : out std_logic;
|
||||
iec_data_o : out std_logic;
|
||||
iec_clk_o : out std_logic;
|
||||
|
||||
sd_miso : in std_logic;
|
||||
sd_cs_n : buffer std_logic;
|
||||
sd_mosi : buffer std_logic;
|
||||
sd_sclk : buffer std_logic;
|
||||
bus_available : in std_logic;
|
||||
|
||||
dbg_track_num_dbl : out std_logic_vector(6 downto 0);
|
||||
dbg_sd_busy : out std_logic;
|
||||
dbg_sd_state : out std_logic_vector(7 downto 0);
|
||||
dbg_read_sector : out std_logic_vector(4 downto 0);
|
||||
dbg_mtr : out std_logic;
|
||||
dbg_act : out std_logic
|
||||
);
|
||||
end c1541_sd;
|
||||
|
||||
architecture struct of c1541_sd is
|
||||
|
||||
signal spi_ram_addr : std_logic_vector(12 downto 0);
|
||||
signal spi_ram_di : std_logic_vector( 7 downto 0);
|
||||
signal spi_ram_we : std_logic;
|
||||
|
||||
signal ram_addr : std_logic_vector(12 downto 0);
|
||||
signal ram_di : std_logic_vector( 7 downto 0);
|
||||
signal ram_do : std_logic_vector( 7 downto 0);
|
||||
signal ram_we : std_logic;
|
||||
|
||||
signal floppy_ram_addr : std_logic_vector(12 downto 0);
|
||||
signal floppy_ram_di : std_logic_vector( 7 downto 0);
|
||||
signal floppy_ram_we : std_logic;
|
||||
|
||||
signal c1541_logic_din : std_logic_vector(7 downto 0); -- data read
|
||||
signal c1541_logic_dout : std_logic_vector(7 downto 0); -- data to write
|
||||
signal mode : std_logic; -- read/write
|
||||
signal mode_r : std_logic; -- read/write
|
||||
signal stp : std_logic_vector(1 downto 0); -- stepper motor control
|
||||
signal stp_r : std_logic_vector(1 downto 0); -- stepper motor control
|
||||
signal mtr : std_logic ; -- stepper motor on/off
|
||||
--signal mtr_r : std_logic ; -- stepper motor on/off
|
||||
signal freq : std_logic_vector(1 downto 0); -- motor (gcr_bit) frequency
|
||||
signal sync_n : std_logic; -- reading SYNC bytes
|
||||
signal byte_n : std_logic; -- byte ready
|
||||
signal act : std_logic; -- activity LED
|
||||
signal act_r : std_logic; -- activity LED
|
||||
|
||||
signal track_num_dbl : std_logic_vector(6 downto 0);
|
||||
signal new_track_num_dbl : std_logic_vector(6 downto 0);
|
||||
signal sd_busy : std_logic;
|
||||
|
||||
type byte_array is array(0 to 8191) of std_logic_vector(7 downto 0);
|
||||
signal track_buffer : byte_array;
|
||||
|
||||
signal save_track : std_logic;
|
||||
signal track_modified : std_logic;
|
||||
signal sector_offset : std_logic;
|
||||
signal save_track_stage : std_logic_vector(3 downto 0);
|
||||
|
||||
signal dbg_sector : std_logic_vector(4 downto 0);
|
||||
signal dbg_adr_fetch : std_logic_vector(15 downto 0);
|
||||
|
||||
|
||||
begin
|
||||
|
||||
c1541 : entity work.c1541_logic
|
||||
generic map
|
||||
(
|
||||
DEVICE_SELECT => "00"
|
||||
)
|
||||
port map
|
||||
(
|
||||
clk_32M => clk32,
|
||||
reset => reset,
|
||||
|
||||
-- serial bus
|
||||
sb_data_oe => iec_data_o,
|
||||
sb_clk_oe => iec_clk_o,
|
||||
sb_atn_oe => iec_atn_o,
|
||||
|
||||
sb_data_in => not iec_data_i,
|
||||
sb_clk_in => not iec_clk_i,
|
||||
sb_atn_in => not iec_atn_i,
|
||||
|
||||
-- drive-side interface
|
||||
ds => "00", -- device select
|
||||
di => c1541_logic_din, -- data read
|
||||
do => c1541_logic_dout, -- data to write
|
||||
mode => mode, -- read/write
|
||||
stp => stp, -- stepper motor control
|
||||
mtr => mtr, -- motor on/off
|
||||
freq => freq, -- motor frequency
|
||||
sync_n => sync_n, -- reading SYNC bytes
|
||||
byte_n => byte_n, -- byte ready
|
||||
wps_n => '1', -- write-protect sense (0 = protected)
|
||||
tr00_sense_n => '1', -- track 0 sense (unused?)
|
||||
act => act, -- activity LED
|
||||
|
||||
dbg_adr_fetch => dbg_adr_fetch,
|
||||
dbg_cpu_irq => open
|
||||
);
|
||||
|
||||
floppy : entity work.gcr_floppy
|
||||
port map
|
||||
(
|
||||
clk32 => clk32,
|
||||
|
||||
c1541_logic_din => c1541_logic_din, -- data read
|
||||
c1541_logic_dout => c1541_logic_dout, -- data to write
|
||||
|
||||
mode => mode, -- read/write
|
||||
-- stp => stp, -- stepper motor control
|
||||
mtr => mtr, -- stepper motor on/off
|
||||
-- freq => freq, -- motor (gcr_bit) frequency
|
||||
sync_n => sync_n, -- reading SYNC bytes
|
||||
byte_n => byte_n, -- byte ready
|
||||
|
||||
track_num => new_track_num_dbl(6 downto 1),
|
||||
|
||||
ram_addr => floppy_ram_addr,
|
||||
ram_do => ram_do,
|
||||
ram_di => floppy_ram_di,
|
||||
ram_we => floppy_ram_we,
|
||||
ram_ready => not sd_busy,
|
||||
|
||||
dbg_sector => dbg_sector
|
||||
);
|
||||
|
||||
process (clk32)
|
||||
begin
|
||||
if rising_edge(clk32) then
|
||||
stp_r <= stp;
|
||||
act_r <= act;
|
||||
mode_r <= mode;
|
||||
if reset = '1' then
|
||||
track_num_dbl <= "0100100";--"0000010";
|
||||
track_modified <= '0';
|
||||
save_track_stage <= X"0";
|
||||
else
|
||||
if mtr = '1' then
|
||||
if( (stp_r = "00" and stp = "10")
|
||||
or (stp_r = "10" and stp = "01")
|
||||
or (stp_r = "01" and stp = "11")
|
||||
or (stp_r = "11" and stp = "00")) then
|
||||
if track_num_dbl < "1010000" then
|
||||
track_num_dbl <= track_num_dbl + '1';
|
||||
if track_modified = '1' then
|
||||
if save_track_stage = X"0" then
|
||||
save_track_stage <= X"1";
|
||||
end if;
|
||||
else
|
||||
new_track_num_dbl <= track_num_dbl + '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if( (stp_r = "00" and stp = "11")
|
||||
or (stp_r = "10" and stp = "00")
|
||||
or (stp_r = "01" and stp = "10")
|
||||
or (stp_r = "11" and stp = "01")) then
|
||||
if track_num_dbl > "0000001" then
|
||||
track_num_dbl <= track_num_dbl - '1';
|
||||
if track_modified = '1' then
|
||||
if save_track_stage = X"0" then
|
||||
save_track_stage <= X"1";
|
||||
end if;
|
||||
else
|
||||
new_track_num_dbl <= track_num_dbl - '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if mode_r = '0' and mode = '1' then -- leaving write mode
|
||||
track_modified <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if act = '0' and act_r = '1' then -- stopping activity
|
||||
if track_modified = '1' and save_track_stage = X"0" then
|
||||
save_track_stage <= X"1";
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- save track state machine
|
||||
case save_track_stage is
|
||||
when X"0" =>
|
||||
new_track_num_dbl <= track_num_dbl;
|
||||
when X"1" =>
|
||||
save_track <= '1';
|
||||
if sd_busy = '1' then
|
||||
save_track_stage <= X"2";
|
||||
end if;
|
||||
when X"2" =>
|
||||
save_track_stage <= X"3";
|
||||
when X"3" =>
|
||||
save_track_stage <= X"4";
|
||||
when X"4" =>
|
||||
save_track <= '0'; -- must released save_track for spi_controler
|
||||
if sd_busy = '0' then
|
||||
save_track_stage <= X"5";
|
||||
end if;
|
||||
when X"5" =>
|
||||
track_modified <= '0';
|
||||
save_track_stage <= X"0";
|
||||
when others =>
|
||||
save_track_stage <= X"0";
|
||||
end case;
|
||||
|
||||
end if; -- reset
|
||||
end if; -- rising edge clock
|
||||
end process;
|
||||
|
||||
|
||||
sd_spi : entity work.spi_controller
|
||||
port map
|
||||
(
|
||||
cs_n => sd_cs_n, --: out std_logic; -- MMC chip select
|
||||
mosi => sd_mosi, --: out std_logic; -- Data to card (master out slave in)
|
||||
miso => sd_miso, --: in std_logic; -- Data from card (master in slave out)
|
||||
sclk => sd_sclk, --: out std_logic; -- Card clock
|
||||
bus_available => bus_available,
|
||||
|
||||
ram_addr => spi_ram_addr, -- out unsigned(13 downto 0);
|
||||
ram_di => spi_ram_di, -- out unsigned(7 downto 0);
|
||||
ram_do => ram_do, -- in unsigned(7 downto 0);
|
||||
ram_we => spi_ram_we,
|
||||
|
||||
track_num => new_track_num_dbl(6 downto 1),
|
||||
disk_num => disk_num,
|
||||
busy => sd_busy,
|
||||
save_track => save_track,
|
||||
sector_offset => sector_offset,
|
||||
|
||||
clk => clk_spi_ctrlr,
|
||||
reset => reset,
|
||||
|
||||
dbg_state => dbg_sd_state
|
||||
);
|
||||
|
||||
|
||||
process(clk32)
|
||||
begin
|
||||
if falling_edge(clk32) then
|
||||
if ram_we = '1' then
|
||||
track_buffer(to_integer(unsigned(ram_addr))) <= ram_di;
|
||||
end if;
|
||||
ram_do <= track_buffer(to_integer(unsigned(ram_addr)));
|
||||
end if;
|
||||
end process;
|
||||
|
||||
ram_addr <= spi_ram_addr when sd_busy = '1' else floppy_ram_addr + ("000"§or_offset&X"00");
|
||||
ram_we <= spi_ram_we when sd_busy = '1' else floppy_ram_we;
|
||||
ram_di <= spi_ram_di when sd_busy = '1' else floppy_ram_di;
|
||||
|
||||
process (clk32)
|
||||
begin
|
||||
if rising_edge(clk32) then
|
||||
if dbg_adr_fetch = X"F4D7" then
|
||||
dbg_read_sector <= dbg_sector;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
dbg_sd_busy <= sd_busy;
|
||||
dbg_track_num_dbl <= new_track_num_dbl;
|
||||
dbg_mtr <= mtr;
|
||||
dbg_act <= act;
|
||||
|
||||
end struct;
|
||||
318
cores/c16/c1541/gcr_floppy.vhd
Normal file
318
cores/c16/c1541/gcr_floppy.vhd
Normal file
@@ -0,0 +1,318 @@
|
||||
---------------------------------------------------------------------------------
|
||||
-- Commodore 1541 gcr floppy (read/write) by Dar (darfpga@aol.fr) 23-May-2017
|
||||
-- http://darfpga.blogspot.fr
|
||||
--
|
||||
-- produces GCR data, byte(ready) and sync signal to feed c1541_logic from current
|
||||
-- track buffer ram which contains D64 data
|
||||
--
|
||||
-- gets GCR data from c1541_logic, while producing byte(ready) signal. Data feed
|
||||
-- track buffer ram after conversion
|
||||
--
|
||||
-- Input clk 32MHz
|
||||
--
|
||||
---------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.std_logic_unsigned.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity gcr_floppy is
|
||||
port(
|
||||
clk32 : in std_logic;
|
||||
c1541_logic_din : out std_logic_vector(7 downto 0); -- data from ram to 1541 logic
|
||||
c1541_logic_dout : in std_logic_vector(7 downto 0); -- data from 1541 logic to ram
|
||||
mode : in std_logic; -- read/write
|
||||
-- stp : in std_logic_vector(1 downto 0); -- stepper motor control
|
||||
mtr : in std_logic; -- stepper motor on/off
|
||||
-- freq : in std_logic_vector(1 downto 0); -- motor (gcr_bit) frequency
|
||||
sync_n : out std_logic; -- reading SYNC bytes
|
||||
byte_n : out std_logic; -- byte ready
|
||||
|
||||
track_num : in std_logic_vector(5 downto 0);
|
||||
|
||||
ram_addr : out std_logic_vector(12 downto 0);
|
||||
ram_do : in std_logic_vector(7 downto 0);
|
||||
ram_di : buffer std_logic_vector(7 downto 0);
|
||||
ram_we : out std_logic;
|
||||
ram_ready : in std_logic;
|
||||
|
||||
dbg_sector : out std_logic_vector(4 downto 0)
|
||||
);
|
||||
end gcr_floppy;
|
||||
|
||||
architecture struct of gcr_floppy is
|
||||
|
||||
signal bit_clk_en : std_logic;
|
||||
signal sync_cnt : std_logic_vector(5 downto 0) := (others => '0');
|
||||
signal byte_cnt : std_logic_vector(8 downto 0) := (others => '0');
|
||||
signal nibble : std_logic := '0';
|
||||
signal gcr_bit_cnt : std_logic_vector(3 downto 0) := (others => '0');
|
||||
signal bit_cnt : std_logic_vector(2 downto 0) := (others => '0');
|
||||
|
||||
signal sync_in_n : std_logic;
|
||||
signal byte_in_n : std_logic;
|
||||
|
||||
signal sector : std_logic_vector(4 downto 0) := (others => '0');
|
||||
signal state : std_logic := '0';
|
||||
|
||||
signal data_header : std_logic_vector(7 downto 0);
|
||||
signal data_body : std_logic_vector(7 downto 0);
|
||||
signal data : std_logic_vector(7 downto 0);
|
||||
signal data_cks : std_logic_vector(7 downto 0);
|
||||
signal gcr_nibble : std_logic_vector(4 downto 0);
|
||||
signal gcr_bit : std_logic;
|
||||
signal gcr_byte : std_logic_vector(7 downto 0);
|
||||
|
||||
signal mode_r1 : std_logic;
|
||||
signal mode_r2 : std_logic;
|
||||
|
||||
type gcr_array is array(0 to 15) of std_logic_vector(4 downto 0);
|
||||
|
||||
signal gcr_lut : gcr_array :=
|
||||
("01010","11010","01001","11001",
|
||||
"01110","11110","01101","11101",
|
||||
"10010","10011","01011","11011",
|
||||
"10110","10111","01111","10101");
|
||||
|
||||
signal sector_max : std_logic_vector(4 downto 0);
|
||||
|
||||
signal gcr_byte_out : std_logic_vector(7 downto 0);
|
||||
signal gcr_bit_out : std_logic;
|
||||
signal gcr_nibble_out : std_logic_vector(4 downto 0);
|
||||
signal nibble_out : std_logic_vector(3 downto 0);
|
||||
|
||||
signal autorise_write : std_logic;
|
||||
signal autorise_count : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
sync_n <= sync_in_n when mtr = '1' and ram_ready = '1' else '1';
|
||||
|
||||
dbg_sector <= sector;
|
||||
|
||||
with byte_cnt select
|
||||
data_header <=
|
||||
X"08" when "000000000",
|
||||
"00"&track_num xor "000"§or when "000000001",
|
||||
"000"§or when "000000010",
|
||||
"00"&track_num when "000000011",
|
||||
X"20" when "000000100",
|
||||
X"20" when "000000101",
|
||||
X"0F" when others;
|
||||
|
||||
with byte_cnt select
|
||||
data_body <=
|
||||
X"07" when "000000000",
|
||||
data_cks when "100000001",
|
||||
X"00" when "100000010",
|
||||
X"00" when "100000011",
|
||||
X"0F" when "100000100",
|
||||
X"0F" when "100000101",
|
||||
X"0F" when "100000110",
|
||||
X"0F" when "100000111",
|
||||
X"0F" when "100001000",
|
||||
X"0F" when "100001001",
|
||||
X"0F" when "100001010",
|
||||
X"0F" when "100001011",
|
||||
X"0F" when "100001100",
|
||||
X"0F" when "100001101",
|
||||
X"0F" when "100001110",
|
||||
X"0F" when "100001111",
|
||||
X"0F" when "100010000",
|
||||
X"0F" when "100010001",
|
||||
ram_do when others;
|
||||
|
||||
with state select
|
||||
data <= data_header when '0', data_body when others;
|
||||
|
||||
with nibble select
|
||||
gcr_nibble <=
|
||||
gcr_lut(to_integer(unsigned(data(7 downto 4)))) when '0',
|
||||
gcr_lut(to_integer(unsigned(data(3 downto 0)))) when others;
|
||||
|
||||
gcr_bit <= gcr_nibble(to_integer(unsigned(gcr_bit_cnt)));
|
||||
|
||||
sector_max <= "10100" when track_num < std_logic_vector(to_unsigned(18,6)) else
|
||||
"10010" when track_num < std_logic_vector(to_unsigned(25,6)) else
|
||||
"10001" when track_num < std_logic_vector(to_unsigned(31,6)) else
|
||||
"10000" ;
|
||||
|
||||
gcr_bit_out <= gcr_byte_out(to_integer(unsigned(not bit_cnt)));
|
||||
|
||||
with gcr_nibble_out select
|
||||
nibble_out <= X"0" when "01010",--"01010",
|
||||
X"1" when "01011",--"11010",
|
||||
X"2" when "10010",--"01001",
|
||||
X"3" when "10011",--"11001",
|
||||
X"4" when "01110",--"01110",
|
||||
X"5" when "01111",--"11110",
|
||||
X"6" when "10110",--"01101",
|
||||
X"7" when "10111",--"11101",
|
||||
X"8" when "01001",--"10010",
|
||||
X"9" when "11001",--"10011",
|
||||
X"A" when "11010",--"01011",
|
||||
X"B" when "11011",--"11011",
|
||||
X"C" when "01101",--"10110",
|
||||
X"D" when "11101",--"10111",
|
||||
X"E" when "11110",--"01111",
|
||||
X"F" when others; --"10101",
|
||||
|
||||
process (clk32)
|
||||
variable bit_clk_cnt : std_logic_vector(7 downto 0) := (others => '0');
|
||||
begin
|
||||
if rising_edge(clk32) then
|
||||
|
||||
mode_r1 <= mode;
|
||||
|
||||
if (mode_r1 xor mode) = '1' then -- read <-> write change
|
||||
bit_clk_cnt := (others => '0');
|
||||
byte_n <= '1';
|
||||
bit_clk_en <= '0';
|
||||
else
|
||||
bit_clk_en <= '0';
|
||||
if bit_clk_cnt = X"6F" then
|
||||
bit_clk_en <= '1';
|
||||
bit_clk_cnt := (others => '0');
|
||||
else
|
||||
bit_clk_cnt := bit_clk_cnt + '1';
|
||||
end if;
|
||||
|
||||
byte_n <= '1';
|
||||
if byte_in_n = '0' and mtr = '1' and ram_ready = '1' then
|
||||
if bit_clk_cnt > X"10" then
|
||||
if bit_clk_cnt < X"5E" then
|
||||
byte_n <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
read_write_process : process (clk32, bit_clk_en)
|
||||
begin
|
||||
if rising_edge(clk32) and bit_clk_en = '1' then
|
||||
|
||||
mode_r2 <= mode;
|
||||
if mode = '1' then autorise_write <= '0'; end if;
|
||||
|
||||
if (mode xor mode_r2) = '1' then
|
||||
if mode = '1' then -- leaving write mode
|
||||
sync_in_n <= '0';
|
||||
sync_cnt <= (others => '0');
|
||||
state <= '0';
|
||||
else -- entering write mode
|
||||
byte_cnt <= (others => '0');
|
||||
nibble <= '0';
|
||||
gcr_bit_cnt <= (others => '0');
|
||||
bit_cnt <= (others => '0');
|
||||
gcr_byte <= (others => '0');
|
||||
data_cks <= (others => '0');
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if sync_in_n = '0' and mode = '1' then
|
||||
|
||||
byte_cnt <= (others => '0');
|
||||
nibble <= '0';
|
||||
gcr_bit_cnt <= (others => '0');
|
||||
bit_cnt <= (others => '0');
|
||||
c1541_logic_din <= (others => '0');
|
||||
gcr_byte <= (others => '0');
|
||||
data_cks <= (others => '0');
|
||||
|
||||
if sync_cnt = X"31" then
|
||||
sync_cnt <= (others => '0');
|
||||
sync_in_n <= '1';
|
||||
else
|
||||
sync_cnt <= sync_cnt + '1';
|
||||
end if;
|
||||
|
||||
end if;
|
||||
|
||||
if sync_in_n = '1' or mode = '0' then
|
||||
|
||||
gcr_bit_cnt <= gcr_bit_cnt + '1';
|
||||
if gcr_bit_cnt = X"4" then
|
||||
gcr_bit_cnt <= (others => '0');
|
||||
if nibble = '1' then
|
||||
nibble <= '0';
|
||||
ram_addr <= sector & byte_cnt(7 downto 0);
|
||||
if byte_cnt = "000000000" then
|
||||
data_cks <= (others => '0');
|
||||
else
|
||||
data_cks <= data_cks xor data;
|
||||
end if;
|
||||
if mode = '1' or (mode = '0' and autorise_count = '1') then
|
||||
byte_cnt <= byte_cnt + '1';
|
||||
end if;
|
||||
else
|
||||
nibble <= '1';
|
||||
if mode = '0' and ram_di = X"07" then
|
||||
autorise_write <= '1';
|
||||
autorise_count <= '1';
|
||||
end if;
|
||||
if byte_cnt >= "100000000" then
|
||||
autorise_write <= '0';
|
||||
autorise_count <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
bit_cnt <= bit_cnt + '1';
|
||||
byte_in_n <= '1';
|
||||
if bit_cnt = X"7" then
|
||||
byte_in_n <= '0';
|
||||
gcr_byte_out <= c1541_logic_dout;
|
||||
end if;
|
||||
|
||||
if state = '0' then
|
||||
if byte_cnt = "000010000" then
|
||||
sync_in_n <= '0';
|
||||
state<= '1';
|
||||
end if;
|
||||
else
|
||||
if byte_cnt = "100010001" then
|
||||
sync_in_n <= '0';
|
||||
state <= '0';
|
||||
if sector = sector_max then
|
||||
sector <= (others=>'0');
|
||||
else
|
||||
sector <= sector + '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- demux byte from floppy (ram)
|
||||
gcr_byte <= gcr_byte(6 downto 0) & gcr_bit;
|
||||
|
||||
if bit_cnt = X"7" then
|
||||
c1541_logic_din <= gcr_byte(6 downto 0) & gcr_bit;
|
||||
end if;
|
||||
|
||||
-- serialise/convert byte to floppy (ram)
|
||||
gcr_nibble_out <= gcr_nibble_out(3 downto 0) & gcr_bit_out;
|
||||
|
||||
if gcr_bit_cnt = X"0" then
|
||||
if nibble = '0' then
|
||||
ram_di(3 downto 0) <= nibble_out;
|
||||
else
|
||||
ram_di(7 downto 4) <= nibble_out;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if gcr_bit_cnt = X"1" and nibble = '0' then
|
||||
if autorise_write = '1' then
|
||||
ram_we <= '1';
|
||||
end if;
|
||||
else
|
||||
ram_we <= '0';
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end struct;
|
||||
128
cores/c16/c1541/mist_sd_card.sv
Normal file
128
cores/c16/c1541/mist_sd_card.sv
Normal file
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// sd_card.v
|
||||
//
|
||||
// Copyright (c) 2016 Sorgelig
|
||||
//
|
||||
// This source file is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the Lesser GNU General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This source file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module mist_sd_card
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
output [31:0] sd_lba,
|
||||
output reg sd_rd,
|
||||
output reg sd_wr,
|
||||
input sd_ack,
|
||||
|
||||
input [8:0] sd_buff_addr,
|
||||
input [7:0] sd_buff_dout,
|
||||
output [7:0] sd_buff_din,
|
||||
input sd_buff_wr,
|
||||
|
||||
input save_track,
|
||||
input change,
|
||||
input [5:0] track,
|
||||
|
||||
output [12:0] ram_addr,
|
||||
output [7:0] ram_di,
|
||||
input [7:0] ram_do,
|
||||
output ram_we,
|
||||
output reg sector_offset, // 0 : sector 0 is at ram adr 0,
|
||||
// 1 : sector 0 is at ram adr 256
|
||||
output reg busy
|
||||
);
|
||||
|
||||
assign sd_lba = lba;
|
||||
assign ram_addr = { rel_lba, sd_buff_addr};
|
||||
assign ram_di = sd_buff_dout;
|
||||
assign sd_buff_din = ram_do;
|
||||
assign ram_we = sd_buff_wr;
|
||||
|
||||
wire [9:0] start_sectors[41] =
|
||||
'{ 0, 0, 21, 42, 63, 84,105,126,147,168,189,210,231,252,273,294,315,336,357,376,395,
|
||||
414,433,452,471,490,508,526,544,562,580,598,615,632,649,666,683,700,717,734,751};
|
||||
|
||||
reg [31:0] lba;
|
||||
reg [3:0] rel_lba;
|
||||
|
||||
always @(posedge clk) begin
|
||||
reg old_ack;
|
||||
reg [5:0] cur_track = 0;
|
||||
reg old_change, ready = 0;
|
||||
reg saving = 0;
|
||||
|
||||
old_change <= change;
|
||||
if(~old_change & change) ready <= 1;
|
||||
|
||||
old_ack <= sd_ack;
|
||||
if(sd_ack) {sd_rd,sd_wr} <= 0;
|
||||
|
||||
if(reset) begin
|
||||
cur_track <= 'b111111;
|
||||
busy <= 0;
|
||||
sd_rd <= 0;
|
||||
sd_wr <= 0;
|
||||
saving<= 0;
|
||||
end
|
||||
else
|
||||
if(busy) begin
|
||||
if(old_ack && ~sd_ack) begin
|
||||
if(~&rel_lba) begin
|
||||
lba <= lba + 1'd1;
|
||||
rel_lba <= rel_lba + 1'd1;
|
||||
if(saving) sd_wr <= 1;
|
||||
else sd_rd <= 1;
|
||||
end
|
||||
else
|
||||
if(saving && (cur_track != track)) begin
|
||||
saving <= 0;
|
||||
cur_track <= track;
|
||||
rel_lba <= 0;
|
||||
sector_offset <= start_sectors[track][0] ;
|
||||
lba <= start_sectors[track][9:1];
|
||||
sd_rd <= 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
busy <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if(ready) begin
|
||||
if(save_track && cur_track != 'b111111) begin
|
||||
saving <= 1;
|
||||
lba <= start_sectors[cur_track][9:1];
|
||||
rel_lba <= 0;
|
||||
sd_wr <= 1;
|
||||
busy <= 1;
|
||||
end
|
||||
else
|
||||
if((cur_track != track) || (old_change && ~change)) begin
|
||||
saving <= 0;
|
||||
cur_track <= track;
|
||||
rel_lba <= 0;
|
||||
sector_offset <= start_sectors[track][0] ;
|
||||
lba <= start_sectors[track][9:1];
|
||||
sd_rd <= 1;
|
||||
busy <= 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
175
cores/c16/c1541/mist_sd_card.sv.bak
Normal file
175
cores/c16/c1541/mist_sd_card.sv.bak
Normal file
@@ -0,0 +1,175 @@
|
||||
//
|
||||
// sd_card.v
|
||||
//
|
||||
// Copyright (c) 2016 Sorgelig
|
||||
//
|
||||
// This source file is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the Lesser GNU General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This source file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module sd_card
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
output [31:0] sd_lba,
|
||||
output reg sd_rd,
|
||||
output reg sd_wr,
|
||||
input sd_ack,
|
||||
|
||||
input [8:0] sd_buff_addr,
|
||||
input [7:0] sd_buff_dout,
|
||||
output [7:0] sd_buff_din,
|
||||
input sd_buff_wr,
|
||||
|
||||
input save_track,
|
||||
input change,
|
||||
input [5:0] track,
|
||||
input [4:0] sector,
|
||||
input [7:0] buff_addr,
|
||||
output [7:0] buff_dout,
|
||||
input [7:0] buff_din,
|
||||
input buff_we,
|
||||
output reg busy
|
||||
);
|
||||
|
||||
assign sd_lba = lba;
|
||||
|
||||
trk_dpram buffer
|
||||
(
|
||||
.clock(clk),
|
||||
|
||||
.address_a(sd_buff_base + base_fix + sd_buff_addr),
|
||||
.data_a(sd_buff_dout),
|
||||
.wren_a(sd_ack & sd_buff_wr),
|
||||
.q_a(sd_buff_din),
|
||||
|
||||
.address_b({sector, buff_addr}),
|
||||
.data_b(buff_din),
|
||||
.wren_b(buff_we),
|
||||
.q_b(buff_dout)
|
||||
);
|
||||
|
||||
wire [9:0] start_sectors[41] =
|
||||
'{ 0, 0, 21, 42, 63, 84,105,126,147,168,189,210,231,252,273,294,315,336,357,376,395,
|
||||
414,433,452,471,490,508,526,544,562,580,598,615,632,649,666,683,700,717,734,751};
|
||||
|
||||
reg [31:0] lba;
|
||||
reg [12:0] base_fix;
|
||||
reg [12:0] sd_buff_base;
|
||||
|
||||
always @(posedge clk) begin
|
||||
reg old_ack;
|
||||
reg [5:0] cur_track = 0;
|
||||
reg old_change, ready = 0;
|
||||
reg saving = 0;
|
||||
|
||||
old_change <= change;
|
||||
if(~old_change & change) ready <= 1;
|
||||
|
||||
old_ack <= sd_ack;
|
||||
if(sd_ack) {sd_rd,sd_wr} <= 0;
|
||||
|
||||
if(reset) begin
|
||||
cur_track <= 'b111111;
|
||||
busy <= 0;
|
||||
sd_rd <= 0;
|
||||
sd_wr <= 0;
|
||||
saving<= 0;
|
||||
end
|
||||
else
|
||||
if(busy) begin
|
||||
if(old_ack && ~sd_ack) begin
|
||||
if(sd_buff_base < 'h1800) begin
|
||||
sd_buff_base <= sd_buff_base + 13'd512;
|
||||
lba <= lba + 1'd1;
|
||||
if(saving) sd_wr <= 1;
|
||||
else sd_rd <= 1;
|
||||
end
|
||||
else
|
||||
if(saving && (cur_track != track)) begin
|
||||
saving <= 0;
|
||||
cur_track <= track;
|
||||
sd_buff_base <= 0;
|
||||
base_fix <= start_sectors[track][0] ? 13'h1F00 : 13'h0000;
|
||||
lba <= start_sectors[track][9:1];
|
||||
sd_rd <= 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
busy <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if(ready) begin
|
||||
if(save_track && cur_track != 'b111111) begin
|
||||
saving <= 1;
|
||||
sd_buff_base <= 0;
|
||||
lba <= start_sectors[cur_track][9:1];
|
||||
sd_wr <= 1;
|
||||
busy <= 1;
|
||||
end
|
||||
else
|
||||
if((cur_track != track) || (old_change && ~change)) begin
|
||||
saving <= 0;
|
||||
cur_track <= track;
|
||||
sd_buff_base <= 0;
|
||||
base_fix <= start_sectors[track][0] ? 13'h1F00 : 13'h0000;
|
||||
lba <= start_sectors[track][9:1];
|
||||
sd_rd <= 1;
|
||||
busy <= 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module trk_dpram #(parameter DATAWIDTH=8, ADDRWIDTH=13)
|
||||
(
|
||||
input clock,
|
||||
|
||||
input [ADDRWIDTH-1:0] address_a,
|
||||
input [DATAWIDTH-1:0] data_a,
|
||||
input wren_a,
|
||||
output reg [DATAWIDTH-1:0] q_a,
|
||||
|
||||
input [ADDRWIDTH-1:0] address_b,
|
||||
input [DATAWIDTH-1:0] data_b,
|
||||
input wren_b,
|
||||
output reg [DATAWIDTH-1:0] q_b
|
||||
);
|
||||
|
||||
logic [DATAWIDTH-1:0] ram[0:(1<<ADDRWIDTH)-1];
|
||||
|
||||
always_ff@(posedge clock) begin
|
||||
if(wren_a) begin
|
||||
ram[address_a] <= data_a;
|
||||
q_a <= data_a;
|
||||
end else begin
|
||||
q_a <= ram[address_a];
|
||||
end
|
||||
end
|
||||
|
||||
always_ff@(posedge clock) begin
|
||||
if(wren_b) begin
|
||||
ram[address_b] <= data_b;
|
||||
q_b <= data_b;
|
||||
end else begin
|
||||
q_b <= ram[address_b];
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -9,39 +9,61 @@
|
||||
-- Stephen A. Edwards (sedwards@cs.columbia.edu)
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-- Principle : (after card init)
|
||||
-- * read track_size data (26*256 bytes) from sd card to ram buffer when
|
||||
-- disk_num or track_num change
|
||||
-- * write track_size data back from ram buffer to sd card when save_track
|
||||
-- is pulsed to '1'
|
||||
--
|
||||
-- Data read from sd_card always start on 512 bytes boundaries.
|
||||
-- When actual D64 track starts on 512 bytes boundary sector_offset is set
|
||||
-- to 0.
|
||||
-- When actual D64 track starts on 256 bytes boundary sector_offset is set
|
||||
-- to 1.
|
||||
-- External ram buffer 'user' should mind sector_offset to retrieve correct
|
||||
-- data offset.
|
||||
--
|
||||
-- One should be advised that extra bytes may be read and write out of disk
|
||||
-- boundary when using last track. With a single sd card user this should
|
||||
-- lead to no problem since written data always comes from the exact same
|
||||
-- read place (extra written data will replaced same value on disk).
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.std_logic_unsigned.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
|
||||
entity spi_controller is
|
||||
generic (
|
||||
BLOCK_SIZE : natural := 512;
|
||||
BLOCK_BITS : natural := 9;
|
||||
-- BLOCK_SIZE : natural := 256;
|
||||
-- BLOCK_BITS : natural := 8;
|
||||
|
||||
TRACK_SIZE : natural := 16#1A00#
|
||||
BLOCK_SIZE : natural := 512; -- necessary for block write
|
||||
BLOCK_BITS : natural := 9;
|
||||
TRACK_SIZE : natural := 16#1A00#
|
||||
);
|
||||
|
||||
port (
|
||||
-- Card Interface ---------------------------------------------------------
|
||||
CS_N : out std_logic; -- MMC chip select
|
||||
MOSI : out std_logic; -- Data to card (master out slave in)
|
||||
MISO : in std_logic; -- Data from card (master in slave out)
|
||||
SCLK : out std_logic; -- Card clock
|
||||
cs_n : out std_logic; -- sd card chip select
|
||||
mosi : out std_logic; -- data to sd card (master out slave in)
|
||||
miso : in std_logic; -- data from sd card (master in slave out)
|
||||
sclk : out std_logic; -- sd card clock
|
||||
bus_available : in std_logic; -- Spi bus available
|
||||
-- Track buffer Interface -------------------------------------------------
|
||||
ram_write_addr : out unsigned(12 downto 0);
|
||||
ram_di : out unsigned(7 downto 0);
|
||||
ram_addr : out std_logic_vector(12 downto 0);
|
||||
ram_di : out std_logic_vector(7 downto 0);
|
||||
ram_do : in std_logic_vector(7 downto 0);
|
||||
ram_we : out std_logic;
|
||||
change : in std_logic; -- Force reload as disk may have changed
|
||||
track : in unsigned(5 downto 0); -- Track number (0-34)
|
||||
image : in unsigned(9 downto 0); -- Which disk image to read
|
||||
busy : out std_logic;
|
||||
-- System Interface -------------------------------------------------------
|
||||
CLK_14M : in std_logic; -- System clock
|
||||
reset : in std_logic;
|
||||
dbg_state : out std_logic_vector(7 downto 0) -- DTX
|
||||
track_num : in std_logic_vector(5 downto 0); -- Track number (0/1-40)
|
||||
disk_num : in std_logic_vector(9 downto 0); -- Which disk image to read
|
||||
busy : buffer std_logic;
|
||||
save_track : in std_logic; -- pulse to 1 to write ram buffer back to sd card
|
||||
sector_offset : out std_logic; -- 0 : sector 0 is at ram adr 0, 1 : sector 0 is at ram adr 256
|
||||
-- System Interface -------------------------------------------------------
|
||||
clk : in std_logic; -- System clock
|
||||
reset : in std_logic;
|
||||
-- Debug ------------------------------------------------------------------
|
||||
dbg_state : out std_logic_vector(7 downto 0)
|
||||
);
|
||||
|
||||
end spi_controller;
|
||||
@@ -69,6 +91,12 @@ architecture rtl of spi_controller is
|
||||
READ_BLOCK_WAIT,
|
||||
READ_BLOCK_DATA,
|
||||
READ_BLOCK_CRC,
|
||||
-- Track write FSM
|
||||
WRITE_TRACK,
|
||||
WRITE_BLOCK_INIT,
|
||||
WRITE_BLOCK_DATA,
|
||||
WRITE_BYTE,
|
||||
WRITE_BLOCK_WAIT,
|
||||
-- SD command embedded FSM
|
||||
WAIT_NRC,
|
||||
SEND_CMD,
|
||||
@@ -80,48 +108,34 @@ architecture rtl of spi_controller is
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
signal slow_clk : boolean := true;
|
||||
signal spi_clk : std_logic;
|
||||
signal spi_clk : std_logic;
|
||||
signal sclk_sig : std_logic;
|
||||
|
||||
signal current_track : unsigned(5 downto 0);
|
||||
signal current_image : unsigned(9 downto 0);
|
||||
-- signal write_addr : unsigned(13 downto 0);
|
||||
signal write_addr : unsigned(12 downto 0);
|
||||
signal current_track_num : std_logic_vector(5 downto 0); -- track number currently in buffer
|
||||
signal current_disk_num : std_logic_vector(9 downto 0); -- disk number currently in buffer
|
||||
signal ram_addr_in : std_logic_vector(12 downto 0) := (others => '0');
|
||||
|
||||
signal command : std_logic_vector(5 downto 0);
|
||||
signal argument : std_logic_vector(31 downto 0);
|
||||
signal crc7 : std_logic_vector(6 downto 0);
|
||||
signal command : std_logic_vector(5 downto 0);
|
||||
signal argument : std_logic_vector(31 downto 0);
|
||||
signal crc7 : std_logic_vector(6 downto 0);
|
||||
signal command_out : std_logic_vector(55 downto 0);
|
||||
signal recv_bytes : unsigned(39 downto 0);
|
||||
signal recv_bytes : std_logic_vector(39 downto 0);
|
||||
type versions is (MMC, SD1x, SD2x);
|
||||
signal version : versions;
|
||||
signal version : versions;
|
||||
signal high_capacity : boolean;
|
||||
|
||||
|
||||
-- C64 - 1541 start_sector in D64 format per track number [0..40]
|
||||
type start_sector_array_type is array(0 to 40) of integer range 0 to 1023;
|
||||
constant start_sector_array : start_sector_array_type :=
|
||||
( 0, 0, 21, 42, 63, 84,105,126,147,168,189,210,231,252,273,294,315,336,357,376,395,
|
||||
414,433,452,471,490,508,526,544,562,580,598,615,632,649,666,683,700,717,734,751);
|
||||
|
||||
signal start_sector : std_logic_vector(9 downto 0);
|
||||
signal reload : std_logic;
|
||||
type start_sector_array_type is array(0 to 40) of integer range 0 to 1023;
|
||||
signal start_sector_array : start_sector_array_type :=
|
||||
( 0, 0, 21, 42, 63, 84,105,126,147,168,189,210,231,252,273,294,315,336,357,376,395,
|
||||
414,433,452,471,490,508,526,544,562,580,598,615,632,649,666,683,700,717,734,751);
|
||||
|
||||
signal start_sector_addr : std_logic_vector(9 downto 0); -- addresse of sector within full disk
|
||||
|
||||
signal cmd_data_mode : std_logic := '1'; -- 1:command to sd card, 0:data to sd card
|
||||
signal data_to_write : std_logic_vector(7 downto 0) := X"00";
|
||||
|
||||
begin
|
||||
|
||||
-- set reload flag whenever "change" rises and clear it once the
|
||||
-- state machine starts reloading the track
|
||||
process(change, state)
|
||||
begin
|
||||
if(state = READ_TRACK) then
|
||||
reload <= '0';
|
||||
else
|
||||
if rising_edge(change) then
|
||||
reload <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--ram_write_addr <= write_addr;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Process var_clkgen
|
||||
--
|
||||
@@ -130,26 +144,26 @@ begin
|
||||
-- If slow_clk is false, spi_clk == CLK_14M, thus SCLK = 7M
|
||||
-- If slow_clk is true, spi_clk = CLK_14M / 32 and SCLK = 223.214kHz, which
|
||||
-- is between 100kHz and 400kHz, as required for MMC compatibility.
|
||||
--
|
||||
--
|
||||
|
||||
var_clkgen : process (CLK_14M, slow_clk)
|
||||
var_clkgen : process (clk, slow_clk)
|
||||
variable var_clk : unsigned(4 downto 0) := (others => '0');
|
||||
begin
|
||||
if slow_clk then
|
||||
spi_clk <= var_clk(4);
|
||||
if rising_edge(CLK_14M) then
|
||||
if rising_edge(clk) then
|
||||
var_clk := var_clk + 1;
|
||||
end if;
|
||||
else
|
||||
spi_clk <= CLK_14M;
|
||||
spi_clk <= clk;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
SCLK <= sclk_sig;
|
||||
sclk <= sclk_sig;
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
start_sector_addr <= std_logic_vector(to_unsigned(start_sector_array(to_integer(unsigned(track_num))),10));
|
||||
sector_offset <= start_sector_addr(0);
|
||||
-----------------------------------------------------------------------------
|
||||
-- Process sd_fsm
|
||||
--
|
||||
@@ -163,36 +177,38 @@ begin
|
||||
constant CMD8 : cmd_t := std_logic_vector(to_unsigned(8, 6));
|
||||
constant CMD16 : cmd_t := std_logic_vector(to_unsigned(16, 6));
|
||||
constant CMD17 : cmd_t := std_logic_vector(to_unsigned(17, 6));
|
||||
constant CMD24 : cmd_t := std_logic_vector(to_unsigned(24, 6));
|
||||
constant CMD55 : cmd_t := std_logic_vector(to_unsigned(55, 6));
|
||||
constant CMD58 : cmd_t := std_logic_vector(to_unsigned(58, 6));
|
||||
constant ACMD41 : cmd_t := std_logic_vector(to_unsigned(41, 6));
|
||||
variable counter : unsigned(7 downto 0);
|
||||
variable byte_counter : unsigned(BLOCK_BITS - 1 downto 0);
|
||||
variable lba : unsigned(31 downto 0);
|
||||
variable byte_counter : unsigned(BLOCK_BITS downto 0);
|
||||
variable lba : std_logic_vector(31 downto 0);
|
||||
|
||||
begin
|
||||
if rising_edge(spi_clk) then
|
||||
ram_we <= '0';
|
||||
if reset = '1' then
|
||||
state <= POWER_UP;
|
||||
state <= POWER_UP;
|
||||
-- Deliberately out of range
|
||||
current_track <= (others => '1');
|
||||
current_image <= (others => '1');
|
||||
sclk_sig <= '0';
|
||||
slow_clk <= true;
|
||||
CS_N <= '1';
|
||||
command <= (others => '0');
|
||||
argument <= (others => '0');
|
||||
crc7 <= (others => '0');
|
||||
command_out <= (others => '1');
|
||||
counter := TO_UNSIGNED(0, 8);
|
||||
byte_counter := TO_UNSIGNED(0, BLOCK_BITS);
|
||||
write_addr <= (others => '0');
|
||||
high_capacity <= false;
|
||||
version <= MMC;
|
||||
lba := (others => '0');
|
||||
busy <= '1';
|
||||
dbg_state <= x"00";
|
||||
current_track_num <= (others => '1');
|
||||
current_disk_num <= (others => '1');
|
||||
sclk_sig <= '0';
|
||||
slow_clk <= true;
|
||||
cs_n <= '1';
|
||||
cmd_data_mode <= '1';
|
||||
command <= (others => '0');
|
||||
argument <= (others => '0');
|
||||
crc7 <= (others => '0');
|
||||
command_out <= (others => '1');
|
||||
counter := TO_UNSIGNED(0, 8);
|
||||
byte_counter := TO_UNSIGNED(0, BLOCK_BITS+1);
|
||||
ram_addr_in <= (others => '0');
|
||||
high_capacity <= false;
|
||||
version <= MMC;
|
||||
lba := (others => '0');
|
||||
busy <= '1';
|
||||
dbg_state <= x"00";
|
||||
else
|
||||
case state is
|
||||
|
||||
@@ -207,12 +223,15 @@ begin
|
||||
-- greater) to wake up the card
|
||||
when RAMP_UP =>
|
||||
if counter = 0 then
|
||||
CS_N <= '0';
|
||||
cs_n <= '0';
|
||||
command <= CMD0;
|
||||
argument <= (others => '0');
|
||||
crc7 <= "1001010";
|
||||
return_state <= CHECK_CMD0;
|
||||
state <= WAIT_NRC;
|
||||
return_state <= CHECK_CMD0;
|
||||
|
||||
if bus_available = '1' then
|
||||
state <= WAIT_NRC;
|
||||
end if;
|
||||
else
|
||||
counter := counter - 1;
|
||||
sclk_sig <= not sclk_sig;
|
||||
@@ -347,78 +366,52 @@ begin
|
||||
when ERROR =>
|
||||
sclk_sig <= '0';
|
||||
slow_clk <= true;
|
||||
CS_N <= '1';
|
||||
cs_n <= '1';
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Embedded "read track" FSM
|
||||
---------------------------------------------------------------------
|
||||
-- Idle state where we sit waiting for user image/track requests ----
|
||||
when IDLE =>
|
||||
dbg_state <= x"01";
|
||||
if reload='1' or track /= current_track or image /= current_image then
|
||||
----------------------------------------------------------
|
||||
-- Compute the LBA (Logical Block Address) from the given
|
||||
-- image/track numbers.
|
||||
-- Each Apple ][ floppy image contains 35 tracks, each consisting of
|
||||
-- 16 x 256-byte sectors.
|
||||
-- However, because of inter-sector gaps and address fields in
|
||||
-- raw mode, the actual length is set to 0x1A00, so each image is
|
||||
-- actually $1A00 bytes * 0x23 tracks = 0x38E00 bytes.
|
||||
-- So: lba = image * 0x38E00 + track * 0x1A00
|
||||
-- In order to avoid multiplications by constants, we replace
|
||||
-- them by direct add/sub of shifted image/track values:
|
||||
-- 0x38E00 = 0011 1000 1110 0000 0000
|
||||
-- = 0x40000 - 0x8000 + 0x1000 - 0x200
|
||||
-- 0x01A00 = 0000 0001 1010 0000 0000
|
||||
-- = 0x1000 + 0x800 + 0x200
|
||||
------------------------------------------------------
|
||||
--lba := ("0000" & image & "000000000000000000") -
|
||||
-- ( image & "000000000000000") +
|
||||
-- ( image & "000000000000") -
|
||||
-- ( image & "000000000") +
|
||||
-- ( track & "000000000") +
|
||||
-- ( track & "00000000000") +
|
||||
-- ( track & "000000000000");
|
||||
------------------------------------------------------
|
||||
|
||||
-- For C64 1541 format D64 image must start every 256Ko --
|
||||
lba := (X"0" & image &
|
||||
to_unsigned(start_sector_array(to_integer(unsigned(track))),10) &
|
||||
X"00");
|
||||
|
||||
-- check if track starts at 512 byte boundary ...
|
||||
if to_unsigned(start_sector_array(to_integer(unsigned(track))),10)(0)='1' then
|
||||
-- ... no it doesn't. We thus start writing before the begin of the
|
||||
-- buffer so the first 256 bytes are effectively skipped
|
||||
write_addr <= "1111100000000";
|
||||
else
|
||||
-- ... yes it does. We can just load the track to memory
|
||||
write_addr <= (others => '0');
|
||||
end if;
|
||||
|
||||
if high_capacity then
|
||||
-- TODO: This probably doesn't work in the same process where lba is set
|
||||
|
||||
-- For SDHC, blocks are addressed by blocks, not bytes
|
||||
lba := lba srl BLOCK_BITS;
|
||||
end if;
|
||||
-- write_addr <= (others => '0');
|
||||
CS_N <= '0';
|
||||
state <= READ_TRACK;
|
||||
current_track <= track;
|
||||
current_image <= image;
|
||||
busy <= '1';
|
||||
else
|
||||
CS_N <= '1';
|
||||
sclk_sig <= '1';
|
||||
busy <= '0';
|
||||
end if;
|
||||
-- Idle state where we sit waiting for user image/track change or
|
||||
-- save request
|
||||
when IDLE =>
|
||||
dbg_state <= x"01";
|
||||
|
||||
-- For C64 1541 format D64 image (disk_num) must start every 256Ko --
|
||||
lba := (X"0" & disk_num & start_sector_addr(9 downto 1) & '0' & X"00");
|
||||
if high_capacity then
|
||||
-- For SDHC, blocks are addressed by blocks, not bytes
|
||||
lba := std_logic_vector(to_unsigned(0,BLOCK_BITS)) & lba(31 downto BLOCK_BITS);
|
||||
end if;
|
||||
|
||||
ram_addr_in <= (others => '0');
|
||||
sclk_sig <= '1';
|
||||
|
||||
cs_n <= '0';
|
||||
busy <= '0';
|
||||
|
||||
if save_track = '1' then
|
||||
if bus_available = '1' then
|
||||
busy <= '1';
|
||||
state <= WRITE_TRACK;
|
||||
end if;
|
||||
else
|
||||
if track_num /= current_track_num or disk_num /= current_disk_num then
|
||||
if bus_available = '1' then -- and busy = '1' then
|
||||
busy <= '1';
|
||||
state <= READ_TRACK;
|
||||
end if;
|
||||
else
|
||||
cs_n <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Read in a whole track into buffer memory -------------------------
|
||||
when READ_TRACK =>
|
||||
dbg_state <= x"02";
|
||||
if write_addr = TRACK_SIZE or write_addr = (TRACK_SIZE-256) then
|
||||
state <= IDLE;
|
||||
dbg_state <= x"02";
|
||||
if ram_addr_in = std_logic_vector(to_unsigned(TRACK_SIZE,13)) then
|
||||
state <= IDLE;
|
||||
current_track_num <= track_num;
|
||||
current_disk_num <= disk_num;
|
||||
else
|
||||
command <= CMD17;
|
||||
argument <= std_logic_vector(lba);
|
||||
@@ -428,10 +421,10 @@ begin
|
||||
|
||||
-- Wait for a 0 bit to signal the start of the block ----------------
|
||||
when READ_BLOCK_WAIT =>
|
||||
dbg_state <= x"03";
|
||||
if sclk_sig = '1' and MISO = '0' then
|
||||
dbg_state <= x"03";
|
||||
if sclk_sig = '1' and miso = '0' then
|
||||
state <= READ_BLOCK_DATA;
|
||||
byte_counter := TO_UNSIGNED(BLOCK_SIZE - 1, BLOCK_BITS);
|
||||
byte_counter := TO_UNSIGNED(BLOCK_SIZE - 1, BLOCK_BITS+1);
|
||||
counter := TO_UNSIGNED(7, 8);
|
||||
return_state <= READ_BLOCK_DATA;
|
||||
state <= RECEIVE_BYTE;
|
||||
@@ -440,10 +433,10 @@ begin
|
||||
|
||||
-- Read a block of data ---------------------------------------------
|
||||
when READ_BLOCK_DATA =>
|
||||
dbg_state <= x"04";
|
||||
dbg_state <= x"04";
|
||||
ram_we <= '1';
|
||||
write_addr <= write_addr + 1;
|
||||
ram_write_addr <= write_addr;
|
||||
ram_addr_in <= ram_addr_in + '1';
|
||||
ram_addr <= ram_addr_in;
|
||||
if byte_counter = 0 then
|
||||
counter := TO_UNSIGNED(7, 8);
|
||||
return_state <= READ_BLOCK_CRC;
|
||||
@@ -457,7 +450,7 @@ begin
|
||||
|
||||
-- Read the block CRC -----------------------------------------------
|
||||
when READ_BLOCK_CRC =>
|
||||
dbg_state <= x"05";
|
||||
dbg_state <= x"05";
|
||||
counter := TO_UNSIGNED(7, 8);
|
||||
return_state <= READ_TRACK;
|
||||
if high_capacity then
|
||||
@@ -466,13 +459,93 @@ begin
|
||||
lba := lba + BLOCK_SIZE;
|
||||
end if;
|
||||
state <= RECEIVE_BYTE;
|
||||
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- write track FSM
|
||||
---------------------------------------------------------------------
|
||||
|
||||
-- write out a whole track from buffer memory -------------------------
|
||||
when WRITE_TRACK =>
|
||||
dbg_state <= x"11";
|
||||
cmd_data_mode <= '1';
|
||||
if ram_addr_in = std_logic_vector(to_unsigned(TRACK_SIZE,13)) then
|
||||
state <= IDLE;
|
||||
else
|
||||
command <= CMD24;
|
||||
argument <= std_logic_vector(lba);
|
||||
return_state <= WRITE_BLOCK_INIT;
|
||||
if save_track = '0' then -- wait cmd released
|
||||
state <= WAIT_NRC;
|
||||
dbg_state <= x"12";
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Wait for a 0 bit to signal the start of the block ----------------
|
||||
when WRITE_BLOCK_INIT =>
|
||||
dbg_state <= x"13";
|
||||
cmd_data_mode <= '0';
|
||||
state <= WRITE_BLOCK_DATA;
|
||||
byte_counter := TO_UNSIGNED(BLOCK_SIZE +3 , BLOCK_BITS+1);
|
||||
counter := TO_UNSIGNED(7, 8);
|
||||
|
||||
-- write a block of data ---------------------------------------------
|
||||
when WRITE_BLOCK_DATA =>
|
||||
dbg_state <= x"14";
|
||||
if byte_counter = 0 then
|
||||
return_state <= WRITE_BLOCK_WAIT;
|
||||
state <= RECEIVE_BYTE_WAIT;
|
||||
else
|
||||
if byte_counter = TO_UNSIGNED(1, BLOCK_BITS+1) or
|
||||
byte_counter = TO_UNSIGNED(2, BLOCK_BITS+1) then
|
||||
data_to_write <= X"FF";
|
||||
elsif byte_counter = TO_UNSIGNED(BLOCK_SIZE +3 , BLOCK_BITS+1) then
|
||||
data_to_write <= X"FE";
|
||||
ram_addr <= ram_addr_in;
|
||||
else
|
||||
data_to_write <= ram_do;
|
||||
ram_addr_in <= ram_addr_in + '1';
|
||||
ram_addr <= ram_addr_in + '1';
|
||||
end if;
|
||||
counter := TO_UNSIGNED(7, 8);
|
||||
state <= WRITE_BYTE;
|
||||
byte_counter := byte_counter - 1;
|
||||
end if;
|
||||
|
||||
-- write one byte --- -----------------------------------------------
|
||||
when WRITE_BYTE =>
|
||||
dbg_state <= x"15";
|
||||
if sclk_sig = '1' then
|
||||
if counter = 0 then
|
||||
state <= WRITE_BLOCK_DATA;
|
||||
else
|
||||
counter := counter - 1;
|
||||
data_to_write <= data_to_write(6 downto 0) & "1";
|
||||
end if;
|
||||
end if;
|
||||
sclk_sig <= not sclk_sig;
|
||||
|
||||
-- wait end of write -----------------------------------------------
|
||||
when WRITE_BLOCK_WAIT =>
|
||||
dbg_state <= x"16";
|
||||
if sclk_sig = '1' then
|
||||
if miso = '1' then
|
||||
dbg_state <= x"17";
|
||||
state <= WRITE_TRACK;
|
||||
if high_capacity then
|
||||
lba := lba + 1;
|
||||
else
|
||||
lba := lba + BLOCK_SIZE;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
sclk_sig <= not sclk_sig;
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Embedded "command" FSM
|
||||
---------------------------------------------------------------------
|
||||
-- Wait for card response in front of host command ------------------
|
||||
when WAIT_NRC =>
|
||||
dbg_state <= x"06";
|
||||
dbg_state <= x"06";
|
||||
counter := TO_UNSIGNED(63, 8);
|
||||
command_out <= "11111111" & "01" & command & argument & crc7 & "1";
|
||||
sclk_sig <= not sclk_sig;
|
||||
@@ -480,7 +553,7 @@ begin
|
||||
|
||||
-- Send a command to the card ---------------------------------------
|
||||
when SEND_CMD =>
|
||||
dbg_state <= x"07";
|
||||
dbg_state <= x"07";
|
||||
if sclk_sig = '1' then
|
||||
if counter = 0 then
|
||||
state <= RECEIVE_BYTE_WAIT;
|
||||
@@ -493,9 +566,9 @@ begin
|
||||
|
||||
-- Wait for a "0", indicating the first bit of a response -----------
|
||||
when RECEIVE_BYTE_WAIT =>
|
||||
dbg_state <= x"08";
|
||||
dbg_state <= x"08";
|
||||
if sclk_sig = '1' then
|
||||
if MISO = '0' then
|
||||
if miso = '0' then
|
||||
recv_bytes <= (others => '0');
|
||||
if command = CMD8 or command = CMD58 then
|
||||
-- This is an R7 response, but we already have read bit 39
|
||||
@@ -512,24 +585,26 @@ begin
|
||||
|
||||
-- Receive a byte ---------------------------------------------------
|
||||
when RECEIVE_BYTE =>
|
||||
dbg_state <= x"09";
|
||||
dbg_state <= x"09";
|
||||
if sclk_sig = '1' then
|
||||
recv_bytes <= recv_bytes(38 downto 0) & MISO;
|
||||
recv_bytes <= recv_bytes(38 downto 0) & miso;
|
||||
if counter = 0 then
|
||||
state <= return_state;
|
||||
ram_di <= recv_bytes(6 downto 0) & MISO;
|
||||
ram_di <= recv_bytes(6 downto 0) & miso;
|
||||
else
|
||||
counter := counter - 1;
|
||||
end if;
|
||||
end if;
|
||||
sclk_sig <= not sclk_sig;
|
||||
|
||||
when others => null;
|
||||
when others =>
|
||||
dbg_state <= x"1F";
|
||||
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process sd_fsm;
|
||||
|
||||
MOSI <= command_out(55);
|
||||
mosi <= command_out(55) when cmd_data_mode = '1' else data_to_write(7);
|
||||
|
||||
end rtl;
|
||||
84
cores/c16/c1541/spram.vhd
Normal file
84
cores/c16/c1541/spram.vhd
Normal file
@@ -0,0 +1,84 @@
|
||||
LIBRARY ieee;
|
||||
USE ieee.std_logic_1164.all;
|
||||
|
||||
LIBRARY altera_mf;
|
||||
USE altera_mf.all;
|
||||
|
||||
ENTITY spram IS
|
||||
GENERIC
|
||||
(
|
||||
init_file : string := "";
|
||||
numwords_a : natural := 0; -- not used
|
||||
widthad_a : natural;
|
||||
width_a : natural := 8;
|
||||
outdata_reg_a : string := "UNREGISTERED"
|
||||
);
|
||||
PORT
|
||||
(
|
||||
address : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0);
|
||||
clock : IN STD_LOGIC ;
|
||||
data : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
|
||||
wren : IN STD_LOGIC ;
|
||||
q : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0)
|
||||
);
|
||||
END spram;
|
||||
|
||||
ARCHITECTURE SYN OF spram IS
|
||||
|
||||
SIGNAL sub_wire0 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
|
||||
|
||||
COMPONENT altsyncram
|
||||
GENERIC (
|
||||
clock_enable_input_a : STRING;
|
||||
clock_enable_output_a : STRING;
|
||||
init_file : STRING;
|
||||
intended_device_family : STRING;
|
||||
lpm_hint : STRING;
|
||||
lpm_type : STRING;
|
||||
numwords_a : NATURAL;
|
||||
operation_mode : STRING;
|
||||
outdata_aclr_a : STRING;
|
||||
outdata_reg_a : STRING;
|
||||
power_up_uninitialized : STRING;
|
||||
widthad_a : NATURAL;
|
||||
width_a : NATURAL;
|
||||
width_byteena_a : NATURAL
|
||||
);
|
||||
PORT (
|
||||
wren_a : IN STD_LOGIC ;
|
||||
clock0 : IN STD_LOGIC ;
|
||||
address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0);
|
||||
q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
|
||||
data_a : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0)
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
BEGIN
|
||||
q <= sub_wire0(width_a-1 DOWNTO 0);
|
||||
|
||||
altsyncram_component : altsyncram
|
||||
GENERIC MAP (
|
||||
clock_enable_input_a => "BYPASS",
|
||||
clock_enable_output_a => "BYPASS",
|
||||
init_file => init_file,
|
||||
intended_device_family => "Cyclone II",
|
||||
lpm_hint => "ENABLE_RUNTIME_MOD=NO",
|
||||
lpm_type => "altsyncram",
|
||||
numwords_a => 2**widthad_a,
|
||||
operation_mode => "SINGLE_PORT",
|
||||
outdata_aclr_a => "NONE",
|
||||
outdata_reg_a => outdata_reg_a,
|
||||
power_up_uninitialized => "FALSE",
|
||||
widthad_a => widthad_a,
|
||||
width_a => width_a,
|
||||
width_byteena_a => 1
|
||||
)
|
||||
PORT MAP (
|
||||
wren_a => wren,
|
||||
clock0 => clock,
|
||||
address_a => address,
|
||||
data_a => data,
|
||||
q_a => sub_wire0
|
||||
);
|
||||
|
||||
END SYN;
|
||||
77
cores/c16/c1541/sprom.vhd
Normal file
77
cores/c16/c1541/sprom.vhd
Normal file
@@ -0,0 +1,77 @@
|
||||
LIBRARY ieee;
|
||||
USE ieee.std_logic_1164.all;
|
||||
|
||||
LIBRARY altera_mf;
|
||||
USE altera_mf.all;
|
||||
|
||||
ENTITY sprom IS
|
||||
GENERIC
|
||||
(
|
||||
init_file : string := "";
|
||||
numwords_a : natural := 0; -- not used any more
|
||||
widthad_a : natural;
|
||||
width_a : natural := 8;
|
||||
outdata_reg_a : string := "UNREGISTERED"
|
||||
);
|
||||
PORT
|
||||
(
|
||||
address : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0);
|
||||
clock : IN STD_LOGIC ;
|
||||
q : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0)
|
||||
);
|
||||
END sprom;
|
||||
|
||||
|
||||
ARCHITECTURE SYN OF sprom IS
|
||||
|
||||
SIGNAL sub_wire0 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
|
||||
|
||||
COMPONENT altsyncram
|
||||
GENERIC (
|
||||
clock_enable_input_a : STRING;
|
||||
clock_enable_output_a : STRING;
|
||||
init_file : STRING;
|
||||
intended_device_family : STRING;
|
||||
lpm_hint : STRING;
|
||||
lpm_type : STRING;
|
||||
numwords_a : NATURAL;
|
||||
operation_mode : STRING;
|
||||
outdata_aclr_a : STRING;
|
||||
outdata_reg_a : STRING;
|
||||
widthad_a : NATURAL;
|
||||
width_a : NATURAL;
|
||||
width_byteena_a : NATURAL
|
||||
);
|
||||
PORT (
|
||||
clock0 : IN STD_LOGIC ;
|
||||
address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0);
|
||||
q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0)
|
||||
);
|
||||
END COMPONENT;
|
||||
|
||||
BEGIN
|
||||
q <= sub_wire0(width_a-1 DOWNTO 0);
|
||||
|
||||
altsyncram_component : altsyncram
|
||||
GENERIC MAP (
|
||||
clock_enable_input_a => "BYPASS",
|
||||
clock_enable_output_a => "BYPASS",
|
||||
init_file => init_file,
|
||||
intended_device_family => "Cyclone II",
|
||||
lpm_hint => "ENABLE_RUNTIME_MOD=NO",
|
||||
lpm_type => "altsyncram",
|
||||
numwords_a => 2**widthad_a,
|
||||
operation_mode => "ROM",
|
||||
outdata_aclr_a => "NONE",
|
||||
outdata_reg_a => outdata_reg_a,
|
||||
widthad_a => widthad_a,
|
||||
width_a => width_a,
|
||||
width_byteena_a => 1
|
||||
)
|
||||
PORT MAP (
|
||||
clock0 => clock,
|
||||
address_a => address,
|
||||
q_a => sub_wire0
|
||||
);
|
||||
|
||||
END SYN;
|
||||
@@ -1,366 +0,0 @@
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
--use work.platform_pkg.all;
|
||||
--use work.project_pkg.all;
|
||||
|
||||
--
|
||||
-- Model 1541B
|
||||
--
|
||||
|
||||
entity c1541_logic is generic(DEVICE_SELECT : std_logic_vector(1 downto 0));
|
||||
port
|
||||
(
|
||||
clk_32M : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
-- serial bus
|
||||
sb_data_oe : out std_logic;
|
||||
sb_data_in : in std_logic;
|
||||
sb_clk_oe : out std_logic;
|
||||
sb_clk_in : in std_logic;
|
||||
sb_atn_oe : out std_logic;
|
||||
sb_atn_in : in std_logic;
|
||||
|
||||
c1541rom_addr : in std_logic_vector(13 downto 0);
|
||||
c1541rom_data : in std_logic_vector(7 downto 0);
|
||||
c1541rom_wr : in std_logic;
|
||||
|
||||
-- drive-side interface
|
||||
ds : in std_logic_vector(1 downto 0); -- device select
|
||||
di : in std_logic_vector(7 downto 0); -- disk write data
|
||||
do : out std_logic_vector(7 downto 0); -- disk read data
|
||||
mode : out std_logic; -- read/write
|
||||
stp : out std_logic_vector(1 downto 0); -- stepper motor control
|
||||
mtr : out std_logic; -- stepper motor on/off
|
||||
freq : out std_logic_vector(1 downto 0); -- motor frequency
|
||||
sync_n : in std_logic; -- reading SYNC bytes
|
||||
byte_n : in std_logic; -- byte ready
|
||||
wps_n : in std_logic; -- write-protect sense
|
||||
tr00_sense_n : in std_logic; -- track 0 sense (unused?)
|
||||
act : out std_logic -- activity LED
|
||||
);
|
||||
end c1541_logic;
|
||||
|
||||
architecture SYN of c1541_logic is
|
||||
|
||||
-- clocks, reset
|
||||
signal reset_n : std_logic;
|
||||
signal clk_4M_en : std_logic;
|
||||
signal p2_h : std_logic;
|
||||
signal clk_1M_pulse : std_logic;
|
||||
|
||||
-- cpu signals
|
||||
signal cpu_a : unsigned(15 downto 0);
|
||||
signal cpu_di : unsigned(7 downto 0);
|
||||
signal cpu_do : unsigned(7 downto 0);
|
||||
signal cpu_a_l : std_logic_vector(23 downto 0);
|
||||
signal cpu_do_l : std_logic_vector(7 downto 0);
|
||||
signal cpu_rw : std_logic;
|
||||
signal cpu_rw_n : std_logic;
|
||||
signal cpu_irq_n : std_logic;
|
||||
signal cpu_so_n : std_logic;
|
||||
|
||||
-- rom signals
|
||||
signal rom_cs : std_logic;
|
||||
signal rom_do : std_logic_vector(cpu_di'range);
|
||||
|
||||
-- ram signals
|
||||
signal ram_cs : std_logic;
|
||||
signal ram_wr : std_logic;
|
||||
signal ram_do : std_logic_vector(cpu_di'range);
|
||||
|
||||
-- UC1 (VIA6522) signals
|
||||
signal uc1_do : std_logic_vector(7 downto 0);
|
||||
signal uc1_cs1 : std_logic;
|
||||
signal uc1_cs2_n : std_logic;
|
||||
signal uc1_irq_n : std_logic;
|
||||
signal uc1_ca1_i : std_logic;
|
||||
signal uc1_pa_i : std_logic_vector(7 downto 0);
|
||||
signal uc1_pb_i : std_logic_vector(7 downto 0) := (others => '0');
|
||||
signal uc1_pb_o : std_logic_vector(7 downto 0);
|
||||
signal uc1_pb_oe_n : std_logic_vector(7 downto 0);
|
||||
|
||||
-- UC3 (VIA6522) signals
|
||||
signal uc3_do : std_logic_vector(7 downto 0);
|
||||
signal uc3_cs1 : std_logic;
|
||||
signal uc3_cs2_n : std_logic;
|
||||
signal uc3_irq_n : std_logic;
|
||||
signal uc3_ca1_i : std_logic;
|
||||
signal uc3_ca2_o : std_logic;
|
||||
signal uc3_ca2_oe_n : std_logic;
|
||||
signal uc3_pa_i : std_logic_vector(7 downto 0);
|
||||
signal uc3_pa_o : std_logic_vector(7 downto 0);
|
||||
signal uc3_cb2_o : std_logic;
|
||||
signal uc3_cb2_oe_n : std_logic;
|
||||
signal uc3_pa_oe_n : std_logic_vector(7 downto 0);
|
||||
signal uc3_pb_i : std_logic_vector(7 downto 0);
|
||||
signal uc3_pb_o : std_logic_vector(7 downto 0);
|
||||
signal uc3_pb_oe_n : std_logic_vector(7 downto 0);
|
||||
|
||||
-- internal signals
|
||||
signal atna : std_logic; -- ATN ACK - input gate array
|
||||
signal atn : std_logic; -- attention
|
||||
signal soe : std_logic; -- set overflow enable
|
||||
|
||||
type t_byte_array is array(2047 downto 0) of std_logic_vector(7 downto 0);
|
||||
signal ram : t_byte_array;
|
||||
|
||||
begin
|
||||
|
||||
reset_n <= not reset;
|
||||
|
||||
process (clk_32M, reset)
|
||||
variable count : std_logic_vector(8 downto 0) := (others => '0');
|
||||
alias hcnt : std_logic_vector(1 downto 0) is count(4 downto 3);
|
||||
begin
|
||||
if rising_edge(clk_32M) then
|
||||
-- generate 1MHz pulse
|
||||
clk_1M_pulse <= '0';
|
||||
--if count(4 downto 0) = "00111" then
|
||||
if count(4 downto 0) = "01000" then
|
||||
clk_1M_pulse <= '1';
|
||||
end if;
|
||||
-- if count = "000100000" then -- DAR divide by 33 (otherwise real c64 miss EOI acknowledge)
|
||||
if count = "000011111" then -- TH: divide by 32
|
||||
count := (others => '0'); -- DAR
|
||||
else -- DAR
|
||||
count := std_logic_vector(unsigned(count) + 1);
|
||||
end if; -- DAR
|
||||
end if;
|
||||
p2_h <= not hcnt(1);
|
||||
|
||||
-- for original m6522 design that requires a real clock
|
||||
-- clk_4M_en <= not count(2);
|
||||
|
||||
-- for version 002 with clock enable
|
||||
if count(2 downto 0) = "111" then
|
||||
clk_4M_en <= '1';
|
||||
else
|
||||
clk_4M_en <= '0';
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- decode logic
|
||||
-- RAM $0000-$07FF (2KB)
|
||||
ram_cs <= '1' when STD_MATCH(cpu_a(15 downto 0), "00000-----------") else '0';
|
||||
-- UC1 (VIA6522) $1800-$180F
|
||||
uc1_cs2_n <= '0' when STD_MATCH(cpu_a(15 downto 0), "000110000000----") else '1';
|
||||
-- UC3 (VIA6522) $1C00-$1C0F
|
||||
uc3_cs2_n <= '0' when STD_MATCH(cpu_a(15 downto 0), "000111000000----") else '1';
|
||||
-- ROM $C000-$FFFF (16KB)
|
||||
rom_cs <= '1' when STD_MATCH(cpu_a(15 downto 0), "11--------------") else '0';
|
||||
|
||||
-- qualified write signals
|
||||
ram_wr <= '1' when ram_cs = '1' and cpu_rw = '1' else '0';
|
||||
|
||||
--
|
||||
-- hook up UC1 ports
|
||||
--
|
||||
|
||||
uc1_cs1 <= cpu_a(11);
|
||||
--uc1_cs2_n: see decode logic above
|
||||
-- CA1
|
||||
--uc1_ca1_i <= not sb_atn_in; -- DAR comment : synched with clk_4M_en see below
|
||||
-- PA
|
||||
uc1_pa_i(0) <= tr00_sense_n;
|
||||
uc1_pa_i(7 downto 1) <= (others => '0'); -- NC
|
||||
-- PB
|
||||
uc1_pb_i(0) <= '1' when sb_data_in = '0' else
|
||||
'1' when (uc1_pb_o(1) = '1' and uc1_pb_oe_n(1) = '0') else -- DAR comment : external OR wired
|
||||
'1' when atn = '1' else -- DAR comment : external OR wired
|
||||
'0';
|
||||
sb_data_oe <= '1' when (uc1_pb_o(1) = '1' and uc1_pb_oe_n(1) = '0') else
|
||||
'1' when atn = '1' else
|
||||
'0';
|
||||
uc1_pb_i(2) <= '1' when sb_clk_in = '0' else
|
||||
'1' when (uc1_pb_o(3) = '1' and uc1_pb_oe_n(3) = '0') else -- DAR comment : external OR wired
|
||||
'0';
|
||||
sb_clk_oe <= '1' when (uc1_pb_o(3) = '1' and uc1_pb_oe_n(3) = '0') else '0';
|
||||
|
||||
atna <= uc1_pb_o(4); -- when uc1_pc_oe = '1'
|
||||
uc1_pb_i(6 downto 5) <= DEVICE_SELECT xor ds; -- allows override
|
||||
uc1_pb_i(7) <= not sb_atn_in;
|
||||
|
||||
--
|
||||
-- hook up UC3 ports
|
||||
--
|
||||
|
||||
uc3_cs1 <= cpu_a(11);
|
||||
--uc3_cs2_n: see decode logic above
|
||||
-- CA1
|
||||
uc3_ca1_i <= cpu_so_n; -- byte ready gated with soe
|
||||
-- CA2
|
||||
soe <= uc3_ca2_o or uc3_ca2_oe_n;
|
||||
-- PA
|
||||
uc3_pa_i <= di;
|
||||
do <= uc3_pa_o or uc3_pa_oe_n;
|
||||
-- CB2
|
||||
mode <= uc3_cb2_o or uc3_cb2_oe_n;
|
||||
-- PB
|
||||
stp(1) <= uc3_pb_o(0) or uc3_pb_oe_n(0);
|
||||
stp(0) <= uc3_pb_o(1) or uc3_pb_oe_n(1);
|
||||
mtr <= uc3_pb_o(2) or uc3_pb_oe_n(2);
|
||||
act <= uc3_pb_o(3) or uc3_pb_oe_n(3);
|
||||
freq <= uc3_pb_o(6 downto 5) or uc3_pb_oe_n(6 downto 5);
|
||||
uc3_pb_i <= sync_n & "11" & wps_n & "1111";
|
||||
|
||||
--
|
||||
-- CPU connections
|
||||
--
|
||||
cpu_di <= unsigned(rom_do) when rom_cs = '1' else
|
||||
unsigned(ram_do) when ram_cs = '1' else
|
||||
unsigned(uc1_do) when (uc1_cs1 = '1' and uc1_cs2_n = '0') else
|
||||
unsigned(uc3_do) when (uc3_cs1 = '1' and uc3_cs2_n = '0') else
|
||||
(others => '1');
|
||||
cpu_irq_n <= uc1_irq_n and uc3_irq_n;
|
||||
cpu_so_n <= byte_n or not soe;
|
||||
|
||||
-- internal connections
|
||||
atn <= atna xor (not sb_atn_in);
|
||||
|
||||
-- external connections
|
||||
-- ATN never driven by the 1541
|
||||
sb_atn_oe <= '0';
|
||||
|
||||
|
||||
-- DAR
|
||||
process (clk_32M)
|
||||
begin
|
||||
if rising_edge(clk_32M) then
|
||||
if clk_4M_en = '1' then
|
||||
uc1_ca1_i <= not sb_atn_in; -- DAR sample external atn to ensure not missing edge within VIA
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cpu: entity work.cpu65xx
|
||||
generic map (
|
||||
pipelineOpcode => false,
|
||||
pipelineAluMux => false,
|
||||
pipelineAluOut => false
|
||||
)
|
||||
port map (
|
||||
clk => clk_32M,
|
||||
enable => clk_1M_pulse,
|
||||
reset => reset,
|
||||
nmi_n => '1',
|
||||
irq_n => cpu_irq_n,
|
||||
so_n => cpu_so_n,
|
||||
di => cpu_di,
|
||||
do => cpu_do,
|
||||
addr => cpu_a,
|
||||
we => cpu_rw
|
||||
);
|
||||
|
||||
rom_inst: entity work.rom_C1541
|
||||
port map (
|
||||
clock => clk_32M,
|
||||
|
||||
wren => c1541rom_wr,
|
||||
data => c1541rom_data,
|
||||
wraddress => c1541rom_addr,
|
||||
|
||||
rdaddress => std_logic_vector(cpu_a(13 downto 0)),
|
||||
q => rom_do
|
||||
);
|
||||
|
||||
process (clk_32M)
|
||||
begin
|
||||
if rising_edge(clk_32M) then
|
||||
ram_do <= ram(to_integer(cpu_a(13 downto 0)));
|
||||
if ram_wr = '1' then
|
||||
ram(to_integer(cpu_a(13 downto 0))) <= std_logic_vector(cpu_do);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
uc1_via6522_inst : entity work.M6522
|
||||
port map
|
||||
(
|
||||
I_RS => std_logic_vector(cpu_a(3 downto 0)),
|
||||
I_DATA => std_logic_vector(cpu_do),
|
||||
O_DATA => uc1_do,
|
||||
O_DATA_OE_L => open,
|
||||
|
||||
I_RW_L => not cpu_rw,
|
||||
I_CS1 => uc1_cs1,
|
||||
I_CS2_L => uc1_cs2_n,
|
||||
|
||||
O_IRQ_L => uc1_irq_n,
|
||||
|
||||
-- port a
|
||||
I_CA1 => uc1_ca1_i,
|
||||
I_CA2 => '0',
|
||||
O_CA2 => open,
|
||||
O_CA2_OE_L => open,
|
||||
|
||||
I_PA => uc1_pa_i,
|
||||
O_PA => open,
|
||||
O_PA_OE_L => open,
|
||||
|
||||
-- port b
|
||||
I_CB1 => '0',
|
||||
O_CB1 => open,
|
||||
O_CB1_OE_L => open,
|
||||
|
||||
I_CB2 => '0',
|
||||
O_CB2 => open,
|
||||
O_CB2_OE_L => open,
|
||||
|
||||
I_PB => uc1_pb_i,
|
||||
O_PB => uc1_pb_o,
|
||||
O_PB_OE_L => uc1_pb_oe_n,
|
||||
|
||||
RESET_L => reset_n,
|
||||
CLK => clk_32M,
|
||||
I_P2_H => p2_h, -- high for phase 2 clock ____----__
|
||||
ENA_4 => clk_4M_en -- 4x system clock (4MHZ) _-_-_-_-_-
|
||||
);
|
||||
|
||||
uc3_via6522_inst : entity work.M6522
|
||||
port map
|
||||
(
|
||||
I_RS => std_logic_vector(cpu_a(3 downto 0)),
|
||||
I_DATA => std_logic_vector(cpu_do),
|
||||
O_DATA => uc3_do,
|
||||
O_DATA_OE_L => open,
|
||||
|
||||
I_RW_L => not cpu_rw,
|
||||
I_CS1 => cpu_a(11),
|
||||
I_CS2_L => uc3_cs2_n,
|
||||
|
||||
O_IRQ_L => uc3_irq_n,
|
||||
|
||||
-- port a
|
||||
I_CA1 => uc3_ca1_i,
|
||||
I_CA2 => '0',
|
||||
O_CA2 => uc3_ca2_o,
|
||||
O_CA2_OE_L => uc3_ca2_oe_n,
|
||||
|
||||
I_PA => uc3_pa_i,
|
||||
O_PA => uc3_pa_o,
|
||||
O_PA_OE_L => uc3_pa_oe_n,
|
||||
|
||||
-- port b
|
||||
I_CB1 => '0',
|
||||
O_CB1 => open,
|
||||
O_CB1_OE_L => open,
|
||||
|
||||
I_CB2 => '0',
|
||||
O_CB2 => uc3_cb2_o,
|
||||
O_CB2_OE_L => uc3_cb2_oe_n,
|
||||
|
||||
I_PB => uc3_pb_i,
|
||||
O_PB => uc3_pb_o,
|
||||
O_PB_OE_L => uc3_pb_oe_n,
|
||||
|
||||
RESET_L => reset_n,
|
||||
CLK => clk_32M,
|
||||
I_P2_H => p2_h, -- high for phase 2 clock ____----__
|
||||
ENA_4 => clk_4M_en -- 4x system clock (4MHZ) _-_-_-_-_-
|
||||
);
|
||||
|
||||
end SYN;
|
||||
@@ -1,217 +0,0 @@
|
||||
---------------------------------------------------------------------------------
|
||||
-- Commodore 1541 to SD card (read only) by Dar (darfpga@aol.fr) 02-April-2015
|
||||
-- http://darfpga.blogspot.fr
|
||||
--
|
||||
-- c1541_sd reads D64 data from raw SD card, produces GCR data, feeds c1541_logic
|
||||
-- Raw SD data : each D64 image must start on 256KB boundaries
|
||||
-- disk_num allow to select D64 image
|
||||
--
|
||||
-- c1541_logic from : Mark McDougall
|
||||
-- spi_controller from : Michel Stempin, Stephen A. Edwards
|
||||
-- via6522 from : Arnim Laeuger, Mark McDougall, MikeJ
|
||||
-- T65 from : Daniel Wallner, MikeJ, ehenciak
|
||||
--
|
||||
-- c1541_logic modified for : slow down CPU (EOI ack missed by real c64)
|
||||
-- : remove iec internal OR wired
|
||||
-- : synched atn_in (sometime no IRQ with real c64)
|
||||
-- spi_controller modified for : sector start and size adapted + busy signal
|
||||
-- via6522 modified for : no modification
|
||||
--
|
||||
--
|
||||
-- Input clk 32MHz and 18MHz (18MHz could be replaced with 32/2 if needed)
|
||||
--
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.std_logic_unsigned.ALL;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
entity c1541_sd is
|
||||
port
|
||||
(
|
||||
clk32 : in std_logic;
|
||||
clk18 : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
disk_change : in std_logic;
|
||||
disk_num : in std_logic_vector(9 downto 0);
|
||||
|
||||
iec_atn_i : in std_logic;
|
||||
iec_data_i : in std_logic;
|
||||
iec_clk_i : in std_logic;
|
||||
|
||||
iec_atn_o : out std_logic;
|
||||
iec_data_o : out std_logic;
|
||||
iec_clk_o : out std_logic;
|
||||
|
||||
sd_dat : in std_logic;
|
||||
sd_dat3 : buffer std_logic;
|
||||
sd_cmd : buffer std_logic;
|
||||
sd_clk : buffer std_logic;
|
||||
|
||||
led : out std_logic_vector(7 downto 0);
|
||||
|
||||
c1541rom_addr : in std_logic_vector(13 downto 0);
|
||||
c1541rom_data : in std_logic_vector(7 downto 0);
|
||||
c1541rom_wr : in std_logic
|
||||
);
|
||||
end c1541_sd;
|
||||
|
||||
architecture struct of c1541_sd is
|
||||
|
||||
signal ram_write_addr : unsigned(12 downto 0);
|
||||
signal ram_addr : unsigned(12 downto 0);
|
||||
signal ram_di : unsigned( 7 downto 0);
|
||||
signal ram_do : unsigned( 7 downto 0);
|
||||
signal ram_we : std_logic;
|
||||
signal do : std_logic_vector(7 downto 0); -- disk read data
|
||||
signal mode : std_logic; -- read/write
|
||||
signal stp : std_logic_vector(1 downto 0); -- stepper motor control
|
||||
signal stp_r : std_logic_vector(1 downto 0); -- stepper motor control
|
||||
signal mtr : std_logic ; -- stepper motor on/off
|
||||
signal freq : std_logic_vector(1 downto 0); -- motor (gcr_bit) frequency
|
||||
signal sync_n : std_logic; -- reading SYNC bytes
|
||||
signal byte_n : std_logic; -- byte ready
|
||||
signal act : std_logic; -- activity LED
|
||||
signal track_dbl : std_logic_vector(6 downto 0);
|
||||
signal sd_busy : std_logic;
|
||||
signal track_read_adr : std_logic_vector(12 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
c1541 : entity work.c1541_logic
|
||||
generic map
|
||||
(
|
||||
DEVICE_SELECT => "00"
|
||||
)
|
||||
port map
|
||||
(
|
||||
clk_32M => clk32,
|
||||
reset => reset,
|
||||
|
||||
-- serial bus
|
||||
sb_data_oe => iec_data_o,
|
||||
sb_clk_oe => iec_clk_o,
|
||||
sb_atn_oe => iec_atn_o,
|
||||
|
||||
sb_data_in => not iec_data_i,
|
||||
sb_clk_in => not iec_clk_i,
|
||||
sb_atn_in => not iec_atn_i,
|
||||
|
||||
c1541rom_addr => c1541rom_addr,
|
||||
c1541rom_data => c1541rom_data,
|
||||
c1541rom_wr => c1541rom_wr,
|
||||
|
||||
-- drive-side interface
|
||||
ds => "00", -- device select
|
||||
di => do, -- disk write data
|
||||
do => open, -- disk read data
|
||||
mode => mode, -- read/write
|
||||
stp => stp, -- stepper motor control
|
||||
mtr => mtr, -- motor on/off
|
||||
freq => freq, -- motor frequency
|
||||
sync_n => sync_n, -- reading SYNC bytes
|
||||
byte_n => byte_n, -- byte ready
|
||||
wps_n => '0', -- write-protect sense
|
||||
tr00_sense_n => '1', -- track 0 sense (unused?)
|
||||
act => act -- activity LED
|
||||
);
|
||||
|
||||
floppy : entity work.gcr_floppy
|
||||
port map
|
||||
(
|
||||
clk32 => clk32,
|
||||
|
||||
do => do, -- disk read data
|
||||
mode => mode, -- read/write
|
||||
stp => stp, -- stepper motor control
|
||||
mtr => mtr, -- stepper motor on/off
|
||||
freq => freq, -- motor (gcr_bit) frequency
|
||||
sync_n => sync_n, -- reading SYNC bytes
|
||||
byte_n => byte_n, -- byte ready
|
||||
|
||||
track => track_dbl(6 downto 1),
|
||||
track_adr => track_read_adr,
|
||||
track_data => std_logic_vector(ram_do),
|
||||
track_ready => not sd_busy
|
||||
);
|
||||
|
||||
process (clk32)
|
||||
begin
|
||||
if rising_edge(clk32) then
|
||||
stp_r <= stp;
|
||||
if reset = '1' then
|
||||
track_dbl <= "0000010";
|
||||
else
|
||||
if mtr = '1' then
|
||||
if( (stp_r = "00" and stp = "10")
|
||||
or (stp_r = "10" and stp = "01")
|
||||
or (stp_r = "01" and stp = "11")
|
||||
or (stp_r = "11" and stp = "00")) then
|
||||
if track_dbl < "1010000" then
|
||||
track_dbl <= std_logic_vector(unsigned(track_dbl) + 1);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if( (stp_r = "00" and stp = "11")
|
||||
or (stp_r = "10" and stp = "00")
|
||||
or (stp_r = "01" and stp = "10")
|
||||
or (stp_r = "11" and stp = "01")) then
|
||||
if track_dbl > "0000001" then
|
||||
track_dbl <= std_logic_vector(unsigned(track_dbl) - 1);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
sd_spi : entity work.spi_controller
|
||||
port map
|
||||
(
|
||||
CS_N => sd_dat3, --: out std_logic; -- MMC chip select
|
||||
MOSI => sd_cmd, --: out std_logic; -- Data to card (master out slave in)
|
||||
MISO => sd_dat, --: in std_logic; -- Data from card (master in slave out)
|
||||
SCLK => sd_clk, --: out std_logic; -- Card clock
|
||||
|
||||
ram_write_addr => ram_write_addr, --: out unsigned(13 downto 0);
|
||||
ram_di => ram_di, --: out unsigned(7 downto 0);
|
||||
ram_we => ram_we,
|
||||
|
||||
change => disk_change,
|
||||
track => unsigned(track_dbl(6 downto 1)),
|
||||
image => unsigned(disk_num),
|
||||
|
||||
CLK_14M => clk18,
|
||||
reset => reset,
|
||||
busy => sd_busy
|
||||
);
|
||||
|
||||
track_buffer : entity work.gen_ram
|
||||
generic map
|
||||
(
|
||||
dWidth => 8,
|
||||
aWidth => 13
|
||||
)
|
||||
port map
|
||||
(
|
||||
clk => not clk18,
|
||||
we => ram_we,
|
||||
addr => ram_addr,
|
||||
d => ram_di,
|
||||
q => ram_do
|
||||
);
|
||||
|
||||
with sd_busy select
|
||||
-- ram_addr <= ram_write_addr when '1', unsigned('0'&track_read_adr) when others;
|
||||
ram_addr <= ram_write_addr when '1', unsigned(track_read_adr) when others;
|
||||
|
||||
led(0) <= mode; -- read/write
|
||||
led(2 downto 1) <= stp; -- stepper motor control
|
||||
led(3) <= mtr; -- stepper motor on/off
|
||||
led(5 downto 4) <= freq; -- motor frequency
|
||||
led(6) <= act; -- activity LED
|
||||
led(7) <= sd_busy; -- SD read
|
||||
end struct;
|
||||
@@ -167,7 +167,7 @@ set_global_assignment -name USE_CONFIGURATION_DEVICE OFF
|
||||
# SignalTap II Assignments
|
||||
# ========================
|
||||
set_global_assignment -name ENABLE_SIGNALTAP OFF
|
||||
set_global_assignment -name USE_SIGNALTAP_FILE stp1.stp
|
||||
set_global_assignment -name USE_SIGNALTAP_FILE output_files/stp1.stp
|
||||
|
||||
# Power Estimation Assignments
|
||||
# ============================
|
||||
@@ -321,14 +321,9 @@ set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_L
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_R
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SPI_DO
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to CONF_DATA0
|
||||
set_global_assignment -name VERILOG_FILE sd_card.v
|
||||
set_global_assignment -name VHDL_FILE spi_controller.vhd
|
||||
set_global_assignment -name VHDL_FILE rom_C1541.vhd
|
||||
set_global_assignment -name VHDL_FILE m6522.vhd
|
||||
set_global_assignment -name VERILOG_INPUT_VERSION VERILOG_2001
|
||||
set_global_assignment -name VERILOG_SHOW_LMF_MAPPING_MESSAGES OFF
|
||||
set_global_assignment -name VHDL_FILE gen_ram.vhd
|
||||
set_global_assignment -name VHDL_FILE gcr_floppy.vhd
|
||||
set_global_assignment -name VHDL_FILE c1541_sd.vhd
|
||||
set_global_assignment -name VHDL_FILE c1541_logic.vhd
|
||||
set_global_assignment -name QIP_FILE pll_ntsc.qip
|
||||
set_global_assignment -name QIP_FILE pll_pal.qip
|
||||
set_global_assignment -name VERILOG_FILE data_io.v
|
||||
@@ -348,4 +343,16 @@ set_global_assignment -name VERILOG_FILE c16_keymatrix.v
|
||||
set_global_assignment -name VERILOG_FILE c16.v
|
||||
set_global_assignment -name VERILOG_FILE basic_rom.v
|
||||
set_global_assignment -name SIGNALTAP_FILE stp1.stp
|
||||
set_global_assignment -name SIGNALTAP_FILE output_files/stp1.stp
|
||||
set_global_assignment -name VHDL_FILE c1541/m6522.vhd
|
||||
set_global_assignment -name VHDL_FILE c1541/gcr_floppy.vhd
|
||||
set_global_assignment -name VHDL_FILE c1541/spram.vhd
|
||||
set_global_assignment -name VHDL_FILE c1541/sprom.vhd
|
||||
set_global_assignment -name VHDL_FILE c1541/c1541_sd.vhd
|
||||
set_global_assignment -name VHDL_FILE c1541/c1541_logic.vhd
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE c1541/mist_sd_card.sv
|
||||
set_global_assignment -name VHDL_FILE t65/T65_Pack.vhd
|
||||
set_global_assignment -name VHDL_FILE t65/T65_MCode.vhd
|
||||
set_global_assignment -name VHDL_FILE t65/T65_ALU.vhd
|
||||
set_global_assignment -name VHDL_FILE t65/T65.vhd
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
52
cores/c16/c16_mist.sdc
Normal file
52
cores/c16/c16_mist.sdc
Normal file
@@ -0,0 +1,52 @@
|
||||
#************************************************************
|
||||
# THIS IS A WIZARD-GENERATED FILE.
|
||||
#
|
||||
# Version 13.1.4 Build 182 03/12/2014 SJ Full Version
|
||||
#
|
||||
#************************************************************
|
||||
|
||||
# Copyright (C) 1991-2014 Altera Corporation
|
||||
# Your use of Altera Corporation's design tools, logic functions
|
||||
# and other software and tools, and its AMPP partner logic
|
||||
# functions, and any output files from any of the foregoing
|
||||
# (including device programming or simulation files), and any
|
||||
# associated documentation or information are expressly subject
|
||||
# to the terms and conditions of the Altera Program License
|
||||
# Subscription Agreement, Altera MegaCore Function License
|
||||
# Agreement, or other applicable license agreement, including,
|
||||
# without limitation, that your use is for the sole purpose of
|
||||
# programming logic devices manufactured by Altera and sold by
|
||||
# Altera or its authorized distributors. Please refer to the
|
||||
# applicable agreement for further details.
|
||||
|
||||
|
||||
|
||||
# Clock constraints
|
||||
|
||||
create_clock -name "CLOCK_27" -period 37.037 [get_ports {CLOCK_27}]
|
||||
create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}]
|
||||
|
||||
# Automatically constrain PLL and other generated clocks
|
||||
derive_pll_clocks -create_base_clocks
|
||||
|
||||
# Automatically calculate clock uncertainty to jitter and other effects.
|
||||
derive_clock_uncertainty
|
||||
|
||||
# Clock groups
|
||||
set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks {pll_pal|altpll_component|auto_generated|pll1|clk[*]}]
|
||||
|
||||
|
||||
# Some relaxed constrain to the VGA pins. The signals should arrive together, the delay is not really important.
|
||||
set_output_delay -clock [get_clocks {pll_pal|altpll_component|auto_generated|pll1|clk[0]}] -max 0 [get_ports {VGA_*}]
|
||||
set_output_delay -clock [get_clocks {pll_pal|altpll_component|auto_generated|pll1|clk[0]}] -min -5 [get_ports {VGA_*}]
|
||||
|
||||
# SDRAM delays
|
||||
set_input_delay -clock [get_clocks {pll_pal|altpll_component|auto_generated|pll1|clk[0]}] -max 6.4 [get_ports SDRAM_DQ[*]]
|
||||
set_input_delay -clock [get_clocks {pll_pal|altpll_component|auto_generated|pll1|clk[0]}] -min 3.2 [get_ports SDRAM_DQ[*]]
|
||||
|
||||
set_output_delay -clock [get_clocks {pll_pal|altpll_component|auto_generated|pll1|clk[0]}] -max 1.5 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}]
|
||||
set_output_delay -clock [get_clocks {pll_pal|altpll_component|auto_generated|pll1|clk[0]}] -min -0.8 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}]
|
||||
|
||||
set_false_path -to [get_ports {AUDIO_L}]
|
||||
set_false_path -to [get_ports {AUDIO_R}]
|
||||
set_false_path -to [get_ports {LED}]
|
||||
@@ -70,14 +70,14 @@ module c16_mist (
|
||||
// it to control the menu on the OSD
|
||||
parameter CONF_STR = {
|
||||
"C16;PRG;",
|
||||
"S1,D64;",
|
||||
"S,D64,Mount Disk;",
|
||||
"O2,Scanlines,Off,On;",
|
||||
"O3,Joysticks,Normal,Swapped;",
|
||||
"O4,Memory,64k,16k;",
|
||||
"T5,Reset"
|
||||
"T5,Reset;"
|
||||
};
|
||||
|
||||
parameter CONF_STR_LEN = 8+7+20+28+18+8;
|
||||
parameter CONF_STR_LEN = 8+17+20+28+18+9;
|
||||
|
||||
// the status register is controlled by the on screen display (OSD)
|
||||
wire [7:0] status;
|
||||
@@ -210,22 +210,26 @@ always @(posedge clk28) begin
|
||||
end
|
||||
|
||||
// signals to connect io controller with virtual sd card
|
||||
wire [32:0] sd_lba;
|
||||
wire [31:0] sd_lba;
|
||||
wire sd_rd;
|
||||
wire sd_wr;
|
||||
wire sd_ack;
|
||||
wire sd_ack_conf;
|
||||
wire sd_conf;
|
||||
wire sd_sdhc;
|
||||
wire sd_sdhc = 1'b1;
|
||||
wire [7:0] sd_dout;
|
||||
wire sd_dout_strobe;
|
||||
wire [7:0] sd_din;
|
||||
wire sd_din_strobe;
|
||||
wire sd_change;
|
||||
|
||||
wire img_mounted;
|
||||
wire [8:0] sd_buff_addr;
|
||||
|
||||
// include user_io module for arm controller communication
|
||||
user_io #(.STRLEN(CONF_STR_LEN)) user_io (
|
||||
.conf_str ( CONF_STR ),
|
||||
|
||||
.clk_sys ( clk28 ),
|
||||
|
||||
.SPI_CLK ( SPI_SCK ),
|
||||
.SPI_SS_IO ( CONF_DATA0 ),
|
||||
.SPI_MISO ( SPI_DO ),
|
||||
@@ -248,44 +252,24 @@ user_io #(.STRLEN(CONF_STR_LEN)) user_io (
|
||||
.sd_rd ( sd_rd ),
|
||||
.sd_wr ( sd_wr ),
|
||||
.sd_ack ( sd_ack ),
|
||||
.sd_ack_conf ( sd_ack_conf ),
|
||||
.sd_conf ( sd_conf ),
|
||||
.sd_sdhc ( sd_sdhc ),
|
||||
.sd_dout ( sd_dout ),
|
||||
.sd_dout_strobe ( sd_dout_strobe ),
|
||||
.sd_din ( sd_din ),
|
||||
.sd_din_strobe ( sd_din_strobe ),
|
||||
.sd_change ( sd_change ),
|
||||
.sd_buff_addr ( sd_buff_addr),
|
||||
.img_mounted ( img_mounted ),
|
||||
|
||||
.status ( status )
|
||||
);
|
||||
|
||||
wire sd_cs;
|
||||
wire sd_dat;
|
||||
wire sd_dat3;
|
||||
wire sd_cmd;
|
||||
wire sd_clk;
|
||||
|
||||
sd_card sd_card (
|
||||
// connection to io controller
|
||||
.io_lba ( sd_lba ),
|
||||
.io_rd ( sd_rd ),
|
||||
.io_wr ( sd_wr ),
|
||||
.io_ack ( sd_ack ),
|
||||
.io_conf ( sd_conf ),
|
||||
.io_sdhc ( sd_sdhc ),
|
||||
.io_din ( sd_dout ),
|
||||
.io_din_strobe ( sd_dout_strobe ),
|
||||
.io_dout ( sd_din ),
|
||||
.io_dout_strobe ( sd_din_strobe ),
|
||||
|
||||
.allow_sdhc ( 1'b1 ),
|
||||
|
||||
// connection to host
|
||||
.sd_cs ( sd_dat3 ),
|
||||
.sd_sck ( sd_clk ),
|
||||
.sd_sdi ( sd_cmd ),
|
||||
.sd_sdo ( sd_dat )
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// ------------------------------ prg memory injection -----------------------------
|
||||
// ---------------------------------------------------------------------------------
|
||||
@@ -570,8 +554,9 @@ C16 c16 (
|
||||
// the FPGATED uses two different clocks for NTSC and PAL mode.
|
||||
// Switching the clocks may crash the system. We might need to force a reset it.
|
||||
wire clk28 = c16_pal?clk28_pal:clk28_ntsc;
|
||||
//wire clk28 = clk28_pal;
|
||||
wire pll_locked = pll_pal_locked && pll_ntsc_locked;
|
||||
|
||||
|
||||
// tv15hkz has quarter the pixel rate, so we need a 7mhz clock for the OSD
|
||||
reg clk7;
|
||||
always @(posedge clk14)
|
||||
@@ -621,18 +606,12 @@ wire c1541_iec_atn_i = c16_iec_atn_i;
|
||||
wire c1541_iec_data_i = c16_iec_data_i;
|
||||
wire c1541_iec_clk_i = c16_iec_clk_i;
|
||||
|
||||
|
||||
c1541_sd c1541_sd (
|
||||
.clk32 ( clk32 ),
|
||||
.clk18 ( clk28 ), // MiST uses virtual SPI SD, so any clock can be used.
|
||||
.clk32 ( clk28 ),
|
||||
.reset ( reset ),
|
||||
|
||||
.c1541rom_addr ( 14'h0000 ),
|
||||
.c1541rom_data ( 8'h00 ),
|
||||
.c1541rom_wr ( 1'b0 ),
|
||||
|
||||
.disk_change ( sd_change ),
|
||||
.disk_num ( 10'd0 ), // not seletable by f8 or similar
|
||||
.disk_change ( img_mounted ),
|
||||
.disk_num ( 10'd0 ), // always 0 on MiST, the image is selected by the OSD menu
|
||||
|
||||
.iec_atn_i ( c1541_iec_atn_i ),
|
||||
.iec_data_i ( c1541_iec_data_i ),
|
||||
@@ -642,12 +621,16 @@ c1541_sd c1541_sd (
|
||||
.iec_data_o ( c1541_iec_data_o ),
|
||||
.iec_clk_o ( c1541_iec_clk_o ),
|
||||
|
||||
.sd_dat ( sd_dat ),
|
||||
.sd_dat3 ( sd_dat3 ),
|
||||
.sd_cmd ( sd_cmd ),
|
||||
.sd_clk ( sd_clk ),
|
||||
.sd_lba ( sd_lba ),
|
||||
.sd_rd ( sd_rd ),
|
||||
.sd_wr ( sd_wr ),
|
||||
.sd_ack ( sd_ack ),
|
||||
.sd_buff_din ( sd_din ),
|
||||
.sd_buff_dout ( sd_dout ),
|
||||
.sd_buff_wr ( sd_dout_strobe ),
|
||||
.sd_buff_addr ( sd_buff_addr ),
|
||||
|
||||
.led ( led_disk )
|
||||
// .led ( led_disk )
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
---------------------------------------------------------------------------------
|
||||
-- Commodore 1541 gcr floppy (read only) by Dar (darfpga@aol.fr) 02-April-2015
|
||||
-- http://darfpga.blogspot.fr
|
||||
--
|
||||
-- produces GCR data, byte(ready) and sync signal to feed c1541_logic from current
|
||||
-- track buffer ram which contains D64 data
|
||||
--
|
||||
-- Input clk 32MHz
|
||||
--
|
||||
---------------------------------------------------------------------------------
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.std_logic_unsigned.ALL;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
entity gcr_floppy is
|
||||
port(
|
||||
clk32 : in std_logic;
|
||||
do : out std_logic_vector(7 downto 0); -- disk read data
|
||||
mode : in std_logic; -- read/write
|
||||
stp : in std_logic_vector(1 downto 0); -- stepper motor control
|
||||
mtr : in std_logic; -- stepper motor on/off
|
||||
freq : in std_logic_vector(1 downto 0); -- motor (gcr_bit) frequency
|
||||
sync_n : out std_logic; -- reading SYNC bytes
|
||||
byte_n : out std_logic; -- byte ready
|
||||
|
||||
track : in std_logic_vector(5 downto 0);
|
||||
track_adr : out std_logic_vector(12 downto 0);
|
||||
track_data : in std_logic_vector(7 downto 0);
|
||||
track_ready : in std_logic;
|
||||
dbg_sector : out std_logic_vector(4 downto 0)
|
||||
|
||||
);
|
||||
end gcr_floppy;
|
||||
|
||||
architecture struct of gcr_floppy is
|
||||
|
||||
signal bit_clk_en : std_logic;
|
||||
signal sync_cnt : std_logic_vector(5 downto 0) := (others => '0');
|
||||
signal byte_cnt : std_logic_vector(8 downto 0) := (others => '0');
|
||||
signal nibble : std_logic := '0';
|
||||
signal gcr_bit_cnt : std_logic_vector(3 downto 0) := (others => '0');
|
||||
signal bit_cnt : std_logic_vector(2 downto 0) := (others => '0');
|
||||
|
||||
signal sync_in_n : std_logic;
|
||||
signal byte_in_n : std_logic;
|
||||
|
||||
signal sector : std_logic_vector(4 downto 0) := (others => '0');
|
||||
signal state : std_logic := '0';
|
||||
|
||||
signal data_header : std_logic_vector(7 downto 0);
|
||||
signal data_body : std_logic_vector(7 downto 0);
|
||||
signal data : std_logic_vector(7 downto 0);
|
||||
signal data_cks : std_logic_vector(7 downto 0);
|
||||
signal gcr_nibble : std_logic_vector(4 downto 0);
|
||||
signal gcr_bit : std_logic;
|
||||
signal gcr_byte : std_logic_vector(7 downto 0);
|
||||
|
||||
|
||||
type gcr_array is array(0 to 15) of std_logic_vector(4 downto 0);
|
||||
|
||||
signal gcr_lut : gcr_array :=
|
||||
("01010","11010","01001","11001",
|
||||
"01110","11110","01101","11101",
|
||||
"10010","10011","01011","11011",
|
||||
"10110","10111","01111","10101");
|
||||
|
||||
|
||||
signal sector_max : std_logic_vector(4 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
sync_n <= sync_in_n when mtr = '1' and track_ready = '1' else '1';
|
||||
|
||||
dbg_sector <= sector;
|
||||
|
||||
with byte_cnt select
|
||||
data_header <=
|
||||
X"08" when "000000000",
|
||||
"00"&track xor "000"§or when "000000001",
|
||||
"000"§or when "000000010",
|
||||
"00"&track when "000000011",
|
||||
X"20" when "000000100",
|
||||
X"20" when "000000101",
|
||||
X"0F" when others;
|
||||
|
||||
with byte_cnt select
|
||||
data_body <=
|
||||
X"07" when "000000000",
|
||||
data_cks when "100000001",
|
||||
X"00" when "100000010",
|
||||
X"00" when "100000011",
|
||||
X"0F" when "100000100",
|
||||
X"0F" when "100000101",
|
||||
X"0F" when "100000110",
|
||||
X"0F" when "100000111",
|
||||
X"0F" when "100001000",
|
||||
X"0F" when "100001001",
|
||||
X"0F" when "100001010",
|
||||
X"0F" when "100001011",
|
||||
X"0F" when "100001100",
|
||||
X"0F" when "100001101",
|
||||
X"0F" when "100001110",
|
||||
X"0F" when "100001111",
|
||||
X"0F" when "100010000",
|
||||
X"0F" when "100010001",
|
||||
track_data when others;
|
||||
|
||||
with state select
|
||||
data <= data_header when '0', data_body when others;
|
||||
|
||||
with nibble select
|
||||
gcr_nibble <=
|
||||
gcr_lut(to_integer(unsigned(data(7 downto 4)))) when '0',
|
||||
gcr_lut(to_integer(unsigned(data(3 downto 0)))) when others;
|
||||
|
||||
gcr_bit <= gcr_nibble(to_integer(unsigned(gcr_bit_cnt)));
|
||||
|
||||
|
||||
sector_max <= "10100" when track < std_logic_vector(to_unsigned(18,6)) else
|
||||
"10010" when track < std_logic_vector(to_unsigned(25,6)) else
|
||||
"10001" when track < std_logic_vector(to_unsigned(31,6)) else
|
||||
"10000" ;
|
||||
|
||||
|
||||
process (clk32)
|
||||
variable bit_clk_cnt : std_logic_vector(7 downto 0) := (others => '0');
|
||||
begin
|
||||
if rising_edge(clk32) then
|
||||
bit_clk_en <= '0';
|
||||
if bit_clk_cnt = X"6F" then
|
||||
bit_clk_en <= '1';
|
||||
bit_clk_cnt := (others => '0');
|
||||
else
|
||||
bit_clk_cnt := std_logic_vector(unsigned(bit_clk_cnt) + 1);
|
||||
end if;
|
||||
|
||||
byte_n <= '1';
|
||||
if byte_in_n = '0' and mtr = '1' and track_ready = '1' then
|
||||
if bit_clk_cnt > X"10" then
|
||||
if bit_clk_cnt < X"5E" then
|
||||
byte_n <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
process (clk32, bit_clk_en)
|
||||
begin
|
||||
if rising_edge(clk32) and bit_clk_en = '1' then
|
||||
|
||||
if sync_in_n = '0' then
|
||||
|
||||
byte_cnt <= (others => '0');
|
||||
nibble <= '0';
|
||||
gcr_bit_cnt <= (others => '0');
|
||||
bit_cnt <= (others => '0');
|
||||
do <= (others => '0');
|
||||
gcr_byte <= (others => '0');
|
||||
data_cks <= (others => '0');
|
||||
|
||||
if sync_cnt = X"31" then
|
||||
sync_cnt <= (others => '0');
|
||||
sync_in_n <= '1';
|
||||
else
|
||||
sync_cnt <= std_logic_vector(unsigned(sync_cnt +1));
|
||||
end if;
|
||||
|
||||
else
|
||||
|
||||
gcr_bit_cnt <= std_logic_vector(unsigned(gcr_bit_cnt)+1);
|
||||
if gcr_bit_cnt = X"4" then
|
||||
gcr_bit_cnt <= (others => '0');
|
||||
if nibble = '1' then
|
||||
nibble <= '0';
|
||||
track_adr <= sector & byte_cnt(7 downto 0);
|
||||
if byte_cnt = "000000000" then
|
||||
data_cks <= (others => '0');
|
||||
else
|
||||
data_cks <= data_cks xor data;
|
||||
end if;
|
||||
byte_cnt <= std_logic_vector(unsigned(byte_cnt)+1);
|
||||
else
|
||||
nibble <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
bit_cnt <= std_logic_vector(unsigned(bit_cnt)+1);
|
||||
byte_in_n <= '1';
|
||||
if bit_cnt = X"7" then
|
||||
byte_in_n <= '0';
|
||||
end if;
|
||||
|
||||
if state = '0' then
|
||||
if byte_cnt = "000010000" then sync_in_n <= '0'; state<= '1'; end if;
|
||||
else
|
||||
if byte_cnt = "100010001" then
|
||||
sync_in_n <= '0';
|
||||
state <= '0';
|
||||
if sector = sector_max then
|
||||
sector <= (others=>'0');
|
||||
else
|
||||
sector <= std_logic_vector(unsigned(sector)+1);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
gcr_byte <= gcr_byte(6 downto 0) & gcr_bit;
|
||||
|
||||
if bit_cnt = X"7" then
|
||||
do <= gcr_byte(6 downto 0) & gcr_bit;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end process;
|
||||
|
||||
end struct;
|
||||
1025
cores/c16/roms/325302-1_901229-03.hex
Normal file
1025
cores/c16/roms/325302-1_901229-03.hex
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,473 +0,0 @@
|
||||
//
|
||||
// sd_card.v
|
||||
//
|
||||
// This file implelents a sd card for the MIST board since on the board
|
||||
// the SD card is connected to the ARM IO controller and the FPGA has no
|
||||
// direct connection to the SD card. This file provides a SD card like
|
||||
// interface to the IO controller easing porting of cores that expect
|
||||
// a direct interface to the SD card.
|
||||
//
|
||||
// Copyright (c) 2014 Till Harbaum <till@harbaum.org>
|
||||
//
|
||||
// This source file is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the Lesser GNU General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This source file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// http://elm-chan.org/docs/mmc/mmc_e.html
|
||||
|
||||
module sd_card (
|
||||
// link to user_io for io controller
|
||||
output [31:0] io_lba,
|
||||
output reg io_rd,
|
||||
output reg io_wr,
|
||||
input io_ack,
|
||||
output io_conf,
|
||||
output io_sdhc,
|
||||
|
||||
// data coming in from io controller
|
||||
input [7:0] io_din,
|
||||
input io_din_strobe,
|
||||
|
||||
// data going out to io controller
|
||||
output [7:0] io_dout,
|
||||
input io_dout_strobe,
|
||||
|
||||
// configuration input
|
||||
input allow_sdhc,
|
||||
|
||||
input sd_cs,
|
||||
input sd_sck,
|
||||
input sd_sdi,
|
||||
output reg sd_sdo
|
||||
);
|
||||
|
||||
// set io_rd once read_state machine starts waiting (rising edge of req_io_rd)
|
||||
// and clear it once io controller uploads something (io_ack==1)
|
||||
reg req_io_rd = 1'b0; // set when write_state is changed to RD_STATE_WAIT_IO
|
||||
always @(posedge req_io_rd or posedge io_ack) begin
|
||||
if(io_ack) io_rd <= 1'b0;
|
||||
else io_rd <= 1'b1;
|
||||
end
|
||||
|
||||
reg req_io_wr = 1'b0; // set when write_state is changed to WR_STATE_BUSY
|
||||
always @(posedge req_io_wr or posedge io_ack) begin
|
||||
if(io_ack) io_wr <= 1'b0;
|
||||
else io_wr <= 1'b1;
|
||||
end
|
||||
|
||||
wire [31:0] OCR = { 1'b0, io_sdhc, 30'h0 }; // bit30 = 1 -> high capaciry card (sdhc)
|
||||
wire [7:0] READ_DATA_TOKEN = 8'hfe;
|
||||
|
||||
// number of bytes to wait after a command before sending the reply
|
||||
localparam NCR=4;
|
||||
|
||||
localparam RD_STATE_IDLE = 2'd0;
|
||||
localparam RD_STATE_WAIT_IO = 2'd1;
|
||||
localparam RD_STATE_SEND_TOKEN = 2'd2;
|
||||
localparam RD_STATE_SEND_DATA = 2'd3;
|
||||
reg [1:0] read_state = RD_STATE_IDLE;
|
||||
|
||||
localparam WR_STATE_IDLE = 3'd0;
|
||||
localparam WR_STATE_EXP_DTOKEN = 3'd1;
|
||||
localparam WR_STATE_RECV_DATA = 3'd2;
|
||||
localparam WR_STATE_RECV_CRC0 = 3'd3;
|
||||
localparam WR_STATE_RECV_CRC1 = 3'd4;
|
||||
localparam WR_STATE_SEND_DRESP = 3'd5;
|
||||
localparam WR_STATE_BUSY = 3'd6;
|
||||
reg [2:0] write_state = WR_STATE_IDLE;
|
||||
|
||||
reg card_is_reset = 1'b0; // flag that card has received a reset command
|
||||
reg [6:0] sbuf;
|
||||
reg cmd55;
|
||||
reg new_cmd_rcvd;
|
||||
reg [7:0] cmd = 8'h00;
|
||||
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
|
||||
reg [3:0] byte_cnt= 4'd15; // counts bytes
|
||||
|
||||
reg [31:0] lba;
|
||||
assign io_lba = io_sdhc?lba:{9'd0, lba[31:9]};
|
||||
|
||||
reg [7:0] reply;
|
||||
reg [7:0] reply0, reply1, reply2, reply3;
|
||||
reg [3:0] reply_len;
|
||||
|
||||
// falling edge of io_ack signals that a sector to be read has been written into
|
||||
// the sector buffer by the io controller. This signal is kept set as long
|
||||
// as the read state machine is in the "wait for io controller" state (state 1)
|
||||
wire rd_wait_io = (read_state != RD_STATE_IDLE);
|
||||
reg rd_io_ack_i = 1'b0;
|
||||
always @(negedge io_ack or negedge rd_wait_io) begin
|
||||
if(!rd_wait_io) rd_io_ack_i <= 1'b0;
|
||||
else rd_io_ack_i <= 1'b1;
|
||||
end
|
||||
|
||||
wire wr_wait_io = (write_state == WR_STATE_BUSY);
|
||||
reg wr_io_ack_i = 1'b0;
|
||||
always @(negedge io_ack or negedge wr_wait_io) begin
|
||||
if(!wr_wait_io) wr_io_ack_i <= 1'b0;
|
||||
else wr_io_ack_i <= 1'b1;
|
||||
end
|
||||
|
||||
// bring xx_io_ack into sd cards clock domain
|
||||
reg wr_io_ack;
|
||||
reg rd_io_ack;
|
||||
always @(posedge sd_sck) begin
|
||||
rd_io_ack <= rd_io_ack_i;
|
||||
wr_io_ack <= wr_io_ack_i;
|
||||
end
|
||||
|
||||
// ------------------------- SECTOR BUFFER -----------------------
|
||||
|
||||
// the buffer itself. Can hold one sector
|
||||
// (* ramstyle = "logic" *) reg [7:0] buffer [511:0];
|
||||
reg [7:0] buffer [511:0];
|
||||
|
||||
// ---------------- buffer read engine -----------------------
|
||||
reg [8:0] buffer_rptr;
|
||||
reg buffer_read_strobe;
|
||||
wire buffer_dout_strobe = buffer_read_strobe || io_dout_strobe;
|
||||
reg [7:0] buffer_dout;
|
||||
assign io_dout = buffer_dout;
|
||||
|
||||
// buffer_rptr is increased in a diferent clock domain than it's
|
||||
// evaluated. These single bit registers bring certain states from
|
||||
// one domain into the other one in a safe (atomic) way
|
||||
reg buffer_read_sector_done;
|
||||
reg buffer_read_ciscid_done;
|
||||
|
||||
always @(posedge buffer_dout_strobe or posedge new_cmd_rcvd) begin
|
||||
if(new_cmd_rcvd == 1) begin
|
||||
buffer_rptr <= 9'd0;
|
||||
buffer_read_sector_done <= 1'b0;
|
||||
buffer_read_ciscid_done <= 1'b0;
|
||||
end else begin
|
||||
buffer_dout <= buffer[buffer_rptr];
|
||||
buffer_rptr <= buffer_rptr + 9'd1;
|
||||
if(buffer_rptr == 511) buffer_read_sector_done <= 1'b1;
|
||||
if(buffer_rptr == 15) buffer_read_ciscid_done <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// ---------------- buffer write engine -----------------------
|
||||
reg [8:0] buffer_wptr;
|
||||
reg buffer_write_strobe;
|
||||
wire buffer_din_strobe = io_din_strobe || buffer_write_strobe;
|
||||
wire [7:0] buffer_din = (cmd == 8'h51)?io_din:{sbuf, sd_sdi};
|
||||
|
||||
always @(posedge buffer_din_strobe or posedge new_cmd_rcvd) begin
|
||||
if(new_cmd_rcvd == 1)
|
||||
buffer_wptr <= 9'd0;
|
||||
else begin
|
||||
buffer[buffer_wptr] <= buffer_din;
|
||||
buffer_wptr <= buffer_wptr + 9'd1;
|
||||
end
|
||||
end
|
||||
|
||||
wire [7:0] WRITE_DATA_RESPONSE = 8'h05;
|
||||
|
||||
// ------------------------- CSD/CID BUFFER ----------------------
|
||||
assign io_conf = (csd_wptr == 0); // csd_wptr still 0 -> configuration required
|
||||
|
||||
// the 32 bytes as sent from the io controller
|
||||
reg [7:0] cid [15:0] /* synthesis ramstyle = "logic" */;
|
||||
reg [7:0] csd [15:0] /* synthesis ramstyle = "logic" */;
|
||||
reg [7:0] conf;
|
||||
|
||||
reg [7:0] cid_byte;
|
||||
reg [7:0] csd_byte;
|
||||
reg [5:0] csd_wptr = 6'd0;
|
||||
|
||||
// conf[0]==1 -> io controller is using an sdhc card
|
||||
wire io_has_sdhc = conf[0];
|
||||
assign io_sdhc = allow_sdhc && io_has_sdhc;
|
||||
|
||||
always @(posedge io_din_strobe) begin
|
||||
// if io controller sends data without asserting io_ack, then it's
|
||||
// updating the config
|
||||
if(!io_ack && (csd_wptr <= 32)) begin
|
||||
|
||||
if(csd_wptr < 16) // first 16 bytes are cid
|
||||
cid[csd_wptr[3:0]] <= io_din;
|
||||
if((csd_wptr >= 16) && (csd_wptr < 32)) // then comes csd
|
||||
csd[csd_wptr[3:0]] <= io_din;
|
||||
if(csd_wptr == 32) // finally a config byte
|
||||
conf <= io_din;
|
||||
|
||||
csd_wptr <= csd_wptr + 6'd1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge buffer_dout_strobe) begin
|
||||
cid_byte <= cid[buffer_rptr[3:0]];
|
||||
csd_byte <= csd[buffer_rptr[3:0]];
|
||||
end
|
||||
|
||||
// ----------------- spi transmitter --------------------
|
||||
// advance transmitter state machine on falling sck edge, so data is valid on the
|
||||
// rising edge
|
||||
always@(negedge sd_sck) begin
|
||||
if(sd_cs == 0) begin
|
||||
buffer_read_strobe <= 1'b0;
|
||||
sd_sdo <= 1'b1; // default: send 1's (busy/wait)
|
||||
req_io_rd <= 1'b0;
|
||||
|
||||
if(byte_cnt == 5+NCR) begin
|
||||
sd_sdo <= reply[~bit_cnt];
|
||||
|
||||
if(bit_cnt == 7) begin
|
||||
// these three commands all have a reply_len of 0 and will thus
|
||||
// not send more than a single reply byte
|
||||
|
||||
// CMD9: SEND_CSD
|
||||
// CMD10: SEND_CID
|
||||
if((cmd == 8'h49)||(cmd == 8'h4a))
|
||||
read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission
|
||||
|
||||
// CMD17: READ_SINGLE_BLOCK
|
||||
if(cmd == 8'h51) begin
|
||||
read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller
|
||||
req_io_rd <= 1'b1; // trigger request to io controller
|
||||
end
|
||||
end
|
||||
end
|
||||
else if((reply_len > 0) && (byte_cnt == 5+NCR+1))
|
||||
sd_sdo <= reply0[~bit_cnt];
|
||||
else if((reply_len > 1) && (byte_cnt == 5+NCR+2))
|
||||
sd_sdo <= reply1[~bit_cnt];
|
||||
else if((reply_len > 2) && (byte_cnt == 5+NCR+3))
|
||||
sd_sdo <= reply2[~bit_cnt];
|
||||
else if((reply_len > 3) && (byte_cnt == 5+NCR+4))
|
||||
sd_sdo <= reply3[~bit_cnt];
|
||||
else
|
||||
sd_sdo <= 1'b1;
|
||||
|
||||
// ---------- read state machine processing -------------
|
||||
|
||||
case(read_state)
|
||||
RD_STATE_IDLE: ;
|
||||
// don't do anything
|
||||
|
||||
// waiting for io controller to return data
|
||||
RD_STATE_WAIT_IO: begin
|
||||
if(rd_io_ack && (bit_cnt == 7))
|
||||
read_state <= RD_STATE_SEND_TOKEN;
|
||||
end
|
||||
|
||||
// send data token
|
||||
RD_STATE_SEND_TOKEN: begin
|
||||
sd_sdo <= READ_DATA_TOKEN[~bit_cnt];
|
||||
|
||||
if(bit_cnt == 7) begin
|
||||
read_state <= RD_STATE_SEND_DATA; // next: send data
|
||||
buffer_read_strobe <= 1'b1; // trigger read of first data byte
|
||||
end
|
||||
end
|
||||
|
||||
// send data
|
||||
RD_STATE_SEND_DATA: begin
|
||||
if(cmd == 8'h51) // CMD17: READ_SINGLE_BLOCK
|
||||
sd_sdo <= buffer_dout[~bit_cnt];
|
||||
else if(cmd == 8'h49) // CMD9: SEND_CSD
|
||||
sd_sdo <= csd_byte[~bit_cnt];
|
||||
else if(cmd == 8'h4a) // CMD10: SEND_CID
|
||||
sd_sdo <= cid_byte[~bit_cnt];
|
||||
else
|
||||
sd_sdo <= 1'b1;
|
||||
|
||||
if(bit_cnt == 7) begin
|
||||
// sent 512 sector data bytes?
|
||||
if((cmd == 8'h51) && buffer_read_sector_done) // (buffer_rptr == 0))
|
||||
read_state <= RD_STATE_IDLE; // next: send crc. It's ignored so return to idle state
|
||||
|
||||
// sent 16 cid/csd data bytes?
|
||||
else if(((cmd == 8'h49)||(cmd == 8'h4a)) && buffer_read_ciscid_done) // && (buffer_rptr == 16))
|
||||
read_state <= RD_STATE_IDLE; // return to idle state
|
||||
|
||||
else
|
||||
buffer_read_strobe <= 1'b1; // not done yet -> trigger read of next data byte
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
// ------------------ write support ----------------------
|
||||
// send write data response
|
||||
if(write_state == WR_STATE_SEND_DRESP)
|
||||
sd_sdo <= WRITE_DATA_RESPONSE[~bit_cnt];
|
||||
|
||||
// busy after write until the io controller sends ack
|
||||
if(write_state == WR_STATE_BUSY)
|
||||
sd_sdo <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// spi receiver
|
||||
always @(posedge sd_sck or posedge sd_cs) begin
|
||||
// cs is active low
|
||||
if(sd_cs == 1) begin
|
||||
bit_cnt <= 3'd0;
|
||||
end else begin
|
||||
new_cmd_rcvd <= 1'b0;
|
||||
buffer_write_strobe <= 1'b0;
|
||||
req_io_wr <= 1'b0;
|
||||
bit_cnt <= bit_cnt + 3'd1;
|
||||
|
||||
// assemble byte
|
||||
if(bit_cnt != 7)
|
||||
sbuf[6:0] <= { sbuf[5:0], sd_sdi };
|
||||
else begin
|
||||
// finished reading one byte
|
||||
// byte counter runs against 15 byte boundary
|
||||
if(byte_cnt != 15)
|
||||
byte_cnt <= byte_cnt + 4'd1;
|
||||
|
||||
// byte_cnt > 6 -> complete command received
|
||||
// first byte of valid command is 01xxxxxx
|
||||
// don't accept new commands once a write or read command has been accepted
|
||||
if((byte_cnt > 5) && (write_state == WR_STATE_IDLE) &&
|
||||
(read_state == RD_STATE_IDLE) && sbuf[6:5] == 2'b01) begin
|
||||
byte_cnt <= 4'd0;
|
||||
cmd <= { sbuf, sd_sdi};
|
||||
new_cmd_rcvd <= 1'b1;
|
||||
|
||||
// set cmd55 flag if previous command was 55
|
||||
cmd55 <= (cmd == 8'h77);
|
||||
end
|
||||
|
||||
// parse additional command bytes
|
||||
if(byte_cnt == 0) lba[31:24] <= { sbuf, sd_sdi};
|
||||
if(byte_cnt == 1) lba[23:16] <= { sbuf, sd_sdi};
|
||||
if(byte_cnt == 2) lba[15:8] <= { sbuf, sd_sdi};
|
||||
if(byte_cnt == 3) lba[7:0] <= { sbuf, sd_sdi};
|
||||
|
||||
// last byte received, evaluate
|
||||
if(byte_cnt == 4) begin
|
||||
|
||||
// default:
|
||||
reply <= 8'h04; // illegal command
|
||||
reply_len <= 4'd0; // no extra reply bytes
|
||||
|
||||
// CMD0: GO_IDLE_STATE
|
||||
if(cmd == 8'h40) begin
|
||||
card_is_reset <= 1'b1;
|
||||
reply <= 8'h01; // ok, busy
|
||||
end
|
||||
|
||||
// every other command is only accepted after a reset
|
||||
else if(card_is_reset) begin
|
||||
// CMD1: SEND_OP_COND
|
||||
if(cmd == 8'h41)
|
||||
reply <= 8'h00; // ok, not busy
|
||||
|
||||
// CMD8: SEND_IF_COND (V2 only)
|
||||
else if(cmd == 8'h48) begin
|
||||
reply <= 8'h01; // ok, busy
|
||||
reply0 <= 8'h00;
|
||||
reply1 <= 8'h00;
|
||||
reply2 <= 8'h01;
|
||||
reply3 <= 8'hAA;
|
||||
reply_len <= 4'd4;
|
||||
end
|
||||
|
||||
// CMD9: SEND_CSD
|
||||
else if(cmd == 8'h49)
|
||||
reply <= 8'h00; // ok
|
||||
|
||||
// CMD10: SEND_CID
|
||||
else if(cmd == 8'h4a)
|
||||
reply <= 8'h00; // ok
|
||||
|
||||
// CMD16: SET_BLOCKLEN
|
||||
else if(cmd == 8'h50) begin
|
||||
// we only support a block size of 512
|
||||
if(lba == 32'd512)
|
||||
reply <= 8'h00; // ok
|
||||
else
|
||||
reply <= 8'h40; // parmeter error
|
||||
end
|
||||
|
||||
// CMD17: READ_SINGLE_BLOCK
|
||||
else if(cmd == 8'h51)
|
||||
reply <= 8'h00; // ok
|
||||
|
||||
// CMD24: WRITE_BLOCK
|
||||
else if(cmd == 8'h58) begin
|
||||
reply <= 8'h00; // ok
|
||||
write_state <= WR_STATE_EXP_DTOKEN; // expect data token
|
||||
end
|
||||
|
||||
// ACMD41: APP_SEND_OP_COND
|
||||
else if(cmd55 && (cmd == 8'h69))
|
||||
reply <= 8'h00; // ok, not busy
|
||||
|
||||
// CMD55: APP_COND
|
||||
else if(cmd == 8'h77)
|
||||
reply <= 8'h01; // ok, busy
|
||||
|
||||
// CMD58: READ_OCR
|
||||
else if(cmd == 8'h7a) begin
|
||||
reply <= 8'h00; // ok
|
||||
|
||||
reply0 <= OCR[31:24]; // bit 30 = 1 -> high capacity card
|
||||
reply1 <= OCR[23:16];
|
||||
reply2 <= OCR[15:8];
|
||||
reply3 <= OCR[7:0];
|
||||
reply_len <= 4'd4;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// ---------- handle write -----------
|
||||
case(write_state)
|
||||
// don't do anything in idle state
|
||||
WR_STATE_IDLE: ;
|
||||
|
||||
// waiting for data token
|
||||
WR_STATE_EXP_DTOKEN:
|
||||
if({ sbuf, sd_sdi} == 8'hfe )
|
||||
write_state <= WR_STATE_RECV_DATA;
|
||||
|
||||
// transfer 512 bytes
|
||||
WR_STATE_RECV_DATA: begin
|
||||
// push one byte into local buffer
|
||||
buffer_write_strobe <= 1'b1;
|
||||
|
||||
// all bytes written?
|
||||
if(buffer_wptr == 511)
|
||||
write_state <= WR_STATE_RECV_CRC0;
|
||||
end
|
||||
|
||||
// transfer 1st crc byte
|
||||
WR_STATE_RECV_CRC0:
|
||||
write_state <= WR_STATE_RECV_CRC1;
|
||||
|
||||
// transfer 2nd crc byte
|
||||
WR_STATE_RECV_CRC1:
|
||||
write_state <= WR_STATE_SEND_DRESP;
|
||||
|
||||
// send data response
|
||||
WR_STATE_SEND_DRESP: begin
|
||||
write_state <= WR_STATE_BUSY;
|
||||
req_io_wr <= 1'b1; // trigger write request to io ontroller
|
||||
end
|
||||
|
||||
// wait for io controller to accept data
|
||||
WR_STATE_BUSY:
|
||||
if(wr_io_ack)
|
||||
write_state <= WR_STATE_IDLE;
|
||||
|
||||
default:;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
564
cores/c16/t65/T65.vhd
Normal file
564
cores/c16/t65/T65.vhd
Normal file
@@ -0,0 +1,564 @@
|
||||
-- ****
|
||||
-- T65(b) core. In an effort to merge and maintain bug fixes ....
|
||||
--
|
||||
--
|
||||
-- Ver 301 more merging
|
||||
-- Ver 300 Bugfixes by ehenciak added, started tidyup *bust*
|
||||
-- MikeJ March 2005
|
||||
-- Latest version from www.fpgaarcade.com (original www.opencores.org)
|
||||
--
|
||||
-- ****
|
||||
--
|
||||
-- 65xx compatible microprocessor core
|
||||
--
|
||||
-- Version : 0246
|
||||
--
|
||||
-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org)
|
||||
--
|
||||
-- All rights reserved
|
||||
--
|
||||
-- Redistribution and use in source and synthezised forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- Redistributions in synthesized form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- Neither the name of the author nor the names of other contributors may
|
||||
-- be used to endorse or promote products derived from this software without
|
||||
-- specific prior written permission.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
|
||||
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
--
|
||||
-- Please report bugs to the author, but before you do so, please
|
||||
-- make sure that this is not a derivative work and that
|
||||
-- you have the latest version of this file.
|
||||
--
|
||||
-- The latest version of this file can be found at:
|
||||
-- http://www.opencores.org/cvsweb.shtml/t65/
|
||||
--
|
||||
-- Limitations :
|
||||
--
|
||||
-- 65C02 and 65C816 modes are incomplete
|
||||
-- Undocumented instructions are not supported
|
||||
-- Some interface signals behaves incorrect
|
||||
--
|
||||
-- File history :
|
||||
--
|
||||
-- 0246 : First release
|
||||
--
|
||||
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
use work.T65_Pack.all;
|
||||
|
||||
-- ehenciak 2-23-2005 : Added the enable signal so that one doesn't have to use
|
||||
-- the ready signal to limit the CPU.
|
||||
entity T65 is
|
||||
port(
|
||||
Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816
|
||||
Res_n : in std_logic;
|
||||
Enable : in std_logic;
|
||||
Clk : in std_logic;
|
||||
Rdy : in std_logic;
|
||||
Abort_n : in std_logic;
|
||||
IRQ_n : in std_logic;
|
||||
NMI_n : in std_logic;
|
||||
SO_n : in std_logic;
|
||||
R_W_n : out std_logic;
|
||||
Sync : out std_logic;
|
||||
EF : out std_logic;
|
||||
MF : out std_logic;
|
||||
XF : out std_logic;
|
||||
ML_n : out std_logic;
|
||||
VP_n : out std_logic;
|
||||
VDA : out std_logic;
|
||||
VPA : out std_logic;
|
||||
A : out std_logic_vector(23 downto 0);
|
||||
DI : in std_logic_vector(7 downto 0);
|
||||
DO : out std_logic_vector(7 downto 0)
|
||||
);
|
||||
end T65;
|
||||
|
||||
architecture rtl of T65 is
|
||||
|
||||
-- Registers
|
||||
signal ABC, X, Y, D : std_logic_vector(15 downto 0);
|
||||
signal P, AD, DL : std_logic_vector(7 downto 0) := x"00";
|
||||
signal BAH : std_logic_vector(7 downto 0);
|
||||
signal BAL : std_logic_vector(8 downto 0);
|
||||
signal PBR : std_logic_vector(7 downto 0);
|
||||
signal DBR : std_logic_vector(7 downto 0);
|
||||
signal PC : unsigned(15 downto 0);
|
||||
signal S : unsigned(15 downto 0);
|
||||
signal EF_i : std_logic;
|
||||
signal MF_i : std_logic;
|
||||
signal XF_i : std_logic;
|
||||
|
||||
signal IR : std_logic_vector(7 downto 0);
|
||||
signal MCycle : std_logic_vector(2 downto 0);
|
||||
|
||||
signal Mode_r : std_logic_vector(1 downto 0);
|
||||
signal ALU_Op_r : std_logic_vector(3 downto 0);
|
||||
signal Write_Data_r : std_logic_vector(2 downto 0);
|
||||
signal Set_Addr_To_r : std_logic_vector(1 downto 0);
|
||||
signal PCAdder : unsigned(8 downto 0);
|
||||
|
||||
signal RstCycle : std_logic;
|
||||
signal IRQCycle : std_logic;
|
||||
signal NMICycle : std_logic;
|
||||
|
||||
signal B_o : std_logic;
|
||||
signal SO_n_o : std_logic;
|
||||
signal IRQ_n_o : std_logic;
|
||||
signal NMI_n_o : std_logic;
|
||||
signal NMIAct : std_logic;
|
||||
|
||||
signal Break : std_logic;
|
||||
|
||||
-- ALU signals
|
||||
signal BusA : std_logic_vector(7 downto 0);
|
||||
signal BusA_r : std_logic_vector(7 downto 0);
|
||||
signal BusB : std_logic_vector(7 downto 0);
|
||||
signal ALU_Q : std_logic_vector(7 downto 0);
|
||||
signal P_Out : std_logic_vector(7 downto 0);
|
||||
|
||||
-- Micro code outputs
|
||||
signal LCycle : std_logic_vector(2 downto 0);
|
||||
signal ALU_Op : std_logic_vector(3 downto 0);
|
||||
signal Set_BusA_To : std_logic_vector(2 downto 0);
|
||||
signal Set_Addr_To : std_logic_vector(1 downto 0);
|
||||
signal Write_Data : std_logic_vector(2 downto 0);
|
||||
signal Jump : std_logic_vector(1 downto 0);
|
||||
signal BAAdd : std_logic_vector(1 downto 0);
|
||||
signal BreakAtNA : std_logic;
|
||||
signal ADAdd : std_logic;
|
||||
signal AddY : std_logic;
|
||||
signal PCAdd : std_logic;
|
||||
signal Inc_S : std_logic;
|
||||
signal Dec_S : std_logic;
|
||||
signal LDA : std_logic;
|
||||
signal LDP : std_logic;
|
||||
signal LDX : std_logic;
|
||||
signal LDY : std_logic;
|
||||
signal LDS : std_logic;
|
||||
signal LDDI : std_logic;
|
||||
signal LDALU : std_logic;
|
||||
signal LDAD : std_logic;
|
||||
signal LDBAL : std_logic;
|
||||
signal LDBAH : std_logic;
|
||||
signal SaveP : std_logic;
|
||||
signal Write : std_logic;
|
||||
|
||||
signal really_rdy : std_logic;
|
||||
signal R_W_n_i : std_logic;
|
||||
|
||||
begin
|
||||
-- ehenciak : gate Rdy with read/write to make an "OK, it's
|
||||
-- really OK to stop the processor now if Rdy is
|
||||
-- deasserted" signal
|
||||
really_rdy <= Rdy or not(R_W_n_i);
|
||||
|
||||
-- ehenciak : Drive R_W_n_i off chip.
|
||||
R_W_n <= R_W_n_i;
|
||||
|
||||
Sync <= '1' when MCycle = "000" else '0';
|
||||
EF <= EF_i;
|
||||
MF <= MF_i;
|
||||
XF <= XF_i;
|
||||
ML_n <= '0' when IR(7 downto 6) /= "10" and IR(2 downto 1) = "11" and MCycle(2 downto 1) /= "00" else '1';
|
||||
VP_n <= '0' when IRQCycle = '1' and (MCycle = "101" or MCycle = "110") else '1';
|
||||
VDA <= '1' when Set_Addr_To_r /= "00" else '0'; -- Incorrect !!!!!!!!!!!!
|
||||
VPA <= '1' when Jump(1) = '0' else '0'; -- Incorrect !!!!!!!!!!!!
|
||||
|
||||
mcode : T65_MCode
|
||||
port map(
|
||||
Mode => Mode_r,
|
||||
IR => IR,
|
||||
MCycle => MCycle,
|
||||
P => P,
|
||||
LCycle => LCycle,
|
||||
ALU_Op => ALU_Op,
|
||||
Set_BusA_To => Set_BusA_To,
|
||||
Set_Addr_To => Set_Addr_To,
|
||||
Write_Data => Write_Data,
|
||||
Jump => Jump,
|
||||
BAAdd => BAAdd,
|
||||
BreakAtNA => BreakAtNA,
|
||||
ADAdd => ADAdd,
|
||||
AddY => AddY,
|
||||
PCAdd => PCAdd,
|
||||
Inc_S => Inc_S,
|
||||
Dec_S => Dec_S,
|
||||
LDA => LDA,
|
||||
LDP => LDP,
|
||||
LDX => LDX,
|
||||
LDY => LDY,
|
||||
LDS => LDS,
|
||||
LDDI => LDDI,
|
||||
LDALU => LDALU,
|
||||
LDAD => LDAD,
|
||||
LDBAL => LDBAL,
|
||||
LDBAH => LDBAH,
|
||||
SaveP => SaveP,
|
||||
Write => Write
|
||||
);
|
||||
|
||||
alu : T65_ALU
|
||||
port map(
|
||||
Mode => Mode_r,
|
||||
Op => ALU_Op_r,
|
||||
BusA => BusA_r,
|
||||
BusB => BusB,
|
||||
P_In => P,
|
||||
P_Out => P_Out,
|
||||
Q => ALU_Q
|
||||
);
|
||||
|
||||
process (Res_n, Clk)
|
||||
begin
|
||||
if Res_n = '0' then
|
||||
PC <= (others => '0'); -- Program Counter
|
||||
IR <= "00000000";
|
||||
S <= (others => '0'); -- Dummy !!!!!!!!!!!!!!!!!!!!!
|
||||
D <= (others => '0');
|
||||
PBR <= (others => '0');
|
||||
DBR <= (others => '0');
|
||||
|
||||
Mode_r <= (others => '0');
|
||||
ALU_Op_r <= "1100";
|
||||
Write_Data_r <= "000";
|
||||
Set_Addr_To_r <= "00";
|
||||
|
||||
R_W_n_i <= '1';
|
||||
EF_i <= '1';
|
||||
MF_i <= '1';
|
||||
XF_i <= '1';
|
||||
|
||||
elsif Clk'event and Clk = '1' then
|
||||
if (Enable = '1') then
|
||||
if (really_rdy = '1') then
|
||||
R_W_n_i <= not Write or RstCycle;
|
||||
|
||||
D <= (others => '1'); -- Dummy
|
||||
PBR <= (others => '1'); -- Dummy
|
||||
DBR <= (others => '1'); -- Dummy
|
||||
EF_i <= '0'; -- Dummy
|
||||
MF_i <= '0'; -- Dummy
|
||||
XF_i <= '0'; -- Dummy
|
||||
|
||||
if MCycle = "000" then
|
||||
Mode_r <= Mode;
|
||||
|
||||
if IRQCycle = '0' and NMICycle = '0' then
|
||||
PC <= PC + 1;
|
||||
end if;
|
||||
|
||||
if IRQCycle = '1' or NMICycle = '1' then
|
||||
IR <= "00000000";
|
||||
else
|
||||
IR <= DI;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
ALU_Op_r <= ALU_Op;
|
||||
Write_Data_r <= Write_Data;
|
||||
if Break = '1' then
|
||||
Set_Addr_To_r <= "00";
|
||||
else
|
||||
Set_Addr_To_r <= Set_Addr_To;
|
||||
end if;
|
||||
|
||||
if Inc_S = '1' then
|
||||
S <= S + 1;
|
||||
end if;
|
||||
if Dec_S = '1' and RstCycle = '0' then
|
||||
S <= S - 1;
|
||||
end if;
|
||||
if LDS = '1' then
|
||||
S(7 downto 0) <= unsigned(ALU_Q);
|
||||
end if;
|
||||
|
||||
if IR = "00000000" and MCycle = "001" and IRQCycle = '0' and NMICycle = '0' then
|
||||
PC <= PC + 1;
|
||||
end if;
|
||||
--
|
||||
-- jump control logic
|
||||
--
|
||||
case Jump is
|
||||
when "01" =>
|
||||
PC <= PC + 1;
|
||||
|
||||
when "10" =>
|
||||
PC <= unsigned(DI & DL);
|
||||
|
||||
when "11" =>
|
||||
if PCAdder(8) = '1' then
|
||||
if DL(7) = '0' then
|
||||
PC(15 downto 8) <= PC(15 downto 8) + 1;
|
||||
else
|
||||
PC(15 downto 8) <= PC(15 downto 8) - 1;
|
||||
end if;
|
||||
end if;
|
||||
PC(7 downto 0) <= PCAdder(7 downto 0);
|
||||
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
PCAdder <= resize(PC(7 downto 0),9) + resize(unsigned(DL(7) & DL),9) when PCAdd = '1'
|
||||
else "0" & PC(7 downto 0);
|
||||
|
||||
process (Clk)
|
||||
begin
|
||||
if Clk'event and Clk = '1' then
|
||||
if (Enable = '1') then
|
||||
if (really_rdy = '1') then
|
||||
if MCycle = "000" then
|
||||
if LDA = '1' then
|
||||
ABC(7 downto 0) <= ALU_Q;
|
||||
end if;
|
||||
if LDX = '1' then
|
||||
X(7 downto 0) <= ALU_Q;
|
||||
end if;
|
||||
if LDY = '1' then
|
||||
Y(7 downto 0) <= ALU_Q;
|
||||
end if;
|
||||
if (LDA or LDX or LDY) = '1' then
|
||||
P <= P_Out;
|
||||
end if;
|
||||
end if;
|
||||
if SaveP = '1' then
|
||||
P <= P_Out;
|
||||
end if;
|
||||
if LDP = '1' then
|
||||
P <= ALU_Q;
|
||||
end if;
|
||||
if IR(4 downto 0) = "11000" then
|
||||
case IR(7 downto 5) is
|
||||
when "000" =>
|
||||
P(Flag_C) <= '0';
|
||||
when "001" =>
|
||||
P(Flag_C) <= '1';
|
||||
when "010" =>
|
||||
P(Flag_I) <= '0';
|
||||
when "011" =>
|
||||
P(Flag_I) <= '1';
|
||||
when "101" =>
|
||||
P(Flag_V) <= '0';
|
||||
when "110" =>
|
||||
P(Flag_D) <= '0';
|
||||
when "111" =>
|
||||
P(Flag_D) <= '1';
|
||||
when others =>
|
||||
end case;
|
||||
end if;
|
||||
|
||||
--if IR = "00000000" and MCycle = "011" and RstCycle = '0' and NMICycle = '0' and IRQCycle = '0' then
|
||||
-- P(Flag_B) <= '1';
|
||||
--end if;
|
||||
--if IR = "00000000" and MCycle = "100" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then
|
||||
-- P(Flag_I) <= '1';
|
||||
-- P(Flag_B) <= B_o;
|
||||
--end if;
|
||||
|
||||
-- B=1 always on the 6502
|
||||
P(Flag_B) <= '1';
|
||||
if IR = "00000000" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then
|
||||
if MCycle = "011" then
|
||||
-- B=0 in *copy* of P pushed onto the stack
|
||||
P(Flag_B) <= '0';
|
||||
elsif MCycle = "100" then
|
||||
P(Flag_I) <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if SO_n_o = '1' and SO_n = '0' then
|
||||
P(Flag_V) <= '1';
|
||||
end if;
|
||||
if RstCycle = '1' and Mode_r /= "00" then
|
||||
P(Flag_1) <= '1';
|
||||
P(Flag_D) <= '0';
|
||||
P(Flag_I) <= '1';
|
||||
end if;
|
||||
P(Flag_1) <= '1';
|
||||
|
||||
B_o <= P(Flag_B);
|
||||
SO_n_o <= SO_n;
|
||||
IRQ_n_o <= IRQ_n;
|
||||
NMI_n_o <= NMI_n;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
--
|
||||
-- Buses
|
||||
--
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
process (Res_n, Clk)
|
||||
begin
|
||||
if Res_n = '0' then
|
||||
BusA_r <= (others => '0');
|
||||
BusB <= (others => '0');
|
||||
AD <= (others => '0');
|
||||
BAL <= (others => '0');
|
||||
BAH <= (others => '0');
|
||||
DL <= (others => '0');
|
||||
elsif Clk'event and Clk = '1' then
|
||||
if (Enable = '1') then
|
||||
if (Rdy = '1') then
|
||||
BusA_r <= BusA;
|
||||
BusB <= DI;
|
||||
|
||||
case BAAdd is
|
||||
when "01" =>
|
||||
-- BA Inc
|
||||
AD <= std_logic_vector(unsigned(AD) + 1);
|
||||
BAL <= std_logic_vector(unsigned(BAL) + 1);
|
||||
when "10" =>
|
||||
-- BA Add
|
||||
BAL <= std_logic_vector(resize(unsigned(BAL(7 downto 0)),9) + resize(unsigned(BusA),9));
|
||||
when "11" =>
|
||||
-- BA Adj
|
||||
if BAL(8) = '1' then
|
||||
BAH <= std_logic_vector(unsigned(BAH) + 1);
|
||||
end if;
|
||||
when others =>
|
||||
end case;
|
||||
|
||||
-- ehenciak : modified to use Y register as well (bugfix)
|
||||
if ADAdd = '1' then
|
||||
if (AddY = '1') then
|
||||
AD <= std_logic_vector(unsigned(AD) + unsigned(Y(7 downto 0)));
|
||||
else
|
||||
AD <= std_logic_vector(unsigned(AD) + unsigned(X(7 downto 0)));
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if IR = "00000000" then
|
||||
BAL <= (others => '1');
|
||||
BAH <= (others => '1');
|
||||
if RstCycle = '1' then
|
||||
BAL(2 downto 0) <= "100";
|
||||
elsif NMICycle = '1' then
|
||||
BAL(2 downto 0) <= "010";
|
||||
else
|
||||
BAL(2 downto 0) <= "110";
|
||||
end if;
|
||||
if Set_addr_To_r = "11" then
|
||||
BAL(0) <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
|
||||
if LDDI = '1' then
|
||||
DL <= DI;
|
||||
end if;
|
||||
if LDALU = '1' then
|
||||
DL <= ALU_Q;
|
||||
end if;
|
||||
if LDAD = '1' then
|
||||
AD <= DI;
|
||||
end if;
|
||||
if LDBAL = '1' then
|
||||
BAL(7 downto 0) <= DI;
|
||||
end if;
|
||||
if LDBAH = '1' then
|
||||
BAH <= DI;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
Break <= (BreakAtNA and not BAL(8)) or (PCAdd and not PCAdder(8));
|
||||
|
||||
|
||||
with Set_BusA_To select
|
||||
BusA <= DI when "000",
|
||||
ABC(7 downto 0) when "001",
|
||||
X(7 downto 0) when "010",
|
||||
Y(7 downto 0) when "011",
|
||||
std_logic_vector(S(7 downto 0)) when "100",
|
||||
P when "101",
|
||||
(others => '-') when others;
|
||||
|
||||
with Set_Addr_To_r select
|
||||
A <= "0000000000000001" & std_logic_vector(S(7 downto 0)) when "01",
|
||||
DBR & "00000000" & AD when "10",
|
||||
"00000000" & BAH & BAL(7 downto 0) when "11",
|
||||
PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when others;
|
||||
|
||||
with Write_Data_r select
|
||||
DO <= DL when "000",
|
||||
ABC(7 downto 0) when "001",
|
||||
X(7 downto 0) when "010",
|
||||
Y(7 downto 0) when "011",
|
||||
std_logic_vector(S(7 downto 0)) when "100",
|
||||
P when "101",
|
||||
std_logic_vector(PC(7 downto 0)) when "110",
|
||||
std_logic_vector(PC(15 downto 8)) when others;
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--
|
||||
-- Main state machine
|
||||
--
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
process (Res_n, Clk)
|
||||
begin
|
||||
if Res_n = '0' then
|
||||
MCycle <= "001";
|
||||
RstCycle <= '1';
|
||||
IRQCycle <= '0';
|
||||
NMICycle <= '0';
|
||||
NMIAct <= '0';
|
||||
elsif Clk'event and Clk = '1' then
|
||||
if (Enable = '1') then
|
||||
if (really_rdy = '1') then
|
||||
if MCycle = LCycle or Break = '1' then
|
||||
MCycle <= "000";
|
||||
RstCycle <= '0';
|
||||
IRQCycle <= '0';
|
||||
NMICycle <= '0';
|
||||
if NMIAct = '1' then
|
||||
NMICycle <= '1';
|
||||
elsif IRQ_n_o = '0' and P(Flag_I) = '0' then
|
||||
IRQCycle <= '1';
|
||||
end if;
|
||||
else
|
||||
MCycle <= std_logic_vector(unsigned(MCycle) + 1);
|
||||
end if;
|
||||
|
||||
if NMICycle = '1' then
|
||||
NMIAct <= '0';
|
||||
end if;
|
||||
if NMI_n_o = '1' and NMI_n = '0' then
|
||||
NMIAct <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end;
|
||||
260
cores/c16/t65/T65_ALU.vhd
Normal file
260
cores/c16/t65/T65_ALU.vhd
Normal file
@@ -0,0 +1,260 @@
|
||||
-- ****
|
||||
-- T65(b) core. In an effort to merge and maintain bug fixes ....
|
||||
--
|
||||
--
|
||||
-- Ver 300 Bugfixes by ehenciak added
|
||||
-- MikeJ March 2005
|
||||
-- Latest version from www.fpgaarcade.com (original www.opencores.org)
|
||||
--
|
||||
-- ****
|
||||
--
|
||||
-- 6502 compatible microprocessor core
|
||||
--
|
||||
-- Version : 0245
|
||||
--
|
||||
-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org)
|
||||
--
|
||||
-- All rights reserved
|
||||
--
|
||||
-- Redistribution and use in source and synthezised forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- Redistributions in synthesized form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- Neither the name of the author nor the names of other contributors may
|
||||
-- be used to endorse or promote products derived from this software without
|
||||
-- specific prior written permission.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
|
||||
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
--
|
||||
-- Please report bugs to the author, but before you do so, please
|
||||
-- make sure that this is not a derivative work and that
|
||||
-- you have the latest version of this file.
|
||||
--
|
||||
-- The latest version of this file can be found at:
|
||||
-- http://www.opencores.org/cvsweb.shtml/t65/
|
||||
--
|
||||
-- Limitations :
|
||||
--
|
||||
-- File history :
|
||||
--
|
||||
-- 0245 : First version
|
||||
--
|
||||
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
use work.T65_Pack.all;
|
||||
|
||||
entity T65_ALU is
|
||||
port(
|
||||
Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816
|
||||
Op : in std_logic_vector(3 downto 0);
|
||||
BusA : in std_logic_vector(7 downto 0);
|
||||
BusB : in std_logic_vector(7 downto 0);
|
||||
P_In : in std_logic_vector(7 downto 0);
|
||||
P_Out : out std_logic_vector(7 downto 0);
|
||||
Q : out std_logic_vector(7 downto 0)
|
||||
);
|
||||
end T65_ALU;
|
||||
|
||||
architecture rtl of T65_ALU is
|
||||
|
||||
-- AddSub variables (temporary signals)
|
||||
signal ADC_Z : std_logic;
|
||||
signal ADC_C : std_logic;
|
||||
signal ADC_V : std_logic;
|
||||
signal ADC_N : std_logic;
|
||||
signal ADC_Q : std_logic_vector(7 downto 0);
|
||||
signal SBC_Z : std_logic;
|
||||
signal SBC_C : std_logic;
|
||||
signal SBC_V : std_logic;
|
||||
signal SBC_N : std_logic;
|
||||
signal SBC_Q : std_logic_vector(7 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
process (P_In, BusA, BusB)
|
||||
variable AL : unsigned(6 downto 0);
|
||||
variable AH : unsigned(6 downto 0);
|
||||
variable C : std_logic;
|
||||
begin
|
||||
AL := resize(unsigned(BusA(3 downto 0) & P_In(Flag_C)), 7) + resize(unsigned(BusB(3 downto 0) & "1"), 7);
|
||||
AH := resize(unsigned(BusA(7 downto 4) & AL(5)), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7);
|
||||
|
||||
-- pragma translate_off
|
||||
if is_x(std_logic_vector(AL)) then AL := "0000000"; end if;
|
||||
if is_x(std_logic_vector(AH)) then AH := "0000000"; end if;
|
||||
-- pragma translate_on
|
||||
|
||||
if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then
|
||||
ADC_Z <= '1';
|
||||
else
|
||||
ADC_Z <= '0';
|
||||
end if;
|
||||
|
||||
if AL(5 downto 1) > 9 and P_In(Flag_D) = '1' then
|
||||
AL(6 downto 1) := AL(6 downto 1) + 6;
|
||||
end if;
|
||||
|
||||
C := AL(6) or AL(5);
|
||||
AH := resize(unsigned(BusA(7 downto 4) & C), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7);
|
||||
|
||||
ADC_N <= AH(4);
|
||||
ADC_V <= (AH(4) xor BusA(7)) and not (BusA(7) xor BusB(7));
|
||||
|
||||
-- pragma translate_off
|
||||
if is_x(std_logic_vector(AH)) then AH := "0000000"; end if;
|
||||
-- pragma translate_on
|
||||
|
||||
if AH(5 downto 1) > 9 and P_In(Flag_D) = '1' then
|
||||
AH(6 downto 1) := AH(6 downto 1) + 6;
|
||||
end if;
|
||||
|
||||
ADC_C <= AH(6) or AH(5);
|
||||
|
||||
ADC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1));
|
||||
end process;
|
||||
|
||||
process (Op, P_In, BusA, BusB)
|
||||
variable AL : unsigned(6 downto 0);
|
||||
variable AH : unsigned(5 downto 0);
|
||||
variable C : std_logic;
|
||||
begin
|
||||
C := P_In(Flag_C) or not Op(0);
|
||||
AL := resize(unsigned(BusA(3 downto 0) & C), 7) - resize(unsigned(BusB(3 downto 0) & "1"), 6);
|
||||
AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(5)), 6);
|
||||
|
||||
-- pragma translate_off
|
||||
if is_x(std_logic_vector(AL)) then AL := "0000000"; end if;
|
||||
if is_x(std_logic_vector(AH)) then AH := "000000"; end if;
|
||||
-- pragma translate_on
|
||||
|
||||
if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then
|
||||
SBC_Z <= '1';
|
||||
else
|
||||
SBC_Z <= '0';
|
||||
end if;
|
||||
|
||||
SBC_C <= not AH(5);
|
||||
SBC_V <= (AH(4) xor BusA(7)) and (BusA(7) xor BusB(7));
|
||||
SBC_N <= AH(4);
|
||||
|
||||
if P_In(Flag_D) = '1' then
|
||||
if AL(5) = '1' then
|
||||
AL(5 downto 1) := AL(5 downto 1) - 6;
|
||||
end if;
|
||||
AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(6)), 6);
|
||||
if AH(5) = '1' then
|
||||
AH(5 downto 1) := AH(5 downto 1) - 6;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
SBC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1));
|
||||
end process;
|
||||
|
||||
process (Op, P_In, BusA, BusB,
|
||||
ADC_Z, ADC_C, ADC_V, ADC_N, ADC_Q,
|
||||
SBC_Z, SBC_C, SBC_V, SBC_N, SBC_Q)
|
||||
variable Q_t : std_logic_vector(7 downto 0);
|
||||
begin
|
||||
-- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC
|
||||
-- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC
|
||||
P_Out <= P_In;
|
||||
Q_t := BusA;
|
||||
case Op(3 downto 0) is
|
||||
when "0000" =>
|
||||
-- ORA
|
||||
Q_t := BusA or BusB;
|
||||
when "0001" =>
|
||||
-- AND
|
||||
Q_t := BusA and BusB;
|
||||
when "0010" =>
|
||||
-- EOR
|
||||
Q_t := BusA xor BusB;
|
||||
when "0011" =>
|
||||
-- ADC
|
||||
P_Out(Flag_V) <= ADC_V;
|
||||
P_Out(Flag_C) <= ADC_C;
|
||||
Q_t := ADC_Q;
|
||||
when "0101" | "1101" =>
|
||||
-- LDA
|
||||
when "0110" =>
|
||||
-- CMP
|
||||
P_Out(Flag_C) <= SBC_C;
|
||||
when "0111" =>
|
||||
-- SBC
|
||||
P_Out(Flag_V) <= SBC_V;
|
||||
P_Out(Flag_C) <= SBC_C;
|
||||
Q_t := SBC_Q;
|
||||
when "1000" =>
|
||||
-- ASL
|
||||
Q_t := BusA(6 downto 0) & "0";
|
||||
P_Out(Flag_C) <= BusA(7);
|
||||
when "1001" =>
|
||||
-- ROL
|
||||
Q_t := BusA(6 downto 0) & P_In(Flag_C);
|
||||
P_Out(Flag_C) <= BusA(7);
|
||||
when "1010" =>
|
||||
-- LSR
|
||||
Q_t := "0" & BusA(7 downto 1);
|
||||
P_Out(Flag_C) <= BusA(0);
|
||||
when "1011" =>
|
||||
-- ROR
|
||||
Q_t := P_In(Flag_C) & BusA(7 downto 1);
|
||||
P_Out(Flag_C) <= BusA(0);
|
||||
when "1100" =>
|
||||
-- BIT
|
||||
P_Out(Flag_V) <= BusB(6);
|
||||
when "1110" =>
|
||||
-- DEC
|
||||
Q_t := std_logic_vector(unsigned(BusA) - 1);
|
||||
when "1111" =>
|
||||
-- INC
|
||||
Q_t := std_logic_vector(unsigned(BusA) + 1);
|
||||
when others =>
|
||||
end case;
|
||||
|
||||
case Op(3 downto 0) is
|
||||
when "0011" =>
|
||||
P_Out(Flag_N) <= ADC_N;
|
||||
P_Out(Flag_Z) <= ADC_Z;
|
||||
when "0110" | "0111" =>
|
||||
P_Out(Flag_N) <= SBC_N;
|
||||
P_Out(Flag_Z) <= SBC_Z;
|
||||
when "0100" =>
|
||||
when "1100" =>
|
||||
P_Out(Flag_N) <= BusB(7);
|
||||
if (BusA and BusB) = "00000000" then
|
||||
P_Out(Flag_Z) <= '1';
|
||||
else
|
||||
P_Out(Flag_Z) <= '0';
|
||||
end if;
|
||||
when others =>
|
||||
P_Out(Flag_N) <= Q_t(7);
|
||||
if Q_t = "00000000" then
|
||||
P_Out(Flag_Z) <= '1';
|
||||
else
|
||||
P_Out(Flag_Z) <= '0';
|
||||
end if;
|
||||
end case;
|
||||
|
||||
Q <= Q_t;
|
||||
end process;
|
||||
|
||||
end;
|
||||
1052
cores/c16/t65/T65_MCode.vhd
Normal file
1052
cores/c16/t65/T65_MCode.vhd
Normal file
File diff suppressed because it is too large
Load Diff
117
cores/c16/t65/T65_Pack.vhd
Normal file
117
cores/c16/t65/T65_Pack.vhd
Normal file
@@ -0,0 +1,117 @@
|
||||
-- ****
|
||||
-- T65(b) core. In an effort to merge and maintain bug fixes ....
|
||||
--
|
||||
--
|
||||
-- Ver 300 Bugfixes by ehenciak added
|
||||
-- MikeJ March 2005
|
||||
-- Latest version from www.fpgaarcade.com (original www.opencores.org)
|
||||
--
|
||||
-- ****
|
||||
--
|
||||
-- 65xx compatible microprocessor core
|
||||
--
|
||||
-- Version : 0246
|
||||
--
|
||||
-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org)
|
||||
--
|
||||
-- All rights reserved
|
||||
--
|
||||
-- Redistribution and use in source and synthezised forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- Redistributions in synthesized form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- Neither the name of the author nor the names of other contributors may
|
||||
-- be used to endorse or promote products derived from this software without
|
||||
-- specific prior written permission.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
|
||||
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
--
|
||||
-- Please report bugs to the author, but before you do so, please
|
||||
-- make sure that this is not a derivative work and that
|
||||
-- you have the latest version of this file.
|
||||
--
|
||||
-- The latest version of this file can be found at:
|
||||
-- http://www.opencores.org/cvsweb.shtml/t65/
|
||||
--
|
||||
-- Limitations :
|
||||
--
|
||||
-- File history :
|
||||
--
|
||||
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
|
||||
package T65_Pack is
|
||||
|
||||
constant Flag_C : integer := 0;
|
||||
constant Flag_Z : integer := 1;
|
||||
constant Flag_I : integer := 2;
|
||||
constant Flag_D : integer := 3;
|
||||
constant Flag_B : integer := 4;
|
||||
constant Flag_1 : integer := 5;
|
||||
constant Flag_V : integer := 6;
|
||||
constant Flag_N : integer := 7;
|
||||
|
||||
component T65_MCode
|
||||
port(
|
||||
Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816
|
||||
IR : in std_logic_vector(7 downto 0);
|
||||
MCycle : in std_logic_vector(2 downto 0);
|
||||
P : in std_logic_vector(7 downto 0);
|
||||
LCycle : out std_logic_vector(2 downto 0);
|
||||
ALU_Op : out std_logic_vector(3 downto 0);
|
||||
Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P
|
||||
Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA
|
||||
Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH
|
||||
Jump : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel
|
||||
BAAdd : out std_logic_vector(1 downto 0); -- None,DB Inc,BA Add,BA Adj
|
||||
BreakAtNA : out std_logic;
|
||||
ADAdd : out std_logic;
|
||||
AddY : out std_logic;
|
||||
PCAdd : out std_logic;
|
||||
Inc_S : out std_logic;
|
||||
Dec_S : out std_logic;
|
||||
LDA : out std_logic;
|
||||
LDP : out std_logic;
|
||||
LDX : out std_logic;
|
||||
LDY : out std_logic;
|
||||
LDS : out std_logic;
|
||||
LDDI : out std_logic;
|
||||
LDALU : out std_logic;
|
||||
LDAD : out std_logic;
|
||||
LDBAL : out std_logic;
|
||||
LDBAH : out std_logic;
|
||||
SaveP : out std_logic;
|
||||
Write : out std_logic
|
||||
);
|
||||
end component;
|
||||
|
||||
component T65_ALU
|
||||
port(
|
||||
Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816
|
||||
Op : in std_logic_vector(3 downto 0);
|
||||
BusA : in std_logic_vector(7 downto 0);
|
||||
BusB : in std_logic_vector(7 downto 0);
|
||||
P_In : in std_logic_vector(7 downto 0);
|
||||
P_Out : out std_logic_vector(7 downto 0);
|
||||
Q : out std_logic_vector(7 downto 0)
|
||||
);
|
||||
end component;
|
||||
|
||||
end;
|
||||
@@ -1,23 +1,23 @@
|
||||
//
|
||||
// user_io.v - interface to MIST arm io controller
|
||||
// user_io.v
|
||||
//
|
||||
// user_io for the MiST board
|
||||
// http://code.google.com/p/mist-board/
|
||||
//
|
||||
// Copyright (c) 2014 Till Harbaum <till@harbaum.org>
|
||||
//
|
||||
// This source file is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Sinclair QL for the MiST
|
||||
// https://github.com/mist-devel
|
||||
//
|
||||
// Copyright (c) 2015 Till Harbaum <till@harbaum.org>
|
||||
//
|
||||
// This source file is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This source file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// parameter STRLEN and the actual length of conf_str have to match
|
||||
@@ -25,59 +25,62 @@
|
||||
module user_io #(parameter STRLEN=0) (
|
||||
input [(8*STRLEN)-1:0] conf_str,
|
||||
|
||||
input SPI_CLK,
|
||||
input SPI_SS_IO,
|
||||
output reg SPI_MISO,
|
||||
input SPI_MOSI,
|
||||
input clk_sys,
|
||||
input SPI_CLK,
|
||||
input SPI_SS_IO,
|
||||
output reg SPI_MISO,
|
||||
input SPI_MOSI,
|
||||
|
||||
output reg [7:0] joystick_0,
|
||||
output reg [7:0] joystick_1,
|
||||
output reg [15:0] joystick_analog_0,
|
||||
output reg [15:0] joystick_analog_1,
|
||||
output [1:0] buttons,
|
||||
output [1:0] switches,
|
||||
output scandoubler_disable,
|
||||
|
||||
output reg [7:0] status,
|
||||
output reg [7:0] joystick_0,
|
||||
output reg [7:0] joystick_1,
|
||||
output reg [15:0] joystick_analog_0,
|
||||
output reg [15:0] joystick_analog_1,
|
||||
output [1:0] buttons,
|
||||
output [1:0] switches,
|
||||
output scandoubler_disable,
|
||||
|
||||
output reg [7:0] status,
|
||||
|
||||
// connection to sd card emulation
|
||||
input [31:0] sd_lba,
|
||||
input sd_rd,
|
||||
input sd_wr,
|
||||
output reg sd_ack,
|
||||
input sd_conf,
|
||||
input sd_sdhc,
|
||||
output [7:0] sd_dout, // valid on rising edge of sd_dout_strobe
|
||||
output reg sd_dout_strobe,
|
||||
input [7:0] sd_din,
|
||||
output reg sd_din_strobe,
|
||||
output reg sd_change,
|
||||
input [31:0] sd_lba,
|
||||
input sd_rd,
|
||||
input sd_wr,
|
||||
output reg sd_ack,
|
||||
output reg sd_ack_conf,
|
||||
input sd_conf,
|
||||
input sd_sdhc,
|
||||
output reg [7:0] sd_dout, // valid on rising edge of sd_dout_strobe
|
||||
output reg sd_dout_strobe,
|
||||
input [7:0] sd_din,
|
||||
output reg sd_din_strobe,
|
||||
output reg [8:0] sd_buff_addr,
|
||||
|
||||
output reg img_mounted, //rising edge if a new image is mounted
|
||||
|
||||
// ps2 keyboard emulation
|
||||
input ps2_clk, // 12-16khz provided by core
|
||||
output ps2_kbd_clk,
|
||||
output reg ps2_kbd_data,
|
||||
output ps2_mouse_clk,
|
||||
output reg ps2_mouse_data,
|
||||
input ps2_clk, // 12-16khz provided by core
|
||||
output ps2_kbd_clk,
|
||||
output reg ps2_kbd_data,
|
||||
output ps2_mouse_clk,
|
||||
output reg ps2_mouse_data,
|
||||
|
||||
// serial com port
|
||||
input [7:0] serial_data,
|
||||
input serial_strobe
|
||||
input [7:0] serial_data,
|
||||
input serial_strobe
|
||||
);
|
||||
|
||||
reg [6:0] sbuf;
|
||||
reg [7:0] cmd;
|
||||
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
|
||||
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
|
||||
reg [7:0] byte_cnt; // counts bytes
|
||||
reg [5:0] joystick0;
|
||||
reg [5:0] joystick1;
|
||||
reg [7:0] but_sw;
|
||||
reg [4:0] but_sw;
|
||||
reg [2:0] stick_idx;
|
||||
|
||||
assign buttons = but_sw[1:0];
|
||||
assign switches = but_sw[3:2];
|
||||
assign scandoubler_disable = but_sw[4];
|
||||
assign sd_dout = { sbuf, SPI_MOSI};
|
||||
|
||||
// this variant of user_io is for 8 bit cores (type == a4) only
|
||||
wire [7:0] core_type = 8'ha4;
|
||||
@@ -86,56 +89,9 @@ wire [7:0] core_type = 8'ha4;
|
||||
wire [7:0] sd_cmd = { 4'h5, sd_conf, sd_sdhc, sd_wr, sd_rd };
|
||||
|
||||
// filter spi clock. the 8 bit gate delay is ~2.5ns in total
|
||||
wire [7:0] spi_sck_D = { spi_sck_D[6:0], SPI_CLK } /* synthesis keep */;
|
||||
wire spi_sck = (spi_sck && spi_sck_D != 8'h00) || (!spi_sck && spi_sck_D == 8'hff);
|
||||
|
||||
// drive MISO only when transmitting core id
|
||||
always@(negedge spi_sck or posedge SPI_SS_IO) begin
|
||||
if(SPI_SS_IO == 1) begin
|
||||
SPI_MISO <= 1'bZ;
|
||||
end else begin
|
||||
|
||||
// first byte returned is always core type, further bytes are
|
||||
// command dependent
|
||||
if(byte_cnt == 0) begin
|
||||
SPI_MISO <= core_type[~bit_cnt];
|
||||
|
||||
end else begin
|
||||
// reading serial fifo
|
||||
if(cmd == 8'h1b) begin
|
||||
// send alternating flag byte and data
|
||||
if(byte_cnt[0]) SPI_MISO <= serial_out_status[~bit_cnt];
|
||||
else SPI_MISO <= serial_out_byte[~bit_cnt];
|
||||
end
|
||||
|
||||
// reading config string
|
||||
else if(cmd == 8'h14) begin
|
||||
// returning a byte from string
|
||||
if(byte_cnt < STRLEN + 1)
|
||||
SPI_MISO <= conf_str[{STRLEN - byte_cnt,~bit_cnt}];
|
||||
else
|
||||
SPI_MISO <= 1'b0;
|
||||
end
|
||||
|
||||
// reading sd card status
|
||||
else if(cmd == 8'h16) begin
|
||||
if(byte_cnt == 1)
|
||||
SPI_MISO <= sd_cmd[~bit_cnt];
|
||||
else if((byte_cnt >= 2) && (byte_cnt < 6))
|
||||
SPI_MISO <= sd_lba[{5-byte_cnt, ~bit_cnt}];
|
||||
else
|
||||
SPI_MISO <= 1'b0;
|
||||
end
|
||||
|
||||
// reading sd card write data
|
||||
else if(cmd == 8'h18)
|
||||
SPI_MISO <= sd_din[~bit_cnt];
|
||||
|
||||
else
|
||||
SPI_MISO <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
//wire [7:0] spi_sck_D = { spi_sck_D[6:0], SPI_CLK } /* synthesis keep */;
|
||||
//wire spi_sck = (spi_sck && spi_sck_D != 8'h00) || (!spi_sck && spi_sck_D == 8'hff);
|
||||
wire spi_sck = SPI_CLK;
|
||||
|
||||
// ---------------- PS2 ---------------------
|
||||
|
||||
@@ -307,112 +263,206 @@ always@(negedge spi_sck or posedge status[0]) begin
|
||||
end
|
||||
end
|
||||
|
||||
// SPI receiver
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin
|
||||
|
||||
// SPI bit and byte counters
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin
|
||||
if(SPI_SS_IO == 1) begin
|
||||
bit_cnt <= 3'd0;
|
||||
byte_cnt <= 8'd0;
|
||||
sd_ack <= 1'b0;
|
||||
sd_dout_strobe <= 1'b0;
|
||||
sd_din_strobe <= 1'b0;
|
||||
sd_change <= 1'b0;
|
||||
bit_cnt <= 0;
|
||||
byte_cnt <= 0;
|
||||
end else begin
|
||||
sd_dout_strobe <= 1'b0;
|
||||
sd_din_strobe <= 1'b0;
|
||||
|
||||
if(bit_cnt != 7)
|
||||
sbuf[6:0] <= { sbuf[5:0], SPI_MOSI };
|
||||
|
||||
bit_cnt <= bit_cnt + 3'd1;
|
||||
if((bit_cnt == 7)&&(byte_cnt != 8'd255))
|
||||
byte_cnt <= byte_cnt + 8'd1;
|
||||
|
||||
// finished reading command byte
|
||||
if(bit_cnt == 7) begin
|
||||
if(byte_cnt == 0) begin
|
||||
cmd <= { sbuf, SPI_MOSI};
|
||||
|
||||
// fetch first byte when sectore FPGA->IO command has been seen
|
||||
if({ sbuf, SPI_MOSI} == 8'h18)
|
||||
sd_din_strobe <= 1'b1;
|
||||
|
||||
if(({ sbuf, SPI_MOSI} == 8'h17) || ({ sbuf, SPI_MOSI} == 8'h18))
|
||||
sd_ack <= 1'b1;
|
||||
|
||||
end else begin
|
||||
|
||||
// buttons and switches
|
||||
if(cmd == 8'h01)
|
||||
but_sw <= { sbuf, SPI_MOSI };
|
||||
bit_cnt <= bit_cnt + 1'd1;
|
||||
end
|
||||
end
|
||||
|
||||
if(cmd == 8'h02)
|
||||
joystick_0 <= { sbuf, SPI_MOSI };
|
||||
|
||||
if(cmd == 8'h03)
|
||||
joystick_1 <= { sbuf, SPI_MOSI };
|
||||
|
||||
if(cmd == 8'h04) begin
|
||||
// store incoming ps2 mouse bytes
|
||||
ps2_mouse_fifo[ps2_mouse_wptr] <= { sbuf, SPI_MOSI };
|
||||
ps2_mouse_wptr <= ps2_mouse_wptr + 1;
|
||||
end
|
||||
// SPI transmitter FPGA -> IO
|
||||
reg [7:0] spi_byte_out;
|
||||
|
||||
if(cmd == 8'h05) begin
|
||||
// store incoming ps2 keyboard bytes
|
||||
ps2_kbd_fifo[ps2_kbd_wptr] <= { sbuf, SPI_MOSI };
|
||||
ps2_kbd_wptr <= ps2_kbd_wptr + 1;
|
||||
end
|
||||
|
||||
if(cmd == 8'h15)
|
||||
status <= { sbuf[6:0], SPI_MOSI };
|
||||
|
||||
// send sector IO -> FPGA
|
||||
if(cmd == 8'h17) begin
|
||||
// flag that download begins
|
||||
sd_dout_strobe <= 1'b1;
|
||||
end
|
||||
|
||||
// send sector FPGA -> IO
|
||||
if(cmd == 8'h18)
|
||||
sd_din_strobe <= 1'b1;
|
||||
|
||||
// send SD config IO -> FPGA
|
||||
if(cmd == 8'h19) begin
|
||||
// flag that download begins
|
||||
// sd card knows data is config if sd_dout_strobe is asserted
|
||||
// with sd_ack still being inactive (low)
|
||||
sd_dout_strobe <= 1'b1;
|
||||
end
|
||||
|
||||
// joystick analog
|
||||
if(cmd == 8'h1a) begin
|
||||
// first byte is joystick indes
|
||||
if(byte_cnt == 1)
|
||||
stick_idx <= { sbuf[1:0], SPI_MOSI };
|
||||
else if(byte_cnt == 2) begin
|
||||
// second byte is x axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[15:8] <= { sbuf, SPI_MOSI };
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[15:8] <= { sbuf, SPI_MOSI };
|
||||
end else if(byte_cnt == 3) begin
|
||||
// third byte is y axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[7:0] <= { sbuf, SPI_MOSI };
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[7:0] <= { sbuf, SPI_MOSI };
|
||||
end
|
||||
end
|
||||
|
||||
// set sd card status. The fact that this register is being
|
||||
// set by the arm controller indicates a possible disk change
|
||||
if(cmd == 8'h1c)
|
||||
sd_change <= 1'b1;
|
||||
always@(negedge spi_sck or posedge SPI_SS_IO) begin
|
||||
if(SPI_SS_IO == 1) begin
|
||||
SPI_MISO <= 1'bZ;
|
||||
end else begin
|
||||
SPI_MISO <= spi_byte_out[~bit_cnt];
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin
|
||||
reg [31:0] sd_lba_r;
|
||||
|
||||
if(SPI_SS_IO == 1) begin
|
||||
spi_byte_out <= core_type;
|
||||
end else begin
|
||||
// read the command byte to choose the response
|
||||
if(bit_cnt == 7) begin
|
||||
if(!byte_cnt) cmd <= {sbuf, SPI_MOSI};
|
||||
|
||||
spi_byte_out <= 0;
|
||||
case({(!byte_cnt) ? {sbuf, SPI_MOSI} : cmd})
|
||||
// reading config string
|
||||
8'h14: if(byte_cnt < STRLEN) spi_byte_out <= conf_str[(STRLEN - byte_cnt - 1)<<3 +:8];
|
||||
|
||||
// reading sd card status
|
||||
8'h16: if(byte_cnt == 0) begin
|
||||
spi_byte_out <= sd_cmd;
|
||||
sd_lba_r <= sd_lba;
|
||||
end
|
||||
else if(byte_cnt < 5) spi_byte_out <= sd_lba_r[(4-byte_cnt)<<3 +:8];
|
||||
|
||||
// reading sd card write data
|
||||
8'h18: spi_byte_out <= sd_din;
|
||||
8'h1b:
|
||||
// send alternating flag byte and data
|
||||
if(byte_cnt[0]) spi_byte_out <= serial_out_status;
|
||||
else spi_byte_out <= serial_out_byte;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// SPI receiver IO -> FPGA
|
||||
|
||||
reg spi_receiver_strobe_r;
|
||||
reg spi_transfer_end_r;
|
||||
reg [7:0] spi_byte_in_r;
|
||||
|
||||
// Read at spi_sck clock domain, assemble bytes for transferring to clk_sys
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin
|
||||
|
||||
if(SPI_SS_IO == 1) begin
|
||||
spi_receiver_strobe_r <= 0;
|
||||
spi_transfer_end_r <= 1;
|
||||
end else begin
|
||||
spi_receiver_strobe_r <= 0;
|
||||
spi_transfer_end_r <= 0;
|
||||
|
||||
if(bit_cnt != 7)
|
||||
sbuf[6:0] <= { sbuf[5:0], SPI_MOSI };
|
||||
|
||||
// finished reading a byte, prepare to transfer to clk_sys
|
||||
if(bit_cnt == 7) begin
|
||||
spi_byte_in_r <= { sbuf, SPI_MOSI};
|
||||
spi_receiver_strobe_r <= 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Process bytes from SPI at the clk_sys domain
|
||||
always @(posedge clk_sys) begin
|
||||
|
||||
reg spi_receiver_strobe;
|
||||
reg spi_transfer_end;
|
||||
reg [7:0] spi_byte_in;
|
||||
reg spi_receiver_strobeD;
|
||||
reg spi_transfer_endD;
|
||||
reg [7:0] spi_byte_inD;
|
||||
reg [7:0] acmd;
|
||||
reg [7:0] abyte_cnt; // counts bytes
|
||||
|
||||
//synchronize between SPI and sys clock domains
|
||||
spi_receiver_strobeD <= spi_receiver_strobe_r;
|
||||
spi_receiver_strobe <= spi_receiver_strobeD;
|
||||
spi_transfer_endD <= spi_transfer_end_r;
|
||||
spi_transfer_end <= spi_transfer_endD;
|
||||
spi_byte_inD <= spi_byte_in_r;
|
||||
spi_byte_in <= spi_byte_inD;
|
||||
|
||||
if(sd_dout_strobe) begin
|
||||
sd_dout_strobe<= 0;
|
||||
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
|
||||
end
|
||||
|
||||
if(sd_din_strobe) begin
|
||||
sd_din_strobe<= 0;
|
||||
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
|
||||
end
|
||||
|
||||
img_mounted <= 0;
|
||||
|
||||
if (~spi_transfer_endD & spi_transfer_end) begin
|
||||
abyte_cnt <= 8'd0;
|
||||
sd_ack <= 1'b0;
|
||||
sd_ack_conf <= 1'b0;
|
||||
sd_dout_strobe <= 1'b0;
|
||||
sd_din_strobe <= 1'b0;
|
||||
sd_buff_addr<= 0;
|
||||
end else if (~spi_receiver_strobeD & spi_receiver_strobe) begin
|
||||
|
||||
if(abyte_cnt != 8'd255)
|
||||
abyte_cnt <= byte_cnt + 8'd1;
|
||||
|
||||
if(abyte_cnt == 0) begin
|
||||
acmd <= spi_byte_in;
|
||||
|
||||
// fetch first byte when sectore FPGA->IO command has been seen
|
||||
if(spi_byte_in == 8'h18)
|
||||
sd_din_strobe <= 1'b1;
|
||||
|
||||
if((spi_byte_in == 8'h17) || (spi_byte_in == 8'h18))
|
||||
sd_ack <= 1'b1;
|
||||
|
||||
end else begin
|
||||
case(acmd)
|
||||
// buttons and switches
|
||||
8'h01: but_sw <= spi_byte_in;
|
||||
8'h02: joystick_0 <= spi_byte_in;
|
||||
8'h03: joystick_1 <= spi_byte_in;
|
||||
8'h04: begin
|
||||
// store incoming ps2 mouse bytes
|
||||
ps2_mouse_fifo[ps2_mouse_wptr] <= spi_byte_in;
|
||||
ps2_mouse_wptr <= ps2_mouse_wptr + 1;
|
||||
end
|
||||
8'h05: begin
|
||||
// store incoming ps2 keyboard bytes
|
||||
ps2_kbd_fifo[ps2_kbd_wptr] <= spi_byte_in;
|
||||
ps2_kbd_wptr <= ps2_kbd_wptr + 1;
|
||||
end
|
||||
|
||||
8'h15: status <= spi_byte_in;
|
||||
|
||||
// send sector IO -> FPGA
|
||||
8'h17: begin
|
||||
// flag that download begins
|
||||
sd_dout_strobe <= 1'b1;
|
||||
sd_dout <= spi_byte_in;
|
||||
end
|
||||
|
||||
// send sector FPGA -> IO
|
||||
8'h18: sd_din_strobe <= 1'b1;
|
||||
|
||||
// send SD config IO -> FPGA
|
||||
8'h19: begin
|
||||
// flag that download begins
|
||||
sd_dout_strobe <= 1'b1;
|
||||
sd_ack_conf <= 1'b1;
|
||||
sd_dout <= spi_byte_in;
|
||||
end
|
||||
|
||||
// joystick analog
|
||||
8'h1a: begin
|
||||
// first byte is joystick indes
|
||||
if(abyte_cnt == 1)
|
||||
stick_idx <= spi_byte_in[2:0];
|
||||
else if(abyte_cnt == 2) begin
|
||||
// second byte is x axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[15:8] <= spi_byte_in;
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[15:8] <= spi_byte_in;
|
||||
end else if(abyte_cnt == 3) begin
|
||||
// third byte is y axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[7:0] <= spi_byte_in;
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[7:0] <= spi_byte_in;
|
||||
end
|
||||
end
|
||||
|
||||
8'h1c: img_mounted <= 1;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user