hw/ip/spi_device/rtl/spi_fwm_txf_ctrl.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: //
   5: // Serial Peripheral Interface (SPI) Device module.
   6: //
   7: 
   8: module spi_fwm_txf_ctrl #(
   9:   parameter int FifoDw = 8,
  10:   parameter int SramAw = 11,
  11:   parameter int SramDw = 32,
  12:   // SramDw should be multiple of FifoDw
  13:   localparam int NumBytes = SramDw/FifoDw, // derived parameter
  14:   localparam int SDW = $clog2(NumBytes),   // derived parameter
  15:   localparam int PtrW = SramAw + SDW + 1   // derived parameter
  16: ) (
  17:   input clk_i,
  18:   input rst_ni,
  19: 
  20:   // Configuration
  21:   input [SramAw-1:0] base_index_i,
  22:   input [SramAw-1:0] limit_index_i,
  23: 
  24:   input                   abort, // Abort State Machine if TX Async at stuck
  25:   input        [PtrW-1:0] wptr,
  26:   output logic [PtrW-1:0] rptr,
  27:   output logic [PtrW-1:0] depth,
  28: 
  29:   output logic              fifo_valid,
  30:   input                     fifo_ready,
  31:   output logic [FifoDw-1:0] fifo_wdata,
  32: 
  33:   output logic              sram_req,
  34:   output logic              sram_write,
  35:   output logic [SramAw-1:0] sram_addr,
  36:   output logic [SramDw-1:0] sram_wdata,
  37:   input                     sram_gnt,
  38:   input                     sram_rvalid,
  39:   input        [SramDw-1:0] sram_rdata,
  40:   input               [1:0] sram_error
  41: );
  42: 
  43:   logic [SDW-1:0] pos;    // Current write position
  44:   logic [SramAw-1:0] sramf_limit;
  45: 
  46:   logic [SramDw-1:0] sram_rdata_q;
  47:   logic [SramDw-1:0] fifo_wdata_d;
  48: 
  49:   logic [PtrW-1:0] wptr_q;
  50: 
  51: 
  52:   // State input
  53:   logic sramf_empty;
  54:   logic cnt_eq_end; // pos goes 0 -> 1 -> 2 -> 3 -> then 0
  55: 
  56:   // State output
  57:   logic sram_req_d;
  58:   logic update_rptr;
  59:   logic latch_wptr;
  60:   logic cnt_rst;  // Reset pos to rptr[SDW-1:0] or 0
  61:   logic cnt_incr;
  62:   logic txf_sel; // 0: sram_rdata, 1: sram_rdata_q
  63: 
  64: 
  65:   typedef enum logic [2:0] {
  66:     StIdle   = 'h0,
  67:     StRead   = 'h1,
  68:     StLatch  = 'h2,
  69:     StPush   = 'h3,
  70:     StUpdate = 'h4
  71:   } state_e;
  72: 
  73:   state_e st_next, st;
  74: 
  75:   always_ff @(posedge clk_i or negedge rst_ni) begin
  76:     if (!rst_ni) st <= StIdle;
  77:     else         st <= st_next;
  78:   end
  79: 
  80:   assign sramf_empty = (rptr == wptr_q);
  81: 
  82:   assign sramf_limit = limit_index_i - base_index_i;
  83: 
  84:   // State Machine next , output logic
  85:   always_comb begin
  86:     // default output value
  87:     sram_req_d  = 1'b0;
  88:     update_rptr = 1'b0;
  89:     latch_wptr  = 1'b0;
  90:     fifo_valid  = 1'b0;
  91:     txf_sel     = 1'b0; // 0: sram_rdata, 1:sram_rdata_q
  92:     cnt_rst     = 1'b0; // reset pos to rptr
  93:     cnt_incr    = 1'b0;
  94:     unique case (st)
  95:       StIdle: begin
  96:         latch_wptr = 1'b1;
  97:         if (!sramf_empty && fifo_ready) begin
  98:           st_next = StRead;
  99:           sram_req_d = 1'b1;
 100:         end else begin
 101:           st_next = StIdle;
 102:         end
 103:       end
 104: 
 105:       StRead: begin
 106:         if (sram_gnt) begin
 107:           st_next = StLatch;
 108:           cnt_rst = 1'b1;
 109:           sram_req_d = 1'b0;
 110:         end else begin
 111:           st_next = StRead;
 112:           sram_req_d = 1'b1;
 113:         end
 114:       end
 115: 
 116:       StLatch: begin
 117:         if (sram_rvalid) begin
 118:           st_next = StPush;
 119:           fifo_valid = 1'b1;
 120:           txf_sel = 1'b0; // select current sram_rdata
 121:           cnt_incr = 1'b1; // increase pos to next byte
 122:         end else begin
 123:           st_next = StLatch;
 124:         end
 125:       end
 126: 
 127:       StPush: begin
 128:         if (abort) begin
 129:           st_next = StUpdate;
 130:         end else if (!fifo_ready) begin
 131:           st_next = StPush;
 132:         end else if (fifo_ready && !cnt_eq_end) begin
 133:           st_next = StPush;
 134:           fifo_valid = 1'b1;
 135:           txf_sel = 1'b1; // select sram_rdata_q
 136:           cnt_incr = 1'b1;
 137:         end else if (fifo_ready && cnt_eq_end) begin
 138:           // current SRAM word is written to FIFO
 139:           st_next = StUpdate;
 140:         end
 141:       end
 142: 
 143:       StUpdate: begin
 144:         st_next = StIdle;
 145:         update_rptr = 1'b1;
 146:       end
 147: 
 148:       default: begin
 149:         st_next = StIdle;
 150:       end
 151:     endcase
 152:   end
 153: 
 154:   always_ff @(posedge clk_i or negedge rst_ni) begin
 155:     if (!rst_ni) begin
 156:       pos <= '0;
 157:     end else if (cnt_rst) begin
 158:       // Reset to rptr to select bytes among fifo_wdata_d
 159:       pos <= rptr[SDW-1:0];
 160:     end else if (cnt_incr) begin
 161:       // Increase position
 162:       pos <= pos + 1'b1;
 163:     end
 164:   end
 165: 
 166:   always_ff @(posedge clk_i or negedge rst_ni) begin
 167:     if (!rst_ni) begin
 168:       wptr_q <= '0;
 169:     end else if (latch_wptr) begin
 170:       wptr_q <= wptr;
 171:     end
 172:   end
 173: 
 174:   always_ff @(posedge clk_i or negedge rst_ni) begin
 175:     if (!rst_ni) begin
 176:       rptr <= '0;
 177:     end else if (update_rptr) begin
 178:       if (pos == '0) begin
 179:         // full sram word is written.
 180:         if (rptr[PtrW-2:SDW] != sramf_limit) begin
 181:           rptr[PtrW-1:SDW] <= rptr[PtrW-1:SDW] + 1'b1;
 182:           rptr[SDW-1:0] <= '0;
 183:         end else begin
 184:           rptr[PtrW-1] <= ~rptr[PtrW-1];
 185:           rptr[PtrW-2:SDW] <= '0;
 186:           rptr[SDW-1:0]    <= '0;
 187:         end
 188:       end else begin
 189:         // Abort, or partial update (fifo_full), or wptr_q is at the same entry
 190:         rptr[SDW-1:0] <= pos;
 191:       end
 192:     end
 193:   end
 194: 
 195:   // Depth
 196:   always_comb begin
 197:     if (wptr[PtrW-1] == rptr[PtrW-1]) begin
 198:       // Same phase
 199:       depth = {1'b0, wptr[PtrW-2:0]} - {1'b0, rptr[PtrW-2:0]};
 200:     end else begin
 201:       depth = {1'b0, wptr[PtrW-2:0]}
 202:             + ({1'b0, sramf_limit,{SDW{1'b1}}} - {1'b0, rptr[PtrW-2:0]} + 1'b1);
 203:     end
 204:   end
 205: 
 206:   assign cnt_eq_end = (wptr_q[PtrW-1:SDW] == rptr[PtrW-1:SDW]) ? wptr_q[SDW-1:0] == pos :
 207:                       pos == '0;
 208: 
 209: 
 210:   // Datapath
 211:   assign sram_addr = base_index_i + rptr[PtrW-2:SDW];
 212:   assign sram_write = 1'b0;
 213:   assign sram_wdata = '0;
 214: 
 215:   always_ff @(posedge clk_i or negedge rst_ni) begin
 216:     if (!rst_ni) sram_req <= 1'b0;
 217:     else         sram_req <= sram_req_d;
 218:   end
 219: 
 220:   always_ff @(posedge clk_i or negedge rst_ni) begin
 221:     if (!rst_ni) sram_rdata_q <= '0;
 222:     else if (sram_rvalid) sram_rdata_q <= sram_rdata;
 223:   end
 224: 
 225:   assign fifo_wdata_d = (txf_sel) ? sram_rdata_q : sram_rdata ;
 226: 
 227:   always_comb begin
 228:     fifo_wdata = '0;
 229:     for (int i = 0 ; i < NumBytes ; i++) begin
 230:       if (pos == i) fifo_wdata = fifo_wdata_d[8*i+:8];
 231:     end
 232:   end
 233: 
 234: endmodule
 235: