mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-06 08:04:41 +00:00
BBC: standard clocks only in sd_card and user_io
This commit is contained in:
@@ -133,7 +133,7 @@ set_location_assignment PIN_65 -to AUDIO_L
|
||||
set_location_assignment PIN_80 -to AUDIO_R
|
||||
|
||||
set_global_assignment -name ENABLE_SIGNALTAP OFF
|
||||
set_global_assignment -name USE_SIGNALTAP_FILE signal_tap.stp
|
||||
set_global_assignment -name USE_SIGNALTAP_FILE output_files/stp2.stp
|
||||
set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF
|
||||
set_global_assignment -name ENABLE_NCE_PIN OFF
|
||||
set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF
|
||||
@@ -185,6 +185,7 @@ set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_clock_div-c
|
||||
set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_clock_div.vhd"
|
||||
set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_attenuator-c.vhd"
|
||||
set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_attenuator.vhd"
|
||||
set_global_assignment -name VERILOG_FILE sd_card.v
|
||||
set_global_assignment -name VERILOG_FILE user_io.v
|
||||
set_global_assignment -name VERILOG_FILE osd.v
|
||||
set_global_assignment -name VERILOG_FILE data_io.v
|
||||
@@ -197,4 +198,4 @@ set_global_assignment -name QIP_FILE smmc.qip
|
||||
set_global_assignment -name QIP_FILE os12.qip
|
||||
set_global_assignment -name QIP_FILE basic2.qip
|
||||
set_global_assignment -name QIP_FILE dfs09.qip
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
|
||||
@@ -34,7 +34,7 @@ module bbc_mist_top(
|
||||
|
||||
|
||||
// SPI
|
||||
inout SPI_DO,
|
||||
output SPI_DO,
|
||||
input SPI_DI,
|
||||
input SPI_SCK,
|
||||
input SPI_SS2, // data_io
|
||||
@@ -157,6 +157,8 @@ wire [7:0] sd_dout;
|
||||
wire sd_dout_strobe;
|
||||
wire [7:0] sd_din;
|
||||
wire sd_din_strobe;
|
||||
wire [8:0] sd_buff_addr;
|
||||
wire sd_ack_conf;
|
||||
|
||||
wire [7:0] joystick_0;
|
||||
wire [7:0] joystick_1;
|
||||
@@ -167,8 +169,9 @@ wire scandoubler_disable;
|
||||
|
||||
user_io #(.STRLEN(CONF_STR_LEN)) user_io(
|
||||
.conf_str ( CONF_STR ),
|
||||
// the spi interface
|
||||
.clk_sys(clk_32m),
|
||||
|
||||
// the spi interface
|
||||
.SPI_CLK ( SPI_SCK ),
|
||||
.SPI_SS_IO ( CONF_DATA0 ),
|
||||
.SPI_MISO ( SPI_DO ), // tristate handling inside user_io
|
||||
@@ -196,6 +199,8 @@ user_io #(.STRLEN(CONF_STR_LEN)) user_io(
|
||||
.sd_dout_strobe(sd_dout_strobe ),
|
||||
.sd_din ( sd_din ),
|
||||
.sd_din_strobe (sd_din_strobe ),
|
||||
.sd_buff_addr (sd_buff_addr ),
|
||||
.sd_ack_conf (sd_ack_conf ),
|
||||
|
||||
.ps2_clk ( clk_14k ),
|
||||
.ps2_kbd_clk ( ps2_clk ),
|
||||
@@ -211,18 +216,21 @@ assign user_via_cb1_in = user_via_pb_out[1];
|
||||
|
||||
sd_card sd_card (
|
||||
// connection to io controller
|
||||
.clk(clk_32m),
|
||||
.io_lba (sd_lba ),
|
||||
.io_rd (sd_rd),
|
||||
.io_wr (sd_wr),
|
||||
.io_ack (sd_ack),
|
||||
.io_ack_conf (sd_ack_conf ),
|
||||
.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),
|
||||
.io_buff_addr (sd_buff_addr ),
|
||||
|
||||
.allow_sdhc ( 1'b0), // SDHC not supported
|
||||
.allow_sdhc ( 1'b1), // SDHC not supported
|
||||
|
||||
// connection to local CPU
|
||||
.sd_cs ( sd_cs ),
|
||||
@@ -459,6 +467,7 @@ wire sideways_ram =
|
||||
|
||||
// status[2] is '1' of low mapping is selected in the menu
|
||||
wire basic_map = status[2]?(mem_romsel == 4'h0):(mem_romsel == 4'he);
|
||||
//wire smmc_map = 0;
|
||||
wire smmc_map = status[2]?(mem_romsel == 4'h2):(mem_romsel == 4'hc);
|
||||
|
||||
assign mem_di =
|
||||
|
||||
@@ -25,25 +25,29 @@
|
||||
// http://elm-chan.org/docs/mmc/mmc_e.html
|
||||
|
||||
module sd_card (
|
||||
input clk,
|
||||
// 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,
|
||||
|
||||
input io_ack,
|
||||
input io_ack_conf,
|
||||
output io_conf,
|
||||
output io_sdhc,
|
||||
|
||||
// data coming in from io controller
|
||||
input [7:0] io_din,
|
||||
input io_din_strobe,
|
||||
input [7:0] io_din,
|
||||
input io_din_strobe,
|
||||
|
||||
// data going out to io controller
|
||||
output [7:0] io_dout,
|
||||
input io_dout_strobe,
|
||||
output [7:0] io_dout,
|
||||
input io_dout_strobe,
|
||||
|
||||
input [8:0] io_buff_addr,
|
||||
|
||||
// configuration input
|
||||
input allow_sdhc,
|
||||
|
||||
|
||||
input sd_cs,
|
||||
input sd_sck,
|
||||
input sd_sdi,
|
||||
@@ -53,15 +57,23 @@ module sd_card (
|
||||
// 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)
|
||||
reg req_io_rd = 1'b0; // set when write_state is changed to 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
|
||||
|
||||
reg req_io_wr = 1'b0; // set when write_state is changed to 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;
|
||||
|
||||
always @(posedge clk) begin
|
||||
reg old_io_ack;
|
||||
reg req_io_rdD;
|
||||
reg req_io_wrD;
|
||||
|
||||
old_io_ack <= io_ack;
|
||||
req_io_rdD <= req_io_rd;
|
||||
req_io_wrD <= req_io_wr;
|
||||
|
||||
if(~old_io_ack & io_ack) { io_rd, io_wr } <= 2'b00;
|
||||
else begin
|
||||
if (~req_io_rdD & req_io_rd) io_rd <= 1;
|
||||
if (~req_io_wrD & req_io_wr) io_wr <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
wire [31:0] OCR = { 1'b0, io_sdhc, 30'h0 }; // bit30 = 1 -> high capaciry card (sdhc)
|
||||
@@ -88,7 +100,6 @@ 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 new_cmd_rcvd;
|
||||
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
|
||||
@@ -104,118 +115,92 @@ reg [3:0] reply_len;
|
||||
// the sector buffer 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_IDLE);
|
||||
reg rd_io_ack_i = 1'b0;
|
||||
always @(negedge io_ack or negedge rd_wait_io) begin
|
||||
if(!rd_wait_io) rd_io_ack_i <= 1'b0;
|
||||
else rd_io_ack_i <= 1'b1;
|
||||
end
|
||||
reg rd_io_ack = 1'b0;
|
||||
|
||||
wire wr_wait_io = (write_state == WR_STATE_BUSY);
|
||||
reg wr_io_ack_i = 1'b0;
|
||||
always @(negedge io_ack or negedge wr_wait_io) begin
|
||||
if(!wr_wait_io) wr_io_ack_i <= 1'b0;
|
||||
else wr_io_ack_i <= 1'b1;
|
||||
end
|
||||
reg wr_io_ack = 1'b0;
|
||||
|
||||
// bring xx_io_ack into sd cards clock domain
|
||||
reg wr_io_ack;
|
||||
reg rd_io_ack;
|
||||
always @(posedge sd_sck) begin
|
||||
rd_io_ack <= rd_io_ack_i;
|
||||
wr_io_ack <= wr_io_ack_i;
|
||||
always @(posedge clk) begin
|
||||
reg old_io_ack;
|
||||
old_io_ack <= io_ack;
|
||||
|
||||
if(!wr_wait_io) wr_io_ack <= 1'b0;
|
||||
else if (~io_ack & old_io_ack) begin
|
||||
wr_io_ack <= 1'b1;
|
||||
end
|
||||
|
||||
if(!rd_wait_io) rd_io_ack <= 1'b0;
|
||||
else if (~io_ack & old_io_ack) begin
|
||||
rd_io_ack <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// ------------------------- SECTOR BUFFER -----------------------
|
||||
|
||||
// the buffer itself. Can hold one sector
|
||||
reg [7:0] buffer [511:0];
|
||||
reg [8:0] buffer_ptr;
|
||||
wire [7:0] buffer_dout;
|
||||
reg [7:0] buffer_din;
|
||||
reg buffer_write_strobe;
|
||||
|
||||
// ---------------- buffer read engine -----------------------
|
||||
reg [8:0] buffer_rptr;
|
||||
reg buffer_read_strobe;
|
||||
wire buffer_dout_strobe = buffer_read_strobe || io_dout_strobe;
|
||||
reg [7:0] buffer_dout;
|
||||
assign io_dout = buffer_dout;
|
||||
sd_card_dpram #(8, 9) buffer_dpram
|
||||
(
|
||||
.clock_a (clk),
|
||||
.address_a (io_buff_addr),
|
||||
.data_a (io_din),
|
||||
.wren_a (io_din_strobe & io_ack),
|
||||
.q_a (io_dout),
|
||||
|
||||
// buffer_rptr is increased in a diferent clock domain than it's
|
||||
// evaluated. These single bit registers bring certain states from
|
||||
// one domain into the other one in a safe (atomic) way
|
||||
reg buffer_read_sector_done;
|
||||
reg buffer_read_ciscid_done;
|
||||
|
||||
always @(posedge buffer_dout_strobe or posedge new_cmd_rcvd) begin
|
||||
if(new_cmd_rcvd == 1) begin
|
||||
buffer_rptr <= 9'd0;
|
||||
buffer_read_sector_done <= 1'b0;
|
||||
buffer_read_ciscid_done <= 1'b0;
|
||||
end else begin
|
||||
buffer_dout <= buffer[buffer_rptr];
|
||||
buffer_rptr <= buffer_rptr + 9'd1;
|
||||
if(buffer_rptr == 511) buffer_read_sector_done <= 1'b1;
|
||||
if(buffer_rptr == 15) buffer_read_ciscid_done <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// ---------------- buffer write engine -----------------------
|
||||
reg [8:0] buffer_wptr;
|
||||
reg buffer_write_strobe;
|
||||
wire buffer_din_strobe = io_din_strobe || buffer_write_strobe;
|
||||
wire [7:0] buffer_din = (cmd == 8'h51)?io_din:{sbuf, sd_sdi};
|
||||
|
||||
always @(posedge buffer_din_strobe or posedge new_cmd_rcvd) begin
|
||||
if(new_cmd_rcvd == 1)
|
||||
buffer_wptr <= 9'd0;
|
||||
else begin
|
||||
buffer[buffer_wptr] <= buffer_din;
|
||||
buffer_wptr <= buffer_wptr + 9'd1;
|
||||
end
|
||||
end
|
||||
.clock_b (clk),
|
||||
.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 ----------------------
|
||||
assign io_conf = (csd_wptr == 0); // csd_wptr still 0 -> configuration required
|
||||
reg [7:0] conf;
|
||||
assign io_conf = io_configuring;
|
||||
|
||||
// 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 io_configuring = 1;
|
||||
reg [4:0] conf_buff_ptr;
|
||||
wire [7:0] conf_byte;
|
||||
|
||||
reg [7:0] cid_byte;
|
||||
reg [7:0] csd_byte;
|
||||
reg [5:0] csd_wptr = 6'd0;
|
||||
sd_card_dpram #(8, 6) conf_dpram
|
||||
(
|
||||
.clock_a (clk),
|
||||
.address_a (io_buff_addr),
|
||||
.data_a (io_din),
|
||||
.wren_a (io_din_strobe & io_ack_conf),
|
||||
|
||||
.clock_b (clk),
|
||||
.address_b (conf_buff_ptr),
|
||||
.q_b (conf_byte)
|
||||
);
|
||||
|
||||
// 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 @(posedge 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[3:0]] <= io_din;
|
||||
if((csd_wptr >= 16) && (csd_wptr < 32)) // then comes csd
|
||||
csd[csd_wptr[3:0]] <= io_din;
|
||||
if(csd_wptr == 32) // finally a config byte
|
||||
conf <= io_din;
|
||||
|
||||
csd_wptr <= csd_wptr + 6'd1;
|
||||
always @(posedge clk) begin
|
||||
if(io_din_strobe && io_ack_conf && io_buff_addr== 32) begin
|
||||
conf <= io_din;
|
||||
io_configuring <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge buffer_dout_strobe) begin
|
||||
cid_byte <= cid[buffer_rptr[3:0]];
|
||||
csd_byte <= csd[buffer_rptr[3:0]];
|
||||
end
|
||||
|
||||
// ----------------- spi transmitter --------------------
|
||||
|
||||
always@(posedge clk) begin
|
||||
|
||||
reg illegal_write_state /* synthesis noprune */;
|
||||
reg old_sd_sck;
|
||||
old_sd_sck <= sd_sck;
|
||||
// advance transmitter state machine on falling sck edge, so data is valid on the
|
||||
// rising edge
|
||||
always@(negedge sd_sck) begin
|
||||
if(sd_cs == 0) begin
|
||||
buffer_read_strobe <= 1'b0;
|
||||
// ----------------- spi transmitter --------------------
|
||||
if(sd_cs == 0 && old_sd_sck && ~sd_sck) begin
|
||||
|
||||
sd_sdo <= 1'b1; // default: send 1's (busy/wait)
|
||||
req_io_rd <= 1'b0;
|
||||
|
||||
@@ -257,8 +242,10 @@ always@(negedge sd_sck) begin
|
||||
|
||||
// waiting for io controller to return data
|
||||
RD_STATE_WAIT_IO: begin
|
||||
buffer_ptr <= 0;
|
||||
if(rd_io_ack && (bit_cnt == 7))
|
||||
read_state <= RD_STATE_SEND_TOKEN;
|
||||
|
||||
end
|
||||
|
||||
// send data token
|
||||
@@ -267,7 +254,7 @@ always@(negedge sd_sck) begin
|
||||
|
||||
if(bit_cnt == 7) begin
|
||||
read_state <= RD_STATE_SEND_DATA; // next: send data
|
||||
buffer_read_strobe <= 1'b1; // trigger read of first data byte
|
||||
conf_buff_ptr <= (cmd == 8'h4a) ? 5'h0 : 5'h10;
|
||||
end
|
||||
end
|
||||
|
||||
@@ -276,27 +263,29 @@ always@(negedge sd_sck) begin
|
||||
if(cmd == 8'h51) // CMD17: READ_SINGLE_BLOCK
|
||||
sd_sdo <= buffer_dout[~bit_cnt];
|
||||
else if(cmd == 8'h49) // CMD9: SEND_CSD
|
||||
sd_sdo <= csd_byte[~bit_cnt];
|
||||
sd_sdo <= conf_byte[~bit_cnt];
|
||||
else if(cmd == 8'h4a) // CMD10: SEND_CID
|
||||
sd_sdo <= cid_byte[~bit_cnt];
|
||||
sd_sdo <= conf_byte[~bit_cnt];
|
||||
else
|
||||
sd_sdo <= 1'b1;
|
||||
|
||||
if(bit_cnt == 7) begin
|
||||
// sent 512 sector data bytes?
|
||||
if((cmd == 8'h51) && buffer_read_sector_done) // (buffer_rptr == 0))
|
||||
if((cmd == 8'h51) && &buffer_ptr) // (buffer_ptr ==511))
|
||||
read_state <= RD_STATE_IDLE; // next: send crc. It's ignored so return to idle state
|
||||
|
||||
|
||||
// sent 16 cid/csd data bytes?
|
||||
else if(((cmd == 8'h49)||(cmd == 8'h4a)) && buffer_read_ciscid_done) // && (buffer_rptr == 16))
|
||||
else 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
|
||||
|
||||
else
|
||||
buffer_read_strobe <= 1'b1; // not done yet -> trigger read of next data byte
|
||||
|
||||
else begin
|
||||
buffer_ptr <= buffer_ptr + 1'd1;
|
||||
conf_buff_ptr<= conf_buff_ptr+ 1'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
|
||||
// ------------------ write support ----------------------
|
||||
// send write data response
|
||||
if(write_state == WR_STATE_SEND_DRESP)
|
||||
@@ -306,19 +295,18 @@ always@(negedge sd_sck) begin
|
||||
if(write_state == WR_STATE_BUSY)
|
||||
sd_sdo <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// spi receiver
|
||||
reg illegal_write_state /* synthesis noprune */;
|
||||
if (buffer_write_strobe) begin
|
||||
buffer_write_strobe <= 1'b0;
|
||||
buffer_ptr <= buffer_ptr + 1'd1;
|
||||
end
|
||||
|
||||
always @(posedge sd_sck or posedge sd_cs) begin
|
||||
// spi receiver
|
||||
// cs is active low
|
||||
if(sd_cs == 1) begin
|
||||
bit_cnt <= 3'd0;
|
||||
end else begin
|
||||
end else if (~old_sd_sck & sd_sck) begin
|
||||
illegal_write_state <= 1'b0;
|
||||
new_cmd_rcvd <= 1'b0;
|
||||
buffer_write_strobe <= 1'b0;
|
||||
req_io_wr <= 1'b0;
|
||||
bit_cnt <= bit_cnt + 3'd1;
|
||||
|
||||
@@ -338,7 +326,6 @@ always @(posedge sd_sck or posedge sd_cs) begin
|
||||
(read_state == RD_STATE_IDLE) && sbuf[6:5] == 2'b01) begin
|
||||
byte_cnt <= 4'd0;
|
||||
cmd <= { sbuf, sd_sdi};
|
||||
new_cmd_rcvd <= 1'b1;
|
||||
|
||||
// set cmd55 flag if previous command was 55
|
||||
cmd55 <= (cmd == 8'h77);
|
||||
@@ -434,16 +421,19 @@ always @(posedge sd_sck or posedge sd_cs) begin
|
||||
|
||||
// waiting for data token
|
||||
WR_STATE_EXP_DTOKEN:
|
||||
if({ sbuf, sd_sdi} == 8'hfe )
|
||||
if({ sbuf, sd_sdi} == 8'hfe ) begin
|
||||
write_state <= WR_STATE_RECV_DATA;
|
||||
buffer_ptr <= 9'd0;
|
||||
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_wptr == 511)
|
||||
if(&buffer_ptr)
|
||||
write_state <= WR_STATE_RECV_CRC0;
|
||||
end
|
||||
|
||||
@@ -465,7 +455,7 @@ always @(posedge sd_sck or posedge sd_cs) begin
|
||||
WR_STATE_BUSY:
|
||||
if(wr_io_ack)
|
||||
write_state <= WR_STATE_IDLE;
|
||||
|
||||
|
||||
default:
|
||||
illegal_write_state <= 1'b1;
|
||||
endcase
|
||||
@@ -474,3 +464,38 @@ always @(posedge sd_sck or posedge sd_cs) begin
|
||||
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
|
||||
@@ -25,9 +25,10 @@
|
||||
module user_io #(parameter STRLEN=0) (
|
||||
input [(8*STRLEN)-1:0] conf_str,
|
||||
|
||||
input clk_sys,
|
||||
input SPI_CLK,
|
||||
input SPI_SS_IO,
|
||||
output reg SPI_MISO,
|
||||
output reg SPI_MISO,
|
||||
input SPI_MOSI,
|
||||
|
||||
output reg [7:0] joystick_0,
|
||||
@@ -41,17 +42,18 @@ module user_io #(parameter STRLEN=0) (
|
||||
output reg [7:0] status,
|
||||
|
||||
// connection to sd card emulation
|
||||
input [31:0] sd_lba,
|
||||
input [31:0] sd_lba,
|
||||
input sd_rd,
|
||||
input sd_wr,
|
||||
output reg sd_ack,
|
||||
output reg sd_ack_conf,
|
||||
input sd_conf,
|
||||
input sd_sdhc,
|
||||
output [7:0] sd_dout, // valid on rising edge of sd_dout_strobe
|
||||
output reg [7:0] sd_dout, // valid on rising edge of sd_dout_strobe
|
||||
output reg sd_dout_strobe,
|
||||
input [7:0] sd_din,
|
||||
input [7:0] sd_din,
|
||||
output reg sd_din_strobe,
|
||||
|
||||
output reg [8:0] sd_buff_addr,
|
||||
|
||||
// ps2 keyboard emulation
|
||||
input ps2_clk, // 12-16khz provided by core
|
||||
@@ -76,7 +78,6 @@ reg [2:0] stick_idx;
|
||||
|
||||
assign buttons = but_sw[1:0];
|
||||
assign switches = but_sw[3:2];
|
||||
assign sd_dout = { sbuf, SPI_MOSI};
|
||||
assign scandoubler_disable = but_sw[4];
|
||||
|
||||
// this variant of user_io is for 8 bit cores (type == a4) only
|
||||
@@ -86,56 +87,9 @@ wire [7:0] core_type = 8'ha4;
|
||||
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
|
||||
//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);
|
||||
wire spi_sck = SPI_CLK;
|
||||
|
||||
// ---------------- PS2 ---------------------
|
||||
|
||||
@@ -307,108 +261,210 @@ always@(negedge spi_sck or posedge status[0]) begin
|
||||
end
|
||||
end
|
||||
|
||||
// SPI receiver
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin
|
||||
|
||||
// SPI bit and byte counters
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin
|
||||
if(SPI_SS_IO == 1) begin
|
||||
bit_cnt <= 3'd0;
|
||||
byte_cnt <= 8'd0;
|
||||
sd_ack <= 1'b0;
|
||||
sd_dout_strobe <= 1'b0;
|
||||
sd_din_strobe <= 1'b0;
|
||||
bit_cnt <= 0;
|
||||
byte_cnt <= 0;
|
||||
end else begin
|
||||
sd_dout_strobe <= 1'b0;
|
||||
sd_din_strobe <= 1'b0;
|
||||
|
||||
if(bit_cnt != 7)
|
||||
sbuf[6:0] <= { sbuf[5:0], SPI_MOSI };
|
||||
|
||||
bit_cnt <= bit_cnt + 3'd1;
|
||||
if((bit_cnt == 7)&&(byte_cnt != 8'd255))
|
||||
byte_cnt <= byte_cnt + 8'd1;
|
||||
|
||||
// finished reading command byte
|
||||
if(bit_cnt == 7) begin
|
||||
if(byte_cnt == 0) begin
|
||||
cmd <= { sbuf, SPI_MOSI};
|
||||
|
||||
// fetch first byte when sectore FPGA->IO command has been seen
|
||||
if({ sbuf, SPI_MOSI} == 8'h18)
|
||||
sd_din_strobe <= 1'b1;
|
||||
|
||||
if(({ sbuf, SPI_MOSI} == 8'h17) || ({ sbuf, SPI_MOSI} == 8'h18))
|
||||
sd_ack <= 1'b1;
|
||||
|
||||
end else begin
|
||||
|
||||
// buttons and switches
|
||||
if(cmd == 8'h01)
|
||||
but_sw <= { sbuf[3:0], SPI_MOSI };
|
||||
bit_cnt <= bit_cnt + 1'd1;
|
||||
end
|
||||
end
|
||||
|
||||
if(cmd == 8'h02)
|
||||
joystick_0 <= { sbuf, SPI_MOSI };
|
||||
|
||||
if(cmd == 8'h03)
|
||||
joystick_1 <= { sbuf, SPI_MOSI };
|
||||
|
||||
if(cmd == 8'h04) begin
|
||||
// store incoming ps2 mouse bytes
|
||||
ps2_mouse_fifo[ps2_mouse_wptr] <= { sbuf, SPI_MOSI };
|
||||
ps2_mouse_wptr <= ps2_mouse_wptr + 1;
|
||||
end
|
||||
// SPI transmitter FPGA -> IO
|
||||
reg [7:0] spi_byte_out;
|
||||
|
||||
if(cmd == 8'h05) begin
|
||||
// store incoming ps2 keyboard bytes
|
||||
ps2_kbd_fifo[ps2_kbd_wptr] <= { sbuf, SPI_MOSI };
|
||||
ps2_kbd_wptr <= ps2_kbd_wptr + 1;
|
||||
end
|
||||
|
||||
if(cmd == 8'h15)
|
||||
status <= { sbuf[6:0], SPI_MOSI };
|
||||
|
||||
// send sector IO -> FPGA
|
||||
if(cmd == 8'h17) begin
|
||||
// flag that download begins
|
||||
// sd_dout <= { sbuf, SPI_MOSI};
|
||||
sd_dout_strobe <= 1'b1;
|
||||
end
|
||||
|
||||
// send sector FPGA -> IO
|
||||
if(cmd == 8'h18)
|
||||
sd_din_strobe <= 1'b1;
|
||||
|
||||
// send SD config IO -> FPGA
|
||||
if(cmd == 8'h19) begin
|
||||
// flag that download begins
|
||||
// sd_dout <= { sbuf, SPI_MOSI};
|
||||
// sd card knows data is config if sd_dout_strobe is asserted
|
||||
// with sd_ack still being inactive (low)
|
||||
sd_dout_strobe <= 1'b1;
|
||||
end
|
||||
|
||||
// joystick analog
|
||||
if(cmd == 8'h1a) begin
|
||||
// first byte is joystick indes
|
||||
if(byte_cnt == 1)
|
||||
stick_idx <= { sbuf[1:0], SPI_MOSI };
|
||||
else if(byte_cnt == 2) begin
|
||||
// second byte is x axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[15:8] <= { sbuf, SPI_MOSI };
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[15:8] <= { sbuf, SPI_MOSI };
|
||||
end else if(byte_cnt == 3) begin
|
||||
// third byte is y axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[7:0] <= { sbuf, SPI_MOSI };
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[7:0] <= { sbuf, SPI_MOSI };
|
||||
end
|
||||
end
|
||||
always@(negedge spi_sck or posedge SPI_SS_IO) begin
|
||||
if(SPI_SS_IO == 1) begin
|
||||
SPI_MISO <= 1'bZ;
|
||||
end else begin
|
||||
SPI_MISO <= spi_byte_out[~bit_cnt];
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin
|
||||
reg [31:0] sd_lba_r;
|
||||
|
||||
if(SPI_SS_IO == 1) begin
|
||||
spi_byte_out <= core_type;
|
||||
end else begin
|
||||
// read the command byte to choose the response
|
||||
if(bit_cnt == 7) begin
|
||||
if(!byte_cnt) cmd <= {sbuf, SPI_MOSI};
|
||||
|
||||
spi_byte_out <= 0;
|
||||
case({(!byte_cnt) ? {sbuf, SPI_MOSI} : cmd})
|
||||
// reading config string
|
||||
8'h14: if(byte_cnt < STRLEN) spi_byte_out <= conf_str[(STRLEN - byte_cnt - 1)<<3 +:8];
|
||||
|
||||
// reading sd card status
|
||||
8'h16: if(byte_cnt == 0) begin
|
||||
spi_byte_out <= sd_cmd;
|
||||
sd_lba_r <= sd_lba;
|
||||
end
|
||||
else if(byte_cnt < 5) spi_byte_out <= sd_lba_r[(4-byte_cnt)<<3 +:8];
|
||||
|
||||
// reading sd card write data
|
||||
8'h18: spi_byte_out <= sd_din;
|
||||
8'h1b:
|
||||
// send alternating flag byte and data
|
||||
if(byte_cnt[0]) spi_byte_out <= serial_out_status;
|
||||
else spi_byte_out <= serial_out_byte;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// SPI receiver IO -> FPGA
|
||||
|
||||
reg spi_receiver_strobe_r;
|
||||
reg spi_transfer_end_r;
|
||||
reg [7:0] spi_byte_in_r;
|
||||
|
||||
// Read at spi_sck clock domain, assemble bytes for transferring to clk_sys
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin
|
||||
|
||||
if(SPI_SS_IO == 1) begin
|
||||
spi_receiver_strobe_r <= 0;
|
||||
spi_transfer_end_r <= 1;
|
||||
end else begin
|
||||
spi_receiver_strobe_r <= 0;
|
||||
spi_transfer_end_r <= 0;
|
||||
|
||||
if(bit_cnt != 7)
|
||||
sbuf[6:0] <= { sbuf[5:0], SPI_MOSI };
|
||||
|
||||
// finished reading a byte, prepare to transfer to clk_sys
|
||||
if(bit_cnt == 7) begin
|
||||
spi_byte_in_r <= { sbuf, SPI_MOSI};
|
||||
spi_receiver_strobe_r <= 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Process bytes from SPI at the clk_sys domain
|
||||
always @(posedge clk_sys) begin
|
||||
|
||||
reg spi_receiver_strobe;
|
||||
reg spi_transfer_end;
|
||||
reg [7:0] spi_byte_in;
|
||||
reg spi_receiver_strobeD;
|
||||
reg spi_transfer_endD;
|
||||
reg [7:0] spi_byte_inD;
|
||||
reg [7:0] acmd;
|
||||
reg [7:0] abyte_cnt; // counts bytes
|
||||
|
||||
//synchronize between SPI and sys clock domains
|
||||
spi_receiver_strobeD <= spi_receiver_strobe_r;
|
||||
spi_receiver_strobe <= spi_receiver_strobeD;
|
||||
spi_transfer_endD <= spi_transfer_end_r;
|
||||
spi_transfer_end <= spi_transfer_endD;
|
||||
spi_byte_inD <= spi_byte_in_r;
|
||||
spi_byte_in <= spi_byte_inD;
|
||||
|
||||
if(sd_dout_strobe) begin
|
||||
sd_dout_strobe<= 0;
|
||||
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
|
||||
end
|
||||
|
||||
if(sd_din_strobe) begin
|
||||
sd_din_strobe<= 0;
|
||||
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
|
||||
end
|
||||
|
||||
if (~spi_transfer_endD & spi_transfer_end) begin
|
||||
abyte_cnt <= 8'd0;
|
||||
sd_ack <= 1'b0;
|
||||
sd_ack_conf <= 1'b0;
|
||||
sd_dout_strobe <= 1'b0;
|
||||
sd_din_strobe <= 1'b0;
|
||||
sd_buff_addr<= 0;
|
||||
end else if (~spi_receiver_strobeD & spi_receiver_strobe) begin
|
||||
|
||||
if(abyte_cnt != 8'd255)
|
||||
abyte_cnt <= byte_cnt + 8'd1;
|
||||
|
||||
if(abyte_cnt == 0) begin
|
||||
acmd <= spi_byte_in;
|
||||
|
||||
// fetch first byte when sectore FPGA->IO command has been seen
|
||||
if(spi_byte_in == 8'h18)
|
||||
sd_din_strobe <= 1'b1;
|
||||
|
||||
if((spi_byte_in == 8'h17) || (spi_byte_in == 8'h18))
|
||||
sd_ack <= 1'b1;
|
||||
|
||||
end else begin
|
||||
|
||||
// buttons and switches
|
||||
if(acmd == 8'h01)
|
||||
but_sw <= spi_byte_in;
|
||||
|
||||
if(acmd == 8'h02)
|
||||
joystick_0 <= spi_byte_in;
|
||||
|
||||
if(acmd == 8'h03)
|
||||
joystick_1 <= spi_byte_in;
|
||||
|
||||
if(acmd == 8'h04) begin
|
||||
// store incoming ps2 mouse bytes
|
||||
ps2_mouse_fifo[ps2_mouse_wptr] <= spi_byte_in;
|
||||
ps2_mouse_wptr <= ps2_mouse_wptr + 1;
|
||||
end
|
||||
|
||||
if(acmd == 8'h05) begin
|
||||
// store incoming ps2 keyboard bytes
|
||||
ps2_kbd_fifo[ps2_kbd_wptr] <= spi_byte_in;
|
||||
ps2_kbd_wptr <= ps2_kbd_wptr + 1;
|
||||
end
|
||||
|
||||
if(acmd == 8'h15)
|
||||
status <= spi_byte_in;
|
||||
|
||||
// send sector IO -> FPGA
|
||||
if(acmd == 8'h17) begin
|
||||
// flag that download begins
|
||||
sd_dout_strobe <= 1'b1;
|
||||
sd_dout <= spi_byte_in;
|
||||
end
|
||||
|
||||
// send sector FPGA -> IO
|
||||
if(acmd == 8'h18)
|
||||
sd_din_strobe <= 1'b1;
|
||||
|
||||
// send SD config IO -> FPGA
|
||||
if(acmd == 8'h19) begin
|
||||
// flag that download begins
|
||||
sd_dout_strobe <= 1'b1;
|
||||
sd_ack_conf <= 1'b1;
|
||||
sd_dout <= spi_byte_in;
|
||||
end
|
||||
|
||||
// joystick analog
|
||||
if(acmd == 8'h1a) begin
|
||||
// first byte is joystick indes
|
||||
if(abyte_cnt == 1)
|
||||
stick_idx <= spi_byte_in[2:0];
|
||||
else if(abyte_cnt == 2) begin
|
||||
// second byte is x axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[15:8] <= spi_byte_in;
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[15:8] <= spi_byte_in;
|
||||
end else if(abyte_cnt == 3) begin
|
||||
// third byte is y axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[7:0] <= spi_byte_in;
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[7:0] <= spi_byte_in;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user