mirror of https://github.com/zxdos/zxuno.git
Test dos
This commit is contained in:
parent
8d140e4c75
commit
3f23152a34
|
@ -19,3 +19,7 @@ vhdl work "../source/led_multiplex.vhd"
|
|||
vhdl work "../source/led_output.vhd"
|
||||
vhdl work "../source/onebitadc.vhd"
|
||||
vhdl work "../source/clkdiv.vhd"
|
||||
vhdl work "../source/controller_8dos.vhd"
|
||||
vhdl work "../source/dos8rom.vhd"
|
||||
#vhdl work "../source/spi_controller.vhd"
|
||||
#vhdl work "../source/disk_ii.vhd"
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity controller_8dos is
|
||||
port (
|
||||
CLK_24 : in std_logic;
|
||||
PHI_2 : in std_logic;
|
||||
RW : in std_logic;
|
||||
IO_SELECTn : in std_logic; -- 0x300 - 0x3ff
|
||||
IO_CONTROLn : out std_logic;
|
||||
RESETn : in std_logic;
|
||||
O_ROMDISn : out std_logic;
|
||||
O_MAPn : out std_logic;
|
||||
A : in std_logic_vector(15 downto 0);
|
||||
D_IN : in std_logic_vector(7 downto 0); -- From 6502
|
||||
D_OUT : out std_logic_vector(7 downto 0) -- To 6502
|
||||
);
|
||||
end controller_8dos;
|
||||
|
||||
architecture imp of controller_8dos is
|
||||
signal s_map :std_logic;
|
||||
signal s_romdis: std_logic;
|
||||
signal s_extension: std_logic;
|
||||
signal rom_out: std_logic_vector(7 downto 0);
|
||||
signal IO_CONTROLn_int : std_logic;
|
||||
begin
|
||||
|
||||
|
||||
--IO_CONTROL_SIGNAL
|
||||
IO_CONTROLn_int <= '0'
|
||||
when (A(15 downto 8) = x"03")
|
||||
and (A(7 downto 4) /= x"3")
|
||||
and (IO_SELECTn = '0')
|
||||
else '1';
|
||||
IO_CONTROLn <= IO_CONTROLn_int;
|
||||
s_romdis <= '1';
|
||||
O_ROMDISn <= s_romdis;
|
||||
|
||||
mappr: process (PHI_2,RESETn)
|
||||
begin
|
||||
if (RESETn = '0') then
|
||||
s_map <= '1';
|
||||
else
|
||||
if (falling_edge(PHI_2)) then
|
||||
if (IO_CONTROLn_int = '0') and (RW = '0') and (A(7 downto 4) = x"8") then
|
||||
s_map <= not A(0);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
O_MAPn <= s_map;
|
||||
|
||||
extension:process (PHI_2, RESETn)
|
||||
begin
|
||||
if (RESETn = '0') then
|
||||
s_extension <= '0';
|
||||
else
|
||||
if (falling_edge(PHI_2)) then
|
||||
if (IO_CONTROLn_int = '0') and (RW = '0') and (A(7 downto 4) = x"8") then
|
||||
s_extension <= A(1);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- 8dos rom
|
||||
|
||||
rom8dos: entity work.dos8rom
|
||||
port map (
|
||||
addr(8) => s_extension,
|
||||
addr(7 downto 0) => A(7 downto 0),
|
||||
clk=>PHI_2,
|
||||
dout => rom_out
|
||||
);
|
||||
|
||||
D_OUT <= rom_out;
|
||||
|
||||
-- disk : entity work.disk_ii port map (
|
||||
-- CLK_14M => CLK_14M,
|
||||
-- CLK_2M => CLK_2M,
|
||||
-- PRE_PHASE_ZERO => PRE_PHASE_ZERO,
|
||||
-- IO_SELECT => IO_SELECT(6),
|
||||
-- DEVICE_SELECT => DEVICE_SELECT(6),
|
||||
-- RESET => reset,
|
||||
-- A => ADDR,
|
||||
-- D_IN => D,
|
||||
-- D_OUT => PD,
|
||||
-- TRACK => TRACK,
|
||||
-- TRACK_ADDR => TRACK_ADDR,
|
||||
-- D1_ACTIVE => D1_ACTIVE,
|
||||
-- D2_ACTIVE => D2_ACTIVE,
|
||||
-- ram_write_addr => TRACK_RAM_ADDR,
|
||||
-- ram_di => TRACK_RAM_DI,
|
||||
-- ram_we => TRACK_RAM_WE
|
||||
-- );
|
||||
|
||||
-- sdcard_interface : entity work.spi_controller port map (
|
||||
-- CLK_14M => CLK_14M,
|
||||
-- RESET => RESET,
|
||||
|
||||
-- CS_N => CS_N,
|
||||
-- MOSI => MOSI,
|
||||
-- MISO => MISO,
|
||||
-- SCLK => SCLK,
|
||||
|
||||
-- track => TRACK,
|
||||
-- image => image,
|
||||
|
||||
-- ram_write_addr => TRACK_RAM_ADDR,
|
||||
-- ram_di => TRACK_RAM_DI,
|
||||
-- ram_we => TRACK_RAM_WE
|
||||
-- );
|
||||
|
||||
-- SD_DAT3 <= CS_N;
|
||||
-- SD_CMD <= MOSI;
|
||||
-- MISO <= SD_DAT;
|
||||
-- SD_CLK <= SCLK;
|
||||
|
||||
end imp;
|
|
@ -0,0 +1,288 @@
|
|||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Disk II emulator
|
||||
--
|
||||
-- This is read-only and only feeds "pre-nibblized" data to the processor
|
||||
-- It has a single-track buffer and only supports one drive (1).
|
||||
--
|
||||
-- Stephen A. Edwards, sedwards@cs.columbia.edu
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Each track is represented as 0x1A00 bytes
|
||||
-- Each disk image consists of 35 * 0x1A00 bytes = 0x38A00 (227.5 K)
|
||||
--
|
||||
-- X = $60 for slot 6
|
||||
--
|
||||
-- Off On
|
||||
-- C080,X C081,X Phase 0 Head Stepper Motor Control
|
||||
-- C082,X C083,X Phase 1
|
||||
-- C084,X C085,X Phase 2
|
||||
-- C086,X C087,X Phase 3
|
||||
-- C088,X C089,X Motor On
|
||||
-- C08A,X C08B,X Select Drive 2 (select drive 1 when off)
|
||||
-- C08C,X C08D,X Q6 (Shift/load?)
|
||||
-- C08E,X C08F,X Q7 (Write request to drive)
|
||||
--
|
||||
--
|
||||
-- Q7 Q6
|
||||
-- 0 0 Read
|
||||
-- 0 1 Sense write protect
|
||||
-- 1 0 Write
|
||||
-- 1 1 Load Write Latch
|
||||
--
|
||||
-- Reading a byte:
|
||||
-- LDA $C08E,X set read mode
|
||||
-- ...
|
||||
-- READ LDA $C08C,X
|
||||
-- BPL READ
|
||||
--
|
||||
-- Sense write protect:
|
||||
-- LDA $C08D,X
|
||||
-- LDA $C08E,X
|
||||
-- BMI PROTECTED
|
||||
--
|
||||
-- Writing
|
||||
-- STA $C08F,X set write mode
|
||||
-- ..
|
||||
-- LDA DATA
|
||||
-- STA $C08D,X load byte to write
|
||||
-- STA $C08C,X write byte to disk
|
||||
--
|
||||
-- Data bytes must be written in 32 cycle loops.
|
||||
--
|
||||
-- There are 70 phases for the head stepper and and 35 tracks,
|
||||
-- i.e., two phase changes per track.
|
||||
--
|
||||
-- The disk spins at 300 rpm; one new bit arrives every 4 us
|
||||
-- The processor's clock is 1 MHz = 1 us, so it takes 8 * 4 = 32 cycles
|
||||
-- for a new byte to arrive
|
||||
--
|
||||
-- This corresponds to dividing the 2 MHz signal by 64 to get the byte clock
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity disk_ii is
|
||||
port (
|
||||
CLK_14M : in std_logic;
|
||||
CLK_2M : in std_logic;
|
||||
PRE_PHASE_ZERO : in std_logic;
|
||||
IO_SELECT : in std_logic; -- e.g., C600 - C6FF ROM
|
||||
DEVICE_SELECT : in std_logic; -- e.g., C0E0 - C0EF I/O locations
|
||||
RESET : in std_logic;
|
||||
A : in unsigned(15 downto 0);
|
||||
D_IN : in unsigned(7 downto 0); -- From 6502
|
||||
D_OUT : out unsigned(7 downto 0); -- To 6502
|
||||
TRACK : out unsigned(5 downto 0); -- Current track (0-34)
|
||||
track_addr : out unsigned(13 downto 0);
|
||||
D1_ACTIVE : out std_logic; -- Disk 1 motor on
|
||||
D2_ACTIVE : out std_logic; -- Disk 2 motor on
|
||||
ram_write_addr : in unsigned(13 downto 0); -- Address for track RAM
|
||||
ram_di : in unsigned(7 downto 0); -- Data to track RAM
|
||||
ram_we : in std_logic -- RAM write enable
|
||||
);
|
||||
end disk_ii;
|
||||
|
||||
architecture rtl of disk_ii is
|
||||
|
||||
signal motor_phase : std_logic_vector(3 downto 0);
|
||||
signal drive_on : std_logic;
|
||||
signal drive2_select : std_logic;
|
||||
signal q6, q7 : std_logic;
|
||||
|
||||
signal rom_dout : unsigned(7 downto 0);
|
||||
|
||||
-- Current phase of the head. This is in half-steps to assign
|
||||
-- a unique position to the case, say, when both phase 0 and phase 1 are
|
||||
-- on simultaneously. phase(7 downto 2) is the track number
|
||||
signal phase : unsigned(7 downto 0); -- 0 - 139
|
||||
|
||||
-- Storage for one track worth of data in "nibblized" form
|
||||
type track_ram is array(0 to 6655) of unsigned(7 downto 0);
|
||||
-- Double-ported RAM for holding a track
|
||||
signal track_memory : track_ram;
|
||||
signal ram_do : unsigned(7 downto 0);
|
||||
|
||||
-- Lower bit indicates whether disk data is "valid" or not
|
||||
-- RAM address is track_byte_addr(14 downto 1)
|
||||
-- This makes it look to the software like new data is constantly
|
||||
-- being read into the shift register, which indicates the data is
|
||||
-- not yet ready.
|
||||
signal track_byte_addr : unsigned(14 downto 0);
|
||||
signal read_disk : std_logic; -- When C08C accessed
|
||||
|
||||
begin
|
||||
|
||||
interpret_io : process (CLK_2M)
|
||||
begin
|
||||
if rising_edge(CLK_2M) then
|
||||
if reset = '1' then
|
||||
motor_phase <= (others => '0');
|
||||
drive_on <= '0';
|
||||
drive2_select <= '0';
|
||||
q6 <= '0';
|
||||
q7 <= '0';
|
||||
else
|
||||
if PRE_PHASE_ZERO = '1' and DEVICE_SELECT = '1' then
|
||||
if A(3) = '0' then -- C080 - C087
|
||||
motor_phase(TO_INTEGER(A(2 downto 1))) <= A(0);
|
||||
else
|
||||
case A(2 downto 1) is
|
||||
when "00" => drive_on <= A(0); -- C088 - C089
|
||||
when "01" => drive2_select <= A(0); -- C08A - C08B
|
||||
when "10" => q6 <= A(0); -- C08C - C08D
|
||||
when "11" => q7 <= A(0); -- C08E - C08F
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
D1_ACTIVE <= drive_on and not drive2_select;
|
||||
D2_ACTIVE <= drive_on and drive2_select;
|
||||
|
||||
-- There are two cases:
|
||||
--
|
||||
-- Current phase is odd (between two poles)
|
||||
-- |
|
||||
-- V
|
||||
-- -3-2-1 0 1 2 3
|
||||
-- X X X X
|
||||
-- 0 1 2 3
|
||||
--
|
||||
--
|
||||
-- Current phase is even (under a pole)
|
||||
-- |
|
||||
-- V
|
||||
-- -4-3-2-1 0 1 2 3 4
|
||||
-- X X X X X
|
||||
-- 0 1 2 3 0
|
||||
--
|
||||
|
||||
update_phase : process (CLK_14M)
|
||||
variable phase_change : integer;
|
||||
variable new_phase : integer;
|
||||
variable rel_phase : std_logic_vector(3 downto 0);
|
||||
begin
|
||||
if rising_edge(CLK_14M) then
|
||||
if reset = '1' then
|
||||
phase <= TO_UNSIGNED(70, 8); -- Deliberately odd to test reset
|
||||
else
|
||||
phase_change := 0;
|
||||
new_phase := TO_INTEGER(phase);
|
||||
rel_phase := motor_phase;
|
||||
case phase(2 downto 1) is
|
||||
when "00" =>
|
||||
rel_phase := rel_phase(1 downto 0) & rel_phase(3 downto 2);
|
||||
when "01" =>
|
||||
rel_phase := rel_phase(2 downto 0) & rel_phase(3);
|
||||
when "10" => null;
|
||||
when "11" =>
|
||||
rel_phase := rel_phase(0) & rel_phase(3 downto 1);
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
if phase(0) = '1' then -- Phase is odd
|
||||
case rel_phase is
|
||||
when "0000" => phase_change := 0;
|
||||
when "0001" => phase_change := -3;
|
||||
when "0010" => phase_change := -1;
|
||||
when "0011" => phase_change := -2;
|
||||
when "0100" => phase_change := 1;
|
||||
when "0101" => phase_change := -1;
|
||||
when "0110" => phase_change := 0;
|
||||
when "0111" => phase_change := -1;
|
||||
when "1000" => phase_change := 3;
|
||||
when "1001" => phase_change := 0;
|
||||
when "1010" => phase_change := 1;
|
||||
when "1011" => phase_change := -3;
|
||||
when "1111" => phase_change := 0;
|
||||
when others => null;
|
||||
end case;
|
||||
else -- Phase is even
|
||||
case rel_phase is
|
||||
when "0000" => phase_change := 0;
|
||||
when "0001" => phase_change := -2;
|
||||
when "0010" => phase_change := 0;
|
||||
when "0011" => phase_change := -1;
|
||||
when "0100" => phase_change := 2;
|
||||
when "0101" => phase_change := 0;
|
||||
when "0110" => phase_change := 1;
|
||||
when "0111" => phase_change := 0;
|
||||
when "1000" => phase_change := 0;
|
||||
when "1001" => phase_change := 1;
|
||||
when "1010" => phase_change := 2;
|
||||
when "1011" => phase_change := -2;
|
||||
when "1111" => phase_change := 0;
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
|
||||
if new_phase + phase_change <= 0 then
|
||||
new_phase := 0;
|
||||
elsif new_phase + phase_change > 139 then
|
||||
new_phase := 139;
|
||||
else
|
||||
new_phase := new_phase + phase_change;
|
||||
end if;
|
||||
phase <= TO_UNSIGNED(new_phase, 8);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
TRACK <= phase(7 downto 2);
|
||||
|
||||
-- Dual-ported RAM holding the contents of the track
|
||||
track_storage : process (CLK_14M)
|
||||
begin
|
||||
if rising_edge(CLK_14M) then
|
||||
if ram_we = '1' then
|
||||
track_memory(to_integer(ram_write_addr)) <= ram_di;
|
||||
end if;
|
||||
ram_do <= track_memory(to_integer(track_byte_addr(14 downto 1)));
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Go to the next byte when the disk is accessed or if the counter times out
|
||||
read_head : process (CLK_2M)
|
||||
variable byte_delay : unsigned(5 downto 0); -- Accounts for disk spin rate
|
||||
begin
|
||||
if rising_edge(CLK_2M) then
|
||||
if reset = '1' then
|
||||
track_byte_addr <= (others => '0');
|
||||
byte_delay := (others => '0');
|
||||
else
|
||||
byte_delay := byte_delay - 1;
|
||||
if (read_disk = '1' and PRE_PHASE_ZERO = '1') or byte_delay = 0 then
|
||||
byte_delay := (others => '0');
|
||||
if track_byte_addr = X"33FE" then
|
||||
track_byte_addr <= (others => '0');
|
||||
else
|
||||
track_byte_addr <= track_byte_addr + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
rom : entity work.disk_ii_rom port map (
|
||||
addr => A(7 downto 0),
|
||||
clk => CLK_14M,
|
||||
dout => rom_dout);
|
||||
|
||||
read_disk <= '1' when DEVICE_SELECT = '1' and A(3 downto 0) = x"C" else
|
||||
'0'; -- C08C
|
||||
|
||||
D_OUT <= rom_dout when IO_SELECT = '1' else
|
||||
ram_do when read_disk = '1' and track_byte_addr(0) = '0' else
|
||||
(others => '0');
|
||||
|
||||
track_addr <= track_byte_addr(14 downto 1);
|
||||
|
||||
end rtl;
|
|
@ -0,0 +1,16 @@
|
|||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.std_logic_arith.all;
|
||||
use ieee.std_logic_unsigned.all;
|
||||
|
||||
library unisim;
|
||||
use unisim.vcomponents.all;
|
||||
|
||||
entity dos8 is
|
||||
port (
|
||||
CLK: in std_logic;
|
||||
|
||||
PHI_2: in std_logic;
|
||||
D_IN: in std_logic_vector(7 downto 0);
|
||||
D_OUT: out std_logic_vector(7 downto 0;
|
||||
IRQ
|
|
@ -0,0 +1,90 @@
|
|||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity dos8rom is
|
||||
port (
|
||||
addr : in std_logic_vector(8 downto 0);
|
||||
clk : in std_logic;
|
||||
dout : out std_logic_vector(7 downto 0));
|
||||
end dos8rom;
|
||||
|
||||
architecture rtl of dos8rom is
|
||||
type rom_array is array(0 to 511) of unsigned(7 downto 0);
|
||||
|
||||
constant ROM : rom_array := (
|
||||
X"30", X"33", X"30", X"30", X"2e", X"2e", X"30", X"33",
|
||||
X"30", X"46", X"20", X"2d", X"20", X"56", X"49", X"41",
|
||||
X"30", X"33", X"31", X"30", X"2e", X"2e", X"30", X"33",
|
||||
X"31", X"46", X"20", X"2d", X"20", X"46", X"44", X"43",
|
||||
X"78", X"a2", X"05", X"bd", X"2f", X"03", X"9d", X"ea",
|
||||
X"02", X"ca", X"10", X"f7", X"4c", X"ea", X"02", X"8d",
|
||||
X"82", X"03", X"4c", X"20", X"03", X"42", X"4f", X"42",
|
||||
X"59", X"ff", X"ff", X"8d", X"81", X"03", X"20", X"03",
|
||||
X"d4", X"8d", X"80", X"03", X"60", X"8d", X"81", X"03",
|
||||
X"20", X"06", X"d4", X"8d", X"80", X"03", X"60", X"8d",
|
||||
X"80", X"03", X"20", X"5f", X"c5", X"8d", X"81", X"03",
|
||||
X"60", X"8d", X"80", X"03", X"20", X"c5", X"e0", X"8d",
|
||||
X"81", X"03", X"60", X"8d", X"80", X"03", X"4c", X"bd",
|
||||
X"c4", X"78", X"8d", X"81", X"03", X"20", X"00", X"d4",
|
||||
X"8d", X"80", X"03", X"58", X"4c", X"03", X"c0", X"78",
|
||||
X"8d", X"81", X"03", X"4c", X"00", X"c0", X"8d", X"80",
|
||||
X"03", X"20", X"92", X"c5", X"8d", X"81", X"03", X"60",
|
||||
X"8d", X"80", X"03", X"20", X"fb", X"cc", X"8d", X"81",
|
||||
X"03", X"60", X"8d", X"80", X"03", X"20", X"a0", X"03",
|
||||
X"8d", X"81", X"03", X"40", X"20", X"a0", X"03", X"40",
|
||||
X"08", X"48", X"a9", X"03", X"48", X"a9", X"ac", X"48",
|
||||
X"08", X"4c", X"22", X"ee", X"68", X"28", X"60", X"ff",
|
||||
X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff",
|
||||
X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff",
|
||||
X"04", X"04", X"0f", X"ff", X"ff", X"ff", X"ff", X"ff",
|
||||
X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff",
|
||||
X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff",
|
||||
X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff",
|
||||
X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff",
|
||||
X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff",
|
||||
X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff",
|
||||
X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff", X"ff",
|
||||
X"30", X"33", X"30", X"30", X"2e", X"2e", X"30", X"33",
|
||||
X"30", X"46", X"20", X"2d", X"20", X"56", X"49", X"41",
|
||||
X"30", X"33", X"31", X"30", X"2e", X"2e", X"30", X"33",
|
||||
X"31", X"46", X"20", X"2d", X"20", X"46", X"44", X"43",
|
||||
X"78", X"d8", X"a0", X"00", X"a2", X"03", X"86", X"78",
|
||||
X"8a", X"0a", X"24", X"78", X"f0", X"10", X"05", X"78",
|
||||
X"49", X"ff", X"29", X"7e", X"b0", X"08", X"4a", X"d0",
|
||||
X"fb", X"98", X"9d", X"56", X"b4", X"c8", X"e8", X"10",
|
||||
X"e5", X"2c", X"1e", X"03", X"2c", X"1c", X"03", X"2c",
|
||||
X"1a", X"03", X"2c", X"19", X"03", X"a2", X"00", X"a0",
|
||||
X"48", X"dd", X"10", X"03", X"98", X"29", X"03", X"0a",
|
||||
X"aa", X"dd", X"11", X"03", X"a2", X"08", X"d6", X"76",
|
||||
X"d0", X"fc", X"ca", X"10", X"f9", X"aa", X"88", X"10",
|
||||
X"e8", X"a9", X"b8", X"85", X"77", X"18", X"08", X"ad",
|
||||
X"1c", X"03", X"10", X"fb", X"49", X"d5", X"d0", X"f7",
|
||||
X"ad", X"1c", X"03", X"10", X"fb", X"c9", X"aa", X"d0",
|
||||
X"f3", X"ea", X"ad", X"1c", X"03", X"10", X"fb", X"c9",
|
||||
X"96", X"f0", X"09", X"28", X"90", X"df", X"49", X"ad",
|
||||
X"f0", X"25", X"d0", X"d9", X"a0", X"03", X"85", X"7c",
|
||||
X"ad", X"1c", X"03", X"10", X"fb", X"2a", X"85", X"78",
|
||||
X"ad", X"1c", X"03", X"10", X"fb", X"25", X"78", X"88",
|
||||
X"d0", X"ec", X"28", X"c5", X"79", X"d0", X"be", X"a5",
|
||||
X"7c", X"c5", X"7d", X"d0", X"b8", X"b0", X"b7", X"a0",
|
||||
X"56", X"84", X"78", X"ac", X"1c", X"03", X"10", X"fb",
|
||||
X"59", X"d6", X"b3", X"a4", X"78", X"88", X"99", X"00",
|
||||
X"b4", X"d0", X"ee", X"84", X"78", X"ac", X"1c", X"03",
|
||||
X"10", X"fb", X"59", X"d6", X"b3", X"a4", X"78", X"91",
|
||||
X"76", X"c8", X"d0", X"ef", X"ac", X"1c", X"03", X"10",
|
||||
X"fb", X"59", X"d6", X"b3", X"d0", X"87", X"a0", X"00",
|
||||
X"a2", X"56", X"ca", X"30", X"fb", X"b1", X"76", X"5e",
|
||||
X"00", X"b4", X"2a", X"5e", X"00", X"b4", X"2a", X"91",
|
||||
X"76", X"c8", X"d0", X"ee", X"4c", X"00", X"b8", X"ff");
|
||||
|
||||
begin
|
||||
|
||||
process (clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
dout <= std_logic_vector(ROM(TO_INTEGER(unsigned(addr))));
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end rtl;
|
|
@ -20,7 +20,7 @@ NET O_VSYNC LOC="P97" | IOSTANDARD = LVCMOS25 | DRIVE = 6 | SLEW = SL
|
|||
# Audio
|
||||
NET "AUDIO_OUT" LOC="P94" | IOSTANDARD = LVCMOS25;
|
||||
NET "AUDIO_OUT2" LOC="P8" | IOSTANDARD = LVCMOS25;
|
||||
NET "K7_TAPEOUT" LOC="P115" | IOSTANDARD = LVCMOS25;
|
||||
#NET "K7_TAPEOUT" LOC="P140" | IOSTANDARD = LVCMOS25;
|
||||
NET "K7_TAPEIN" LOC="P116" | IOSTANDARD = LVCMOS25;
|
||||
|
||||
# Keyboard and mouse
|
||||
|
|
|
@ -62,8 +62,6 @@ entity ORIC is
|
|||
-- PRT_STR : out std_logic; -- strobe
|
||||
-- PRT_ACK : in std_logic; -- ack
|
||||
|
||||
-- MAPn : in std_logic;
|
||||
-- ROMDISn : in std_logic;
|
||||
-- IRQn : in std_logic;
|
||||
---
|
||||
-- CLK_EXT : out std_logic; -- 1 MHZ
|
||||
|
@ -74,6 +72,13 @@ entity ORIC is
|
|||
O_NTSC : out std_logic; --Q
|
||||
O_PAL : out std_logic; --Q
|
||||
|
||||
|
||||
--8dos controller
|
||||
SD_DAT : in std_logic; -- SD Card Data SD pin 7 "DAT 0/DataOut" //misoP117
|
||||
SD_DAT3 : out std_logic; -- SD Card Data 3 SD pin 1 "DAT 3/nCS" cs P121
|
||||
SD_CMD : out std_logic; -- SD Card Command SD pin 2 "CMD/DataIn"mosiP119
|
||||
SD_CLK : out std_logic; -- SD Card Clock SD pin 5 "CLK" //sckP115
|
||||
|
||||
-- Clk master
|
||||
CLK_50 : in std_logic; -- MASTER CLK
|
||||
segment : out std_logic_vector( 7 downto 0);
|
||||
|
@ -106,11 +111,12 @@ architecture RTL of ORIC is
|
|||
signal CPU_DI : std_logic_vector( 7 downto 0);
|
||||
signal CPU_DO : std_logic_vector( 7 downto 0);
|
||||
signal DATA_BUS_OUT:std_logic_vector(7 downto 0);
|
||||
signal cpu_rw : std_logic;
|
||||
signal cpu_rw : std_logic;
|
||||
signal cpu_irq : std_logic;
|
||||
signal ad : std_logic_vector(15 downto 0);
|
||||
signal NMI_INT :std_logic;
|
||||
signal RESET_INT:std_logic;
|
||||
signal RESET_INTn:std_logic;
|
||||
|
||||
|
||||
-- VIA
|
||||
signal via_pa_out_oe : std_logic_vector( 7 downto 0);
|
||||
|
@ -151,7 +157,6 @@ architecture RTL of ORIC is
|
|||
signal ula_WE_SRAM : std_logic;
|
||||
signal ula_LE_SRAM : std_logic;
|
||||
signal ula_CLK_4 : std_logic;
|
||||
signal ula_IOCONTROL : std_logic;
|
||||
signal ula_VIDEO_R : std_logic;
|
||||
signal ula_VIDEO_G : std_logic;
|
||||
signal ula_VIDEO_B : std_logic;
|
||||
|
@ -182,20 +187,30 @@ architecture RTL of ORIC is
|
|||
signal led_signals_save : std_logic_vector(31 downto 0);
|
||||
signal led_signal_update : std_logic;
|
||||
signal led_mutiplex_clk : std_logic;
|
||||
signal CS_N, MOSI, MISO, SCLK : std_logic;
|
||||
|
||||
signal track : unsigned(5 downto 0);
|
||||
signal image : unsigned(9 downto 0);
|
||||
signal D1_ACTIVE, D2_ACTIVE : std_logic;
|
||||
signal track_addr : unsigned(13 downto 0);
|
||||
signal TRACK_RAM_ADDR : unsigned(13 downto 0);
|
||||
signal TRACK_RAM_DI : unsigned(7 downto 0);
|
||||
signal TRACK_RAM_WE : std_logic;
|
||||
|
||||
-- 8dos controler
|
||||
signal cont_MAPn : std_logic;
|
||||
signal cont_ROMDISn : std_logic;
|
||||
signal cont_D_OUT : std_logic_vector(7 downto 0);
|
||||
signal cont_IOCONTROLn : std_logic;
|
||||
|
||||
begin
|
||||
-----------------------------------------------
|
||||
-- generate all the system clocks required
|
||||
-----------------------------------------------
|
||||
|
||||
--D_VIDEO_R <= O_VIDEO_R;
|
||||
--D_VIDEO_G <= O_VIDEO_G;
|
||||
--D_VIDEO_B <= O_VIDEO_B;
|
||||
--D_HSYNC <= O_HSYNC;
|
||||
--D_VSYNC <= O_VSYNC;
|
||||
|
||||
NMI_INT <= not I_NMI;
|
||||
RESET_INT <= not I_RESET;
|
||||
RESET_INTn <= not I_RESET and loc_reset_n;
|
||||
|
||||
inst_pll_base : PLL_BASE
|
||||
generic map (
|
||||
|
@ -243,7 +258,7 @@ begin
|
|||
LOCKED => pll_locked, -- Active high PLL lock signal
|
||||
CLKFBIN => CLKFB, -- Clock feedback input
|
||||
CLKIN => CLK_50, -- Clock input
|
||||
RST => RESET_INT -- Asynchronous PLL reset
|
||||
RST => RESET_INTn -- Asynchronous PLL reset
|
||||
);
|
||||
|
||||
|
||||
|
@ -322,7 +337,7 @@ begin
|
|||
RW => cpu_rw,
|
||||
ADDR => CPU_ADDR(15 downto 0),
|
||||
-- MAPn => MAPn,
|
||||
MAPn => '1',
|
||||
MAPn => cont_MAPn,
|
||||
DB => SRAM_DO,
|
||||
|
||||
-- DRAM
|
||||
|
@ -451,7 +466,6 @@ begin
|
|||
------------------------------------------------------------
|
||||
-- VIA
|
||||
------------------------------------------------------------
|
||||
ula_CSIO <= not ula_CSIOn;
|
||||
|
||||
inst_via : entity work.M6522
|
||||
port map (
|
||||
|
@ -461,8 +475,8 @@ begin
|
|||
O_DATA_OE_L => open,
|
||||
|
||||
I_RW_L => cpu_rw,
|
||||
I_CS1 => ula_CSIO,
|
||||
I_CS2_L => ula_IOCONTROL,
|
||||
I_CS1 => cont_IOCONTROLn,
|
||||
I_CS2_L => ula_CSIOn,
|
||||
|
||||
O_IRQ_L => cpu_irq, -- note, not open drain
|
||||
|
||||
|
@ -613,30 +627,48 @@ begin
|
|||
segment => segment,
|
||||
position => position
|
||||
);
|
||||
|
||||
|
||||
controller8dos : entity work.controller_8dos
|
||||
port map
|
||||
(
|
||||
CLK_24 => clk24,
|
||||
PHI_2 => ula_phi2,
|
||||
RW => cpu_rw,
|
||||
IO_SELECTn => ULA_CSIOn,
|
||||
IO_CONTROLn => cont_IOCONTROLn,
|
||||
RESETn => RESET_INTn,
|
||||
O_ROMDISn => cont_ROMDISn,
|
||||
O_MAPn => cont_MAPn,
|
||||
A => CPU_ADDR(15 downto 0),
|
||||
D_IN => CPU_DO,
|
||||
D_OUT => cont_D_OUT
|
||||
);
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Multiplex CPU , RAM/VIA , ROM
|
||||
------------------------------------------------------------
|
||||
ula_IOCONTROL <= '0';
|
||||
|
||||
process
|
||||
begin
|
||||
wait until rising_edge(clk24);
|
||||
|
||||
-- expansion port
|
||||
if cpu_rw = '1' and ula_IOCONTROL = '1' and ula_CSIOn = '0' then
|
||||
CPU_DI <= SRAM_DO;
|
||||
if cpu_rw = '1' and cont_IOCONTROLn = '0' and ula_CSIOn = '0' then
|
||||
CPU_DI <= cont_D_OUT;
|
||||
-- Via
|
||||
elsif cpu_rw = '1' and ula_IOCONTROL = '0' and ula_CSIOn = '0' and ula_LE_SRAM = '0' then
|
||||
elsif cpu_rw = '1' and cont_IOCONTROLn = '1' and ula_CSIOn = '0' and ula_LE_SRAM = '0' then
|
||||
CPU_DI <= VIA_DO;
|
||||
-- ROM
|
||||
elsif cpu_rw = '1' and ula_IOCONTROL = '0' and ula_CSROMn = '0' then
|
||||
elsif cpu_rw = '1' and cont_IOCONTROLn = '0' and ula_CSROMn = '0' and cont_ROMDISn = '1' then
|
||||
CPU_DI <= ROM_DO;
|
||||
-- Read data
|
||||
elsif cpu_rw = '1' and ula_IOCONTROL = '0' and ula_phi2 = '1' and ula_LE_SRAM = '0' then
|
||||
cpu_di <= SRAM_DO;
|
||||
elsif cpu_rw = '1' and cont_IOCONTROLn = '1' and ula_phi2 = '1' and ula_LE_SRAM = '0' then
|
||||
CPU_DI <= SRAM_DO;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
process -- figure out ram
|
||||
begin
|
||||
wait until rising_edge(clk24);
|
||||
|
@ -659,4 +691,11 @@ begin
|
|||
------------------------------------------------------------
|
||||
-- PRT_DATA <= via_pa_out;
|
||||
-- PRT_STR <= via_out(4);
|
||||
|
||||
|
||||
-- sd card
|
||||
SD_DAT3 <= '0';
|
||||
SD_CMD <= '0';
|
||||
SD_CLK <= '0';
|
||||
|
||||
end RTL;
|
||||
|
|
|
@ -31,19 +31,21 @@ port (
|
|||
end;
|
||||
|
||||
architecture RTL of ram48k is
|
||||
signal ro0, ro1, ro2 : std_logic_vector(7 downto 0);
|
||||
signal cs0, cs1, cs2 : std_logic := '0';
|
||||
signal ro0, ro1, ro2, ro3 : std_logic_vector(7 downto 0);
|
||||
signal cs0, cs1, cs2, cs3: std_logic := '0';
|
||||
begin
|
||||
|
||||
cs0 <= '1' when cs='1' and addr(15 downto 14)="00" else '0';
|
||||
cs1 <= '1' when cs='1' and addr(15 downto 14)="01" else '0';
|
||||
cs2 <= '1' when cs='1' and addr(15 downto 14)="10" else '0';
|
||||
cs3 <= '1' when cs='1' and addr(15 downto 14)="11" else '0';
|
||||
|
||||
do <=
|
||||
ro0 when oe='1' and cs0='1' else
|
||||
ro1 when oe='1' and cs1='1' else
|
||||
ro2 when oe='1' and cs2='1' else
|
||||
(others=>'0');
|
||||
do <=
|
||||
ro0 when oe='1' and cs0='1' else
|
||||
ro1 when oe='1' and cs1='1' else
|
||||
ro2 when oe='1' and cs2='1' else
|
||||
ro3 when oe='1' and cs3='1' else
|
||||
(others=>'0');
|
||||
|
||||
RAM_0000_3FFF : entity work.ram16k
|
||||
port map (
|
||||
|
@ -74,5 +76,14 @@ begin
|
|||
di => di,
|
||||
do => ro2
|
||||
);
|
||||
RAM_C000_FFFF : entity work.ram16k
|
||||
port map (
|
||||
clk => clk,
|
||||
cs => cs3,
|
||||
we => we,
|
||||
addr => addr(13 downto 0),
|
||||
di => di,
|
||||
do => ro3
|
||||
);
|
||||
|
||||
end RTL;
|
||||
|
|
|
@ -82,7 +82,11 @@ entity VGA_SCANCONV is
|
|||
end;
|
||||
|
||||
architecture RTL of VGA_SCANCONV is
|
||||
--
|
||||
type ram_t is array (0 to 1023) of std_logic_vector(15 downto 0);
|
||||
signal ram : ram_t := (others => (others => '0'));
|
||||
attribute ram_style: string;
|
||||
attribute ram_style of ram : signal is "distributed";
|
||||
--
|
||||
-- input timing
|
||||
--
|
||||
signal ivsync_last_x2 : std_logic := '1';
|
||||
|
@ -101,32 +105,46 @@ architecture RTL of VGA_SCANCONV is
|
|||
signal CLK_x2_n : std_logic := '1';
|
||||
|
||||
begin
|
||||
-- dual port line buffer, max line of 1024 pixels
|
||||
u_ram : RAMB16_S18_S18
|
||||
generic map (INIT_A => X"00000", INIT_B => X"00000", SIM_COLLISION_CHECK => "ALL") -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL"
|
||||
port map (
|
||||
-- input
|
||||
DOA => open,
|
||||
DIA => I_VIDEO,
|
||||
DOPA => open,
|
||||
DIPA => "00",
|
||||
ADDRA => hpos_i,
|
||||
WEA => '1',
|
||||
ENA => CLK,
|
||||
SSRA => '0',
|
||||
CLKA => CLK_x2,
|
||||
-- dual port line buffer, max line of 1024 pixels
|
||||
ram_write :process(CLK_x2)
|
||||
begin
|
||||
if rising_edge(CLK_x2) then
|
||||
ram(to_integer(unsigned((hpos_i)))) <= I_VIDEO;
|
||||
end if;
|
||||
end process;
|
||||
ram_read :process(CLK_x2)
|
||||
begin
|
||||
if falling_edge(CLK_x2) then
|
||||
O_VIDEO <= ram(to_integer(unsigned(hpos_o)));
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-- output
|
||||
DOB => O_VIDEO,
|
||||
DIB => x"0000",
|
||||
DOPB => open,
|
||||
DIPB => "00",
|
||||
ADDRB => hpos_o,
|
||||
WEB => '0',
|
||||
ENB => '1',
|
||||
SSRB => '0',
|
||||
CLKB => CLK_x2_n
|
||||
);
|
||||
-- u_ram : RAMB16_S18_S18
|
||||
-- generic map (INIT_A => X"00000", INIT_B => X"00000", SIM_COLLISION_CHECK => "ALL") -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL"
|
||||
-- port map (
|
||||
-- -- input
|
||||
-- DOA => open,
|
||||
-- DIA => I_VIDEO,
|
||||
-- DOPA => open,
|
||||
-- DIPA => "00",
|
||||
-- ADDRA => hpos_i,
|
||||
-- WEA => '1',
|
||||
-- ENA => CLK,
|
||||
-- SSRA => '0',
|
||||
-- CLKA => CLK_x2,
|
||||
|
||||
-- -- output
|
||||
-- DOB => O_VIDEO,
|
||||
-- DIB => x"0000",
|
||||
-- DOPB => open,
|
||||
-- DIPB => "00",
|
||||
-- ADDRB => hpos_o,
|
||||
-- WEB => '0',
|
||||
-- ENB => '1',
|
||||
-- SSRB => '0',
|
||||
-- CLKB => CLK_x2_n
|
||||
-- );
|
||||
|
||||
CLK_x2_n <= not CLK_x2;
|
||||
|
||||
|
|
|
@ -0,0 +1,471 @@
|
|||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- SD/MMC interface (SPI-style) for the Apple ][ Emulator
|
||||
--
|
||||
-- Michel Stempin (michel.stempin@wanadoo.fr)
|
||||
-- Working with MMC/SD/SDHC cards
|
||||
--
|
||||
-- From previous work by:
|
||||
-- Stephen A. Edwards (sedwards@cs.columbia.edu)
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity spi_controller is
|
||||
generic (
|
||||
BLOCK_SIZE : natural := 512;
|
||||
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
|
||||
-- Track buffer Interface -------------------------------------------------
|
||||
ram_write_addr : out unsigned(13 downto 0);
|
||||
ram_di : out unsigned(7 downto 0);
|
||||
ram_we : out std_logic;
|
||||
track : in unsigned(5 downto 0); -- Track number (0-34)
|
||||
image : in unsigned(9 downto 0); -- Which disk image to read
|
||||
-- System Interface -------------------------------------------------------
|
||||
CLK_14M : in std_logic; -- System clock
|
||||
reset : in std_logic
|
||||
);
|
||||
|
||||
end spi_controller;
|
||||
|
||||
architecture rtl of spi_controller is
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- States of the combined MMC/SD/SDHC reset, track and command FSM
|
||||
--
|
||||
type states is (
|
||||
-- Reset FSM
|
||||
POWER_UP,
|
||||
RAMP_UP,
|
||||
CHECK_CMD0,
|
||||
CHECK_CMD8,
|
||||
CHECK_CMD55,
|
||||
CHECK_ACMD41,
|
||||
CHECK_CMD1,
|
||||
CHECK_CMD58,
|
||||
CHECK_SET_BLOCKLEN,
|
||||
ERROR,
|
||||
-- Track read FSM
|
||||
IDLE,
|
||||
READ_TRACK,
|
||||
READ_BLOCK_WAIT,
|
||||
READ_BLOCK_DATA,
|
||||
READ_BLOCK_CRC,
|
||||
-- SD command embedded FSM
|
||||
WAIT_NRC,
|
||||
SEND_CMD,
|
||||
RECEIVE_BYTE_WAIT,
|
||||
RECEIVE_BYTE);
|
||||
--
|
||||
signal state, return_state : states;
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
signal slow_clk : boolean := true;
|
||||
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 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);
|
||||
type versions is (MMC, SD1x, SD2x);
|
||||
signal version : versions;
|
||||
signal high_capacity : boolean;
|
||||
|
||||
begin
|
||||
|
||||
ram_write_addr <= write_addr;
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Process var_clkgen
|
||||
--
|
||||
-- Purpose:
|
||||
-- Implements the variable speed clock for MMC compatibility.
|
||||
-- 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)
|
||||
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
|
||||
var_clk := var_clk + 1;
|
||||
end if;
|
||||
else
|
||||
spi_clk <= CLK_14M;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
SCLK <= sclk_sig;
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Process sd_fsm
|
||||
--
|
||||
-- Purpose:
|
||||
-- Implements the combined "SD Card init", "track read" and "command" FSMs.
|
||||
--
|
||||
sd_fsm : process(spi_clk)
|
||||
subtype cmd_t is std_logic_vector(5 downto 0);
|
||||
constant CMD0 : cmd_t := std_logic_vector(to_unsigned(0, 6));
|
||||
constant CMD1 : cmd_t := std_logic_vector(to_unsigned(1, 6));
|
||||
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 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);
|
||||
|
||||
begin
|
||||
if rising_edge(spi_clk) then
|
||||
ram_we <= '0';
|
||||
if reset = '1' then
|
||||
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');
|
||||
else
|
||||
case state is
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- SD Card init FSM
|
||||
---------------------------------------------------------------------
|
||||
when POWER_UP =>
|
||||
counter := TO_UNSIGNED(224, 8);
|
||||
state <= RAMP_UP;
|
||||
|
||||
-- Output a series of 74 clock signals (or 1ms delay, whichever is
|
||||
-- greater) to wake up the card
|
||||
when RAMP_UP =>
|
||||
if counter = 0 then
|
||||
CS_N <= '0';
|
||||
command <= CMD0;
|
||||
argument <= (others => '0');
|
||||
crc7 <= "1001010";
|
||||
return_state <= CHECK_CMD0;
|
||||
state <= WAIT_NRC;
|
||||
else
|
||||
counter := counter - 1;
|
||||
sclk_sig <= not sclk_sig;
|
||||
end if;
|
||||
|
||||
-- CMD0: GO_IDLE_STATE ----------------------------------------------
|
||||
when CHECK_CMD0 =>
|
||||
if recv_bytes(7 downto 0) = x"01" then
|
||||
command <= CMD8;
|
||||
-- Propose 2.7-3.6V operating voltage and a "10101010" test pattern
|
||||
argument <= x"000001aa";
|
||||
crc7 <= "1000011";
|
||||
return_state <= CHECK_CMD8;
|
||||
state <= WAIT_NRC;
|
||||
else
|
||||
state <= ERROR;
|
||||
end if;
|
||||
|
||||
-- CMD8: SEND_IF_COND -----------------------------------------------
|
||||
when CHECK_CMD8 =>
|
||||
argument <= (others => '0');
|
||||
crc7 <= (others => '0');
|
||||
if recv_bytes(39 downto 32) <= x"01" then
|
||||
-- This is an SD 2.x/3.x Card
|
||||
version <= SD2x;
|
||||
if recv_bytes(11 downto 8) /= "0001" or recv_bytes(7 downto 0) /= x"aa" then
|
||||
-- Operating voltage or pattern check failure
|
||||
state <= ERROR;
|
||||
else
|
||||
command <= CMD55;
|
||||
high_capacity <= true;
|
||||
return_state <= CHECK_CMD55;
|
||||
state <= WAIT_NRC;
|
||||
end if;
|
||||
else
|
||||
-- This is an MMC Card or an SD 1.x Card
|
||||
version <= SD1x;
|
||||
high_capacity <= false;
|
||||
command <= CMD55;
|
||||
return_state <= CHECK_CMD55;
|
||||
state <= WAIT_NRC;
|
||||
end if;
|
||||
|
||||
-- CMD55: APP_CMD ---------------------------------------------------
|
||||
when CHECK_CMD55 =>
|
||||
if recv_bytes(7 downto 0) = x"01" then
|
||||
-- This is an SD Card
|
||||
command <= ACMD41;
|
||||
if high_capacity then
|
||||
-- Ask for HCS (High Capacity Support)
|
||||
argument <= x"40000000";
|
||||
end if;
|
||||
return_state <= CHECK_ACMD41;
|
||||
state <= WAIT_NRC;
|
||||
else
|
||||
-- This is an MMC Card
|
||||
version <= MMC;
|
||||
command <= CMD1;
|
||||
return_state <= CHECK_CMD1;
|
||||
state <= WAIT_NRC;
|
||||
end if;
|
||||
|
||||
-- ACMD41: SEND_OP_CMD (SD Card) ------------------------------------
|
||||
when CHECK_ACMD41 =>
|
||||
if recv_bytes(7 downto 0) = x"00" then
|
||||
if version = SD2x then
|
||||
-- This is an SD 2.x/3.x Card, read OCR
|
||||
command <= CMD58;
|
||||
argument <= (others => '0');
|
||||
return_state <= CHECK_CMD58;
|
||||
state <= WAIT_NRC;
|
||||
else
|
||||
-- This is an SD 1.x Card, no HCS
|
||||
command <= CMD16;
|
||||
argument <= std_logic_vector(to_unsigned(BLOCK_SIZE, 32));
|
||||
return_state <= CHECK_SET_BLOCKLEN;
|
||||
state <= WAIT_NRC;
|
||||
end if;
|
||||
elsif recv_bytes(7 downto 0) = x"01" then
|
||||
-- Wait until the card goes out of idle state
|
||||
command <= CMD55;
|
||||
argument <= (others => '0');
|
||||
return_state <= CHECK_CMD55;
|
||||
state <= WAIT_NRC;
|
||||
else
|
||||
-- Found an MMC card that understands CMD55, but not ACMD41
|
||||
command <= CMD1;
|
||||
return_state <= CHECK_CMD1;
|
||||
state <= WAIT_NRC;
|
||||
end if;
|
||||
|
||||
-- CMD1: SEND_OP_CMD (MMC Card) -------------------------------------
|
||||
when CHECK_CMD1 =>
|
||||
if recv_bytes(7 downto 0) <= x"01" then
|
||||
command <= CMD16;
|
||||
argument <= std_logic_vector(to_unsigned(BLOCK_SIZE, 32));
|
||||
return_state <= CHECK_SET_BLOCKLEN;
|
||||
state <= WAIT_NRC;
|
||||
else
|
||||
-- Wait until the card goes out of idle state
|
||||
command <= CMD1;
|
||||
return_state <= CHECK_CMD1;
|
||||
state <= WAIT_NRC;
|
||||
end if;
|
||||
|
||||
-- CMD58: READ_OCR --------------------------------------------------
|
||||
when CHECK_CMD58 =>
|
||||
if recv_bytes(7 downto 0) = x"00" then
|
||||
if recv_bytes(30) = '1' then
|
||||
high_capacity <= true;
|
||||
else
|
||||
high_capacity <= false;
|
||||
end if;
|
||||
command <= CMD16;
|
||||
argument <= std_logic_vector(to_unsigned(BLOCK_SIZE, 32));
|
||||
return_state <= CHECK_SET_BLOCKLEN;
|
||||
state <= WAIT_NRC;
|
||||
else
|
||||
state <= ERROR;
|
||||
end if;
|
||||
|
||||
-- CMD16: SET_BLOCKLEN (BLOCK_SIZE) ---------------------------------
|
||||
when CHECK_SET_BLOCKLEN =>
|
||||
if recv_bytes(7 downto 0) = x"00" then
|
||||
slow_clk <= false;
|
||||
state <= IDLE;
|
||||
else
|
||||
state <= ERROR;
|
||||
end if;
|
||||
|
||||
-- Error state ------------------------------------------------------
|
||||
when ERROR =>
|
||||
sclk_sig <= '0';
|
||||
slow_clk <= true;
|
||||
CS_N <= '1';
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Embedded "read track" FSM
|
||||
---------------------------------------------------------------------
|
||||
-- Idle state where we sit waiting for user image/track requests ----
|
||||
when IDLE =>
|
||||
if 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");
|
||||
if high_capacity then
|
||||
-- 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;
|
||||
else
|
||||
CS_N <= '1';
|
||||
sclk_sig <= '1';
|
||||
end if;
|
||||
|
||||
-- Read in a whole track into buffer memory -------------------------
|
||||
when READ_TRACK =>
|
||||
if write_addr = TRACK_SIZE then
|
||||
state <= IDLE;
|
||||
else
|
||||
command <= CMD17;
|
||||
argument <= std_logic_vector(lba);
|
||||
return_state <= READ_BLOCK_WAIT;
|
||||
state <= WAIT_NRC;
|
||||
end if;
|
||||
|
||||
-- Wait for a 0 bit to signal the start of the block ----------------
|
||||
when READ_BLOCK_WAIT =>
|
||||
if sclk_sig = '1' and MISO = '0' then
|
||||
state <= READ_BLOCK_DATA;
|
||||
byte_counter := TO_UNSIGNED(BLOCK_SIZE - 1, BLOCK_BITS);
|
||||
counter := TO_UNSIGNED(7, 8);
|
||||
return_state <= READ_BLOCK_DATA;
|
||||
state <= RECEIVE_BYTE;
|
||||
end if;
|
||||
sclk_sig <= not sclk_sig;
|
||||
|
||||
-- Read a block of data ---------------------------------------------
|
||||
when READ_BLOCK_DATA =>
|
||||
ram_we <= '1';
|
||||
write_addr <= write_addr + 1;
|
||||
if byte_counter = 0 then
|
||||
counter := TO_UNSIGNED(7, 8);
|
||||
return_state <= READ_BLOCK_CRC;
|
||||
state <= RECEIVE_BYTE;
|
||||
else
|
||||
byte_counter := byte_counter - 1;
|
||||
counter := TO_UNSIGNED(7, 8);
|
||||
return_state <= READ_BLOCK_DATA;
|
||||
state <= RECEIVE_BYTE;
|
||||
end if;
|
||||
|
||||
-- Read the block CRC -----------------------------------------------
|
||||
when READ_BLOCK_CRC =>
|
||||
counter := TO_UNSIGNED(7, 8);
|
||||
return_state <= READ_TRACK;
|
||||
if high_capacity then
|
||||
lba := lba + 1;
|
||||
else
|
||||
lba := lba + BLOCK_SIZE;
|
||||
end if;
|
||||
state <= RECEIVE_BYTE;
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Embedded "command" FSM
|
||||
---------------------------------------------------------------------
|
||||
-- Wait for card response in front of host command ------------------
|
||||
when WAIT_NRC =>
|
||||
counter := TO_UNSIGNED(63, 8);
|
||||
command_out <= "11111111" & "01" & command & argument & crc7 & "1";
|
||||
sclk_sig <= not sclk_sig;
|
||||
state <= SEND_CMD;
|
||||
|
||||
-- Send a command to the card ---------------------------------------
|
||||
when SEND_CMD =>
|
||||
if sclk_sig = '1' then
|
||||
if counter = 0 then
|
||||
state <= RECEIVE_BYTE_WAIT;
|
||||
else
|
||||
counter := counter - 1;
|
||||
command_out <= command_out(54 downto 0) & "1";
|
||||
end if;
|
||||
end if;
|
||||
sclk_sig <= not sclk_sig;
|
||||
|
||||
-- Wait for a "0", indicating the first bit of a response -----------
|
||||
when RECEIVE_BYTE_WAIT =>
|
||||
if sclk_sig = '1' 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
|
||||
counter := TO_UNSIGNED(38,8);
|
||||
else
|
||||
-- This is a data byte or an r1 response, but we already read
|
||||
-- bit 7
|
||||
counter := TO_UNSIGNED(6, 8);
|
||||
end if;
|
||||
state <= RECEIVE_BYTE;
|
||||
end if;
|
||||
end if;
|
||||
sclk_sig <= not sclk_sig;
|
||||
|
||||
-- Receive a byte ---------------------------------------------------
|
||||
when RECEIVE_BYTE =>
|
||||
if sclk_sig = '1' then
|
||||
recv_bytes <= recv_bytes(38 downto 0) & MISO;
|
||||
if counter = 0 then
|
||||
state <= return_state;
|
||||
ram_di <= recv_bytes(6 downto 0) & MISO;
|
||||
else
|
||||
counter := counter - 1;
|
||||
end if;
|
||||
end if;
|
||||
sclk_sig <= not sclk_sig;
|
||||
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process sd_fsm;
|
||||
|
||||
MOSI <= command_out(55);
|
||||
|
||||
end rtl;
|
Loading…
Reference in New Issue