Advertisement
MysteriousWolf

spi.v

Oct 31st, 2024
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VeriLog 2.75 KB | Source Code | 0 0
  1. /** Format: [R/W bit, addr, msg] **/
  2. module soft_spi_slave
  3. #(
  4.     parameter msg_width = 32,
  5.     parameter addr_width = 7,
  6.     localparam rw_bit = 1,
  7.     localparam meta_width = rw_bit + addr_width,
  8.     localparam data_width = msg_width - meta_width,
  9.     localparam counter_width = $clog2(msg_width),
  10.     localparam data_counter_width = $clog2(data_width)
  11. )
  12. (
  13.     // General signals
  14.     input rst,
  15.    
  16.     // SPI MCU connections
  17.     input       sck,
  18.     input       ncs,
  19.     output reg  so,
  20.     input       si,
  21.    
  22.     // SPI Control
  23.     output reg [addr_width-1:0] addr,
  24.     output reg                  addr_ready,
  25.     output reg                  rw,             // 1 is read 0 is write
  26.     output reg                  rw_ready,
  27.     output reg [data_width-1:0] data_out,
  28.     output reg                  data_ready,
  29.     input      [data_width-1:0] data_in         // Must be ready within 1 serial clock cycle
  30. );
  31.     // Wires
  32.     wire spi_rst = rst || ncs;
  33.  
  34.     // Counters
  35.     wire [counter_width-1:0] data_count;
  36.     spi_counter SPI_CNT(
  37.         .clk_i(~sck),
  38.         .clk_en_i(~ncs),
  39.         .aclr_i(spi_rst),
  40.         .q_o(data_count)
  41.     );
  42.    
  43.     // Data shift reg (needs 1 less bit due to how last bit is handled to reduce output latency and allow consecutive packets)
  44.     reg [data_width-2:0] data_reg;
  45.  
  46.     // condition flags
  47.     wire rw_ready_c = data_count == 0;
  48.     wire addr_ready_c = data_count == (addr_width + rw_bit) - 1;
  49.     wire data_ready_c = data_count == (msg_width) - 1;
  50.    
  51.     // Incoming data shift reg
  52.     always @ (posedge sck or posedge spi_rst) begin
  53.         if (spi_rst) begin
  54.             // Reset outputs
  55.             rw <= 0;
  56.             rw_ready <= 0;
  57.             addr_ready <= 0;
  58.             data_ready <= 0;
  59.             // Reset registers
  60.             data_reg <= 0;
  61.             addr <= 0;
  62.             data_out <= 0;
  63.         end else begin
  64.             // Shifting into the data register
  65.             data_reg <= {data_reg[data_width-3:0], si};
  66.  
  67.             // Check the R/W bit
  68.             if (rw_ready_c) begin
  69.                 rw <= si;
  70.                 rw_ready <= 1;
  71.             end else if (data_ready_c) begin
  72.                 rw <= 0;
  73.                 rw_ready <= 0;
  74.             end
  75.            
  76.             // Check when the address portion is fully received and move it to the output
  77.             if (addr_ready_c) begin
  78.                 addr <= {data_reg[addr_width-2:0], si};
  79.                 addr_ready <= 1;
  80.             end else if (data_ready_c) begin
  81.                 addr <= 0;
  82.                 addr_ready <= 0;
  83.             end
  84.  
  85.             // Check when the entire message is received
  86.             if (data_ready_c) begin
  87.                 data_out <= {data_reg[data_width-2:0], si};
  88.                 data_ready <= 1;
  89.             end else if (rw_ready_c) begin
  90.                 data_out <= 0;
  91.                 data_ready <= 0;
  92.             end
  93.         end
  94.     end
  95.  
  96.     // Data out handling
  97.     always @ (negedge sck or posedge spi_rst) begin
  98.         if (spi_rst) begin
  99.             // Reset outputs
  100.             so <= 0;
  101.         end else begin
  102.             // Counter overflow, prepare for another data packet
  103.             if (addr_ready && (data_count < (msg_width - 1))) begin
  104.                 // Shift out the outgoing data
  105.                 so <= data_in[msg_width - (data_count + 2)];
  106.             end else begin
  107.                 so <= 0;
  108.             end
  109.         end
  110.     end
  111. endmodule
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement