// NOTE: The first byte is used for syncing due to using different clock domains `include module spi_interface( input logic rst, input logic sys_clk, input logic mosi, input logic cs, input logic sclk, output logic miso, output logic [7:0] rx_byte, output logic rx_valid, input logic rx_ready, output logic [PACKET_ADDR_LEN - 1:0] rx_pkt_addr, input logic [7:0] tx_byte, input logic tx_valid, output logic tx_ready, output logic [PACKET_ADDR_LEN - 1:0] tx_pkt_addr, output logic [QUEUE_ADDR_LEN - 1:0] tx_queue_addr, input logic [QUEUE_ADDR_LEN - 1:0] tx_new_queue, input logic tx_new_queue_valid, output logic tx_new_queue_ready, input logic free_queue_empty); timeunit 1ns; timeprecision 1ps; // SPI logic logic sclk_rising_edge; logic sclk_falling_edge; async_get_clk_edges sync (.rst(rst), .ext_clk(sclk), .sys_clk(sys_clk), .clk_rising_edge(sclk_rising_edge), .clk_falling_edge(sclk_falling_edge)); shortint bit_cnt = 0; logic [7:0] rx_shift; logic [7:0] tx_shift = 8'b00101010; logic [7:0] rx_buff = '0; logic byte_ready = 0; always_ff @ (posedge sclk_rising_edge or posedge rst) begin if (rst) begin rx_shift <= '0; rx_buff <= '0; bit_cnt <= '0; byte_ready <= 0; end else begin if (cs) begin rx_shift <= 0; rx_buff <= 0; bit_cnt <= 0; end else begin rx_shift <= {rx_shift[6:0], mosi}; bit_cnt <= bit_cnt + 1; if (bit_cnt == 7) begin bit_cnt <= 0; rx_buff <= {rx_shift[6:0], mosi}; byte_ready <= 1; end else begin byte_ready <= 0; end end // else: !if(cs) end // else: !if(rst) end // always_ff @ (posedge sclk) shortint idle_cntdn; logic rx_drained; always_ff @ (posedge sys_clk or rst) begin if (rst) begin rx_drained <= 0; rx_pkt_addr <= '1; rx_byte <= '0; rx_valid <= 0; idle_cntdn <= 0; end else begin if (!rx_drained && byte_ready) begin rx_byte <= rx_buff; rx_valid <= 1; idle_cntdn <= INTERFACE_IDLE_COUNTDOWN; rx_drained <= 1; rx_pkt_addr <= rx_pkt_addr + 1; end else if (!byte_ready) begin rx_drained <= 0; if (!(|idle_cntdn)) begin rx_valid <= 0; end else begin idle_cntdn <= idle_cntdn - 1; end end end end always_ff @ (posedge sclk_falling_edge or rst) begin if (rst) begin tx_shift <= 8'b00101010; end else begin if (cs) begin tx_shift <= 0; end else begin if (bit_cnt == 0) begin tx_shift <= rx_buff[7:0]; end else begin tx_shift <= {tx_shift[6:0], 1'b0}; end end end // else: !if(rst) $display("last bit sent: %b", miso); $display("[%0d] current tx_shift: %b", $time, tx_shift); $display("-----------------------------------------"); end // always_ff @ (negedge sclk) assign miso = tx_shift[7]; endmodule // spi_interface module async_get_clk_edges( input logic rst, input logic ext_clk, input logic sys_clk, output logic clk_rising_edge, output logic clk_falling_edge); timeunit 1ns; timeprecision 1ps; logic sync_0 = 0; logic sync_1 = 0; always_ff @ (posedge sys_clk) begin if (rst) begin sync_0 <= 0; sync_1 <= 0; end else begin sync_0 <= ext_clk; sync_1 <= sync_0; end end assign clk_rising_edge = sync_0 & ~sync_1; assign clk_falling_edge = ~sync_0 & sync_1; endmodule // async_get_clk_edges