../src/lowrisc_ip_spi_device_0.1/rtl/spi_fwm_rxf_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_rxf_ctrl #(
   9:   parameter int unsigned FifoDw = 8,
  10:   parameter int unsigned SramAw = 11,
  11:   parameter int unsigned SramDw = 32,
  12:   // Do not touch below
  13:   // SramDw should be multiple of FifoDw
  14:   localparam int unsigned NumBytes = SramDw/FifoDw,    // derived parameter
  15:   localparam int unsigned SDW      = $clog2(NumBytes), // derived parameter
  16:   localparam int unsigned PtrW     = SramAw + SDW + 1  // derived parameter
  17: ) (
  18:   input clk_i,
  19:   input rst_ni,
  20: 
  21:   // Configuration
  22:   input      [SramAw-1:0] base_index_i,
  23:   input      [SramAw-1:0] limit_index_i,
  24:   input             [7:0] timer_v,
  25:   input        [PtrW-1:0] rptr,
  26:   output logic [PtrW-1:0] wptr,
  27:   output logic [PtrW-1:0] depth,
  28: 
  29:   output logic            full,
  30: 
  31:   input               fifo_valid,
  32:   output logic        fifo_ready,
  33:   input  [FifoDw-1:0] fifo_rdata,
  34: 
  35:   output logic              sram_req,
  36:   output logic              sram_write,
  37:   output logic [SramAw-1:0] sram_addr,
  38:   output logic [SramDw-1:0] sram_wdata,
  39:   input                     sram_gnt,
  40:   input                     sram_rvalid,
  41:   input        [SramDw-1:0] sram_rdata,
  42:   input               [1:0] sram_error
  43: );
  44: 
  45:   // Internal variable
  46:   logic [NumBytes-1:0] byte_enable;
  47:   logic [SDW-1:0]      pos;   // current byte position
  48:   logic [7:0] cur_timer;
  49:   logic [SramAw-1:0] sramf_limit;
  50: 
  51:   // State input
  52:   logic sramf_full;   // SRAM Fifo full
  53:   logic full_sramwidth;   // Write data filled full SRAM
  54:   logic timer_expired;
  55: 
  56:   // State output
  57:   logic update_wdata;
  58:   logic clr_byte_enable;
  59:   logic sram_req_d;
  60:   logic sram_write_d;
  61:   logic sram_wdata_sel;
  62:   logic timer_rst;
  63:   logic update_wptr;
  64: 
  65:   typedef enum logic [2:0] {
  66:     StIdle   = 'h0,
  67:     StPop    = 'h1,
  68:     StWait   = 'h2,
  69:     StRead   = 'h3,
  70:     StModify = 'h4,
  71:     StWrite  = 'h5,
  72:     StUpdate = 'h6
  73:   } state_e;
  74: 
  75:   state_e st_next, st;
  76: 
  77:   always_ff @(posedge clk_i or negedge rst_ni) begin
  78:     if (!rst_ni) st <= StIdle;
  79:     else         st <= st_next;
  80:   end
  81: 
  82: 
  83:   logic [PtrW-1:0] ptr_cmp;
  84:   assign ptr_cmp = rptr ^ wptr;
  85:   // TODO: Check partial SRAM width read condition
  86:   assign sramf_full = (ptr_cmp[PtrW-1] == 1'b1) && (ptr_cmp[PtrW-2:SDW] == '0);
  87:   assign full = sramf_full;
  88: 
  89:   assign sramf_limit = limit_index_i - base_index_i;
  90: 
  91:   // Write pointer update
  92:   always_ff @(posedge clk_i or negedge rst_ni) begin
  93:     if (!rst_ni) begin
  94:       wptr <= '0;
  95:     end else if (update_wptr) begin
  96:       if (byte_enable == '0) begin
  97:         // as byte enable is cleared, it means full write was done
  98:         if (wptr[PtrW-2:SDW] == sramf_limit) begin
  99:           wptr[PtrW-1] <= ~wptr[PtrW-1];
 100:           wptr[PtrW-2:0] <= '0;
 101:         end else begin
 102:           wptr[PtrW-2:SDW] <= wptr[PtrW-2:SDW] + 1'b1;
 103:           wptr[SDW-1:0] <= '0;
 104:         end
 105:       end else begin
 106:         wptr[SDW-1:0] <= pos;
 107:       end
 108:     end
 109:   end
 110: 
 111:   // Full check
 112:   assign full_sramwidth = (1'b1 == &byte_enable);
 113: 
 114:   // Depth
 115:   always_comb begin
 116:     if (wptr[PtrW-1] == rptr[PtrW-1]) begin
 117:       // Same phase
 118:       depth = {1'b0, wptr[PtrW-2:0]} - {1'b0, rptr[PtrW-2:0]};
 119:     end else begin
 120:       depth = {1'b0, wptr[PtrW-2:0]}
 121:             + ({1'b0, sramf_limit,{SDW{1'b1}}} - {1'b0, rptr[PtrW-2:0]} + 1'b1);
 122:     end
 123:   end
 124: 
 125:   //timer
 126:   always_ff @(posedge clk_i or negedge rst_ni) begin
 127:     if (!rst_ni) begin
 128:       cur_timer <= '1;
 129:     end else if (timer_rst) begin
 130:       cur_timer <= timer_v;
 131:     end else if (st == StWait) begin
 132:       if (cur_timer != '0) cur_timer <= cur_timer - 1'b1;
 133:     end
 134:   end
 135:   assign timer_expired = (cur_timer == '0);
 136: 
 137:   // Data output
 138:   assign sram_addr = base_index_i + wptr[PtrW-2:SDW];
 139: 
 140:   // Byte Enable control
 141:   always_ff @(posedge clk_i or negedge rst_ni) begin
 142:     if (!rst_ni) begin
 143:       byte_enable <= '0;
 144:       pos <= '0;
 145:     end else if (update_wdata) begin
 146:       byte_enable[pos] <= 1'b1;
 147:       if (pos == SDW'(NumBytes-1)) pos <= '0;
 148:       else                         pos <= pos + 1'b1;
 149:     end else if (clr_byte_enable) begin
 150:       byte_enable <= '0;
 151:       pos <= '0;
 152:     end
 153:   end
 154: 
 155:   always_ff @(posedge clk_i or negedge rst_ni) begin
 156:     if (!rst_ni) begin
 157:       sram_wdata <= '0;
 158:     end else if (update_wdata) begin
 159:       sram_wdata[8*pos+:8] <= fifo_rdata;
 160:     end else if (sram_wdata_sel == 1'b1) begin
 161:       for (int i = 0 ; i < NumBytes ; i++) begin
 162:         if (!byte_enable[i]) begin
 163:           sram_wdata[8*i+:8] <= sram_rdata[8*i+:8];
 164:         end
 165:       end
 166:     end
 167:   end
 168: 
 169:   `COVER(partialWriteCover, st == StModify, clk_i, !rst_ni)
 170: 
 171:   // If FIFO is not empty, initiate SRAM write.
 172:   // As FIFOWidth and SRAM Width are different, RMW is required.
 173:   // If host writes always DWord size, it is easy but it is not guaranteed.
 174:   //
 175: 
 176:   // Next State & output logic
 177:   always_comb begin
 178:     fifo_ready = 1'b0;
 179:     update_wdata = 1'b0;
 180:     clr_byte_enable = 1'b0;
 181:     sram_req_d = 1'b0;
 182:     sram_write_d = 1'b0;
 183:     sram_wdata_sel = 1'b0;
 184:     timer_rst = 1'b0;
 185:     update_wptr = 1'b0;
 186: 
 187:     unique case (st)
 188:       StIdle: begin
 189:         // Out of reset state. If SRAM Fifo is not full and RX Fifo is not empty,
 190:         // state machine starts process incoming data
 191:         if (fifo_valid && !sramf_full) begin
 192:           st_next = StPop;
 193:           fifo_ready = 1'b1;
 194:           update_wdata = 1'b1;
 195:         end else begin
 196:           st_next = StIdle;
 197:         end
 198:       end
 199: 
 200:       StPop: begin
 201:         // Pop entries from FIFO. It moves to WAIT if Fifo is empty and still not
 202:         // filled up full sram data width. If anytime while popping the entries
 203:         // and full sram data width is filled, it directly moves to Write state
 204:         if (fifo_valid && !full_sramwidth) begin
 205:           st_next = StPop;
 206:           fifo_ready = 1'b1;
 207:           update_wdata = 1'b1;
 208:         end else if (full_sramwidth) begin
 209:           st_next = StWrite;
 210:           clr_byte_enable = 1'b1;
 211:           sram_req_d   = 1'b1;
 212:           sram_write_d = 1'b1;
 213:         end else begin
 214:           st_next = StWait;
 215:           timer_rst = 1'b1;
 216:         end
 217:       end
 218: 
 219:       StWait: begin
 220:         // Wait up to X clocks. This state is useful to reduce traffic to SRAM.
 221:         // State machine gathers up to SramDw then tries to write at once.
 222:         // If not, it needs to Read-Modify-Write for every byte
 223:         if (fifo_valid) begin
 224:           st_next = StPop;
 225:           fifo_ready = 1'b1;
 226:           update_wdata = 1'b1;
 227:         end else if (!fifo_valid && timer_expired) begin
 228:           st_next = StRead;
 229:           sram_req_d   = 1'b1;
 230:           sram_write_d = 1'b0;
 231:         end else begin
 232:           st_next = StWait;
 233:         end
 234:       end
 235: 
 236:       StRead: begin
 237:         // As counter expires, RMW is only option. State machine reads from current
 238:         // write pointer address (chopping lower bits).
 239:         if (sram_gnt) begin
 240:           st_next = StModify;
 241:         end else begin
 242:           st_next = StRead;
 243:           sram_req_d   = 1'b1;
 244:           sram_write_d = 1'b0;
 245:         end
 246:       end
 247: 
 248:       StModify: begin
 249:         // Waits until read data arrives.
 250:         if (sram_rvalid) begin
 251:           st_next = StWrite;
 252:           sram_req_d   = 1'b1;
 253:           sram_write_d = 1'b1;
 254:           sram_wdata_sel = 1'b1;
 255:         end else begin
 256:           st_next = StModify;
 257:         end
 258:       end
 259: 
 260:       StWrite: begin
 261:         // Regardless of RMW or just full Words write, statemachine writes data
 262:         // into SRAM Fifo
 263:         if (sram_gnt) begin
 264:           st_next = StUpdate;
 265:         end else begin
 266:           st_next = StWrite;
 267:           sram_req_d   = 1'b1;
 268:           sram_write_d = 1'b1;
 269:         end
 270:       end
 271: 
 272:       StUpdate: begin
 273:         // Now, update write pointer then goes back to StIdle.
 274:         // It can goes to StPop state directly but doesn't have to as SPI is slower
 275:         st_next = StIdle;
 276:         update_wptr = 1'b1;
 277:       end
 278: 
 279:       default: begin
 280:         st_next = StIdle;
 281:       end
 282:     endcase
 283:   end
 284: 
 285:   always_ff @(posedge clk_i or negedge rst_ni) begin
 286:     if (!rst_ni) begin
 287:       sram_req <= 1'b0;
 288:       sram_write <= 1'b0;
 289:     end else begin
 290:       sram_req <= sram_req_d;
 291:       sram_write <= sram_write_d;
 292:     end
 293:   end
 294: 
 295: endmodule
 296: