../src/lowrisc_ip_spi_device_0.1/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:     st_next     = StIdle;
  88:     sram_req_d  = 1'b0;
  89:     update_rptr = 1'b0;
  90:     latch_wptr  = 1'b0;
  91:     fifo_valid  = 1'b0;
  92:     txf_sel     = 1'b0; // 0: sram_rdata, 1:sram_rdata_q
  93:     cnt_rst     = 1'b0; // reset pos to rptr
  94:     cnt_incr    = 1'b0;
  95:     unique case (st)
  96:       StIdle: begin
  97:         latch_wptr = 1'b1;
  98:         if (!sramf_empty && fifo_ready) begin
  99:           st_next = StRead;
 100:           sram_req_d = 1'b1;
 101:         end else begin
 102:           st_next = StIdle;
 103:         end
 104:       end
 105: 
 106:       StRead: begin
 107:         if (sram_gnt) begin
 108:           st_next = StLatch;
 109:           cnt_rst = 1'b1;
 110:           sram_req_d = 1'b0;
 111:         end else begin
 112:           st_next = StRead;
 113:           sram_req_d = 1'b1;
 114:         end
 115:       end
 116: 
 117:       StLatch: begin
 118:         if (sram_rvalid) begin
 119:           st_next = StPush;
 120:           fifo_valid = 1'b1;
 121:           txf_sel = 1'b0; // select current sram_rdata
 122:           cnt_incr = 1'b1; // increase pos to next byte
 123:         end else begin
 124:           st_next = StLatch;
 125:         end
 126:       end
 127: 
 128:       StPush: begin
 129:         if (abort) begin
 130:           st_next = StUpdate;
 131:         end else if (!fifo_ready) begin
 132:           st_next = StPush;
 133:         end else if (fifo_ready && !cnt_eq_end) begin
 134:           st_next = StPush;
 135:           fifo_valid = 1'b1;
 136:           txf_sel = 1'b1; // select sram_rdata_q
 137:           cnt_incr = 1'b1;
 138:         end else begin //if (fifo_ready && cnt_eq_end) begin
 139:           // current SRAM word is written to FIFO
 140:           st_next = StUpdate;
 141:         end
 142:       end
 143: 
 144:       StUpdate: begin
 145:         st_next = StIdle;
 146:         update_rptr = 1'b1;
 147:       end
 148: 
 149:       default: begin
 150:         st_next = StIdle;
 151:       end
 152:     endcase
 153:   end
 154: 
 155:   always_ff @(posedge clk_i or negedge rst_ni) begin
 156:     if (!rst_ni) begin
 157:       pos <= '0;
 158:     end else if (cnt_rst) begin
 159:       // Reset to rptr to select bytes among fifo_wdata_d
 160:       pos <= rptr[SDW-1:0];
 161:     end else if (cnt_incr) begin
 162:       // Increase position
 163:       pos <= pos + 1'b1;
 164:     end
 165:   end
 166: 
 167:   always_ff @(posedge clk_i or negedge rst_ni) begin
 168:     if (!rst_ni) begin
 169:       wptr_q <= '0;
 170:     end else if (latch_wptr) begin
 171:       wptr_q <= wptr;
 172:     end
 173:   end
 174: 
 175:   always_ff @(posedge clk_i or negedge rst_ni) begin
 176:     if (!rst_ni) begin
 177:       rptr <= '0;
 178:     end else if (update_rptr) begin
 179:       if (pos == '0) begin
 180:         // full sram word is written.
 181:         if (rptr[PtrW-2:SDW] != sramf_limit) begin
 182:           rptr[PtrW-1:SDW] <= rptr[PtrW-1:SDW] + 1'b1;
 183:           rptr[SDW-1:0] <= '0;
 184:         end else begin
 185:           rptr[PtrW-1] <= ~rptr[PtrW-1];
 186:           rptr[PtrW-2:SDW] <= '0;
 187:           rptr[SDW-1:0]    <= '0;
 188:         end
 189:       end else begin
 190:         // Abort, or partial update (fifo_full), or wptr_q is at the same entry
 191:         rptr[SDW-1:0] <= pos;
 192:       end
 193:     end
 194:   end
 195: 
 196:   // Depth
 197:   always_comb begin
 198:     if (wptr[PtrW-1] == rptr[PtrW-1]) begin
 199:       // Same phase
 200:       depth = {1'b0, wptr[PtrW-2:0]} - {1'b0, rptr[PtrW-2:0]};
 201:     end else begin
 202:       depth = {1'b0, wptr[PtrW-2:0]}
 203:             + ({1'b0, sramf_limit,{SDW{1'b1}}} - {1'b0, rptr[PtrW-2:0]} + 1'b1);
 204:     end
 205:   end
 206: 
 207:   assign cnt_eq_end = (wptr_q[PtrW-1:SDW] == rptr[PtrW-1:SDW]) ? wptr_q[SDW-1:0] == pos :
 208:                       pos == '0;
 209: 
 210: 
 211:   // Datapath
 212:   assign sram_addr = base_index_i + rptr[PtrW-2:SDW];
 213:   assign sram_write = 1'b0;
 214:   assign sram_wdata = '0;
 215: 
 216:   always_ff @(posedge clk_i or negedge rst_ni) begin
 217:     if (!rst_ni) sram_req <= 1'b0;
 218:     else         sram_req <= sram_req_d;
 219:   end
 220: 
 221:   always_ff @(posedge clk_i or negedge rst_ni) begin
 222:     if (!rst_ni) sram_rdata_q <= '0;
 223:     else if (sram_rvalid) sram_rdata_q <= sram_rdata;
 224:   end
 225: 
 226:   assign fifo_wdata_d = (txf_sel) ? sram_rdata_q : sram_rdata ;
 227: 
 228:   always_comb begin
 229:     fifo_wdata = '0;
 230:     for (int i = 0 ; i < NumBytes ; i++) begin
 231:       if (pos == i) fifo_wdata = fifo_wdata_d[8*i+:8];
 232:     end
 233:   end
 234: 
 235: endmodule
 236: