1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-18 17:06:57 +00:00

Update Mist Modules

This commit is contained in:
Marcel 2021-04-04 14:14:14 +02:00
parent 540d571150
commit b277089158
3 changed files with 528 additions and 36 deletions

View File

@ -1,33 +0,0 @@
Common components for MiST board
================================
This repository contains common components, which should be used by almost all cores.
The modules:
- user_io.v - communicating with the IO controller.
- data_io.v - handling file uploads from the IO controller.
- mist_video.v - a video pipeline, which gives an optional scandoubler, OSD and rgb2ypbpr conversion.
- osd.v, scandoubler.v, rgb2ypbpr.sv, cofi.sv - these are used in mist_video, but can be used separately, too.
- sd_card.v - gives an SPI interface with SD-Card commands towards the IO-Controller, accessing .VHD and other mounted files.
- dac.vhd - a simple sigma-delta DAC for audio output.
- arcade_inputs.v - mostly for arcade-style games, gives access to the joysticks with MAME-style keyboard mapping.
- mist.vhd - VHDL component declarations for user_io and mist_video.
- mist_core.qip - collects the core components, which are needed in almost every case.
Usage hints
===========
All of these components should be clocked by a synchronous clock to the core. The data between the external SPI
interface and this internal clock are synchronized. However to make Quartus' job easier, you have to tell it to
don't try to optimize paths between the SPI and the system clock domain. Also you have to define the incoming
27 MHz and the SPI clocks. These lines in the .sdc file do that:
```
set sys_clk "your_system_clock"
create_clock -name {clk_27} -period 37.037 -waveform { 0.000 18.500 } [get_ports {CLOCK_27[0]}]
create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}]
set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks $sys_clk]
```
Replace "your_system_clock" with the name of the pll clock, like "pll|altpll_component|auto_generated|pll1|clk[0]".

View File

@ -112,10 +112,10 @@ always @(posedge clk) begin
'h06: btn_two_players <= key_pressed; // F2
'h04: btn_three_players <= key_pressed; // F3
'h0C: btn_four_players <= key_pressed; // F4
'h14: btn_fireA <= key_pressed; // ctrl
'h11: btn_fireB <= key_pressed; // alt
'h29: btn_fireC <= key_pressed; // Space
'h12: btn_fireD <= key_pressed; // l-shift
'h14: btn_fireC <= key_pressed; // ctrl
'h11: btn_fireB <= key_pressed; // alt
'h29: btn_fireA <= key_pressed; // Space
'h1A: btn_fireE <= key_pressed; // Z
'h22: btn_fireF <= key_pressed; // X
'h21: btn_fireG <= key_pressed; // C

525
common/mist/sd_card.v Normal file
View File

@ -0,0 +1,525 @@
//
// sd_card.v
//
// This file implelents a sd card for the MIST board since on the board
// the SD card is connected to the ARM IO controller and the FPGA has no
// direct connection to the SD card. This file provides a SD card like
// interface to the IO controller easing porting of cores that expect
// a direct interface to the SD card.
//
// Copyright (c) 2014 Till Harbaum <till@harbaum.org>
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the Lesser GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// http://elm-chan.org/docs/mmc/mmc_e.html
module sd_card (
input clk_sys,
// link to user_io for io controller
output reg[31:0] sd_lba,
output reg sd_rd,
output reg sd_wr,
input sd_ack,
input sd_ack_conf,
output sd_conf,
output sd_sdhc,
input img_mounted,
input [31:0] img_size,
output reg sd_busy = 0,
// data coming in from io controller
input [7:0] sd_buff_dout,
input sd_buff_wr,
// data going out to io controller
output [7:0] sd_buff_din,
input [8:0] sd_buff_addr,
// configuration input
input allow_sdhc,
input sd_cs,
input sd_sck,
input sd_sdi,
output reg sd_sdo
);
wire [31:0] OCR = { 1'b1, sd_sdhc, 6'h0, 9'h1f, 15'h0 }; // bit31 = finished powerup
// bit30 = 1 -> high capaciry card (sdhc)
// 15-23 supported voltage range
wire [7:0] READ_DATA_TOKEN = 8'hfe;
// number of bytes to wait after a command before sending the reply
localparam NCR=4;
localparam RD_STATE_IDLE = 3'd0;
localparam RD_STATE_WAIT_IO = 3'd1;
localparam RD_STATE_SEND_TOKEN = 3'd2;
localparam RD_STATE_SEND_DATA = 3'd3;
localparam RD_STATE_DELAY = 3'd4;
reg [2:0] read_state = RD_STATE_IDLE;
localparam WR_STATE_IDLE = 3'd0;
localparam WR_STATE_EXP_DTOKEN = 3'd1;
localparam WR_STATE_RECV_DATA = 3'd2;
localparam WR_STATE_RECV_CRC0 = 3'd3;
localparam WR_STATE_RECV_CRC1 = 3'd4;
localparam WR_STATE_SEND_DRESP = 3'd5;
localparam WR_STATE_BUSY = 3'd6;
reg [2:0] write_state = WR_STATE_IDLE;
reg card_is_reset = 1'b0; // flag that card has received a reset command
reg [6:0] sbuf;
reg cmd55;
reg terminate_cmd = 1'b0;
reg [7:0] cmd = 8'h00;
reg [2:0] bit_cnt = 3'd0; // counts bits 0-7 0-7 ...
reg [3:0] byte_cnt= 4'd15; // counts bytes
reg [4:0] delay_cnt;
reg [39:0] args;
reg [7:0] reply;
reg [7:0] reply0, reply1, reply2, reply3;
reg [3:0] reply_len;
// ------------------------- SECTOR BUFFER -----------------------
// the buffer itself. Can hold two sectors
reg [9:0] buffer_ptr;
wire [7:0] buffer_dout;
reg [7:0] buffer_din;
reg buffer_write_strobe;
reg sd_buff_sel;
sd_card_dpram #(8, 10) buffer_dpram
(
.clock_a (clk_sys),
.address_a ({sd_buff_sel, sd_buff_addr}),
.data_a (sd_buff_dout),
.wren_a (sd_buff_wr & sd_ack),
.q_a (sd_buff_din),
.clock_b (clk_sys),
.address_b (buffer_ptr),
.data_b (buffer_din),
.wren_b (buffer_write_strobe),
.q_b (buffer_dout)
);
wire [7:0] WRITE_DATA_RESPONSE = 8'h05;
// ------------------------- CSD/CID BUFFER ----------------------
reg [7:0] conf;
assign sd_conf = sd_configuring;
reg sd_configuring = 1;
reg [4:0] conf_buff_ptr;
reg [7:0] conf_byte;
reg[255:0] csdcid;
// conf[0]==1 -> io controller is using an sdhc card
wire sd_has_sdhc = conf[0];
assign sd_sdhc = allow_sdhc && sd_has_sdhc;
always @(posedge clk_sys) begin
reg old_mounted;
if (sd_buff_wr & sd_ack_conf) begin
if (sd_buff_addr == 32) begin
conf <= sd_buff_dout;
sd_configuring <= 0;
end
else csdcid[(31-sd_buff_addr) << 3 +:8] <= sd_buff_dout;
end
conf_byte <= csdcid[(31-conf_buff_ptr) << 3 +:8];
old_mounted <= img_mounted;
if (~old_mounted & img_mounted) begin
// update card size in case of a virtual SD image
if (sd_sdhc)
// CSD V2.0 size = (c_size + 1) * 512K
csdcid[69:48] <= {9'd0, img_size[31:19] };
else begin
// CSD V1.0 no. of blocks = c_size ** (c_size_mult + 2)
csdcid[49:47] <= 3'd7; //c_size_mult
csdcid[73:62] <= img_size[29:18]; //c_size
end
end
end
always@(posedge clk_sys) begin
reg old_sd_sck;
reg [5:0] ack;
ack <= {ack[4:0], sd_ack};
if(ack[5:4] == 'b01) { sd_rd, sd_wr } <= 2'b00;
if(ack[5:4] == 'b10) sd_busy <= 0;
buffer_write_strobe <= 0;
if (buffer_write_strobe) buffer_ptr <= buffer_ptr + 1'd1;
old_sd_sck <= sd_sck;
// advance transmitter state machine on falling sck edge, so data is valid on the
// rising edge
// ----------------- spi transmitter --------------------
if(sd_cs == 0 && old_sd_sck && ~sd_sck) begin
sd_sdo <= 1'b1; // default: send 1's (busy/wait)
if(byte_cnt == 5+NCR) begin
sd_sdo <= reply[~bit_cnt];
if(bit_cnt == 7) begin
// these three commands all have a reply_len of 0 and will thus
// not send more than a single reply byte
// CMD9: SEND_CSD
// CMD10: SEND_CID
if((cmd == 8'h49)||(cmd == 8'h4a))
read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission
// CMD17: READ_SINGLE_BLOCK
// CMD18: READ_MULTIPLE_BLOCK
if((cmd == 8'h51 || cmd == 8'h52) && !terminate_cmd) begin
sd_lba <= sd_sdhc?args[39:8]:{9'd0, args[39:17]};
read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller
sd_rd <= 1; // trigger request to io controller
sd_busy <= 1;
end
end
end
else if((reply_len > 0) && (byte_cnt == 5+NCR+1))
sd_sdo <= reply0[~bit_cnt];
else if((reply_len > 1) && (byte_cnt == 5+NCR+2))
sd_sdo <= reply1[~bit_cnt];
else if((reply_len > 2) && (byte_cnt == 5+NCR+3))
sd_sdo <= reply2[~bit_cnt];
else if((reply_len > 3) && (byte_cnt == 5+NCR+4))
sd_sdo <= reply3[~bit_cnt];
// ---------- read state machine processing -------------
case(read_state)
RD_STATE_IDLE: ;
// don't do anything
// waiting for io controller to return data
RD_STATE_WAIT_IO: begin
buffer_ptr <= 0;
sd_buff_sel <= 0;
if(~sd_busy) begin
if (terminate_cmd) begin
cmd <= 0;
read_state <= RD_STATE_IDLE;
end else if (bit_cnt == 7)
read_state <= RD_STATE_SEND_TOKEN;
end
end
// send data token
RD_STATE_SEND_TOKEN: begin
if(~sd_busy) begin
sd_sdo <= READ_DATA_TOKEN[~bit_cnt];
if(bit_cnt == 7) begin
read_state <= RD_STATE_SEND_DATA; // next: send data
conf_buff_ptr <= (cmd == 8'h4a) ? 5'h0 : 5'h10;
end
end
end
// send data
RD_STATE_SEND_DATA: begin
if(cmd == 8'h51 || (cmd == 8'h52 && !terminate_cmd)) // CMD17: READ_SINGLE_BLOCK, CMD18: READ_MULTIPLE_BLOCK
sd_sdo <= buffer_dout[~bit_cnt];
else if(cmd == 8'h49 || cmd == 8'h4a) // CMD9: SEND_CSD, CMD10: SEND CID
sd_sdo <= conf_byte[~bit_cnt];
if(bit_cnt == 7) begin
// sent 512 sector data bytes?
if((cmd == 8'h51) && &buffer_ptr[8:0])
read_state <= RD_STATE_IDLE; // next: send crc. It's ignored so return to idle state
if (cmd == 8'h52) begin
if (terminate_cmd) begin
read_state <= RD_STATE_IDLE;
cmd <= 0;
end else if (buffer_ptr[8:0] == 10) begin
// prefetch the next sector into the other buffer
sd_lba <= sd_lba + 1'd1;
sd_rd <= 1;
sd_busy <= 1;
sd_buff_sel <= !sd_buff_sel;
end else if (&buffer_ptr[8:0]) begin
delay_cnt <= 20;
read_state <= RD_STATE_DELAY;
end
end
// sent 16 cid/csd data bytes?
if(((cmd == 8'h49)||(cmd == 8'h4a)) && conf_buff_ptr[3:0] == 4'h0f) // && (buffer_rptr == 16))
read_state <= RD_STATE_IDLE; // return to idle state
buffer_ptr <= buffer_ptr + 1'd1;
conf_buff_ptr<= conf_buff_ptr+ 1'd1;
end
end
RD_STATE_DELAY:
if(bit_cnt == 7) begin
if (delay_cnt == 0) begin
read_state <= RD_STATE_SEND_TOKEN;
end else begin
delay_cnt <= delay_cnt - 1'd1;
end
end
endcase
// ------------------ write support ----------------------
// send write data response
if(write_state == WR_STATE_SEND_DRESP)
sd_sdo <= WRITE_DATA_RESPONSE[~bit_cnt];
// busy after write until the io controller sends ack
if(write_state == WR_STATE_BUSY)
sd_sdo <= 1'b0;
end
// spi receiver
// cs is active low
if(sd_cs == 1) begin
bit_cnt <= 3'd0;
terminate_cmd <= 0;
cmd <= 0;
read_state <= RD_STATE_IDLE;
end else if (~old_sd_sck & sd_sck) begin
bit_cnt <= bit_cnt + 3'd1;
// assemble byte
if(bit_cnt != 7)
sbuf[6:0] <= { sbuf[5:0], sd_sdi };
else begin
// finished reading one byte
// byte counter runs against 15 byte boundary
if(byte_cnt != 15)
byte_cnt <= byte_cnt + 4'd1;
// byte_cnt > 6 -> complete command received
// first byte of valid command is 01xxxxxx
// don't accept new commands (except STOP TRANSMISSION) once a write or read command has been accepted
if((byte_cnt > 5) &&
(write_state == WR_STATE_IDLE) &&
(read_state == RD_STATE_IDLE || (read_state != RD_STATE_IDLE && { sbuf, sd_sdi} == 8'h4c)) &&
sbuf[6:5] == 2'b01)
begin
byte_cnt <= 4'd0;
terminate_cmd <= 0;
if ({ sbuf, sd_sdi } == 8'h4c) begin
terminate_cmd <= 1;
end else
cmd <= { sbuf, sd_sdi};
end
// parse additional command bytes
if(byte_cnt == 0) args[39:32] <= { sbuf, sd_sdi};
if(byte_cnt == 1) args[31:24] <= { sbuf, sd_sdi};
if(byte_cnt == 2) args[23:16] <= { sbuf, sd_sdi};
if(byte_cnt == 3) args[15:8] <= { sbuf, sd_sdi};
if(byte_cnt == 4) args[7:0] <= { sbuf, sd_sdi};
// last byte received, evaluate
if(byte_cnt == 5) begin
// default:
reply <= 8'h04; // illegal command
reply_len <= 4'd0; // no extra reply bytes
cmd55 <= 0;
// CMD0: GO_IDLE_STATE
if(cmd == 8'h40) begin
card_is_reset <= 1'b1;
reply <= 8'h01; // ok, busy
end
// every other command is only accepted after a reset
else if(card_is_reset) begin
// CMD12: STOP_TRANSMISSION
if (terminate_cmd)
reply <= 8'h00; // ok
else case(cmd)
// CMD1: SEND_OP_COND
8'h41: reply <= 8'h00; // ok, not busy
// CMD8: SEND_IF_COND (V2 only)
8'h48: begin
reply <= 8'h01; // ok, busy
reply0 <= 8'h00;
reply1 <= 8'h00;
reply2 <= { 4'b0, args[19:16] };
reply3 <= args[15:8];
reply_len <= 4'd4;
end
// CMD9: SEND_CSD
8'h49: reply <= 8'h00; // ok
// CMD10: SEND_CID
8'h4a: reply <= 8'h00; // ok
// CMD13: SEND_STATUS
8'h4d: begin
reply <= 8'h00; // ok
reply0 <=8'h00;
reply_len <= 4'd1;
end
// CMD16: SET_BLOCKLEN
8'h50:
// we only support a block size of 512
if(args[39:8] == 32'd512)
reply <= 8'h00; // ok
else
reply <= 8'h40; // parmeter error
// CMD17: READ_SINGLE_BLOCK
8'h51: reply <= 8'h00; // ok
// CMD18: READ_MULTIPLE_BLOCK
8'h52: reply <= 8'h00; // ok
// CMD24: WRITE_BLOCK
8'h58: begin
reply <= 8'h00; // ok
sd_lba <= sd_sdhc?args[39:8]:{9'd0, args[39:17]};
write_state <= WR_STATE_EXP_DTOKEN; // expect data token
end
// ACMD41: APP_SEND_OP_COND
8'h69: if(cmd55) begin
reply <= 8'h00; // ok, not busy
end
// CMD55: APP_COND
8'h77: begin
reply <= 8'h01; // ok, busy
cmd55 <= 1;
end
// CMD58: READ_OCR
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
endcase
end
end
// ---------- handle write -----------
case(write_state)
// don't do anything in idle state
WR_STATE_IDLE: ;
// waiting for data token
WR_STATE_EXP_DTOKEN:
if({ sbuf, sd_sdi} == 8'hfe ) begin
write_state <= WR_STATE_RECV_DATA;
buffer_ptr <= 0;
sd_buff_sel <= 0;
end
// transfer 512 bytes
WR_STATE_RECV_DATA: begin
// push one byte into local buffer
buffer_write_strobe <= 1'b1;
buffer_din <= { sbuf, sd_sdi };
// all bytes written?
if(&buffer_ptr[8:0])
write_state <= WR_STATE_RECV_CRC0;
end
// transfer 1st crc byte
WR_STATE_RECV_CRC0:
write_state <= WR_STATE_RECV_CRC1;
// transfer 2nd crc byte
WR_STATE_RECV_CRC1:
write_state <= WR_STATE_SEND_DRESP;
// send data response
WR_STATE_SEND_DRESP: begin
write_state <= WR_STATE_BUSY;
sd_wr <= 1; // trigger write request to io ontroller
sd_busy <= 1;
end
// wait for io controller to accept data
WR_STATE_BUSY:
if(~sd_busy)
write_state <= WR_STATE_IDLE;
default: ;
endcase
end
end
end
endmodule
module sd_card_dpram #(parameter DATAWIDTH=8, ADDRWIDTH=9)
(
input clock_a,
input [ADDRWIDTH-1:0] address_a,
input [DATAWIDTH-1:0] data_a,
input wren_a,
output reg [DATAWIDTH-1:0] q_a,
input clock_b,
input [ADDRWIDTH-1:0] address_b,
input [DATAWIDTH-1:0] data_b,
input wren_b,
output reg [DATAWIDTH-1:0] q_b
);
reg [DATAWIDTH-1:0] ram[0:(1<<ADDRWIDTH)-1];
always @(posedge clock_a) begin
q_a <= ram[address_a];
if(wren_a) begin
q_a <= data_a;
ram[address_a] <= data_a;
end
end
always @(posedge clock_b) begin
q_b <= ram[address_b];
if(wren_b) begin
q_b <= data_b;
ram[address_b] <= data_b;
end
end
endmodule