Update code from upstream repository
https://github.com/lowRISC/opentitan to revision
34ba5e45f9af7d8ca6c9bdae8bd11eeeeb669d6c

* [dv] Add new ECC code options to mem_bkdr_util (Michael Schaffner)
* [secded_gen] Define and generate inverted ECC enc/dec modules
  (Michael Schaffner)
* [dv] Only run registers through one csr_rw sequence at once (Rupert
  Swarbrick)
* [alert_handler] Minor lint fix (Michael Schaffner)
* [prim_clock_div] Fix minor Verilator lint warning (Michael
  Schaffner)
* [dvsim/lint] Make message reporting more flexible (Michael
  Schaffner)
* [lint] Unify lint parser scripts (Michael Schaffner)
* [rom_cntrl, dv] Test to verify successful rom check (Prajwala
  Puttappa)
* [dv, dv_macros] Enhance `DV_GET_ENUM_PLUSARG` macro (Srikrishna
  Iyer)
* [sram/dv] Fix mem data check (Weicai Yang)
* [prim] Add flop wrapper for sparse fsm (Timothy Chen)
* [flash_ctrl] Make data / metadata memories a single entry (Timothy
  Chen)
* [dv] Teach encrypt/decrypt_sram_data to support OTBN (Rupert
  Swarbrick)

Signed-off-by: Michael Schaffner <msf@google.com>
This commit is contained in:
Michael Schaffner 2021-12-02 11:34:22 -08:00
parent 53b1732b19
commit 4df2221dee
99 changed files with 4611 additions and 1321 deletions

View file

@ -187,14 +187,27 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
// arg csr_test_type: what csr test to run {hw_reset, rw, bit_bash, aliasing}
// arg num_test_csrs:instead of testing the entire ral model or passing test chunk info via
// plusarg, provide ability to set a random number of csrs to test from higher level sequence
virtual task run_csr_vseq(string csr_test_type = "",
int num_test_csrs = 0,
bit do_rand_wr_and_reset = 1);
csr_base_seq m_csr_seq;
virtual task run_csr_vseq(string csr_test_type = "",
int num_test_csrs = 0,
bit do_rand_wr_and_reset = 1,
string ral_name = "");
csr_base_seq m_csr_seq;
dv_base_reg_block models[string];
// env needs to have a ral instance
// env needs to have at least one ral instance
`DV_CHECK_GE_FATAL(cfg.ral_models.size(), 1)
// If ral_name is specified, only use registers on that named interface. Otherwise, use all
// registers.
if (ral_name != "") begin
`DV_CHECK_FATAL(cfg.ral_models.exists(ral_name))
models[ral_name] = cfg.ral_models[ral_name];
end else begin
foreach (cfg.ral_models[i]) begin
models[i] = cfg.ral_models[i];
end
end
// check which csr test type
case (csr_test_type)
"hw_reset": csr_base_seq::type_id::set_type_override(csr_hw_reset_seq::get_type());
@ -206,8 +219,8 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
endcase
// Print the list of available exclusions that are in effect for debug.
foreach (cfg.ral_models[i]) begin
csr_excl_item csr_excl = csr_utils_pkg::get_excl_item(cfg.ral_models[i]);
foreach (models[i]) begin
csr_excl_item csr_excl = csr_utils_pkg::get_excl_item(models[i]);
if (csr_excl != null) csr_excl.print_exclusions();
end
@ -227,8 +240,8 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
m_csr_write_seq = csr_write_seq::type_id::create("m_csr_write_seq");
// We have to assign this array in a loop because the element types aren't equivalent, so
// the array types aren't assignment compatible.
foreach (cfg.ral_models[i]) begin
m_csr_write_seq.models[i] = cfg.ral_models[i];
foreach (models[i]) begin
m_csr_write_seq.models[i] = models[i];
end
m_csr_write_seq.external_checker = cfg.en_scb;
m_csr_write_seq.en_rand_backdoor_write = 1'b1;
@ -248,8 +261,8 @@ class dv_base_vseq #(type RAL_T = dv_base_reg_block,
m_csr_seq = csr_base_seq::type_id::create("m_csr_seq");
// We have to assign this array in a loop because the element types aren't equivalent, so
// the array types aren't assignment compatible.
foreach (cfg.ral_models[i]) begin
m_csr_seq.models[i] = cfg.ral_models[i];
foreach (models[i]) begin
m_csr_seq.models[i] = models[i];
end
m_csr_seq.external_checker = cfg.en_scb;
m_csr_seq.num_test_csrs = num_test_csrs;

View file

@ -413,20 +413,25 @@
end
`endif
// This macro converts a string input from plusarg to an enum variable
// ENUM_: the name of enum type
// PLUSARG_: the name of the plusargs, which is also the name of the enum variable
// CHECK_EXIST_: set to 1, `$value$plusargs()` should return true
// Retrieves a plusarg value representing an enum literal.
//
// The plusarg is parsed as a string, which needs to be converted into the enum literal whose name
// matches the string. This functionality is provided by the UVM helper function below.
//
// ENUM_: The enum type.
// VAR_: The enum variable to which the plusarg value will be set (must be declared already).
// PLUSARG_: the name of the plusarg (as raw text). This is typically the same as the enum variable.
// CHECK_EXISTS_: Throws a fatal error if the plusarg is not set.
`ifndef DV_GET_ENUM_PLUSARG
`define DV_GET_ENUM_PLUSARG(ENUM_, PLUSARG_, CHECK_EXIST_ = 0, ID_ = `gfn) \
`define DV_GET_ENUM_PLUSARG(ENUM_, VAR_, PLUSARG_ = VAR_, CHECK_EXISTS_ = 0, ID_ = `gfn) \
begin \
string str; \
if ($value$plusargs("``PLUSARG_``=%0s", str)) begin \
if (!uvm_enum_wrapper#(ENUM_)::from_name(str, PLUSARG_)) begin \
`uvm_fatal(ID_, $sformatf("Cannot find %s from enum ``ENUM_``", PLUSARG_.name)) \
if (!uvm_enum_wrapper#(ENUM_)::from_name(str, VAR_)) begin \
`uvm_fatal(ID_, $sformatf("Cannot find %s from enum ``ENUM_``", VAR_.name())) \
end \
end else if (CHECK_EXIST_) begin \
`uvm_fatal(ID_, "Can't find plusargs ``PLUSARG_``") \
end else if (CHECK_EXISTS_) begin \
`uvm_fatal(ID_, "Please pass the plusarg +``PLUSARG_``=<``ENUM_``-literal>") \
end \
end
`endif

View file

@ -313,6 +313,27 @@ class mem_bkdr_util extends uvm_object;
EccHamming_76_68: begin
rw_data = prim_secded_pkg::prim_secded_hamming_76_68_enc(rw_data[63:0]);
end
EccInv_22_16: begin
rw_data = prim_secded_pkg::prim_secded_inv_22_16_enc(rw_data[15:0]);
end
EccInvHamming_22_16: begin
rw_data = prim_secded_pkg::prim_secded_inv_hamming_22_16_enc(rw_data[15:0]);
end
EccInv_39_32: begin
rw_data = prim_secded_pkg::prim_secded_inv_39_32_enc(rw_data[31:0]);
end
EccInvHamming_39_32: begin
rw_data = prim_secded_pkg::prim_secded_inv_hamming_39_32_enc(rw_data[31:0]);
end
EccInv_72_64: begin
rw_data = prim_secded_pkg::prim_secded_inv_72_64_enc(rw_data[63:0]);
end
EccInvHamming_72_64: begin
rw_data = prim_secded_pkg::prim_secded_inv_hamming_72_64_enc(rw_data[63:0]);
end
EccInvHamming_76_68: begin
rw_data = prim_secded_pkg::prim_secded_inv_hamming_76_68_enc(rw_data[63:0]);
end
default: begin
`uvm_error(`gfn, $sformatf("ECC scheme %0s is unsupported.", err_detection_scheme))
end
@ -383,6 +404,12 @@ class mem_bkdr_util extends uvm_object;
EccHamming_22_16: begin
return prim_secded_pkg::prim_secded_hamming_22_16_dec(data);
end
EccInv_22_16: begin
return prim_secded_pkg::prim_secded_inv_22_16_dec(data);
end
EccInvHamming_22_16: begin
return prim_secded_pkg::prim_secded_inv_hamming_22_16_dec(data);
end
default: return 'x;
endcase
endfunction
@ -399,6 +426,12 @@ class mem_bkdr_util extends uvm_object;
EccHamming_39_32: begin
return prim_secded_pkg::prim_secded_hamming_39_32_dec(data);
end
EccInv_39_32: begin
return prim_secded_pkg::prim_secded_inv_39_32_dec(data);
end
EccInvHamming_39_32: begin
return prim_secded_pkg::prim_secded_inv_hamming_39_32_dec(data);
end
default: return 'x;
endcase
endfunction
@ -415,6 +448,12 @@ class mem_bkdr_util extends uvm_object;
EccHamming_72_64: begin
return prim_secded_pkg::prim_secded_hamming_72_64_dec(data);
end
EccInv_72_64: begin
return prim_secded_pkg::prim_secded_inv_72_64_dec(data);
end
EccInvHamming_72_64: begin
return prim_secded_pkg::prim_secded_inv_hamming_72_64_dec(data);
end
default: return 'x;
endcase
endfunction

View file

@ -66,3 +66,57 @@ virtual function bit [38:0] rom_encrypt_read32(bit [bus_params_pkg::BUS_AW-1:0]
return data;
endfunction
virtual function void rom_encrypt_write32_integ(logic [bus_params_pkg::BUS_AW-1:0] addr,
logic [31:0] data,
logic [SRAM_KEY_WIDTH-1:0] key,
logic [SRAM_BLOCK_WIDTH-1:0] nonce,
bit scramble_data);
logic [bus_params_pkg::BUS_AW-1:0] bus_addr = '0;
logic [38:0] integ_data;
logic [38:0] scrambled_data;
logic wdata_arr [] = new[39];
logic scrambled_addr [] = new[addr_width];
logic rom_addr [] = new[addr_width];
logic key_arr [] = new[SRAM_KEY_WIDTH];
logic nonce_arr [] = new[SRAM_BLOCK_WIDTH];
key_arr = {<<{key}};
nonce_arr = {<<{nonce}};
for (int i = 0; i < addr_width; i++) begin
rom_addr[i] = addr[addr_lsb + i];
end
// Calculate the scrambled address
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(rom_addr, addr_width, nonce_arr);
if(scramble_data) begin
// Calculate the integrity constant
integ_data = prim_secded_pkg::prim_secded_39_32_enc(data);
// Calculate the scrambled data
wdata_arr = {<<{integ_data}};
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
wdata_arr, 39, 0, rom_addr, addr_width, key_arr, nonce_arr
);
scrambled_data = {<<{wdata_arr}};
end
else begin
scrambled_data = data;
end
// Construct bus representation of the address
for (int i = 0; i < addr_lsb; i++) begin
bus_addr[i] = addr[i];
end
for (int i = 0; i < addr_width; i++) begin
bus_addr[addr_lsb + i] = scrambled_addr[i];
end
// Write the scrambled data to memory
write39integ(bus_addr, scrambled_data);
endfunction

View file

@ -39,7 +39,7 @@ virtual function logic [7:0] sram_encrypt_read8(logic [bus_params_pkg::BUS_AW-1:
rdata = read8(bus_addr);
rdata_arr = {<<{rdata}};
rdata_arr = sram_scrambler_pkg::decrypt_sram_data(
rdata_arr, 8, 1, sram_addr, addr_width, key_arr, nonce_arr
rdata_arr, 8, 8, sram_addr, addr_width, key_arr, nonce_arr
);
rdata = {<<{rdata_arr}};
return rdata;
@ -79,7 +79,7 @@ virtual function logic [15:0] sram_encrypt_read16(logic [bus_params_pkg::BUS_AW-
rdata = read16(bus_addr);
rdata_arr = {<<{rdata}};
rdata_arr = sram_scrambler_pkg::decrypt_sram_data(
rdata_arr, 16, 1, sram_addr, addr_width, key_arr, nonce_arr
rdata_arr, 16, 8, sram_addr, addr_width, key_arr, nonce_arr
);
rdata = {<<{rdata_arr}};
return rdata;
@ -118,7 +118,7 @@ virtual function logic [31:0] sram_encrypt_read32(logic [bus_params_pkg::BUS_AW-
rdata = read32(bus_addr);
rdata_arr = {<<{rdata}};
rdata_arr = sram_scrambler_pkg::decrypt_sram_data(
rdata_arr, 32, 1, sram_addr, addr_width, key_arr, nonce_arr
rdata_arr, 32, 8, sram_addr, addr_width, key_arr, nonce_arr
);
rdata = {<<{rdata_arr}};
return rdata;
@ -159,7 +159,7 @@ virtual function logic [38:0] sram_encrypt_read32_integ(logic [bus_params_pkg::B
`uvm_info(`gfn, $sformatf("scr data: 0x%0x", rdata), UVM_HIGH)
rdata_arr = {<<{rdata}};
rdata_arr = sram_scrambler_pkg::decrypt_sram_data(
rdata_arr, 39, 0, sram_addr, addr_width, key_arr, nonce_arr
rdata_arr, 39, 39, sram_addr, addr_width, key_arr, nonce_arr
);
rdata = {<<{rdata_arr}};
// Only return the data payload without ECC bits.
@ -201,7 +201,7 @@ virtual function logic [63:0] sram_encrypt_read64(logic [bus_params_pkg::BUS_AW-
rdata = read64(bus_addr);
rdata_arr = {<<{rdata}};
rdata_arr = sram_scrambler_pkg::decrypt_sram_data(
rdata_arr, 64, 1, sram_addr, addr_width, key_arr, nonce_arr
rdata_arr, 64, 8, sram_addr, addr_width, key_arr, nonce_arr
);
rdata = {<<{rdata_arr}};
return rdata;
@ -234,7 +234,7 @@ virtual function void sram_encrypt_write8(logic [bus_params_pkg::BUS_AW-1:0] add
// Calculate the scrambled data
wdata_arr = {<<{data}};
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
wdata_arr, 8, 1, sram_addr, addr_width, key_arr, nonce_arr
wdata_arr, 8, 8, sram_addr, addr_width, key_arr, nonce_arr
);
scrambled_data = {<<{wdata_arr}};
@ -276,7 +276,7 @@ virtual function void sram_encrypt_write16(logic [bus_params_pkg::BUS_AW-1:0] ad
// Calculate the scrambled data
wdata_arr = {<<{data}};
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
wdata_arr, 16, 1, sram_addr, addr_width, key_arr, nonce_arr
wdata_arr, 16, 8, sram_addr, addr_width, key_arr, nonce_arr
);
scrambled_data = {<<{wdata_arr}};
@ -318,7 +318,7 @@ virtual function void sram_encrypt_write32(logic [bus_params_pkg::BUS_AW-1:0] ad
// Calculate the scrambled data
wdata_arr = {<<{data}};
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
wdata_arr, 32, 1, sram_addr, addr_width, key_arr, nonce_arr
wdata_arr, 32, 8, sram_addr, addr_width, key_arr, nonce_arr
);
scrambled_data = {<<{wdata_arr}};
@ -359,12 +359,12 @@ virtual function void sram_encrypt_write32_integ(logic [bus_params_pkg::BUS_AW-1
scrambled_addr = sram_scrambler_pkg::encrypt_sram_addr(sram_addr, addr_width, nonce_arr);
// Calculate the integrity constant
integ_data = prim_secded_pkg::prim_secded_39_32_enc(data);
integ_data = prim_secded_pkg::prim_secded_inv_39_32_enc(data);
// Calculate the scrambled data
wdata_arr = {<<{integ_data}};
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
wdata_arr, 39, 0, sram_addr, addr_width, key_arr, nonce_arr
wdata_arr, 39, 39, sram_addr, addr_width, key_arr, nonce_arr
);
scrambled_data = {<<{wdata_arr}};
@ -406,7 +406,7 @@ virtual function void sram_encrypt_write64(logic [bus_params_pkg::BUS_AW-1:0] ad
// Calculate the scrambled data
wdata_arr = {<<{data}};
wdata_arr = sram_scrambler_pkg::encrypt_sram_data(
wdata_arr, 64, 1, sram_addr, addr_width, key_arr, nonce_arr
wdata_arr, 64, 8, sram_addr, addr_width, key_arr, nonce_arr
);
scrambled_data = {<<{wdata_arr}};

View file

@ -26,6 +26,15 @@ package mem_bkdr_util_pkg;
EccHamming_39_32 = prim_secded_pkg::SecdedHamming_39_32,
EccHamming_72_64 = prim_secded_pkg::SecdedHamming_72_64,
EccHamming_76_68 = prim_secded_pkg::SecdedHamming_76_68,
EccInv_22_16 = prim_secded_pkg::SecdedInv_22_16,
EccInv_28_22 = prim_secded_pkg::SecdedInv_28_22,
EccInv_39_32 = prim_secded_pkg::SecdedInv_39_32,
EccInv_64_57 = prim_secded_pkg::SecdedInv_64_57,
EccInv_72_64 = prim_secded_pkg::SecdedInv_72_64,
EccInvHamming_22_16 = prim_secded_pkg::SecdedInvHamming_22_16,
EccInvHamming_39_32 = prim_secded_pkg::SecdedInvHamming_39_32,
EccInvHamming_72_64 = prim_secded_pkg::SecdedInvHamming_72_64,
EccInvHamming_76_68 = prim_secded_pkg::SecdedInvHamming_76_68,
ParityEven,
ParityOdd
} err_detection_e;

View file

@ -216,17 +216,15 @@ package sram_scrambler_pkg;
// and then XOR the result with the data.
//
// After that, the XORed data neeeds to them be passed through the S&P network one byte at a time.
//
// TODO: We currently do not support data size of >64bits.
function automatic state_t encrypt_sram_data(logic data[], int data_width, bit byte_diff,
function automatic state_t encrypt_sram_data(logic data[], int data_width, int sp_width,
logic addr[], int addr_width,
logic key[], logic nonce[]);
// Generate the keystream
logic keystream[] = new[SRAM_BLOCK_WIDTH];
logic data_enc[] = new[data_width];
logic byte_to_enc[] = new[8];
logic enc_byte[] = new[8];
logic zero_key[] = new[data_width];
int ks_width = (data_width < 64) ? data_width : 64;
// the key used for byte diffusion is all-zero.
for (int i = 0; i < data_width; i++) begin
@ -237,27 +235,44 @@ package sram_scrambler_pkg;
keystream = gen_keystream(addr, addr_width, key, nonce);
// XOR keystream with input data
// Assumes data width <= 64.
// Assumes ks_width <= 64.
for (int i = 0; i < data_width; i++) begin
data_enc[i] = data[i] ^ keystream[i];
data_enc[i] = data[i] ^ keystream[i % ks_width];
end
// pass each byte of the encoded result through the subst/perm network
if (byte_diff) begin
if (data_width == sp_width) begin
// pass the entire word through the subst/perm network at once (the next cases would give the
// same results too, but this should be a bit more efficient)
data_enc = sp_encrypt(data_enc, data_width, zero_key);
end else if (sp_width == 8) begin
// pass each byte of the encoded result through the subst/perm network (special case of the
// general code below)
for (int i = 0; i < data_width / 8; i++) begin
byte_to_enc = data_enc[i*8 +: 8];
enc_byte = sp_encrypt(byte_to_enc, 8, zero_key);
data_enc[i*8 +: 8] = enc_byte;
end
// pass the entire word through the subst/perm network
end else begin
data_enc = sp_encrypt(data_enc, data_width, zero_key);
// divide the word into sp_width chunks to pass it through the subst/perm network
for (int chunk_lsb = 0; chunk_lsb < data_width; chunk_lsb += sp_width) begin
int bits_remaining = data_width - chunk_lsb;
int chunk_width = (bits_remaining < sp_width) ? bits_remaining : sp_width;
logic chunk[] = new[chunk_width];
for (int j = 0; j < chunk_width; j++) begin
chunk[j] = data_enc[chunk_lsb + j];
end
chunk = sp_encrypt(chunk, chunk_width, zero_key);
for (int j = 0; j < chunk_width; j++) begin
data_enc[chunk_lsb + j] = chunk[j];
end
end
end
return data_enc;
endfunction : encrypt_sram_data
function automatic state_t decrypt_sram_data(logic data[], int data_width, bit byte_diff,
function automatic state_t decrypt_sram_data(logic data[], int data_width, int sp_width,
logic addr[], int addr_width,
logic key[], logic nonce[]);
logic keystream[] = new[SRAM_BLOCK_WIDTH];
@ -265,6 +280,7 @@ package sram_scrambler_pkg;
logic byte_to_dec[] = new[8];
logic dec_byte[] = new[8];
logic zero_key[] = new[data_width];
int ks_width = (data_width < 64) ? data_width : 64;
// the key used for byte diffusion is all-zero.
for (int i = 0; i < data_width; i++) begin
@ -274,21 +290,38 @@ package sram_scrambler_pkg;
// Generate the keystream
keystream = gen_keystream(addr, addr_width, key, nonce);
// pass each byte of the data through the subst/perm network
if (byte_diff) begin
if (data_width == sp_width) begin
// pass the entire word through the subst/perm network at once (the next cases would give the
// same results too, but this should be a bit more efficient)
data_dec = sp_decrypt(data, data_width, zero_key);
end else if (sp_width == 8) begin
// pass each byte of the data through the subst/perm network (special case of the general code
// below)
for (int i = 0; i < data_width / 8; i++) begin
byte_to_dec = data[i*8 +: 8];
dec_byte = sp_decrypt(byte_to_dec, 8, zero_key);
data_dec[i*8 +: 8] = dec_byte;
end
// pass the entire word through the subst/perm network
end else begin
data_dec = sp_decrypt(data, data_width, zero_key);
// divide the word into sp_width chunks to pass it through the subst/perm network
for (int chunk_lsb = 0; chunk_lsb < data_width; chunk_lsb += sp_width) begin
int bits_remaining = data_width - chunk_lsb;
int chunk_width = (bits_remaining < sp_width) ? bits_remaining : sp_width;
logic chunk[] = new[chunk_width];
for (int j = 0; j < chunk_width; j++) begin
chunk[j] = data[chunk_lsb + j];
end
chunk = sp_decrypt(chunk, chunk_width, zero_key);
for (int j = 0; j < chunk_width; j++) begin
data_dec[chunk_lsb + j] = chunk[j];
end
end
end
// XOR result data with the keystream
for (int i = 0; i < data_width; i++) begin
data_dec[i] = data_dec[i] ^ keystream[i];
data_dec[i] = data_dec[i] ^ keystream[i % ks_width];
end
return data_dec;

View file

@ -16,6 +16,10 @@ class mem_model #(int AddrWidth = bus_params_pkg::BUS_AW,
`uvm_object_new
function void init();
system_memory.delete();
endfunction
function int get_written_bytes();
return system_memory.size();
endfunction
@ -33,14 +37,13 @@ class mem_model #(int AddrWidth = bus_params_pkg::BUS_AW,
endfunction
function void write_byte(mem_addr_t addr, bit [7:0] data);
`uvm_info(`gfn, $sformatf("Write Mem : Addr[0x%0h], Data[0x%0h]", addr, data), UVM_HIGH)
`uvm_info(`gfn, $sformatf("Write Mem : Addr[0x%0h], Data[0x%0h]", addr, data), UVM_MEDIUM)
system_memory[addr] = data;
endfunction
function void compare_byte(mem_addr_t addr, bit [7:0] act_data);
`uvm_info(`gfn, $sformatf("Compare Mem : Addr[0x%0h], Act Data[0x%0h], Exp Data[0x%0h]",
addr, act_data, system_memory[addr]), UVM_HIGH)
system_memory[addr] = act_data;
addr, act_data, system_memory[addr]), UVM_MEDIUM)
`DV_CHECK_EQ(act_data, system_memory[addr], $sformatf("addr 0x%0h read out mismatch", addr))
endfunction
@ -67,12 +70,14 @@ class mem_model #(int AddrWidth = bus_params_pkg::BUS_AW,
return data;
endfunction
function void compare(mem_addr_t addr, mem_data_t act_data, mem_mask_t mask = '1);
function void compare(mem_addr_t addr, mem_data_t act_data, mem_mask_t mask = '1,
bit compare_exist_addr_only = 1);
bit [7:0] byte_data;
for (int i = 0; i < DataWidth / 8; i++) begin
mem_addr_t byte_addr = addr + i;
byte_data = act_data[7:0];
if (mask[0]) begin
compare_byte(addr + i, byte_data);
if (mask[0] && (!compare_exist_addr_only || system_memory.exists(byte_addr))) begin
compare_byte(byte_addr, byte_data);
end else begin
// Nothing to do here: since this byte wasn't selected by the mask, there are no
// requirements about what data came back.