blob: c495fea3c43863ad088c066b13e8af7cd3ded6c7 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
`include "prim_assert.sv"
/**
* OTBN Load-Store Unit
*
* Read and write data from/to the data memory (DMEM). Used by the base and the BN instruction
* subset; loads and stores are hence either 32b or WLEN bit wide.
*
* The data memory interface makes the following assumptions:
* - All requests are answered in the next cycle; the LSU must have exclusive access to the memory.
* - The write mask supports aligned 32b write accesses.
*/
module otbn_lsu
import otbn_pkg::*;
#(
parameter int DmemSizeByte = 4096,
localparam int DmemAddrWidth = prim_util_pkg::vbits(DmemSizeByte)
) (
input logic clk_i,
input logic rst_ni,
// Data memory (DMEM) interface
output logic dmem_req_o,
output logic dmem_write_o,
output logic [DmemAddrWidth-1:0] dmem_addr_o,
output logic [WLEN-1:0] dmem_wdata_o,
output logic [WLEN-1:0] dmem_wmask_o,
input logic [WLEN-1:0] dmem_rdata_i,
input logic dmem_rvalid_i,
input logic [1:0] dmem_rerror_i, // Bit1: Uncorrectable, Bit0: Correctable
input logic lsu_load_req_i,
input logic lsu_store_req_i,
input insn_subset_e lsu_req_subset_i,
input logic [DmemAddrWidth-1:0] lsu_addr_i,
input logic [31:0] lsu_base_wdata_i,
input logic [WLEN-1:0] lsu_bignum_wdata_i,
output logic [31:0] lsu_base_rdata_o,
output logic [WLEN-1:0] lsu_bignum_rdata_o,
output logic [1:0] lsu_rdata_err_o // Bit1: Uncorrectable, Bit0: Correctable
);
localparam int BaseWordsPerWLen = WLEN / 32;
localparam int BaseWordAddrW = prim_util_pkg::vbits(WLEN/8);
// Produce a WLEN bit mask for 32-bit writes given the 32-bit word write address. This doesn't
// propagate X so a seperate assertion must be used to check the input isn't X when a valid output
// is desired.
function automatic logic [WLEN-1:0] mask_from_word_addr(logic [BaseWordAddrW-1:2] addr);
logic [WLEN-1:0] mask;
mask = '0;
// Use of logic == int comparison in this loop works as BaseWordsPerWLen is a constant, so the
// loop can be unrolled. Due to the use of '==' any X or Z in addr will result in an X result
// for the comparison (so mask will remain 0).
for (int i = 0; i < BaseWordsPerWLen; i++) begin
if (addr == i) begin
mask[i*32+:32] = 32'hFFFFFFFF;
end
end
return mask;
endfunction
assign dmem_req_o = lsu_load_req_i | lsu_store_req_i;
assign dmem_write_o = lsu_store_req_i;
assign dmem_addr_o = lsu_addr_i;
// For base 32-bit writes replicate write data across dmem_wdata. dmem_wmask will be set
// appropriately so only the target word is written.
assign dmem_wdata_o = lsu_req_subset_i == InsnSubsetBase ?
{BaseWordsPerWLen{lsu_base_wdata_i}} : lsu_bignum_wdata_i;
assign dmem_wmask_o = lsu_req_subset_i == InsnSubsetBase ?
mask_from_word_addr(lsu_addr_i[BaseWordAddrW-1:2]) : {WLEN{1'b1}};
// From the WLEN word read from DMem select out a 32-bit word for base instructions.
for (genvar i_bit = 0; i_bit < 32; i_bit++) begin : g_base_rdata
logic [BaseWordsPerWLen-1:0] bit_mux;
for (genvar j_word = 0; j_word < BaseWordsPerWLen; j_word++) begin : g_bit_mux
assign bit_mux[j_word] =
(lsu_addr_i[BaseWordAddrW-1:2] == j_word) & dmem_rdata_i[i_bit + j_word * 32];
end
assign lsu_base_rdata_o[i_bit] = |bit_mux;
end
// Data appears the cycle following the request, LSU assume lsu_addr_i is kept stable by the
// controller to mux out the required 32-bit word.
`ASSERT(LsuLoadAddrStable, lsu_load_req_i |=> $stable(lsu_addr_i));
`ASSERT_KNOWN_IF(LsuAddrKnown, lsu_addr_i, lsu_load_req_i | lsu_store_req_i);
// TODO: Produce an error/alert if this doesn't hold?
`ASSERT(DMemRValidAfterReq, dmem_req_o & ~dmem_write_o |=> dmem_rvalid_i);
assign lsu_bignum_rdata_o = dmem_rdata_i;
assign lsu_rdata_err_o = dmem_rerror_i;
// clk_i, rst_ni and dmem_rvalid_i are only used by assertions
logic unused_clk;
logic unused_rst_n;
logic unused_dmem_rvalid;
assign unused_clk = clk_i;
assign unused_rst_n = rst_ni;
assign unused_dmem_rvalid = dmem_rvalid_i;
endmodule