1
0
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:
Gyorgy Szombathelyi
2018-08-17 00:37:11 +02:00
parent ae8e19adf1
commit 9d250a8234
4 changed files with 369 additions and 278 deletions

View File

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

View File

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

View File

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

View File

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