module BUS_Con ( input i_sys_clk, input i_rst_n, // SPI Interface input i_sclk, input i_mosi, input i_cs, output o_miso, // <-- MISO Logic added here // Local Interface output o_rvaild, // (Typo in original: o_rvalid) input i_rvaild, // Valid signal from Backend (Data is ready) input i_wvaild, output o_wready, input i_reg_busy, input [23:0] i_rdata, // Data from Backend to send to Master output o_wr, output o_cmd_vaild, output [23:0] o_data, output [6:0] o_addr, output o_err ); // --- 1. Synchronization --- reg [1:0] cs_sync; reg [1:0] sclk_sync; reg [1:0] mosi_sync; wire cs_active; wire cs_rise; wire sclk_rise; // For Sampling MOSI wire sclk_fall; // For Shifting MISO wire mosi_data; always @(posedge i_sys_clk) begin if (!i_rst_n) begin cs_sync <= 2'b11; sclk_sync <= 2'b00; mosi_sync <= 2'b00; end else begin cs_sync <= {cs_sync[0], i_cs}; sclk_sync <= {sclk_sync[0], i_sclk}; mosi_sync <= {mosi_sync[0], i_mosi}; end end assign cs_active = ~cs_sync[1]; assign cs_rise = (!cs_sync[1] && cs_sync[0]); // SPI Mode 0: Sample MOSI on Rising, Shift MISO on Falling assign sclk_rise = (!sclk_sync[1] && sclk_sync[0]); assign sclk_fall = (sclk_sync[1] && !sclk_sync[0]); // Logic for MISO assign mosi_data = mosi_sync[1]; // --- 2. MOSI (Receive) Logic --- reg [31:0] recv_reg; reg [5:0] bit_cnt; reg data_ready; reg err_flag; reg [1:0] state; // reg [31:0] tx_buffer; // Holds data waiting for the next CS Low reg [31:0] miso_shift; // The actual shifter // Output Registers reg [6:0] addr_out; reg [23:0] data_out; reg wr_out; reg cmd_valid_out; // localparam IDLE = 2'b00; localparam CMD_SENT = 2'b01; localparam WAIT_BUSY = 2'b10; localparam DONE = 2'b11; always @(posedge i_sys_clk) begin if (!i_rst_n) begin recv_reg <= 32'd0; bit_cnt <= 6'd0; data_ready <= 1'b0; err_flag <= 1'b0; end else begin data_ready <= 1'b0; if (cs_active) begin if (sclk_rise) begin recv_reg <= {recv_reg[30:0], mosi_data}; bit_cnt <= bit_cnt + 1'b1; end else if (cs_rise) begin if (bit_cnt == 6'd32) begin data_ready <= 1'b1; err_flag <= 1'b0; bit_cnt <= 6'd0; end else if (bit_cnt != 0) begin err_flag <= 1'b1; bit_cnt <= 6'd0; recv_reg <= 'd0; end end end if (state == DONE) begin recv_reg <= 'd0; end end end // --- 3. MISO (Transmit) Logic --- // Protocol: We shift out 32 bits. // Format: [8 bit Status/Padding] + [24 bit i_rdata] // Capture data from backend when valid always @(posedge i_sys_clk) begin if (!i_rst_n) begin tx_buffer <= 32'd0; end else begin // If backend provides valid read data, store it. // We pad the top 8 bits with Zeros (or you can put status flags here) if (i_rvaild) begin tx_buffer <= {8'h00, i_rdata}; end end end // Shift data out always @(posedge i_sys_clk) begin if (!i_rst_n) begin miso_shift <= 32'd0; end else begin if (!cs_active) begin // Pre-load the shifter while CS is High // This ensures Bit 31 is ready BEFORE the first clock edge miso_shift <= tx_buffer; end else begin // Shift on Falling Edge (Master samples on Rising) if (sclk_fall) begin miso_shift <= {miso_shift[30:0], 1'b0}; end end end end // Tri-state MISO when CS is high (optional, usually good practice) // If your board doesn't need tristate, just use: assign o_miso = miso_shift[31]; assign o_miso = (cs_active) ? miso_shift[31] : 1'bz; // --- 4. Register Control FSM --- always @(posedge i_sys_clk) begin if (!i_rst_n) begin state <= IDLE; cmd_valid_out <= 1'b0; addr_out <= 7'd0; data_out <= 24'd0; wr_out <= 1'b0; end else begin case (state) IDLE: begin if (data_ready) begin addr_out <= recv_reg[30:24]; data_out <= recv_reg[23:0]; wr_out <= recv_reg[31]; if (!i_reg_busy) begin cmd_valid_out <= 1'b1; state <= CMD_SENT; end else begin state <= WAIT_BUSY; end end end WAIT_BUSY: begin if (!i_reg_busy) begin cmd_valid_out <= 1'b1; state <= CMD_SENT; end end CMD_SENT: begin cmd_valid_out <= 1'b0; state <= DONE; end DONE: begin if (!i_reg_busy) begin state <= IDLE; addr_out <= 'd0; data_out <= 'd0; wr_out <= 'd0; end end endcase end end assign o_addr = addr_out; assign o_data = data_out; assign o_wr = wr_out; assign o_cmd_vaild = cmd_valid_out; assign o_err = err_flag; assign o_wready = (state == IDLE); // Pass through unused signal or hook it up if needed assign o_rvaild = 1'b0; endmodule