This commit is contained in:
byrtolet 2018-10-12 20:22:46 +03:00
parent 8d140e4c75
commit 3f23152a34
10 changed files with 1115 additions and 57 deletions

View File

@ -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"

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;