From 9d250a8234da73334a47f72b992f13c81d2d25cc Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi Date: Fri, 17 Aug 2018 00:37:11 +0200 Subject: [PATCH] BBC: standard clocks only in sd_card and user_io --- cores/bbc/fpga/mist/bbc_mist_top.qsf | 5 +- cores/bbc/fpga/mist/bbc_mist_top.v | 15 +- cores/bbc/fpga/mist/sd_card.v | 275 +++++++++++---------- cores/bbc/fpga/mist/user_io.v | 352 ++++++++++++++++----------- 4 files changed, 369 insertions(+), 278 deletions(-) diff --git a/cores/bbc/fpga/mist/bbc_mist_top.qsf b/cores/bbc/fpga/mist/bbc_mist_top.qsf index 2be9912..d40c332 100644 --- a/cores/bbc/fpga/mist/bbc_mist_top.qsf +++ b/cores/bbc/fpga/mist/bbc_mist_top.qsf @@ -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 \ No newline at end of file +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top diff --git a/cores/bbc/fpga/mist/bbc_mist_top.v b/cores/bbc/fpga/mist/bbc_mist_top.v index 823352c..cf48ddf 100755 --- a/cores/bbc/fpga/mist/bbc_mist_top.v +++ b/cores/bbc/fpga/mist/bbc_mist_top.v @@ -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 = diff --git a/cores/bbc/fpga/mist/sd_card.v b/cores/bbc/fpga/mist/sd_card.v index 5e7fed3..fa7ef95 100644 --- a/cores/bbc/fpga/mist/sd_card.v +++ b/cores/bbc/fpga/mist/sd_card.v @@ -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<= 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