-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[rtl] RRAM bkdr #30740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
[rtl] RRAM bkdr #30740
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| CAPI=2: | ||
| # Copyright lowRISC contributors (OpenTitan project). | ||
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| name: lowrisc:dv:rram_ctrl_bkdr_util:0.1 | ||
| description: "Backdoor read/write rram memory for DV" | ||
|
|
||
| filesets: | ||
| files_dv: | ||
| depend: | ||
| - lowrisc:opentitan:bus_params_pkg | ||
| - lowrisc:dv:dv_utils | ||
| - lowrisc:dv:crypto_dpi_prince:0.1 | ||
| - lowrisc:dv:crypto_dpi_present:0.1 | ||
| - lowrisc:prim:secded:0.1 | ||
| - lowrisc:ip:rram_ctrl_pkg | ||
| - lowrisc:dv:mem_bkdr_util | ||
| files: | ||
| - rram_ctrl_bkdr_util_pkg.sv | ||
| - rram_ctrl_bkdr_util.sv: {is_include_file: true} | ||
| file_type: systemVerilogSource | ||
|
|
||
| targets: | ||
| default: | ||
| filesets: | ||
| - files_dv |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| // Copyright lowRISC contributors (OpenTitan project). | ||
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| // Specialization of the `mem_bkdr_util` class for RRAM memory | ||
|
|
||
| class rram_ctrl_bkdr_util extends mem_bkdr_util; | ||
|
|
||
| localparam int unsigned RramDataWidth = rram_ctrl_pkg::DataWidth; | ||
| localparam int unsigned RramKeySize = rram_ctrl_pkg::KeySize; | ||
| localparam int unsigned RramAddrW = rram_ctrl_pkg::AddrW; | ||
| localparam int unsigned RramStagesPerCycle = RramDataWidth / rram_ctrl_pkg::GfMultCycles; | ||
| localparam int unsigned RramNumRoundsHalf = crypto_dpi_prince_pkg::NumRoundsHalf; | ||
| localparam int unsigned RramDataByteWidth = $clog2(RramDataWidth / 8); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if this doesn't divide cleanly? Do you want a +7 here? (Or maybe a check in the constructor? "These parameters don't make sense, so you can't make the class today")
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
But I guess I can add a check to verify the parameters |
||
|
|
||
| // A GF-multiplier stage matrix, as produced by rram_gen_matrix() and consumed by | ||
| // rram_galois_multiply(). | ||
| typedef bit [RramStagesPerCycle-1:0][RramDataWidth-1:0] rram_gf_matrix_t; | ||
|
|
||
| // Initialize the class instance. | ||
| // | ||
| // All arguments are forwarded unmodified to `mem_bkdr_util::new()` | ||
| // | ||
| // name UVM object instance name. | ||
| // path Hierarchical HDL path to the memory. | ||
| // depth The number of memory rows. | ||
| // n_bits The total size of the memory in bits. | ||
| // err_detection_scheme The error detection scheme implemented for the memory. This class | ||
| // only supports `ErrDetectionNone` for now (checked below). | ||
| // row_adapter Adapter to access the internal row of a memory, for integrators | ||
| // with a custom memory architecture - not used. | ||
| // num_prince_rounds_half The number of PRINCE half-rounds - not used | ||
| // extra_bits_per_subword The width of any additional metadata that is not captured in the | ||
| // secded package - not used. | ||
| // system_base_addr Base address of the memory. | ||
| function new(string name = "", string path, int unsigned depth, | ||
| longint unsigned n_bits, err_detection_e err_detection_scheme, | ||
| mem_bkdr_util_row_adapter row_adapter = null, | ||
| int num_prince_rounds_half = 3, | ||
| int extra_bits_per_subword = 0, int unsigned system_base_addr = 0); | ||
|
|
||
| super.new(name, path, depth, n_bits, err_detection_scheme, row_adapter, | ||
| num_prince_rounds_half, extra_bits_per_subword, system_base_addr); | ||
|
|
||
| // No ECC for now. once added, the functions below need to be adjusted | ||
| `DV_CHECK_EQ_FATAL(err_detection_scheme, mem_bkdr_util_pkg::ErrDetectionNone) | ||
|
|
||
| // The GF multiplier decomposition below mirrors the `prim_gf_mult` hardware, which requires | ||
| // the datapath width to divide evenly into the number of multiplier stages. | ||
| `DV_CHECK_EQ_FATAL(RramDataWidth % rram_ctrl_pkg::GfMultCycles, 0, | ||
| "RramDataWidth must be a multiple of GfMultCycles") | ||
| `DV_CHECK_EQ_FATAL(RramDataWidth % 8, 0, "RramDataWidth must be a multiple of bytes") | ||
| endfunction | ||
|
|
||
| // Randomize the memory | ||
| virtual function void randomize_mem(); | ||
| `uvm_info(`gfn, "Randomizing rram mem contents", UVM_LOW) | ||
| for (int i = 0; i < depth; i++) begin | ||
| uvm_hdl_data_t data; | ||
| `DV_CHECK_STD_RANDOMIZE_FATAL(data, "Randomization failed!", path) | ||
| write(i * bytes_per_word, data); | ||
| end | ||
| endfunction | ||
|
|
||
| static function bit [RramDataWidth-1:0] rram_gf_mult2(bit [RramDataWidth-1:0] operand); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function needs a documentation comment (which should describe the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just the inner part of the gfmultiplier. I also don't really know what it is doing in detail. I took it over from flash_ctrl |
||
| bit [RramDataWidth-1:0] mult_out; | ||
|
|
||
| mult_out = operand[RramDataWidth-1] ? (operand << 1) ^ rram_ctrl_pkg::ScrambleIPoly : | ||
| (operand << 1); | ||
| return mult_out; | ||
| endfunction | ||
|
|
||
| // Generate the per-stage GF-multiplier matrix consumed by rram_galois_multiply(), mirroring | ||
| // `prim_gf_mult`'s `gen_matrix` step. | ||
| // `seed` is the running GF value carried over from the previous cycle's last row; `init` is set | ||
| // for the very first iteration, in which case `seed` is used directly as row 0 instead of first | ||
| // being multiplied by x. Each subsequent row is the previous row multiplied by x (rram_gf_mult2). | ||
| static function rram_gf_matrix_t rram_gen_matrix(bit [RramDataWidth-1:0] seed, bit init); | ||
| rram_gf_matrix_t matrix_out; | ||
|
|
||
| matrix_out[0] = init ? seed : rram_gf_mult2(seed); | ||
| for (int i = 1; i < RramStagesPerCycle; i++) begin | ||
| matrix_out[i] = rram_gf_mult2(matrix_out[i-1]); | ||
| end | ||
| return matrix_out; | ||
| endfunction | ||
|
|
||
| // Compute the tweak for the XEX cipher. Tweak = GfMult128(addr, addr_key) | ||
| static function bit [RramDataWidth-1:0] rram_galois_multiply(bit [RramKeySize-1:0] addr_key, | ||
| bit [RramAddrW-1:0] addr); | ||
| bit [RramDataWidth-1:0] total_product = '0; | ||
| bit [RramDataWidth-1:0] next_seed; | ||
|
|
||
| // Initial seed | ||
| next_seed = {'0, addr}; | ||
|
|
||
| for (int j = 0; j < rram_ctrl_pkg::GfMultCycles; j++) begin | ||
| rram_gf_matrix_t current_matrix; | ||
| bit [RramDataWidth-1:0] mult_out = '0; | ||
|
|
||
| // Generate matrix for this chunk | ||
| // Use init = 1 for the very first chunk, init = 0 for subsequent ones | ||
| current_matrix = rram_gen_matrix(next_seed, (j == 0)); | ||
| for (int i = 0; i < RramStagesPerCycle; i++) begin | ||
| if (addr_key[(j * RramStagesPerCycle) + i]) begin | ||
| mult_out = mult_out ^ current_matrix[i]; | ||
| end | ||
| end | ||
| // Accumulate result | ||
| total_product = total_product ^ mult_out; | ||
| // Prepare seed for next loop: the last row of current matrix | ||
| next_seed = current_matrix[RramStagesPerCycle-1]; | ||
| end | ||
|
|
||
| return total_product; | ||
| endfunction | ||
|
|
||
| // Scramble a single RRAM word using the XEX cipher: | ||
| // 1. Compute the tweak (gfmult128(addr_key, addr)) | ||
| // 2. Apply the tweak | ||
| // 3. Encrypt the data with the data_key | ||
| // 4. Remove the tweak | ||
| function bit [RramDataWidth-1:0] rram_scramble_data(bit [RramDataWidth-1:0] data, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function needs documenting.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added |
||
| bit [RramAddrW-1:0] word_addr, | ||
| bit [RramKeySize-1:0] rram_addr_key, | ||
| bit [RramKeySize-1:0] rram_data_key); | ||
| bit [RramDataWidth-1:0] masked_data; | ||
| bit [RramDataWidth-1:0] scrambled_data; | ||
| bit [RramDataWidth-1:0] mask; | ||
|
|
||
| mask = rram_galois_multiply(rram_addr_key, word_addr); | ||
| masked_data = data ^ mask; | ||
|
|
||
| for (int k = 0; k < 2; k++) begin | ||
| bit [RramDataWidth/2-1:0] cipher_in; | ||
| bit [RramNumRoundsHalf-1:0][RramDataWidth/2-1:0] cipher_out; | ||
| for (int i = 0; i < RramDataWidth/2; i++) begin | ||
| cipher_in[i] = masked_data[2*i+k]; | ||
| end | ||
| crypto_dpi_prince_pkg::sv_dpi_prince_encrypt(.plaintext(cipher_in), | ||
| .key(rram_data_key), | ||
| .old_key_schedule(0), | ||
| .ciphertext(cipher_out)); | ||
| for (int i = 0; i < RramDataWidth/2; i++) begin | ||
| scrambled_data[2*i+k] = cipher_out[RramNumRoundsHalf-1][i]; | ||
| end | ||
| end | ||
| return scrambled_data ^ mask; | ||
| endfunction | ||
|
|
||
| // Descramble a single RRAM word using the XEX cipher: | ||
| // 1. Compute the tweak (gfmult128(addr_key, addr)) | ||
| // 2. Apply the tweak | ||
| // 3. Decrypt the data with the data_key | ||
| // 4. Remove the tweak | ||
| function bit [RramDataWidth-1:0] rram_descramble_data(bit [RramDataWidth-1:0] data, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function needs documenting.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added |
||
| bit [RramAddrW-1:0] word_addr, | ||
| bit [RramKeySize-1:0] rram_addr_key, | ||
| bit [RramKeySize-1:0] rram_data_key); | ||
| bit [RramDataWidth-1:0] masked_data; | ||
| bit [RramDataWidth-1:0] descrambled_data; | ||
| bit [RramDataWidth-1:0] mask; | ||
|
|
||
| mask = rram_galois_multiply(rram_addr_key, word_addr); | ||
| masked_data = data ^ mask; | ||
|
|
||
| for (int k = 0; k < 2; k++) begin | ||
| bit [RramDataWidth/2-1:0] cipher_in; | ||
| bit [RramDataWidth/2-1:0] cipher_out; | ||
| for (int i = 0; i < RramDataWidth/2; i++) begin | ||
| cipher_in[i] = masked_data[2*i+k]; | ||
| end | ||
| cipher_out = crypto_dpi_prince_pkg::c_dpi_prince_decrypt(cipher_in, | ||
| rram_data_key[127:64], | ||
| rram_data_key[63:0], | ||
| RramNumRoundsHalf, | ||
| 0); | ||
| for (int i = 0; i < RramDataWidth/2; i++) begin | ||
| descrambled_data[2*i+k] = cipher_out[i]; | ||
| end | ||
| end | ||
|
|
||
| return descrambled_data ^ mask; | ||
| endfunction | ||
|
|
||
| endclass | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| // Copyright lowRISC contributors (OpenTitan project). | ||
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package rram_ctrl_bkdr_util_pkg; | ||
| // dep packages | ||
| import bus_params_pkg::BUS_AW; | ||
| import dv_utils_pkg::uint32_t, dv_utils_pkg::addr_range_t; | ||
| import lc_ctrl_state_pkg::*; | ||
| import mem_bkdr_util_pkg::*; | ||
| import prim_secded_pkg::*; | ||
| import uvm_pkg::*; | ||
|
|
||
| // macro includes | ||
| `include "uvm_macros.svh" | ||
| `include "dv_macros.svh" | ||
|
|
||
| // sources | ||
| `include "rram_ctrl_bkdr_util.sv" | ||
| endpackage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if this doesn't divide cleanly? (And do we care?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its a requirement of the gfmultiplier hardware module. so it must be a clean division