Project

General

Profile

« Previous | Next » 

Revision 229

Added by markw almost 11 years ago

Some 5200 fixes, reverted to data_io mist interface

View differences:

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 == RD_STATE_WAIT_IO);
always @(posedge req_io_rd or posedge io_ack) begin
if(io_ack) io_rd <= 1'b0;
else io_rd <= 1'b1;
end
wire req_io_wr = (write_state == WR_STATE_BUSY);
always @(posedge req_io_wr or posedge io_ack) begin
if(io_ack) io_wr <= 1'b0;
else io_wr <= 1'b1;
end
wire [31:0] OCR = { 1'b0, io_sdhc, 30'h0 }; // bit30 = 1 -> high capaciry card (sdhc)
wire [7:0] READ_DATA_TOKEN = 8'hfe;
localparam NCR=4;
// 0=idle, 1=wait for io ctrl, 2=wait for byte start, 3=send token, 4=send data, 5/6=send crc[0..1]
localparam RD_STATE_IDLE = 3'd0;
localparam RD_STATE_WAIT_IO = 3'd1;
localparam RD_STATE_WAIT_START = 3'd2;
localparam RD_STATE_SEND_TOKEN = 3'd3;
localparam RD_STATE_SEND_DATA = 3'd4;
localparam RD_STATE_SEND_CRC0 = 3'd5;
localparam RD_STATE_SEND_CRC1 = 3'd6;
reg [2:0] read_state = RD_STATE_IDLE;
// 0=idle
localparam WR_STATE_IDLE = 3'd0;
localparam WR_STATE_EXP_DTOKEN = 3'd1;
localparam WR_STATE_RECV_DATA = 3'd2;
localparam WR_STATE_RECV_CRC0 = 3'd3;
localparam WR_STATE_RECV_CRC1 = 3'd4;
localparam WR_STATE_SEND_DRESP = 3'd5;
localparam WR_STATE_BUSY = 3'd6;
reg [2:0] write_state = WR_STATE_IDLE;
reg [6:0] sbuf;
reg cmd55;
reg new_cmd_rcvd;
reg [7:0] cmd;
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
reg [3:0] byte_cnt= 4'd15; // counts bytes
reg [31:0] lba;
assign io_lba = io_sdhc?lba:{9'd0, lba[31:9]};
// 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;
// signals to address buffer on SD card write (data coming from SD spi)
reg write_strobe;
reg [7:0] write_data;
// falling edge of io_ack signals that a sector to be read has been written into
// the sector bufffer by the io controller. This signal is kept set as long
// as the read state machine is in the "wait for io controller" state (state 1)
wire rd_wait_io = (read_state == RD_STATE_WAIT_IO);
reg rd_io_ack = 1'b0 /* synthesis noprune */;
always @(negedge io_ack or negedge rd_wait_io) begin
if(!rd_wait_io) rd_io_ack <= 1'b0;
else rd_io_ack <= 1'b1;
end
wire wr_wait_io = (write_state == WR_STATE_BUSY);
reg wr_io_ack = 1'b0 /* synthesis noprune */;
always @(negedge io_ack or negedge wr_wait_io) begin
if(!wr_wait_io) wr_io_ack <= 1'b0;
else wr_io_ack <= 1'b1;
end
// ------------------------- 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 != RD_STATE_IDLE);
wire writing = (write_state != WR_STATE_IDLE);
// 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 new_cmd_rcvd) begin
if(new_cmd_rcvd == 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 new_cmd_rcvd) begin
if(new_cmd_rcvd == 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); // csd_wptr still 0 -> configuration required
// 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 --------------------
reg rd_io_ackD, wr_io_ackD;
always@(negedge sd_sck or posedge sd_cs) begin
if(sd_cs == 1) begin
// sd_sdo <= 1'b1;
// read_state <= RD_STATE_IDLE;
end else begin
core_buffer_read_strobe <= 1'b0;
// using rd_io_ack directly brings the read state machine into an
// non-existing state every now and then. For unknown reason
rd_io_ackD <= rd_io_ack;
// -------- catch read commmand and reset read state machine ------
if(bit_cnt == 7) begin
if(byte_cnt == 4) begin
// CMD17: READ_SINGLE_BLOCK
if(cmd == 8'h51)
read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller
end
end
if(byte_cnt < 5+NCR) begin
sd_sdo <= 1'b1; // reply $ff -> wait
end else begin
if(byte_cnt == 5+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 <= RD_STATE_SEND_TOKEN; // jump directly to data transmission
end
end
else if((reply_len > 0) && (byte_cnt == 5+NCR+1))
sd_sdo <= reply0[~bit_cnt];
else if((reply_len > 1) && (byte_cnt == 5+NCR+2))
sd_sdo <= reply1[~bit_cnt];
else if((reply_len > 2) && (byte_cnt == 5+NCR+3))
sd_sdo <= reply2[~bit_cnt];
else if((reply_len > 3) && (byte_cnt == 5+NCR+4))
sd_sdo <= reply3[~bit_cnt];
else
sd_sdo <= 1'b1;
// falling edge of io_ack signals end of incoming data stream
if((read_state == RD_STATE_WAIT_IO) && rd_io_ackD)
read_state <= RD_STATE_WAIT_START;
// wait for begin of new byte
else if((read_state == RD_STATE_WAIT_START) && (bit_cnt == 7))
read_state <= RD_STATE_SEND_TOKEN;
// send data token
else if(read_state == RD_STATE_SEND_TOKEN) begin
sd_sdo <= READ_DATA_TOKEN[~bit_cnt];
if(bit_cnt == 7)
read_state <= RD_STATE_SEND_DATA; // next: send data
end
// send data
else if(read_state == RD_STATE_SEND_DATA) 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 <= RD_STATE_SEND_CRC0; // next: send crc
// send 16 cid/csd data bytes?
if(((cmd == 8'h49)||(cmd == 8'h4a)) && (buffer_rptr == 15))
read_state <= RD_STATE_IDLE; // return to idle state
end
end
// send crc[0]
else if(read_state == RD_STATE_SEND_CRC0) begin
sd_sdo <= 1'b1;
if(bit_cnt == 7)
read_state <= RD_STATE_SEND_CRC1; // send second crc byte
end
// send crc[1]
else if(read_state == RD_STATE_SEND_CRC1) begin
sd_sdo <= 1'b1;
if(bit_cnt == 7)
read_state <= RD_STATE_IDLE; // return to idle state
end
// ------------------ write support ----------------------
// send write data response
if(write_state == WR_STATE_SEND_DRESP)
sd_sdo <= WRITE_DATA_RESPONSE[~bit_cnt];
// busy after write until the io controller sends ack
if(write_state == WR_STATE_BUSY)
sd_sdo <= 1'b0;
end
end
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 <= 4'd15;
// write_state <= WR_STATE_IDLE;
// write_strobe <= 1'b0;
end else begin
new_cmd_rcvd <= 1'b0;
write_strobe <= 1'b0;
sbuf[6:0] <= { sbuf[5:0], sd_sdi };
bit_cnt <= bit_cnt + 3'd1;
// using wr_io_ack directly brings the write state machine into an
// non-existing state every now and then. For unknown reason
wr_io_ackD <= wr_io_ack;
// finished reading command byte
if(bit_cnt == 7) begin
// byte counter runs against 15 byte boundary
if(byte_cnt != 15)
byte_cnt <= byte_cnt + 8'd1;
// byte_cnt > 6 -> complete command received
// first byte of valid command is 01xxxxxx
if((byte_cnt > 5) && (write_state == WR_STATE_IDLE) && sbuf[6:5] == 2'b01)
byte_cnt <= 4'd0;
// don't accept new commands once a write command has been accepted
if((write_state == WR_STATE_IDLE) && (byte_cnt > 5)&&(sbuf[6:5] == 2'b01)) begin
cmd <= { sbuf, sd_sdi};
new_cmd_rcvd <= 1'b1;
// set cmd55 flag if previous command was 55
cmd55 <= (cmd == 8'h77);
end
// parse additional command bytes
if(byte_cnt == 0) lba[31:24] <= { sbuf, sd_sdi};
if(byte_cnt == 1) lba[23:16] <= { sbuf, sd_sdi};
if(byte_cnt == 2) lba[15:8] <= { sbuf, sd_sdi};
if(byte_cnt == 3) lba[7:0] <= { sbuf, sd_sdi};
// last byte received, evaluate
if(byte_cnt == 4) begin
// crc is currently unused
crc <= { sbuf, sd_sdi};
// 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 <= WR_STATE_EXP_DTOKEN; // expect data token
end
// ACMD41: APP_SEND_OP_COND
else if(cmd55 && (cmd == 8'h69))
reply <= 8'h00; // ok, not busy
// CMD55: APP_COND
else if(cmd == 8'h77)
reply <= 8'h01; // ok, busy
// CMD58: READ_OCR
else if(cmd == 8'h7a) begin
reply <= 8'h00; // ok
reply0 <= OCR[31:24]; // bit 30 = 1 -> high capacity card
reply1 <= OCR[23:16];
reply2 <= OCR[15:8];
reply3 <= OCR[7:0];
reply_len <= 4'd4;
end
end
// ---------- handle write -----------
// waiting for data token
if(write_state == WR_STATE_EXP_DTOKEN) begin
if({ sbuf, sd_sdi} == 8'hfe )
write_state <= WR_STATE_RECV_DATA;
end
// transfer 512 bytes
if(write_state == WR_STATE_RECV_DATA) begin
// push one byte into local buffer
write_strobe <= 1'b1;
write_data <= { sbuf, sd_sdi};
if(buffer_wptr == 511)
write_state <= WR_STATE_RECV_CRC0;
end
// transfer 1st crc byte
if(write_state == WR_STATE_RECV_CRC0)
write_state <= WR_STATE_RECV_CRC1;
// transfer 2nd crc byte
if(write_state == WR_STATE_RECV_CRC1)
write_state <= WR_STATE_SEND_DRESP;
// send data response
if(write_state == WR_STATE_SEND_DRESP)
write_state <= WR_STATE_BUSY;
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 == WR_STATE_BUSY && wr_io_ackD)
write_state <= WR_STATE_IDLE;
end
end
endmodule
mist_5200/atari800core.qsf
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
set_global_assignment -name VHDL_FILE data_io.vhdl
set_global_assignment -name VHDL_FILE zpu_rom.vhdl
set_global_assignment -name SDC_FILE atari800core.sdc
set_global_assignment -name QIP_FILE mist_sector_buffer.qip
set_global_assignment -name VHDL_FILE atari800core_mist.vhd
set_global_assignment -name VERILOG_FILE sd_card.v
set_global_assignment -name VERILOG_FILE user_io.v
set_global_assignment -name QIP_FILE pll_pal_pre.qip
set_global_assignment -name QIP_FILE pll_pal_post.qip
mist_5200/atari800core_mist.vhd
);
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 PS2_CLK : std_logic;
SIGNAL PS2_DAT : std_logic;
SIGNAL CONSOL_OPTION_RAW : STD_LOGIC;
SIGNAL CONSOL_OPTION : STD_LOGIC;
SIGNAL CONSOL_SELECT_RAW : STD_LOGIC;
SIGNAL CONSOL_SELECT : STD_LOGIC;
SIGNAL CONSOL_START_RAW : STD_LOGIC;
SIGNAL CONSOL_START : STD_LOGIC;
SIGNAL FKEYS : std_logic_vector(11 downto 0);
signal capslock_pressed : std_logic;
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);
-- 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;
-- 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;
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
spi_do <= spi_miso_io when CONF_DATA0 ='0' else 'Z';
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);
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,
......
JOYSTICK_ANALOG_1(7 downto 0) => joy1y,
BUTTONS => mist_buttons,
SWITCHES => mist_switches,
STATUS => open,
PS2_CLK => SLOW_PS2_CLK,
PS2_KBD_CLK => ps2_clk,
PS2_KBD_DATA => ps2_dat,
STATUS => open,
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
sd_lba => (others=>'0'),
sd_rd => '0',
sd_wr => '0',
sd_conf => '0',
sd_sdhc => '0',
sd_din => (others=>'0')
);
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));
joy1_n <= not(joy1(5)&joy1(3 downto 0));
joy2_n <= not(joy2(5)&joy2(3 downto 0));
-- PS2 to pokey
keyboard_map1 : entity work.ps2_to_atari5200
......
PS2_CLK => ps2_clk,
PS2_DAT => ps2_dat,
FIRE2 => '0'&'0'&joy2(5)&joy1(5),
FIRE2 => '0'&'0'&joy2(4)&joy1(4),
CONTROLLER_SELECT => CONTROLLER_SELECT, -- selected stick keyboard/shift button
KEYBOARD_SCAN => KEYBOARD_SCAN,
......
FKEYS => FKEYS
);
-- stick 0: consol(1 downto 0)="00"
--keyboard_map1 : entity work.ps2_to_atari800
-- PORT MAP
-- (
-- CLK => clk,
-- RESET_N => reset_n,
-- PS2_CLK => ps2_clk,
-- PS2_DAT => ps2_dat,
--
-- KEYBOARD_SCAN => KEYBOARD_SCAN,
-- KEYBOARD_RESPONSE => KEYBOARD_RESPONSE,
--
-- CONSOL_START => CONSOL_START_RAW,
-- CONSOL_SELECT => CONSOL_SELECT_RAW,
-- CONSOL_OPTION => CONSOL_OPTION_RAW,
--
-- FKEYS => FKEYS
-- );
joy_still <= joy1_n(3) and joy1_n(2) and joy1_n(1) and joy1_n(0); -- TODO, need something better here I think! e.g. keypad? 5200 not centreing
CONSOL_START <= CONSOL_START_RAW or (mist_buttons(1) and not(joy1_n(4)));
joy_still <= joy1_n(3) and joy1_n(2) and joy1_n(1) and joy1_n(0);
CONSOL_SELECT <= CONSOL_SELECT_RAW or (mist_buttons(1) and joy1_n(4) and not(joy_still));
CONSOL_OPTION <= CONSOL_OPTION_RAW or (mist_buttons(1) and joy1_n(4) and joy_still);
dac_left : hq_dac
port map
......
-- JOYSTICK
JOY1_X => signed(joy1x),
JOY1_Y => signed(joy1y),
JOY1_BUTTON => joy1(4),
JOY1_BUTTON => joy1_n(4),
JOY2_X => signed(joy2x),
JOY2_Y => signed(joy2y),
JOY2_BUTTON => joy2(4),
JOY2_BUTTON => joy2_n(4),
-- Pokey keyboard matrix
-- Standard component available to connect this to PS2
......
GENERIC MAP
(
platform => 1,
spi_clock_div => 16 -- 28MHz/2. Max for SD cards is 25MHz...
spi_clock_div => 1 -- 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,
ZPU_ROM_DATA => zpu_rom_data_mux,
ZPU_ROM_WREN => open,
ZPU_ROM_WREN => zpu_rom_wren, -- special for mist...
-- spi master
ZPU_SD_DAT0 => mist_sd_sdo,
ZPU_SD_CLK => mist_sd_sck,
ZPU_SD_CMD => mist_sd_sdi,
ZPU_SD_DAT3 => mist_sd_cs,
-- not used for mist...
ZPU_SD_DAT0 => '0',
ZPU_SD_CLK => open,
ZPU_SD_CMD => open,
ZPU_SD_DAT3 => open,
-- 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"00000000",
ZPU_IN4 => X"000000"&"0000000"&mist_sector_ready_sync,
-- 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/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;
mist_5200/zpu_rom.vhdl
X"00000000",
X"00000000",
X"71fc0608",
X"0b0b80e5",
X"d0738306",
X"0b0b80dd",
X"d8738306",
X"10100508",
X"060b0b0b",
X"88a20400",
......
X"00000000",
X"00000000",
X"00000000",
X"810b80e8",
X"f00c5104",
X"810b80e0",
X"f80c5104",
X"00000000",
X"00000000",
X"00000000",
......
X"83e08008",
X"83e08408",
X"83e08808",
X"757580df",
X"fe2d5050",
X"757580d8",
X"872d5050",
X"83e08008",
X"5683e088",
X"0c83e084",
......
X"e0800883",
X"e0840883",
X"e0880875",
X"7580de92",
X"7580d69b",
X"2d505083",
X"e0800856",
X"83e0880c",
......
X"51040000",
X"800489aa",
X"0489aa0b",
X"80d9d404",
X"80cfd504",
X"f43d0d7e",
X"8f3dec11",
X"56565890",
X"53f01552",
X"775193b0",
X"775193ae",
X"3f83e080",
X"0880d638",
X"78902e09",
X"810680cd",
X"3802ab05",
X"3380e8f8",
X"0b80e8f8",
X"3380e180",
X"0b80e180",
X"33575856",
X"8c397476",
X"2e8a3884",
......
X"56705556",
X"5696800a",
X"52775192",
X"df3f83e0",
X"dd3f83e0",
X"80088638",
X"78752e85",
X"38805685",
......
X"800c8e3d",
X"0d04fc3d",
X"0d767052",
X"55b3923f",
X"55b3903f",
X"83e08008",
X"15ff0554",
X"73752e8e",
......
X"38ff1454",
X"ef397752",
X"811451b2",
X"aa3f83e0",
X"a83f83e0",
X"80083070",
X"83e08008",
X"07802583",
......
X"863d0d04",
X"fc3d0d76",
X"70525599",
X"cb3f83e0",
X"c93f83e0",
X"80085481",
X"5383e080",
X"0880c738",
X"7451998e",
X"7451998c",
X"3f83e080",
X"080b0b80",
X"e7b05383",
X"dfb85383",
X"e0800852",
X"53ff8f3f",
X"83e08008",
X"a5380b0b",
X"80e7b452",
X"80dfbc52",
X"7251fefe",
X"3f83e080",
X"0894380b",
X"0b80e7b8",
X"0b80dfc0",
X"527251fe",
X"ed3f83e0",
X"8008802e",
......
X"e0800c86",
X"3d0d04fd",
X"3d0d7570",
X"525498e4",
X"525498e2",
X"3f815383",
X"e0800898",
X"38735198",
X"ad3f83e0",
X"ab3f83e0",
X"a0085283",
X"e0800851",
X"feb43f83",
......
X"0c853d0d",
X"04e03d0d",
X"a33d0870",
X"525e8ed3",
X"525e8ed1",
X"3f83e080",
X"0833943d",
X"56547394",
X"3880ea80",
X"3880e288",
X"52745184",
X"c7397d52",
X"785191d6",
X"3f84d139",
X"7d518ebb",
X"c6397d52",
X"785191d4",
X"3f84d039",
X"7d518eb9",
X"3f83e080",
X"08527451",
X"8deb3f83",
X"8de93f83",
X"e0a80852",
X"933d7052",
X"5d94c63f",
X"5d94c43f",
X"83e08008",
X"59800b83",
X"e0800855",
X"5b83e080",
X"087b2e94",
X"38811b74",
X"525b97c7",
X"525b97c5",
X"3f83e080",
X"085483e0",
X"8008ee38",
......
X"5a525555",
X"80752595",
X"38765197",
X"863f83e0",
X"843f83e0",
X"800876ff",
X"18585557",
X"738024ed",
X"38747f2e",
X"873880c2",
X"db3f745f",
X"78ff1b70",
X"585d5880",
X"7a259538",
X"775196db",
X"8638b8dd",
X"3f745f78",
X"ff1b7058",
X"5d58807a",
X"25953877",
X"5196da3f",
X"83e08008",
X"76ff1858",
X"55587380",
X"24ed3880",
X"0b83e3a8",
X"0c800b83",
X"e3cc0c0b",
X"0b80dfc4",
X"518bad3f",
X"81800b83",
X"e3cc0c0b",
X"0b80dfcc",
X"518b9d3f",
X"a80b83e3",
X"a80c7680",
X"2e80e838",
X"83e3a808",
X"77793270",
X"30707207",
X"80257087",
X"2b83e3cc",
X"0c515678",
X"53565696",
X"8d3f83e0",
X"8008802e",
X"8a380b0b",
X"80dfd451",
X"8ae23f76",
X"5195cd3f",
X"83e08008",
X"520b0b80",
X"e088518a",
X"cf3f7651",
X"95d33f83",
X"e0800883",
X"e3a80855",
X"57757425",
X"8638a816",
X"56f73975",
X"83e3a80c",
X"86f07624",
X"ff943887",
X"980b83e3",
X"a80c7780",
X"2eb73877",
X"5195893f",
X"83e08008",
X"78525595",
X"a93f0b0b",
X"80dfdc54",
X"83e08008",
X"8f388739",
X"807634fd",
X"96390b0b",
X"80dfd854",
X"74537352",
X"0b0b80df",
X"a85189e8",
X"3f80540b",
X"0b80dfb0",
X"5189dd3f",
X"81145473",
X"a82e0981",
X"06ed3886",
X"8da051b4",
X"d33f8052",
X"903d7052",
X"5480c2e7",
X"3f835273",
X"5180c2df",
X"3f61802e",
X"80ff387b",
X"5473ff2e",
X"96387880",
X"2e818038",
X"785194a9",
X"3f83e080",
X"0876ff18",
X"58555873",
X"8024ed38",
X"800b83e7",
X"bc0c800b",
X"83e7e00c",
X"0b0b80e7",
X"bc518bae",
X"3f81800b",
X"83e7e00c",
X"0b0b80e7",
X"c4518b9e",
X"3fa80b83",
X"e7bc0c76",
X"802e80e8",
X"3883e7bc",
X"08777932",
X"70307072",
X"07802570",
X"872b83e7",
X"e00c5156",
X"78535656",
X"968e3f83",
X"e0800880",
X"2e8a380b",
X"0b80e7cc",
X"518ae33f",
X"765195ce",
X"3f83e080",
X"08520b0b",
X"80e88051",
X"8ad03f76",
X"5195d43f",
X"08ff1555",
X"59e73978",
X"802e80eb",
X"38785194",
X"a53f83e0",
X"8008802e",
X"fc843878",
X"5193ed3f",
X"83e08008",
X"83e7bc08",
X"55577574",
X"258638a8",
X"1656f739",
X"7583e7bc",
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff