blob: 8f4aa03d3c0ceeca478a34e8ed4bdb44b542f15b [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class aes_seq_item extends uvm_sequence_item;
`uvm_object_utils(aes_seq_item)
aes_item_type_e item_type;
aes_op_e operation;
///////////////////////////////////////
// Control Knobs //
///////////////////////////////////////
// set if this item contains valid information
bit valid = 0;
// 0: auto mode 1: manual start
bit manual_op;
// 0: output data cannot be overwritten
// lenth of plaintext / cypher (max is 128b/16b per block)
// used to mask bits that are not part of the data vector
bit [3:0] data_len = 0;
// key len 0: 128, 1: 192, 2: 256 3: NOT VALID
bit [2:0] key_len;
// 256 bit key (8x32 bit) in two shares, key = share0 ^ share1
bit [7:0][31:0] key [2];
// which fields of the key is valid
bit [7:0] key_vld [2] = '{8'b0, 8'b0};
// randomized data to add to queue
bit [3:0][31:0] iv;
// indicate if the initialization vector is valid
bit [3:0] iv_vld;
aes_mode_e mode;
bit [2:0] reseed_rate;
bit en_b2b_transactions = 1;
int b2b_pct = 80;
// percentage of items that will// clear one or more registers
int clear_reg_pct = 0;
// clear registers with random data
bit clear_reg_w_rand = 0;
///////////////////////////////////////
// Fixed variables //
///////////////////////////////////////
// indicate which words has data
bit [3:0] data_in_vld = 4'b0;
// indicate which words has data
bit [3:0] data_out_vld = 4'b0;
// data out was cleared and will not match output from DUT
bit data_was_cleared = 0;
// used by the checker
bit [3:0][31:0] data_out ='0;
// set if data should be fixed and not randomized
bit fixed_data = 0;
// if set unused key bytes will be forced to 0 - controlled from test
bit key_mask = 1;
// indicate message start in manual mode
bit start_item = 0;
// indicate a message was split in two with this item.
bit split_item = 0;
// use sideload
bit sideload_en;
///////////////////////////////////////
// Randomizable variables //
///////////////////////////////////////
// used by the checker
rand bit [3:0][31:0] data_in;
// back to back
rand bit do_b2b;
// bit to select if we clear 1 or more regs
rand int clr_reg_dist_select;
// this is only used to program dut in illegal mode
rand bit [$bits(aes_mode_e) -1:0] aes_mode;
// clear reg vector
// [3] output data
// [2] input data
// [1] IV
// [0] key
rand clear_t clear_reg;
constraint aes_mode_c {
// force to be !onehot
if (mode == AES_NONE) {
!($countones(aes_mode) == 1);
} else {
aes_mode == mode;
}
}
constraint aes_clear_reg_c {
solve clr_reg_dist_select before clear_reg;
clr_reg_dist_select dist { 0 :/ (100 - clear_reg_pct),
[1:2] :/ clear_reg_pct
};
clr_reg_dist_select == 0 -> clear_reg == 0;
clr_reg_dist_select == 1 -> $countones(clear_reg) > 1;
clr_reg_dist_select == 2 -> clear_reg dist { 1 :/ clear_reg_pct/2,
2 :/ clear_reg_pct/2
};
}
constraint back2back_c {
if (en_b2b_transactions) {
do_b2b dist { 0 :/ (100-b2b_pct),
1 :/ b2b_pct };
} else {
do_b2b == 0
};
}
function new( string name="aes_sequence_item");
super.new(name);
endfunction
function void post_randomize();
bit [3:0] index;
`uvm_info(`gfn, $sformatf("Key Mask %b", key_mask), UVM_LOW)
if (key_mask) begin
case (key_len)
3'b001: begin
key[0][7:4] = 32'h00000000;
key[1][7:4] = 32'h00000000;
end
3'b010: begin
key[0][7:6] = 32'h00000000;
key[1][7:6] = 32'h00000000;
end
default: begin
end
endcase // case (key_len)
end
// mask unused data bits
if (data_len != 0) begin
for (int i=data_len; i<16; i++) begin
data_in[i[3:2]][i[1:0]*8+7 -:8] = 8'd0;
end
end
endfunction // post_randomize
// function to detect if all datafields
// have been updated.
function bit data_in_valid();
`uvm_info(`gfn, $sformatf("\n\t ----| Checking if ALL data is updated %4b", data_in_vld)
, UVM_FULL)
return &data_in_vld;
endfunction // data_in_valid
// function to detect if all datafields
// have been updated.
function bit data_out_valid();
`uvm_info(`gfn, $sformatf("\n\t ----| Checking if ALL data is valid %4b", data_out_vld)
, UVM_FULL)
return &data_out_vld;
endfunction // data_in_valid
// if ret_clean = 0
// return 1 only of all registers have been written
// if ret_clean = 1
// return 1 if all or none of the registers have been written
// if clear is set the register will be reset
function bit key_clean(bit ret_clean, bit clear);
`uvm_info(`gfn, $sformatf("\n\t ----| Key status %b %b", key_vld[0], key_vld[1]), UVM_MEDIUM)
if (clear) begin
if (clear_reg_w_rand) begin
key = '{default: {8{$urandom()}}};
end else begin
key = '{default: '0};
end
key_vld[0] = '0;
key_vld[1] = '0;
end
if (ret_clean) begin
return ((&key_vld[0] && &key_vld[1]) || ~(|key_vld[0] || |key_vld[1]));
end else begin
return (&key_vld[0] && &key_vld[1]);
end
endfunction // key_clean
// if ret_clean = 0
// return 1 only of all registers have been written
// if ret_celan = 1
// return 1 if all or none of the registers have been written
function bit iv_clean(bit ret_clean, bit clear);
`uvm_info(`gfn, $sformatf("\n\t ----| IV status %b ", iv_vld), UVM_MEDIUM)
if (clear) begin
if (clear_reg_w_rand) begin
iv = {4{$urandom()}};
end else begin
iv = '0;
end
iv_vld = '0;
end
if (ret_clean) begin
return ((&iv_vld) || ~(|iv_vld));
end else begin
return &iv_vld;
end
endfunction
// bases on the AES mode
// function will return 1 if this is the start of a new message
function bit message_start();
case(mode)
AES_ECB: begin
`uvm_info(`gfn, $sformatf("return key vld(%b, %b) %b",
key_vld[0], key_vld[1], &key_vld[0] && &key_vld[1]), UVM_MEDIUM)
return (&key_vld[0] && &key_vld[1]);
end
AES_CBC: begin
`uvm_info(`gfn, $sformatf("return key vld(%b, %b) %b AND iv (%b) &%b",
key_vld[0], key_vld[1], (&key_vld[0] && &key_vld[1]), iv_vld, &iv_vld), UVM_MEDIUM)
return ((&key_vld[0] && &key_vld[1]) && &iv_vld);
end
AES_CFB: begin
`uvm_info(`gfn, $sformatf("return key vld(%b, %b) %b AND iv (%b) &%b a",
key_vld[0], key_vld[1], (&key_vld[0] && &key_vld[1]), iv_vld, &iv_vld), UVM_MEDIUM)
return ((&key_vld[0] && &key_vld[1]) && &iv_vld);
end
AES_OFB: begin
`uvm_info(`gfn, $sformatf("return key vld(%b, %b) %b AND iv (%b) &%b",
key_vld[0], key_vld[1], (&key_vld[0] && &key_vld[1]), iv_vld, &iv_vld), UVM_MEDIUM)
return ((&key_vld[0] && &key_vld[1]) && &iv_vld);
end
AES_CTR: begin
`uvm_info(`gfn, $sformatf("return key vld(%b, %b) %b AND iv (%b) &%b",
key_vld[0], key_vld[1], (&key_vld[0] && &key_vld[1]), iv_vld, &iv_vld), UVM_MEDIUM)
return ((&key_vld[0] && &key_vld[1]) && &iv_vld);
end
default: begin
// only happen in illegal cases so always return "not start"
return 0;
end
endcase // case (mode)
endfunction // message_start
function void clean_data_in();
if (clear_reg_w_rand) begin
data_in = {4{$urandom()}};
end else begin
data_in = '0;
end
data_in_vld = '0;
endfunction // clean_data_in
function void clean();
data_in_vld = '0;
iv_vld = '0;
key_vld = '{default: '0};
data_out_vld = '0;
start_item = 0;
endfunction // clean
virtual function void do_copy(uvm_object rhs);
aes_seq_item rhs_;
`downcast(rhs_,rhs)
super.do_copy(rhs);
item_type = rhs_.item_type;
operation = rhs_.operation;
mode = rhs_.mode;
data_in = rhs_.data_in;
data_in_vld = rhs_.data_in_vld;
key = rhs_.key;
key_len = rhs_.key_len;
key_vld = rhs_.key_vld;
iv = rhs_.iv;
iv_vld = rhs_.iv_vld;
data_out = rhs_.data_out;
data_len = rhs_.data_len;
manual_op = rhs_.manual_op;
clear_reg_w_rand = rhs_.clear_reg_w_rand;
key_mask = rhs_.key_mask;
aes_mode = rhs_.aes_mode;
do_b2b = rhs_.do_b2b;
clear_reg = rhs_.clear_reg;
start_item = rhs_.start_item;
split_item = rhs_.split_item;
data_was_cleared = rhs_.data_was_cleared;
sideload_en = rhs_.sideload_en;
reseed_rate = rhs_.reseed_rate;
endfunction // copy
// do compare //
virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer);
aes_seq_item rhs_;
`downcast(rhs_,rhs)
return(super.do_compare(rhs,comparer) &&
(operation == rhs_.operation) &&
(mode == rhs_.mode) &&
(data_in == rhs_.data_in) &&
(key == rhs_.key) &&
(data_out == rhs_.data_out) );
endfunction // compare
// convert to string //
virtual function string convert2string();
string str;
str = super.convert2string();
str = {str, $psprintf("\n\t ----| AES SEQUENCE ITEM |----\t ")
};
str = {str, $psprintf("\n\t ----| Item Type: \t %s |----\t ",
item_type.name()) };
str = {str, $psprintf("\n\t ----| AES Mode: \t %s |----\t ",
mode.name()) };
str = {str, $psprintf("\n\t ----| Operation: \t %s |----\t ",
operation.name() ) };
str = {str, $psprintf("\n\t ----| Key len: \t %s \t(%3b) |----\t ",
(key_len==3'b001) ? "128b" : (key_len == 3'b010) ? "192b" : "256b", key_len)};
str = {str, $psprintf("\n\t ----| Key Share 0: \t ")};
for (int i=0; i <8; i++) begin
str = {str, $psprintf("%h ",key[0][i])};
end
str = {str, $psprintf("\n\t ----| Key Share 1: \t ") };
for (int i=0; i <8; i++) begin
str = {str, $psprintf("%h ",key[1][i])};
end
str = {str, $sformatf("\n\t ----| Initializaion vector: \t ")};
for (int i=0; i <4; i++) begin
str = {str, $sformatf("%h ",iv[i])};
end
str = {str, $psprintf("\n\t ----| key_mask: \t %d |----\t \t", key_mask)};
str = {str, $psprintf("\n\t ----| Data Length: \t %d |----\t \t", data_len)};
str = {str, $psprintf("\n\t ----| Input data: \t %h |----\t ", data_in)};
str = {str, $psprintf("\n\t ----| Output data: \t %h |----\t ", data_out)};
str = {str, $psprintf("\n\t") };
return str;
endfunction // conver2string
virtual function string bytes2string();
string str="\n\t ----| data_out: ";
for(int i=0; i<4; i++) begin
str = {str, $psprintf("%h", data_out[i][31:0])};
end
return str;
endfunction
endclass