Skip to content

Commit

Permalink
[prim_ram_1p] Ram tiling for sram_ctrl and prim_ram_1p
Browse files Browse the repository at this point in the history
Signed-off-by: Robert Schilling <[email protected]>

Signed-off-by: Robert Schilling <[email protected]>
  • Loading branch information
Razer6 committed Dec 23, 2024
1 parent 1f5772d commit 625e839
Show file tree
Hide file tree
Showing 21 changed files with 489 additions and 128 deletions.
8 changes: 4 additions & 4 deletions hw/dv/verilator/cpp/scrambled_ecc32_mem_area.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ std::vector<uint8_t> ScrambledEcc32MemArea::GetScrambleNonce() const {
ScrambledEcc32MemArea::ScrambledEcc32MemArea(const std::string &scope,
uint32_t size, uint32_t width_32,
bool repeat_keystream)
: Ecc32MemArea(
SVScoped::join_sv_scopes(
scope, "u_prim_ram_1p_adv.u_mem.gen_generic.u_impl_generic"),
size, width_32),
: Ecc32MemArea(SVScoped::join_sv_scopes(scope,
"u_prim_ram_1p_adv.gen_ram_inst[0]."
"u_mem.gen_generic.u_impl_generic"),
size, width_32),
scr_scope_(scope) {
addr_width_ = vbits(size);
repeat_keystream_ = repeat_keystream;
Expand Down
4 changes: 2 additions & 2 deletions hw/ip/otbn/dv/uvm/tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -342,15 +342,15 @@ module tb;
//
// Note that n_bits is the number of bits in the memory, including ECC check bits.
imem_util = new(.name ("imem_util"),
.path ({"tb.dut.u_imem.u_prim_ram_1p_adv.",
.path ({"tb.dut.u_imem.u_prim_ram_1p_adv.gen_ram_inst[0].",
"u_mem.gen_generic.u_impl_generic.mem"}),
.depth (ImemSizeByte / 4),
.n_bits (ImemSizeByte / 4 * 39),
.err_detection_scheme (mem_bkdr_util_pkg::EccInv_39_32));

// DMEM is twice as big as the bus-accessible part
dmem_util = new(.name ("dmem_util"),
.path ({"tb.dut.u_dmem.u_prim_ram_1p_adv.",
.path ({"tb.dut.u_dmem.u_prim_ram_1p_adv.gen_ram_inst[0].",
"u_mem.gen_generic.u_impl_generic.mem"}),
.depth (DmemSizeByte / 32),
.n_bits (DmemSizeByte / 32 * 312),
Expand Down
2 changes: 2 additions & 0 deletions hw/ip/otbn/dv/verilator/otbn_top_sim.sv
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ module otbn_top_sim (
prim_ram_1p_scr #(
.Width ( ExtWLEN ),
.Depth ( DmemSizeWords ),
.InstDepth ( DmemSizeWords ),
.DataBitsPerMask ( 39 ),
.EnableParity ( 0 ),
.ReplicateKeyStream ( 1 )
Expand Down Expand Up @@ -298,6 +299,7 @@ module otbn_top_sim (
prim_ram_1p_scr #(
.Width ( 39 ),
.Depth ( ImemSizeWords ),
.InstDepth ( ImemSizeWords ),
.DataBitsPerMask ( 39 ),
.EnableParity ( 0 )
) u_imem (
Expand Down
2 changes: 2 additions & 0 deletions hw/ip/otbn/rtl/otbn.sv
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ module otbn
prim_ram_1p_scr #(
.Width (39),
.Depth (ImemSizeWords),
.InstDepth (ImemSizeWords),
.DataBitsPerMask(39),
.EnableParity (0)
) u_imem (
Expand Down Expand Up @@ -547,6 +548,7 @@ module otbn
prim_ram_1p_scr #(
.Width (ExtWLEN),
.Depth (DmemSizeWords),
.InstDepth (DmemSizeWords),
.DataBitsPerMask (39),
.EnableParity (0),
.ReplicateKeyStream(1)
Expand Down
2 changes: 1 addition & 1 deletion hw/ip/otp_ctrl/dv/tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ module tb;

if (`PRIM_DEFAULT_IMPL == prim_pkg::ImplGeneric) begin : gen_impl_generic
`define MEM_MODULE_PATH \
tb.dut.u_otp.gen_generic.u_impl_generic.u_prim_ram_1p_adv
tb.dut.u_otp.gen_generic.u_impl_generic.u_prim_ram_1p_adv.gen_ram_inst[0]

`define MEM_ARRAY_PATH \
`MEM_MODULE_PATH.u_mem.gen_generic.u_impl_generic.mem
Expand Down
115 changes: 87 additions & 28 deletions hw/ip/prim/rtl/prim_ram_1p_adv.sv
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

module prim_ram_1p_adv import prim_ram_1p_pkg::*; #(
parameter int Depth = 512,
parameter int InstDepth = Depth,
parameter int Width = 32,
parameter int DataBitsPerMask = 1, // Number of data bits per bit of write mask
parameter MemInitFile = "", // VMEM file to initialize the memory with
Expand All @@ -32,32 +33,36 @@ module prim_ram_1p_adv import prim_ram_1p_pkg::*; #(
// since this results in a more compact and faster implementation.
parameter bit HammingECC = 0,

localparam int Aw = prim_util_pkg::vbits(Depth)
localparam int Aw = prim_util_pkg::vbits(Depth),
// Compute RAM tiling
localparam int NumRamInst = int'($ceil(Depth / real'(InstDepth))),
localparam int InstAw = prim_util_pkg::vbits(InstDepth)
) (
input clk_i,
input rst_ni,

input req_i,
input write_i,
input [Aw-1:0] addr_i,
input [Width-1:0] wdata_i,
input [Width-1:0] wmask_i,
output logic [Width-1:0] rdata_o,
output logic rvalid_o, // read response (rdata_o) is valid
output logic [1:0] rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
input req_i,
input write_i,
input [Aw-1:0] addr_i,
input [Width-1:0] wdata_i,
input [Width-1:0] wmask_i,
output logic [Width-1:0] rdata_o,
output logic rvalid_o, // read response (rdata_o) is valid
output logic [1:0] rerror_o, // Bit1: Uncorrectable, Bit0: Correctable

// config
input ram_1p_cfg_t cfg_i,
input ram_1p_cfg_t [NumRamInst-1:0] cfg_i,

// When detecting multi-bit encoding errors, raise alert.
output logic alert_o
output logic alert_o
);

import prim_mubi_pkg::mubi4_t;
import prim_mubi_pkg::mubi4_and_hi;
import prim_mubi_pkg::mubi4_bool_to_mubi;
import prim_mubi_pkg::mubi4_test_invalid;
import prim_mubi_pkg::mubi4_test_true_loose;
import prim_mubi_pkg::mubi4_test_true_strict;
import prim_mubi_pkg::MuBi4True;
import prim_mubi_pkg::MuBi4False;
import prim_mubi_pkg::MuBi4Width;
Expand Down Expand Up @@ -102,23 +107,77 @@ module prim_ram_1p_adv import prim_ram_1p_pkg::*; #(
assign req_q_b = mubi4_test_true_loose(req_q);
assign write_q_b = mubi4_test_true_loose(write_q);

prim_ram_1p #(
.MemInitFile (MemInitFile),

.Width (TotalWidth),
.Depth (Depth),
.DataBitsPerMask (LocalDataBitsPerMask)
) u_mem (
.clk_i,

.req_i (req_q_b),
.write_i (write_q_b),
.addr_i (addr_q),
.wdata_i (wdata_q),
.wmask_i (wmask_q),
.rdata_o (rdata_sram),
.cfg_i
);
logic [NumRamInst-1:0] inst_req_d, inst_req_q, rvalid_inst;
logic [InstAw-1:0] inst_addr;
logic [NumRamInst-1:0] [Width-1:0] inst_rdata;

// The lower InstAw bits of the address are used to address within one RAM primitive
assign inst_addr = addr_q[InstAw-1:0];

// The upper bits Aw-1:InstAw of the address select which RAM instance is selected. A special case
// is needed when no tiling is performed and only a single RAM macro is instantiated. Here, we
// can directly use the request signal and no demuxing is needed.
if (NumRamInst == 1) begin : gen_single_inst_req
assign inst_req_d[0] = req_q_b;
end else begin : gen_multi_inst_req
always_comb begin
inst_req_d = '0;

for (int i = 0; i < NumRamInst; i++) begin
if (req_q_b && (i == addr_q[Aw-1:InstAw])) begin
inst_req_d[i] = 1'b1;
end
end
end
end

// Flop the instance request signal to know
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
inst_req_q <= '0;
end else begin
inst_req_q <= inst_req_d;
end
end

// Ensure that only one RAM instance gets activated
`ASSERT(OneHotInstReq_A, $onehot0(inst_req_d))

for (genvar i = 0; i < NumRamInst; i++) begin : gen_ram_inst
prim_ram_1p #(
.MemInitFile (MemInitFile),

.Width (TotalWidth),
.Depth (InstDepth),
.DataBitsPerMask (LocalDataBitsPerMask)
) u_mem (
.clk_i,

.req_i (inst_req_d[i]),
.write_i (write_q_b),
.addr_i (inst_addr),
.wdata_i (wdata_q),
.wmask_i (wmask_q),
.rdata_o (inst_rdata[i]),
.cfg_i (cfg_i[i])
);
end

// Mux output data
always_comb begin
rdata_sram = '0;

for (int i = 0; i < NumRamInst; i++) begin
// Determine which RAM tile we accessed based on the floped inst_req signal and we really
// got an rvalid. This determines if we mux the output data of that particular RAM tile.
rvalid_inst[i] = mubi4_test_true_strict(
mubi4_and_hi(mubi4_bool_to_mubi(inst_req_q[i]), rvalid_sram_q));

if(rvalid_inst[i]) begin
rdata_sram = inst_rdata[i];
end
end
end

assign rvalid_sram_d = mubi4_and_hi(req_q, mubi4_t'(~write_q));

Expand Down
46 changes: 25 additions & 21 deletions hw/ip/prim/rtl/prim_ram_1p_scr.sv
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

module prim_ram_1p_scr import prim_ram_1p_pkg::*; #(
parameter int Depth = 16*1024, // Needs to be a power of 2 if NumAddrScrRounds > 0.
parameter int InstDepth = Depth,
parameter int Width = 32, // Needs to be byte aligned if byte parity is enabled.
parameter int DataBitsPerMask = 8, // Needs to be set to 8 in case of byte parity.
parameter bit EnableParity = 1, // Enable byte parity.
Expand Down Expand Up @@ -58,39 +59,41 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #(
// use the same key, but they use a different IV
localparam int DataKeyWidth = 128,
// Each 64 bit scrambling primitive requires a 64bit IV
localparam int NonceWidth = 64 * NumParScr
localparam int NonceWidth = 64 * NumParScr,
// Compute RAM tiling
localparam int NumRamInst = int'($ceil(Depth / real'(InstDepth)))
) (
input clk_i,
input rst_ni,
input clk_i,
input rst_ni,

// Key interface. Memory requests will not be granted if key_valid is set to 0.
input key_valid_i,
input [DataKeyWidth-1:0] key_i,
input [NonceWidth-1:0] nonce_i,
input key_valid_i,
input [DataKeyWidth-1:0] key_i,
input [NonceWidth-1:0] nonce_i,

// Interface to TL-UL SRAM adapter
input req_i,
output logic gnt_o,
input write_i,
input [AddrWidth-1:0] addr_i,
input [Width-1:0] wdata_i,
input [Width-1:0] wmask_i, // Needs to be byte-aligned for parity
input req_i,
output logic gnt_o,
input write_i,
input [AddrWidth-1:0] addr_i,
input [Width-1:0] wdata_i,
input [Width-1:0] wmask_i, // Needs to be byte-aligned for parity
// On integrity errors, the primitive surpresses any real transaction to the memory.
input intg_error_i,
output logic [Width-1:0] rdata_o,
output logic rvalid_o, // Read response (rdata_o) is valid
output logic [1:0] rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
output logic [31:0] raddr_o, // Read address for error reporting.
input intg_error_i,
output logic [Width-1:0] rdata_o,
output logic rvalid_o, // Read response (rdata_o) is valid
output logic [1:0] rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
output logic [31:0] raddr_o, // Read address for error reporting.

// config
input ram_1p_cfg_t cfg_i,
input ram_1p_cfg_t [NumRamInst-1:0] cfg_i,

// Write currently pending inside this module.
output logic wr_collision_o,
output logic write_pending_o,
output logic wr_collision_o,
output logic write_pending_o,

// When detecting multi-bit encoding errors, raise alert.
output logic alert_o
output logic alert_o
);

import prim_mubi_pkg::mubi4_t;
Expand Down Expand Up @@ -481,6 +484,7 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #(

prim_ram_1p_adv #(
.Depth(Depth),
.InstDepth(InstDepth),
.Width(Width),
.DataBitsPerMask(DataBitsPerMask),
.EnableECC(1'b0),
Expand Down
17 changes: 9 additions & 8 deletions hw/ip/prim_generic/rtl/prim_generic_ram_1p.sv
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ module prim_generic_ram_1p import prim_ram_1p_pkg::*; #(

localparam int Aw = $clog2(Depth) // derived parameter
) (
input logic clk_i,
input logic clk_i,

input logic req_i,
input logic write_i,
input logic [Aw-1:0] addr_i,
input logic [Width-1:0] wdata_i,
input logic [Width-1:0] wmask_i,
output logic [Width-1:0] rdata_o, // Read data. Data is returned one cycle after req_i is high.
input ram_1p_cfg_t cfg_i
input logic req_i,
input logic write_i,
input logic [Aw-1:0] addr_i,
input logic [Width-1:0] wdata_i,
input logic [Width-1:0] wmask_i,
output logic [Width-1:0] rdata_o, // Read data. Data is returned one cycle after req_i
// is high.
input ram_1p_cfg_t cfg_i
);

// For certain synthesis experiments we compile the design with generic models to get an unmapped
Expand Down
15 changes: 15 additions & 0 deletions hw/ip/sram_ctrl/data/sram_ctrl.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,20 @@
type: "int",
default: "0x1000"
},
{ name: "InstSize",
desc: "Memory size of a single RAM tile (in bytes).",
type: "int",
default: "4096"
local: "false"
expose: "true"
},
{ name: "NumRamInst",
desc: "Number of internal RAM instances. Must be the same as ceil(MemSizeRam / InstSize) .",
type: "int",
default: "1"
local: "false"
expose: "true"
},
{ name: "InstrExec",
desc: "Support execution from SRAM",
type: "bit",
Expand Down Expand Up @@ -155,6 +169,7 @@
type: "uni"
name: "cfg"
act: "rcv"
width: "NumRamInst",
default: "'0"
package: "prim_ram_1p_pkg"
},
Expand Down
18 changes: 9 additions & 9 deletions hw/ip/sram_ctrl/doc/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ Referring to the [Comportable guideline for peripheral device functionality](htt

## [Inter-Module Signals](https://opentitan.org/book/doc/contributing/hw/comportability/index.html#inter-signal-handling)

| Port Name | Package::Struct | Type | Act | Width | Description |
|:-------------------|:----------------------------|:--------|:------|--------:|:--------------|
| sram_otp_key | otp_ctrl_pkg::sram_otp_key | req_rsp | req | 1 | |
| cfg | prim_ram_1p_pkg::ram_1p_cfg | uni | rcv | 1 | |
| lc_escalate_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | |
| lc_hw_debug_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | |
| otp_en_sram_ifetch | prim_mubi_pkg::mubi8 | uni | rcv | 1 | |
| regs_tl | tlul_pkg::tl | req_rsp | rsp | 1 | |
| ram_tl | tlul_pkg::tl | req_rsp | rsp | 1 | |
| Port Name | Package::Struct | Type | Act | Width | Description |
|:-------------------|:----------------------------|:--------|:------|:-----------|:--------------|
| sram_otp_key | otp_ctrl_pkg::sram_otp_key | req_rsp | req | 1 | |
| cfg | prim_ram_1p_pkg::ram_1p_cfg | uni | rcv | NumRamInst | |
| lc_escalate_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | |
| lc_hw_debug_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | |
| otp_en_sram_ifetch | prim_mubi_pkg::mubi8 | uni | rcv | 1 | |
| regs_tl | tlul_pkg::tl | req_rsp | rsp | 1 | |
| ram_tl | tlul_pkg::tl | req_rsp | rsp | 1 | |

## Security Alerts

Expand Down
4 changes: 2 additions & 2 deletions hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_ram_cfg_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ class sram_ctrl_ram_cfg_vseq extends sram_ctrl_base_vseq;
virtual task body();
prim_ram_1p_pkg::ram_1p_cfg_t src_ram_cfg, dst_ram_cfg;
string src_path = "tb.dut.cfg_i";
string dst_path =
"tb.dut.u_prim_ram_1p_scr.u_prim_ram_1p_adv.u_mem.gen_generic.u_impl_generic.cfg_i";
string dst_path = {"tb.dut.u_prim_ram_1p_scr.u_prim_ram_1p_adv.gen_ram_inst[0].",
"u_mem.gen_generic.u_impl_generic.cfg_i"};

repeat (100) begin
`DV_CHECK_STD_RANDOMIZE_FATAL(src_ram_cfg)
Expand Down
Loading

0 comments on commit 625e839

Please sign in to comment.