Project

General

Profile

« Previous | Next » 

Revision 220

Added by markw almost 11 years ago

Switched mist_5200 to use sd card emulation. NB SD cart emulation does not work yet with this core, but problem identified and Till will be fixing. Thanks Till!

View differences:

mist_5200/data_io.vhdl
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;
LIBRARY work;
ENTITY data_io IS
PORT
(
CLK : in std_logic;
RESET_n : in std_logic;
-- SPI connection - up to upstream to make miso 'Z' on ss_io going high
SPI_CLK : in std_logic;
SPI_SS_IO : in std_logic;
SPI_MISO: out std_logic;
SPI_MOSI : in std_logic;
-- Sector access read_request
read_request : in std_logic;
write_request : in std_logic;
sector : in std_logic_vector(25 downto 0);
ready : out std_logic;
-- DMA to RAM
ADDR: out std_logic_vector(8 downto 0);
DATA_OUT : out std_logic_vector(7 downto 0);
DATA_IN : in std_logic_vector(7 downto 0);
WR_EN : out std_logic
);
end data_io;
architecture vhdl of data_io is
signal sbuf_next : std_logic_vector(6 downto 0);
signal sbuf_reg : std_logic_vector(6 downto 0);
signal cmd_next : std_logic_vector(7 downto 0);
signal cmd_reg : std_logic_vector(7 downto 0);
signal cnt_next : std_logic_vector(15 downto 0);
signal cnt_reg : std_logic_vector(15 downto 0);
signal data_in_next : std_logic_vector(7 downto 0);
signal data_in_reg : std_logic_vector(7 downto 0);
signal data_out_next : std_logic_vector(7 downto 0);
signal data_out_reg : std_logic_vector(7 downto 0);
signal addr_next : std_logic_vector(8 downto 0);
signal addr_reg : std_logic_vector(8 downto 0);
signal wren_next : std_logic;
signal wren_reg : std_logic;
signal ready_next : std_logic;
signal ready_reg : std_logic;
signal transmit_next : std_logic_vector(7 downto 0);
signal transmit_reg : std_logic_vector(7 downto 0);
signal sector_next : std_logic_vector(25 downto 0);
signal sector_reg : std_logic_vector(25 downto 0);
signal read_request_next : std_logic;
signal read_request_reg : std_logic;
signal write_request_next : std_logic;
signal write_request_reg : std_logic;
signal clk2 : std_logic;
begin
clk2 <= clk or spi_ss_io;
process(clk2,reset_n,spi_ss_io)
begin
if (spi_ss_io = '1') then
cnt_reg <= (others=>'0');
cmd_reg <= (others=>'0');
wren_reg <= '0';
elsif (reset_n = '0') then
cnt_reg <= (others=>'0');
cmd_reg <= (others=>'0');
sbuf_reg <= (others=>'0');
addr_reg <= (others => '0');
data_in_reg <= (others => '0');
data_out_reg <= (others => '0');
wren_reg <= '0';
ready_reg <= '0';
transmit_reg <= (others=>'0');
read_request_reg <= '0';
write_request_reg <= '0';
sector_reg <=(others=>'0');
elsif (clk2'event and clk2='1') then
cnt_reg <= cnt_next;
cmd_reg <= cmd_next;
sbuf_reg <= sbuf_next;
addr_reg <= addr_next;
data_in_reg <= data_in_next;
data_out_reg <= data_out_next;
wren_reg <= wren_next;
ready_reg <= ready_next;
transmit_reg <= transmit_next;
read_request_reg <= read_request_next;
write_request_reg <= write_request_next;
sector_reg <= sector_next;
end if;
end process;
-- clk_sync : synchronizer
-- PORT MAP ( CLK => clk, raw => spi_clk, sync=>spi_clk_next);
--spi_clk_next <= spi_clk;
-- input_sync : synchronizer
-- PORT MAP ( CLK => clk, raw => spi_mosi, sync=>spi_mosi_next);
-- select_sync : synchronizer
-- PORT MAP ( CLK => clk, raw => spi_ss_io, sync=>spi_ss_next);
data_in_next <= data_in;
process(spi_ss_io,cnt_reg, sbuf_reg, transmit_reg, spi_mosi, addr_reg, cmd_reg, sector_reg, write_request_reg, read_request_reg, ready_reg,read_request,write_request,sector,data_in_reg)
begin
cnt_next <= cnt_reg;
sbuf_next <= sbuf_reg;
cmd_next <= cmd_reg;
ready_next <= ready_reg and (read_request or write_request); -- stay ready until read_request cleared (received by other end)
transmit_next <= transmit_reg;
wren_next <= '0';
data_out_next <= (others=>'0');
addr_next <= addr_reg;
sector_next <= sector_reg;
read_request_next <= read_request_reg;
write_request_next <= write_request_reg;
--- It polls get_status 10 times a second
--- it uses SPI_SS2 for this
--- it sends command code 0x50
--- reads 4 bytes afterwards
--- it reports whenever the returned value is different then the one from previous get_status
--- if the lowest byte of the status (the last transmitted of the four) is 0xa5:
--- a sector is read from sd card with the sector no being the upper/first three bytes transmitted
--- if the sector could be read
--- SPI_SS2 is activated
--- command byte 0x51 is sent
--- all 512 sector bytes are sent
--if (spi_clk_reg = '1' and spi_clk_next = '0') then
transmit_next(7 downto 1) <= transmit_reg(6 downto 0);
transmit_next(0) <= '0';
cnt_next <= std_logic_vector(unsigned(cnt_reg) + 1);
sbuf_next(6 downto 1) <= sbuf_reg(5 downto 0);
sbuf_next(0) <= SPI_MOSI;
if (cnt_reg = X"0000") then
addr_next <= (others=>'0');
end if;
if (cnt_reg = X"0007") then
cmd_next(7 downto 1) <= sbuf_reg;
cmd_next(0) <= SPI_MOSI;
sector_next <= sector;
read_request_next <= read_request;
write_request_next <= write_request;
end if;
--end if;
case cmd_reg is
when X"50" => --get status
case cnt_reg is
when X"0008" =>
transmit_next <= sector_reg(25 downto 18);
when X"0010" =>
transmit_next <= sector_reg(17 downto 10);
when X"0018" =>
transmit_next <= sector_reg(9 downto 2);
when X"0020" =>
transmit_next <= sector_reg(1 downto 0)&"1010"&write_request_reg&read_request_reg; --read read_request
when others =>
-- nothing
end case;
when X"51" => --sector read from sd, write it...
if (cnt_reg = X"0008") then
addr_next <= (others=>'1');
end if;
if (cnt_reg(2 downto 0) = "111") then
addr_next <= std_logic_vector(unsigned(addr_reg) + 1);
data_out_next(7 downto 1) <= sbuf_reg;
data_out_next(0) <= SPI_MOSI;
wren_next <= read_request;
if (cnt_reg(12) = '1')then
ready_next <= '1';
end if;
end if;
when X"52" => -- read from write, write to sd
if (cnt_reg(2 downto 0) = "000") then
addr_next <= std_logic_vector(unsigned(addr_reg) + 1);
transmit_next <= data_in_reg;
if (cnt_reg(12) = '1')then
ready_next <= '1';
end if;
end if;
when others =>
-- nop
end case;
end process;
-- outputs
addr <= addr_next;
data_out <= data_out_next;
wr_en <= wren_next;
ready <= ready_reg;
spi_miso <= transmit_next(7);
end vhdl;
firmware/Makefile
MIST_OBJ = $(patsubst %.c,$(MIST_BUILD_DIR)/%.o,$(MIST_SRC))
MIST_5200_PRJ = MIST_5200
MIST_5200_SRC = $(COMMON_SRC) $(5200_SRC) mist/diskio_sectorrequest.c mist/dirs.c
MIST_5200_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(5200_SRC) mist/dirs.c
MIST_5200_OBJ = $(patsubst %.c,$(MIST_5200_BUILD_DIR)/%.o,$(MIST_5200_SRC))
LINKMAP = ./standalone_simple.ld
mist_5200/atari800core_mist.vhd
end component;
component user_io
GENERIC(
STRLEN : in integer := 0
);
PORT(
SPI_CLK : in std_logic;
SPI_SS_IO : in std_logic;
SPI_MISO : out std_logic;
SPI_MOSI : in std_logic;
CORE_TYPE : in std_logic_vector(7 downto 0);
JOY0 : out std_logic_vector(5 downto 0);
JOY1 : out std_logic_vector(5 downto 0);
-- conf_str? how to do in vhdl...
-- mist spi to firmware
SPI_CLK : in std_logic;
SPI_SS_IO : in std_logic;
SPI_MISO : out std_logic;
SPI_MOSI : in std_logic;
-- joysticks
JOYSTICK_0 : out std_logic_vector(5 downto 0);
JOYSTICK_1 : out std_logic_vector(5 downto 0);
JOYSTICK_ANALOG_0 : out std_logic_vector(15 downto 0);
JOYSTICK_ANALOG_1 : out std_logic_vector(15 downto 0);
BUTTONS : out std_logic_vector(1 downto 0);
SWITCHES : out std_logic_vector(1 downto 0);
CLK : in std_logic;
PS2_CLK : out std_logic;
PS2_DATA : out std_logic
STATUS : out std_logic_vector(7 downto 0); -- what is this?
-- ps2
PS2_CLK : in std_logic; --12-16khz
PS2_KBD_CLK : out std_logic;
PS2_KBD_DATA : out std_logic;
-- serial (one way?)
SERIAL_DATA : in std_logic_vector(7 downto 0);
SERIAL_STROBE : in std_logic;
-- connection to sd card emulation
sd_lba : in std_logic_vector(31 downto 0);
sd_rd : in std_logic;
sd_wr : in std_logic;
sd_ack : out std_logic;
sd_conf : in std_logic;
sd_sdhc : in std_logic;
sd_dout : out std_logic_vector(7 downto 0);
sd_dout_strobe : out std_logic;
sd_din : in std_logic_vector(7 downto 0);
sd_din_strobe : out std_logic
);
end component;
end component;
component sd_card
PORT (
-- link to user_io for io controller
io_lba : out std_logic_vector(31 downto 0);
io_rd : out std_logic;
io_wr : out std_logic;
io_ack : in std_logic;
io_conf : out std_logic;
io_sdhc : out std_logic;
-- data coming in from io controller
io_din : in std_logic_vector(7 downto 0);
io_din_strobe : in std_logic;
-- data going out to io controller
io_dout : out std_logic_vector(7 downto 0);
io_dout_strobe : in std_logic;
-- configuration input
allow_sdhc : in std_logic;
sd_cs : in std_logic;
sd_sck : in std_logic;
sd_sdi : in std_logic;
sd_sdo : out std_logic
);
end component;
signal AUDIO_L_PCM : std_logic_vector(15 downto 0);
signal AUDIO_R_PCM : std_logic_vector(15 downto 0);
......
signal capsheld_next : std_logic;
signal capsheld_reg : std_logic;
signal mist_sector_ready : std_logic;
signal mist_sector_ready_sync : std_logic;
signal mist_sector_request : std_logic;
signal mist_sector_request_sync : std_logic;
signal mist_sector_write : std_logic;
signal mist_sector_write_sync : std_logic;
signal mist_sector : std_logic_vector(25 downto 0);
signal mist_sector_sync : std_logic_vector(25 downto 0);
signal mist_addr : std_logic_vector(8 downto 0);
signal mist_do : std_logic_vector(7 downto 0);
signal mist_di : std_logic_vector(7 downto 0);
signal mist_wren : std_logic;
signal spi_miso_data : std_logic;
signal spi_miso_io : std_logic;
signal mist_buttons : std_logic_vector(1 downto 0);
......
signal pause_atari : std_logic;
SIGNAL speed_6502 : std_logic_vector(5 downto 0);
-- mist sector
signal ZPU_ROM_DATA_MUX : std_logic_vector(31 downto 0);
signal ZPU_SECTOR_DATA : std_logic_vector(31 downto 0);
signal ZPU_ROM_DO : std_logic_vector(31 downto 0);
signal ZPU_ROM_WREN : std_logic;
-- connection to sd card emulation
signal sd_lba : std_logic_vector(31 downto 0);
signal sd_rd : std_logic;
signal sd_wr : std_logic;
signal sd_ack : std_logic;
signal sd_conf : std_logic;
signal sd_sdhc : std_logic;
signal sd_dout : std_logic_vector(7 downto 0);
signal sd_dout_strobe : std_logic;
signal sd_din : std_logic_vector(7 downto 0);
signal sd_din_strobe : std_logic;
signal mist_sd_sdo : std_logic;
signal mist_sd_sck : std_logic;
signal mist_sd_sdi : std_logic;
signal mist_sd_cs : std_logic;
-- ps2
signal SLOW_PS2_CLK : std_logic; -- around 16KHz
......
composite_on_hsync <= '1' when composite_sync=1 else '0';
-- mist spi io
mist_spi_interface : entity work.data_io
PORT map
(
CLK =>spi_sck,
RESET_n =>reset_n,
-- SPI connection - up to upstream to make miso 'Z' on ss_io going high
SPI_CLK =>spi_sck,
SPI_SS_IO => spi_ss2,
SPI_MISO => spi_miso_data,
SPI_MOSI => spi_di,
-- Sector access request
read_request => mist_sector_request_sync,
write_request => mist_sector_write_sync,
--request => mist_sector_request_sync,
sector => mist_sector_sync(25 downto 0),
ready => mist_sector_ready,
-- DMA to RAM
ADDR => mist_addr,
DATA_OUT => mist_do,
DATA_IN => mist_di,
WR_EN => mist_wren
);
-- TODO, review if these are all needed when ZPU connected again...
select_sync : entity work.synchronizer
PORT MAP ( CLK => clk, raw => mist_sector_ready, sync=>mist_sector_ready_sync);
spi_do <= spi_miso_io when CONF_DATA0 ='0' else 'Z';
select_sync2 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector_request, sync=>mist_sector_request_sync);
select_sync3 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector_write, sync=>mist_sector_write_sync);
sector_sync0 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(0), sync=>mist_sector_sync(0));
sector_sync1 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(1), sync=>mist_sector_sync(1));
sector_sync2 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(2), sync=>mist_sector_sync(2));
sector_sync3 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(3), sync=>mist_sector_sync(3));
sector_sync4 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(4), sync=>mist_sector_sync(4));
sector_sync5 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(5), sync=>mist_sector_sync(5));
sector_sync6 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(6), sync=>mist_sector_sync(6));
sector_sync7 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(7), sync=>mist_sector_sync(7));
sector_sync8 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(8), sync=>mist_sector_sync(8));
sector_sync9 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(9), sync=>mist_sector_sync(9));
sector_sync10 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(10), sync=>mist_sector_sync(10));
sector_sync11 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(11), sync=>mist_sector_sync(11));
sector_sync12 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(12), sync=>mist_sector_sync(12));
sector_sync13 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(13), sync=>mist_sector_sync(13));
sector_sync14 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(14), sync=>mist_sector_sync(14));
sector_sync15 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(15), sync=>mist_sector_sync(15));
sector_sync16 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(16), sync=>mist_sector_sync(16));
sector_sync17 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(17), sync=>mist_sector_sync(17));
sector_sync18 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(18), sync=>mist_sector_sync(18));
sector_sync19 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(19), sync=>mist_sector_sync(19));
sector_sync20 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(20), sync=>mist_sector_sync(20));
sector_sync21 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(21), sync=>mist_sector_sync(21));
sector_sync22 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(22), sync=>mist_sector_sync(22));
sector_sync23 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(23), sync=>mist_sector_sync(23));
sector_sync24 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(24), sync=>mist_sector_sync(24));
sector_sync25 : entity work.synchronizer
PORT MAP ( CLK => spi_sck, raw => mist_sector(25), sync=>mist_sector_sync(25));
spi_do <= spi_miso_io when CONF_DATA0 ='0' else spi_miso_data when spi_SS2='0' else 'Z';
mist_sector_buffer1 : entity work.mist_sector_buffer
PORT map
(
address_a => mist_addr,
address_b => zpu_addr_rom(8 downto 2),
clock_a => spi_sck,
clock_b => clk,
data_a => mist_do,
data_b => dma_write_data(7 downto 0)&dma_write_data(15 downto 8)&dma_write_data(23 downto 16)&dma_write_data(31 downto 24),
wren_a => mist_wren,
wren_b => zpu_rom_wren,
q_a => mist_di,
q_b => zpu_sector_data
);
my_user_io : user_io
PORT map(
SPI_CLK => SPI_SCK,
SPI_SS_IO => CONF_DATA0,
SPI_MISO => SPI_miso_io,
SPI_MOSI => SPI_DI,
CORE_TYPE => x"A4",
JOY0 => joy2,
JOY1 => joy1,
JOYSTICK_0 => joy2,
JOYSTICK_1 => joy1,
JOYSTICK_ANALOG_0 => open,
JOYSTICK_ANALOG_1 => open, -- todo, wire up to paddles
BUTTONS => mist_buttons,
SWITCHES => mist_switches,
CLK => SLOW_PS2_CLK,
PS2_CLK => ps2_clk,
PS2_DATA => ps2_dat
STATUS => open,
PS2_CLK => SLOW_PS2_CLK,
PS2_KBD_CLK => ps2_clk,
PS2_KBD_DATA => ps2_dat,
SERIAL_DATA => (others=>'0'),
SERIAL_STROBE => '0',
sd_lba => sd_lba,
sd_rd => sd_rd,
sd_wr => sd_wr,
sd_ack => sd_ack,
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
);
my_sd_card : sd_card
PORT map (
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',
sd_cs => mist_sd_cs,
sd_sck => mist_sd_sck,
sd_sdi => mist_sd_sdi,
sd_sdo => mist_sd_sdo
);
joy1_n <= not(joy1(4 downto 0));
joy2_n <= not(joy2(4 downto 0));
......
GENERIC MAP
(
platform => 1,
spi_clock_div => 1 -- 28MHz/2. Max for SD cards is 25MHz...
spi_clock_div => 16 -- 28MHz/2. Max for SD cards is 25MHz...
)
PORT MAP
(
......
-- rom bus master
-- data on next cycle after addr
ZPU_ADDR_ROM => zpu_addr_rom,
ZPU_ROM_DATA => zpu_rom_data_mux,
ZPU_ROM_DATA => zpu_rom_data,
ZPU_ROM_WREN => zpu_rom_wren, -- special for mist...
ZPU_ROM_WREN => open,
-- spi master
-- not used for mist...
ZPU_SD_DAT0 => '0',
ZPU_SD_CLK => open,
ZPU_SD_CMD => open,
ZPU_SD_DAT3 => open,
ZPU_SD_DAT0 => mist_sd_sdo,
ZPU_SD_CLK => mist_sd_sck,
ZPU_SD_CMD => mist_sd_sdi,
ZPU_SD_DAT3 => mist_sd_cs,
-- SIO
-- Ditto for speaking to Atari, we have a built in Pokey
......
ZPU_IN1 => X"00000"&(FKEYS(11) or (mist_buttons(0) and not(joy1_n(4))))&(FKEYS(10) or (mist_buttons(0) and joy1_n(4) and joy_still))&(FKEYS(9) or (mist_buttons(0) and joy1_n(4) and not(joy_still)))&FKEYS(8 downto 0),
ZPU_IN2 => X"00000000",
ZPU_IN3 => X"00000000",
ZPU_IN4 => X"000000"&"0000000"&mist_sector_ready_sync,
ZPU_IN4 => X"00000000",
-- ouputs - e.g. Atari system control, halt, throttle, rom select
ZPU_OUT1 => zpu_out1,
......
ZPU_OUT4 => zpu_out4
);
mist_sector <= zpu_out4(25 downto 0);
mist_sector_request <= zpu_out4(26);
mist_sector_write <= zpu_out4(27);
pause_atari <= zpu_out1(0);
reset_atari <= zpu_out1(1);
speed_6502 <= zpu_out1(7 downto 2);
......
q => zpu_rom_data
);
process(zpu_addr_rom, zpu_rom_data, zpu_sector_data)
begin
zpu_rom_data_mux <= zpu_rom_data;
if (zpu_addr_rom(15 downto 14) = "01") then
zpu_rom_data_mux <= zpu_sector_data(7 downto 0)&zpu_sector_data(15 downto 8)&zpu_sector_data(23 downto 16)&zpu_sector_data(31 downto 24);
end if;
end process;
enable_179_clock_div_zpu_pokey : entity work.enable_divider
generic map (COUNT=>32) -- cycle_length
port map(clk=>clk,reset_n=>reset_n,enable_in=>'1',enable_out=>zpu_pokey_enable);
mist_5200/sd_card.v
//
// 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
// TODO:
// - CMD9: SEND_CSD (requires device capacity)
// - CMD10: SEND_CID
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)
wire req_io_rd = (read_state == 3'd1);
wire io_reset = io_ack || sd_cs;
always @(posedge req_io_rd or posedge io_reset) begin
if(io_reset) io_rd <= 1'b0;
else io_rd <= 1'b1;
end
wire req_io_wr = (write_state == 3'd6);
always @(posedge req_io_wr or posedge io_reset) begin
if(io_reset) 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;
localparam NCR=4;
// 0=idle, 1=wait for io ctrl, 2=wait for byte start, 2=send token, 3=send data, 4/5=send crc[0..1]
reg [2:0] read_state;
// 0=idle
reg [2:0] write_state;
reg [6:0] sbuf;
reg cmd55;
reg [7:0] cmd;
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
reg [7:0] byte_cnt; // counts bytes
reg [7:0] cmd_cnt; // counts command bytes
reg [7:0] lba0, lba1, lba2, lba3;
assign io_lba = io_sdhc?{ lba3, lba2, lba1, lba0 }:{9'd0, lba3, lba2, lba1[7:1]};
// the command crc is actually never evaluated
reg [7:0] crc;
reg [7:0] reply;
reg [7:0] reply0, reply1, reply2, reply3;
reg [3:0] reply_len;
reg io_ackD, io_ackD2;
// signals to address buffer on SD card write (data coming from SD spi)
reg write_strobe;
reg [7:0] write_data;
// ------------------------- SECTOR BUFFER -----------------------
// access to the sector buffer is multiplexed. When reading sectors
// the io controller writes into the buffer and the sd card implementation
// reads. And vice versa when writing sectors
wire reading = (read_state != 0);
wire writing = (write_state != 0);
// the buffer itself. Can hold one sector
reg [8:0] buffer_wptr;
reg [8:0] buffer_rptr;
reg [7:0] buffer [511:0];
reg [7:0] buffer_byte;
// ---------------- buffer read engine -----------------------
reg core_buffer_read_strobe;
wire buffer_read_latch = reading?sd_sck:io_dout_strobe;
wire buffer_read_strobe = reading?core_buffer_read_strobe:!io_dout_strobe;
assign io_dout = buffer_byte;
// sdo is sampled on negative sd clock so set it on positive edge
always @(posedge buffer_read_latch)
buffer_byte <= buffer[buffer_rptr];
always @(posedge buffer_read_strobe or posedge sd_cs) begin
if(sd_cs == 1) buffer_rptr <= 9'd0;
else buffer_rptr <= buffer_rptr + 9'd1;
end
// ---------------- buffer write engine -----------------------
wire [7:0] buffer_din = reading?io_din:write_data;
wire buffer_din_strobe = reading?io_din_strobe:write_strobe;
always @(negedge buffer_din_strobe or posedge sd_cs) begin
if(sd_cs == 1) begin
buffer_wptr <= 9'd0;
end 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);
// the 32 bytes as sent from the io controller
reg [7:0] cid [15:0];
reg [7:0] csd [15:0];
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 @(negedge 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] <= io_din;
if((csd_wptr >= 16) && (csd_wptr < 32)) // then comes csd
csd[csd_wptr-16] <= io_din;
if(csd_wptr == 32) // finally a config byte
conf <= io_din;
csd_wptr <= csd_wptr + 1;
end
end
always @(posedge buffer_read_latch)
cid_byte <= cid[buffer_rptr];
always @(posedge buffer_read_latch)
csd_byte <= csd[buffer_rptr];
// ----------------- spi transmitter --------------------
always@(negedge sd_sck or posedge sd_cs) begin
if(sd_cs == 1) begin
sd_sdo <= 1'b1;
read_state <= 3'd0;
end else begin
core_buffer_read_strobe <= 1'b0;
// bring io ack in local clock domain
io_ackD <= io_ack;
io_ackD2 <= io_ackD;
// -------- catch read commmand and reset read state machine ------
if(bit_cnt == 7) begin
if(cmd_cnt == 5) begin
// CMD17: READ_SINGLE_BLOCK
if(cmd == 8'h51)
read_state <= 3'd1; // start waiting for data from io controller
end
end
if(byte_cnt < 6+NCR) begin
sd_sdo <= 1'b1; // reply $ff -> wait
end else begin
if(byte_cnt == 6+NCR) begin
sd_sdo <= reply[~bit_cnt];
if(bit_cnt == 7) begin
// CMD9: SEND_CSD
// CMD10: SEND_CID
if((cmd == 8'h49)||(cmd == 8'h4a))
read_state <= 3'd3; // jump directly to data transmission
end
end
else if((reply_len > 0) && (byte_cnt == 6+NCR+1))
sd_sdo <= reply0[~bit_cnt];
else if((reply_len > 1) && (byte_cnt == 6+NCR+2))
sd_sdo <= reply1[~bit_cnt];
else if((reply_len > 2) && (byte_cnt == 6+NCR+3))
sd_sdo <= reply2[~bit_cnt];
else if((reply_len > 3) && (byte_cnt == 6+NCR+4))
sd_sdo <= reply3[~bit_cnt];
else
sd_sdo <= 1'b1;
// falling edge of io_ack signals end of incoming data stream
if((read_state == 3'd1) && !io_ackD && io_ackD2)
read_state <= 3'd2;
// wait for begin of new byte
if((read_state == 3'd2) && (bit_cnt == 7))
read_state <= 3'd3;
// send data token
if(read_state == 3'd3) begin
sd_sdo <= READ_DATA_TOKEN[~bit_cnt];
if(bit_cnt == 7)
read_state <= 3'd4; // next: send data
end
// send data
if(read_state == 3'd4) begin
if(cmd == 8'h51) // CMD17: READ_SINGLE_BLOCK
sd_sdo <= buffer_byte[~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];
if(bit_cnt == 7) begin
core_buffer_read_strobe <= 1'b1;
// send 512 sector data bytes?
if((cmd == 8'h51) && (buffer_rptr == 511))
read_state <= 3'd5; // next: send crc
// send 16 cid/csd data bytes?
if(((cmd == 8'h49)||(cmd == 8'h4a)) && (buffer_rptr == 15))
read_state <= 3'd0; // return to idle state
end
end
// send crc[0]
if(read_state == 3'd5) begin
sd_sdo <= 1'b1;
if(bit_cnt == 7)
read_state <= 3'd6; // send second crc byte
end
// send crc[1]
if(read_state == 3'd6) begin
sd_sdo <= 1'b1;
if(bit_cnt == 7)
read_state <= 3'd0; // return to idle state
end
// send write data response
if(write_state == 3'd5)
sd_sdo <= WRITE_DATA_RESPONSE[~bit_cnt];
// busy after write until the io controller sends ack
if(write_state == 3'd6)
sd_sdo <= 1'b0;
end
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;
byte_cnt <= 8'd0;
cmd_cnt <= 8'd0;
write_state <= 3'd0;
write_strobe <= 1'b0;
end else begin
write_strobe <= 1'b0;
sbuf[6:0] <= { sbuf[5:0], sd_sdi };
bit_cnt <= bit_cnt + 3'd1;
if((bit_cnt == 7)&&(byte_cnt != 255)) begin
byte_cnt <= byte_cnt + 8'd1;
if(cmd_cnt == 0) begin
// first byte of valid command is 01xxxxxx
if((write_state == 3'd0) && sbuf[6:5] == 2'b01) begin
cmd_cnt <= 8'd1;
byte_cnt <= 8'd1;
end
end else if(cmd_cnt < 6)
cmd_cnt <= cmd_cnt + 8'd1;
else
// command counting stops after last command byte.
cmd_cnt <= 8'd0;
end
// finished reading command byte
if(bit_cnt == 7) begin
// don't accept new commands once a write command has been accepted
if((write_state == 3'd0) && (cmd_cnt == 0)&&(sbuf[6:5] == 2'b01)) begin
cmd <= { sbuf, sd_sdi};
// set cmd55 flag if previous command was 55
cmd55 <= (cmd == 8'h77);
end
// parse additional command bytes
if(cmd_cnt == 1) lba3 <= { sbuf, sd_sdi};
if(cmd_cnt == 2) lba2 <= { sbuf, sd_sdi};
if(cmd_cnt == 3) lba1 <= { sbuf, sd_sdi};
if(cmd_cnt == 4) lba0 <= { sbuf, sd_sdi};
if(cmd_cnt == 5) crc <= { sbuf, sd_sdi};
// last byte received, evaluate
if(cmd_cnt == 5) begin
// default:
reply <= 8'h04; // illegal command
reply_len <= 4'd0; // no extra reply bytes
// CMD0: GO_IDLE_STATE
if(cmd == 8'h40)
reply <= 8'h01; // ok, busy
// CMD1: SEND_OP_COND
else 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(io_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 <= 3'd1; // 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
// ---------- handle write -----------
// waiting for data token
if(write_state == 3'd1) begin
if({ sbuf, sd_sdi} == 8'hfe )
write_state <= 3'd2;
end
// transfer 512 bytes
if(write_state == 3'd2) begin
// push one byte into local buffer
write_strobe <= 1'b1;
write_data <= { sbuf, sd_sdi};
if(buffer_wptr == 511)
write_state <= 3'd3;
end
// transfer 1st crc byte
if(write_state == 3'd3)
write_state <= 3'd4;
// transfer 2nd crc byte
if(write_state == 3'd4)
write_state <= 3'd5;
// send data response
if(write_state == 3'd5)
write_state <= 3'd6;
end
// wait for io controller to accept data
// this happens outside the bit_cnt == 7 test as the
// transition may happen at any time
if(write_state == 3'd6 && !io_ackD && io_ackD2)
write_state <= 3'd0;
end
end
endmodule
mist_5200/user_io.v
// MiST user_io
module user_io(
input SPI_CLK,
input SPI_SS_IO,
output reg SPI_MISO,
input SPI_MOSI,
input [7:0] CORE_TYPE,
output [5:0] JOY0,
output [5:0] JOY1,
output [1:0] BUTTONS,
output [1:0] SWITCHES,
input clk,
output ps2_clk,
output reg ps2_data
);
reg [6:0] sbuf;
reg [7:0] cmd;
reg [4:0] cnt;
reg [5:0] joystick0;
reg [5:0] joystick1;
reg [3:0] but_sw;
assign JOY0 = joystick0;
assign JOY1 = joystick1;
assign BUTTONS = but_sw[1:0];
assign SWITCHES = but_sw[3:2];
// drive MISO only when transmitting core id
always@(negedge SPI_CLK or posedge SPI_SS_IO) begin
if(SPI_SS_IO == 1) begin
SPI_MISO <= 1'bZ;
end else begin
if(cnt < 8) begin
SPI_MISO <= CORE_TYPE[7-cnt];
end else begin
SPI_MISO <= 1'bZ;
end
end
end
// 8 byte fifo to store ps2 bytes
localparam PS2_FIFO_BITS = 3;
reg [7:0] ps2_fifo [(2**PS2_FIFO_BITS)-1:0];
reg [PS2_FIFO_BITS-1:0] ps2_wptr;
reg [PS2_FIFO_BITS-1:0] ps2_rptr;
// ps2 transmitter state machine
reg [3:0] ps2_tx_state;
reg [7:0] ps2_tx_byte;
reg ps2_parity;
assign ps2_clk = clk || (ps2_tx_state == 0);
// ps2 transmitter
// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
reg ps2_r_inc;
always@(posedge clk) begin
ps2_r_inc <= 1'b0;
if(ps2_r_inc)
ps2_rptr <= ps2_rptr + 1;
// transmitter is idle?
if(ps2_tx_state == 0) begin
// data in fifo present?
if(ps2_wptr != ps2_rptr) begin
// load tx register from fifo
ps2_tx_byte <= ps2_fifo[ps2_rptr];
ps2_r_inc <= 1'b1;
// reset parity
ps2_parity <= 1'b1;
// start transmitter
ps2_tx_state <= 4'd1;
// put start bit on data line
ps2_data <= 1'b0; // start bit is 0
end
end else begin
// transmission of 8 data bits
if((ps2_tx_state >= 1)&&(ps2_tx_state < 9)) begin
ps2_data <= ps2_tx_byte[0]; // data bits
ps2_tx_byte[6:0] <= ps2_tx_byte[7:1]; // shift down
if(ps2_tx_byte[0])
ps2_parity <= !ps2_parity;
end
// transmission of parity
if(ps2_tx_state == 9)
ps2_data <= ps2_parity;
// transmission of stop bit
if(ps2_tx_state == 10)
ps2_data <= 1'b1; // stop bit is 1
// advance state machine
if(ps2_tx_state < 11)
ps2_tx_state <= ps2_tx_state + 4'd1;
else
ps2_tx_state <= 4'd0;
end
end
// SPI receiver
//reg ps2_w_inc;
always@(posedge SPI_CLK or posedge SPI_SS_IO) begin
// ps2_w_inc <= 1'b0;
// if(ps2_w_inc)
// ps2_wptr <= ps2_wptr + 1;
if(SPI_SS_IO == 1) begin
cnt <= 1'b0;
end else begin
sbuf[6:0] <= { sbuf[5:0], SPI_MOSI };
// counter counts 0-7, 8-15, 8-15 ...
// 0-7 is command, 8-15 is payload
if(cnt != 15) cnt <= cnt + 4'd1;
else cnt <= 4'd8;
// finished reading command byte
if(cnt == 7)
cmd <= { sbuf, SPI_MOSI};
if(cnt == 15) begin
if(cmd == 1)
but_sw <= { sbuf[2:0], SPI_MOSI };
if(cmd == 2)
joystick0 <= { sbuf[4:0], SPI_MOSI };
if(cmd == 3)
joystick1 <= { sbuf[4:0], SPI_MOSI };
if(cmd == 5) begin
// store incoming keyboard bytes in
ps2_fifo[ps2_wptr] <= { sbuf, SPI_MOSI };
ps2_wptr <= ps2_wptr + 1;
end
end
end
end
endmodule
//
// 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 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/>.
//
// parameter STRLEN and the actual length of conf_str have to match
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,
output reg [5:0] joystick_0,
output reg [5: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 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 reg [7:0] sd_dout,
output reg sd_dout_strobe,
input [7:0] sd_din,
output reg sd_din_strobe,
// ps2 keyboard emulation
input ps2_clk, // 12-16khz provided by core
output ps2_kbd_clk,
output reg ps2_kbd_data,
// serial com port
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 [7:0] byte_cnt; // counts bytes
reg [5:0] joystick0;
reg [5:0] joystick1;
reg [3:0] but_sw;
reg [2:0] stick_idx;
assign buttons = but_sw[1:0];
assign switches = but_sw[3:2];
// this variant of user_io is for 8 bit cores (type == a4) only
wire [7:0] core_type = 8'ha4;
// command byte read by the io controller
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
// 8 byte fifo to store ps2 bytes
localparam PS2_FIFO_BITS = 3;
reg [7:0] ps2_fifo [(2**PS2_FIFO_BITS)-1:0];
reg [PS2_FIFO_BITS-1:0] ps2_wptr;
reg [PS2_FIFO_BITS-1:0] ps2_rptr;
// ps2 transmitter state machine
reg [3:0] ps2_tx_state;
reg [7:0] ps2_tx_byte;
reg ps2_parity;
assign ps2_kbd_clk = ps2_clk || (ps2_tx_state == 0);
// ps2 transmitter
// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
reg ps2_r_inc;
always@(posedge ps2_clk) begin
ps2_r_inc <= 1'b0;
if(ps2_r_inc)
ps2_rptr <= ps2_rptr + 1;
// transmitter is idle?
if(ps2_tx_state == 0) begin
// data in fifo present?
if(ps2_wptr != ps2_rptr) begin
// load tx register from fifo
ps2_tx_byte <= ps2_fifo[ps2_rptr];
ps2_r_inc <= 1'b1;
// reset parity
ps2_parity <= 1'b1;
// start transmitter
ps2_tx_state <= 4'd1;
// put start bit on data line
ps2_kbd_data <= 1'b0; // start bit is 0
end
end else begin
// transmission of 8 data bits
if((ps2_tx_state >= 1)&&(ps2_tx_state < 9)) begin
ps2_kbd_data <= ps2_tx_byte[0]; // data bits
ps2_tx_byte[6:0] <= ps2_tx_byte[7:1]; // shift down
if(ps2_tx_byte[0])
ps2_parity <= !ps2_parity;
end
// transmission of parity
if(ps2_tx_state == 9)
ps2_kbd_data <= ps2_parity;
// transmission of stop bit
if(ps2_tx_state == 10)
ps2_kbd_data <= 1'b1; // stop bit is 1
// advance state machine
if(ps2_tx_state < 11)
ps2_tx_state <= ps2_tx_state + 4'd1;
else
ps2_tx_state <= 4'd0;
end
end
// fifo to receive serial data from core to be forwarded to io controller
// 16 byte fifo to store serial bytes
localparam SERIAL_OUT_FIFO_BITS = 6;
reg [7:0] serial_out_fifo [(2**SERIAL_OUT_FIFO_BITS)-1:0];
reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_wptr;
reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_rptr;
wire serial_out_data_available = serial_out_wptr != serial_out_rptr;
wire [7:0] serial_out_byte = serial_out_fifo[serial_out_rptr] /* synthesis keep */;
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff