| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| import aes_model_dpi_pkg::*; |
| import aes_pkg::*; |
| |
| class aes_scoreboard extends cip_base_scoreboard #( |
| .CFG_T(aes_env_cfg), |
| .RAL_T(aes_reg_block), |
| .COV_T(aes_env_cov) |
| ); |
| |
| `uvm_component_utils(aes_scoreboard) |
| `uvm_component_new |
| |
| // local variables |
| aes_seq_item input_item; // item containing data and config |
| aes_seq_item output_item; // item containing resulting output |
| aes_seq_item complete_item; // merge of input and output items |
| aes_seq_item key_item; // sequence item holding last sideload valid key |
| bit ok_to_fwd = 0; // 0: item is not ready to forward |
| bit finish_message = 0; // set when test is trying to end |
| // - to indicate the last message is finished |
| int good_cnt = 0; // number of good messages |
| int corrupt_cnt = 0; // number of aes_mode errors seen |
| int skipped_cnt = 0; // number of skipped messages |
| bit reset_compare = 0; // reset compare task |
| bit exp_clear = 0; // if using sideload - we are expecting a clear |
| keymgr_pkg::hw_key_req_t sideload_key = 0; // will hold the key from sideload |
| uvm_tlm_analysis_fifo #(key_sideload_item) key_manager_fifo; |
| bit [3:0] datain_rdy = '0; // indicate if DATA_IN can be updated |
| |
| virtual aes_cov_if cov_if; // handle to aes coverage interface |
| // local queues to hold incoming packets pending comparison // |
| |
| // Items containing both input and output data, ready to be added to a message |
| mailbox #(aes_seq_item) item_fifo; |
| // completed message item ready for scoring |
| mailbox #(aes_message_item) msg_fifo; |
| // once an operation is started the item is put here to wait for the resuting output |
| aes_seq_item rcv_item_q[$]; |
| |
| function void build_phase(uvm_phase phase); |
| super.build_phase(phase); |
| msg_fifo = new(); |
| item_fifo = new(); |
| key_manager_fifo = new("keymgr_analysis_fifo"); |
| input_item = new("input_item"); |
| key_item = new("key_item"); |
| output_item = new (); |
| |
| if (!uvm_config_db#(virtual aes_cov_if)::get(null, "*.env" , "aes_cov_if", cov_if)) begin |
| `uvm_fatal(`gfn, $sformatf("FAILED TO GET HANDLE TO COVER IF")) |
| end |
| endfunction |
| |
| |
| function void connect_phase(uvm_phase phase); |
| super.connect_phase(phase); |
| endfunction |
| |
| |
| task run_phase(uvm_phase phase); |
| // disable check as we don't |
| // know when the alert will happen |
| do_alert_check = 0; |
| super.run_phase(phase); |
| if (cfg.en_scb) begin |
| fork |
| compare(); |
| process_sideload_key(); |
| rebuild_message(); |
| join_none |
| end |
| endtask |
| |
| function void on_ctrl_shadowed_write(logic [31:0] wdata); |
| input_item.manual_op = get_field_val(ral.ctrl_shadowed.manual_operation, wdata); |
| input_item.key_len = get_field_val(ral.ctrl_shadowed.key_len, wdata); |
| input_item.sideload_en = get_field_val(ral.ctrl_shadowed.sideload, wdata); |
| `downcast(input_item.operation, get_field_val(ral.ctrl_shadowed.operation, wdata)); |
| input_item.valid = 1'b1; |
| case (get_field_val(ral.ctrl_shadowed.mode, wdata)) |
| 6'b00_0001: input_item.mode = AES_ECB; |
| 6'b00_0010: input_item.mode = AES_CBC; |
| 6'b00_0100: input_item.mode = AES_CFB; |
| 6'b00_1000: input_item.mode = AES_OFB; |
| 6'b01_0000: input_item.mode = AES_CTR; |
| 6'b10_0000: input_item.mode = AES_NONE; |
| default: input_item.mode = AES_NONE; |
| endcase |
| // sample coverage on ctrl register |
| cov_if.cg_ctrl_sample(get_field_val(ral.ctrl_shadowed.operation, wdata), |
| get_field_val(ral.ctrl_shadowed.mode, wdata), |
| get_field_val(ral.ctrl_shadowed.key_len, wdata), |
| get_field_val(ral.ctrl_shadowed.manual_operation, wdata), |
| get_field_val(ral.ctrl_shadowed.sideload, wdata), |
| get_field_val(ral.ctrl_shadowed.prng_reseed_rate, wdata)); |
| |
| input_item.clean(); |
| input_item.start_item = 1; |
| if (input_item.sideload_en) begin |
| exp_clear = 1; |
| end |
| endfunction |
| |
| function void on_key_share_write(string csr_name, logic [31:0] wdata); |
| for (int share = 0; share < 2; share++) begin |
| for (int i = 0; i < 8; i++) begin |
| string keyname = $sformatf("key_share%0d_%0d", share, i); |
| if (keyname == csr_name) begin |
| input_item.key[share][i] = wdata; |
| input_item.key_vld[share][i] = 1'b1; |
| cov_if.cg_key_sample(i + 8 * share); |
| end |
| end |
| end |
| endfunction |
| |
| function void on_data_in_write(string csr_name, logic [31:0] wdata); |
| for (int i = 0; i < 4; i++) begin |
| string keyname = $sformatf("data_in_%0d", i); |
| // you can update datain until all have been |
| // updated then DUT will auto start |
| if (keyname == csr_name && (|datain_rdy || input_item.manual_op)) begin |
| input_item.data_in[i] = wdata; |
| input_item.data_in_vld[i] = 1'b1; |
| cov_if.cg_wr_data_sample(i); |
| datain_rdy[i] = 0; |
| end |
| end |
| endfunction |
| |
| function void on_iv_in_write(string csr_name, logic [31:0] wdata); |
| for (int i = 0; i < 4; i++) begin |
| string keyname = $sformatf("iv_%0d", i); |
| if (keyname == csr_name) begin |
| input_item.iv[i] = wdata; |
| input_item.iv_vld[i] = 1'b1; |
| cov_if.cg_iv_sample(i); |
| end |
| end |
| endfunction |
| |
| function void on_trigger_write(logic [31:0] wdata); |
| //start triggered |
| cov_if.cg_trigger_sample(get_field_val(ral.trigger.start, wdata), |
| get_field_val(ral.trigger.key_iv_data_in_clear, wdata), |
| get_field_val(ral.trigger.data_out_clear, wdata), |
| get_field_val(ral.trigger.prng_reseed, wdata)); |
| `uvm_info(`gfn, $sformatf("\n CLEAR REGISTER SEEN 0x%h", wdata), UVM_MEDIUM) |
| if (get_field_val(ral.trigger.start, wdata)) begin |
| ok_to_fwd = input_item.mode != AES_NONE; |
| end |
| // clear key, IV, data_in |
| if (get_field_val(ral.trigger.key_iv_data_in_clear, wdata)) begin |
| void'(input_item.key_clean(0, 1)); |
| void'(input_item.iv_clean(0, 1)); |
| void'(key_item.key_clean(0, 1)); |
| input_item.clean_data_in(); |
| datain_rdy = 4'b0; |
| // if in the middle of a message |
| // this is seen as the beginning of a new message |
| if (!input_item.start_item) begin |
| input_item.start_item = 1; |
| if (!exp_clear) input_item.split_item = 1; |
| exp_clear = 0; |
| `uvm_info(`gfn, $sformatf("splitting message"), UVM_MEDIUM) |
| end |
| `uvm_info(`gfn, $sformatf("\n\t ----| clearing KEY"), UVM_MEDIUM) |
| `uvm_info(`gfn, $sformatf("\n\t ----| clearing IV"), UVM_MEDIUM) |
| `uvm_info(`gfn, $sformatf("\n\t ----| clearing DATA_IN"), UVM_MEDIUM) |
| end |
| // clear data out |
| if (get_field_val(ral.trigger.data_out_clear, wdata)) begin |
| `uvm_info(`gfn, $sformatf("\n\t ----| clearing DATA_OUT"), UVM_MEDIUM) |
| if (cfg.clear_reg_w_rand) begin |
| input_item.data_out = {4{$urandom()}}; |
| end else begin |
| input_item.data_out = '0; |
| end |
| // marking the output item as potentially bad |
| output_item.data_was_cleared = 1; |
| // set to make sure any input item |
| // waiting for output data is forwarded without the data. |
| end |
| // reseed |
| if (wdata[5]) begin |
| // nothing to do for DV |
| end |
| endfunction |
| |
| // Handle a write to a named CSR on the A channel |
| function void on_addr_channel_write(string csr_name, logic [31:0] wdata); |
| // add individual case item for each csr |
| case (1) |
| (!uvm_re_match("alert_test", csr_name)): begin |
| cov_if.cg_alert_test_sample(wdata); |
| end |
| |
| (!uvm_re_match("ctrl_shadowed", csr_name)): begin |
| // ignore reg write if busy |
| if (cfg.idle_vif) on_ctrl_shadowed_write(wdata); |
| end |
| |
| (!uvm_re_match("key_share*", csr_name)): begin |
| // ignore reg write if busy |
| if (cfg.idle_vif) on_key_share_write(csr_name, wdata); |
| end |
| |
| (!uvm_re_match("data_in_*", csr_name)): begin |
| on_data_in_write(csr_name, wdata); |
| end |
| |
| (!uvm_re_match("iv_*", csr_name)): begin |
| // ignore reg write if busy |
| if (cfg.idle_vif) on_iv_in_write(csr_name, wdata); |
| end |
| |
| (!uvm_re_match("trigger", csr_name)): begin |
| on_trigger_write(wdata); |
| end |
| |
| (!uvm_re_match("ctrl_aux_regwen", csr_name)): begin |
| cov_if.cg_aux_regwen_sample(wdata[0]); |
| end |
| |
| // (!uvm_re_match("status", csr_name)): begin |
| // // not used in scoreboard |
| // end |
| |
| default: begin |
| // DO nothing- trying to write to a read only register |
| end |
| endcase |
| endfunction |
| |
| virtual task process_tl_access(tl_seq_item item, tl_channels_e channel, string ral_name); |
| uvm_reg csr; |
| aes_seq_item input_clone; |
| aes_seq_item complete_clone; |
| bit do_read_check = 1'b0; |
| bit write = item.is_write(); |
| uvm_reg_addr_t csr_addr = cfg.ral_models[ral_name].get_word_aligned_addr(item.a_addr); |
| |
| // if access was to a valid csr, get the csr handle |
| if (csr_addr inside {cfg.ral_models[ral_name].csr_addrs}) begin |
| csr = cfg.ral_models[ral_name].default_map.get_reg_by_offset(csr_addr); |
| `DV_CHECK_NE_FATAL(csr, null) |
| end else begin |
| `uvm_fatal(`gfn, $sformatf("Access unexpected addr 0x%0h", csr_addr)) |
| end |
| |
| if (channel == AddrChannel) begin |
| string csr_name = csr.get_name(); |
| `uvm_info(`gfn, $sformatf("\n\t ----| ITEM received reg name : %s",csr.get_name()), UVM_FULL) |
| |
| // if incoming access is a write to a valid csr, then make updates right away |
| if (write) begin |
| void'(csr.predict(.value(item.a_data), .kind(UVM_PREDICT_WRITE), .be(item.a_mask))); |
| on_addr_channel_write(csr_name, item.a_data); |
| end |
| |
| /////////////////////////////////////// |
| // Valid checks // |
| /////////////////////////////////////// |
| |
| // check that the item is valid - all registers clean base on mode // |
| if (input_item.valid && !input_item.manual_op) begin |
| // update key with what came from sideload |
| if(input_item.sideload_en && input_item.start_item) begin |
| input_item.key = key_item.key; |
| input_item.key_vld = key_item.key_vld; |
| end |
| case (input_item.mode) |
| AES_ECB: begin |
| `uvm_info(`gfn, $sformatf("\n\t ----| ECB mode"), UVM_FULL) |
| if (input_item.start_item) begin |
| // verify that all 4 data_in and all 8 key have been updated |
| if (input_item.data_in_valid() && input_item.key_clean(0,0)) begin |
| //clone and add to ref and rec data fifo |
| ok_to_fwd = 1; |
| input_item.start_item = 0; |
| end |
| end else begin |
| // verify that all 4 data_in and all 8 key are clean |
| `uvm_info(`gfn, $sformatf("\n\t ----|data_inv_vld? %b, key clean ? %b", |
| input_item.data_in_valid(), input_item.key_clean(1,0)), UVM_MEDIUM) |
| |
| if (input_item.data_in_valid() && input_item.key_clean(1,0)) begin |
| //clone and add to ref and rec data fifo |
| ok_to_fwd = 1; |
| end |
| end |
| end |
| |
| AES_CBC: begin |
| `uvm_info(`gfn, $sformatf("\n\t ----| CBC mode"), UVM_FULL) |
| if (input_item.start_item) begin |
| // verify that all 4 data_in and all 8 key and all 4 IV have been updated |
| if (input_item.data_in_valid() && input_item.key_clean(0,0) |
| && input_item.iv_clean(0,0)) begin |
| //clone and add to ref and rec data fifo |
| ok_to_fwd = 1; |
| input_item.start_item = 0; |
| end |
| end else begin |
| // verify that all 4 data_in and all 8 key and all 4 IV are clean |
| `uvm_info(`gfn, $sformatf("\n\t ----|data_inv_vld? %b, key clean ? %b", |
| input_item.data_in_valid(), input_item.key_clean(1,0)), UVM_MEDIUM) |
| |
| if (input_item.data_in_valid() && input_item.key_clean(1,0) |
| && input_item.iv_clean(1,0)) begin |
| //clone and add to ref and rec data fifo |
| ok_to_fwd = 1; |
| end |
| end |
| end |
| |
| AES_CFB: begin |
| if (input_item.start_item) begin |
| // verify that all 4 data_in and all 8 key and all 4 IV have been updated |
| if (input_item.data_in_valid() && input_item.key_clean(0,0) |
| && input_item.iv_clean(0,0)) begin |
| //clone and add to ref and rec data fifo |
| ok_to_fwd = 1; |
| input_item.start_item = 0; |
| end |
| end else begin |
| // verify that all 4 data_in and all 8 key and all 4 IV are clean |
| if (input_item.data_in_valid() && input_item.key_clean(1,0) |
| && input_item.iv_clean(1,0)) begin |
| //clone and add to ref and rec data fifo |
| ok_to_fwd = 1; |
| end |
| end |
| end |
| |
| AES_OFB: begin |
| if (input_item.start_item) begin |
| // verify that all 4 data_in and all 8 key and all 4 IV have been updated |
| if (input_item.data_in_valid() && input_item.key_clean(0,0) |
| && input_item.iv_clean(0,0)) begin |
| //clone and add to ref and rec data fifo |
| ok_to_fwd = 1; |
| input_item.start_item = 0; |
| end |
| end else begin |
| // verify that all 4 data_in and all 8 key and all 4 IV are clean |
| `uvm_info(`gfn, $sformatf("\n\t ----|data_inv_vld? %b, key clean ? %b", |
| input_item.data_in_valid(), input_item.key_clean(1,0)), UVM_HIGH) |
| |
| if (input_item.data_in_valid() && input_item.key_clean(1,0) |
| && input_item.iv_clean(1,0)) begin |
| //clone and add to ref and rec data fifo |
| ok_to_fwd = 1; |
| end |
| end |
| end |
| |
| AES_CTR: begin |
| `uvm_info(`gfn, $sformatf("\n\t ----| CTR mode"), UVM_FULL) |
| if (input_item.start_item) begin |
| // verify that all 4 data_in and all 8 key and all 4 IV have been updated |
| if (input_item.data_in_valid() && input_item.key_clean(0,0) |
| && input_item.iv_clean(0,0)) begin |
| //clone and add to ref and rec data fifo |
| ok_to_fwd = 1; |
| input_item.start_item = 0; |
| end |
| end else begin |
| // verify that all 4 data_in and all 8 and all 4 IV key are clean |
| `uvm_info(`gfn, $sformatf("\n\t ----|data_inv_vld? %b, key clean ? %b", |
| input_item.data_in_valid(), |
| input_item.key_clean(1,0)),UVM_MEDIUM) |
| if (input_item.data_in_valid() && input_item.key_clean(1,0) |
| && input_item.iv_clean(1,0)) begin |
| //clone and add to ref and rec data fifo |
| ok_to_fwd = 1; |
| end |
| end |
| end |
| default: begin |
| `uvm_info(`gfn, |
| $sformatf("\n\t ----| Received illegal AES_MODE setting reverting to AES_NONE "), |
| UVM_HIGH) |
| end |
| endcase // case (input_item.mode) |
| end // if (input_item.valid) |
| |
| // forward item to receive side |
| if (ok_to_fwd) begin |
| ok_to_fwd = 0; |
| `downcast(input_clone, input_item.clone()); |
| `uvm_info(`gfn, $sformatf("\n\t AES INPUT ITEM RECEIVED - \n %s \n\t split message: %0b", |
| input_clone.convert2string(), input_clone.split_item), |
| UVM_MEDIUM) |
| rcv_item_q.push_front(input_clone); |
| input_item.clean(); |
| // only reset the split here |
| // in the case the reset comes after data input |
| // having it in clean will reset it when the ctrl |
| // is written |
| input_item.split_item = 0; |
| end |
| end |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // get an item from the rcv queue and wait for all output data to be received |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| `uvm_info(`gfn, $sformatf("\n\t ---| channel %h", channel), UVM_DEBUG) |
| if (!write && channel == DataChannel) begin |
| if (do_read_check) begin |
| `DV_CHECK_EQ(csr.get_mirrored_value(), item.d_data, |
| $sformatf("reg name: %0s", csr.get_full_name())) |
| end |
| void'(csr.predict(.value(item.d_data), .kind(UVM_PREDICT_READ))); |
| `uvm_info(`gfn, $sformatf("\n\t ----| SAW READ - %s data %02h",csr.get_name(), item.d_data) |
| , UVM_MEDIUM) |
| |
| case (csr.get_name()) |
| "data_out_0": begin |
| output_item.data_out[0] = item.d_data; |
| output_item.data_out_vld[0] = 1; |
| cov_if.cg_rd_data_sample(0); |
| end |
| "data_out_1": begin |
| output_item.data_out[1] = item.d_data; |
| output_item.data_out_vld[1] = 1; |
| cov_if.cg_rd_data_sample(1); |
| end |
| "data_out_2": begin |
| output_item.data_out[2] = item.d_data; |
| output_item.data_out_vld[2] = 1; |
| cov_if.cg_rd_data_sample(2); |
| end |
| "data_out_3": begin |
| output_item.data_out[3] = item.d_data; |
| output_item.data_out_vld[3] = 1; |
| cov_if.cg_rd_data_sample(3); |
| end |
| |
| "status": begin |
| cov_if.cg_status_sample(item.d_data); |
| datain_rdy = (get_field_val(ral.status.input_ready, item.d_data) == 1) ? '1 : '0; |
| // if dut IDLE and able to accept input |
| // and no output is ready |
| // there won't be a response for this item |
| // reset/clear was triggered |
| `uvm_info(`gfn, $sformatf("\n\t ---| Status read: \n\t idle %0b \n\t output lost %0b ", |
| get_field_val(ral.status.idle, item.d_data), |
| get_field_val(ral.status.output_lost, item.d_data)), UVM_MEDIUM) |
| |
| if (get_field_val(ral.status.idle, item.d_data) && |
| get_field_val(ral.status.output_lost, item.d_data)) begin |
| if (rcv_item_q.size() != 0) begin |
| void'(rcv_item_q.pop_back()); |
| `uvm_info(`gfn, $sformatf("\n\t ----| removing item from input queue"), UVM_MEDIUM) |
| end |
| end |
| end |
| endcase // case (csr.get_name()) |
| |
| if (output_item.data_out_valid() || output_item.data_was_cleared) begin |
| // if data_out is read multipletimes in a row we should not pop input more than once |
| if (rcv_item_q.size() == 0) begin |
| output_item = new(); |
| end else begin |
| |
| complete_item = rcv_item_q.pop_back(); |
| complete_item.data_out = output_item.data_out; |
| complete_item.data_was_cleared = output_item.data_was_cleared; |
| // if message was split and data was read out. |
| // we will have one more message than expected. |
| if (complete_item.split_item) begin |
| cfg.split_cnt++; |
| `uvm_info(`gfn, $sformatf("\n\t ----| incrementing split count now at: %d", |
| cfg.split_cnt), UVM_MEDIUM) |
| end |
| |
| `downcast(complete_clone, complete_item.clone()); |
| item_fifo.put(complete_clone); |
| output_item = new(); |
| complete_item = new(); |
| end |
| end |
| end |
| endtask // process_tl_access |
| |
| |
| //This task will check for any sideload keys that have been provided |
| virtual task process_sideload_key(); |
| key_sideload_item sideload_item; |
| sideload_item = new("sideload_item"); |
| |
| forever begin |
| // Wait for a valid sideloaded key |
| key_manager_fifo.get(sideload_item); |
| // Note: max size of sideloaded key is keymgr_pkg::KeyWidth |
| |
| for (int i = 0; i < keymgr_pkg::KeyWidth / 32; i++) begin |
| key_item.key[0][i] = sideload_item.key0[i*32 +: 32]; |
| key_item.key[1][i] = sideload_item.key1[i*32 +: 32]; |
| key_item.key_vld[0][i] = sideload_item.valid; |
| key_item.key_vld[1][i] = sideload_item.valid; |
| end |
| end |
| endtask |
| |
| |
| // takes items from the item queue and builds full |
| // aes_messages with both input data and output data. |
| virtual task rebuild_message(); |
| typedef enum { MSG_START,MSG_RUN } aes_message_stat_t; |
| |
| aes_message_item message, msg_clone; |
| aes_seq_item full_item; |
| aes_message_stat_t msg_state = MSG_START; |
| |
| |
| message = new(); |
| |
| fork |
| begin |
| forever begin |
| item_fifo.get(full_item); |
| case (msg_state) |
| MSG_START: begin |
| `uvm_info(`gfn, $sformatf("\t ----| got item from item fifo"), UVM_MEDIUM) |
| if (!full_item.message_start()) begin |
| // check if start trigger was fired prematurely |
| if (full_item.start_item && full_item.manual_op) begin |
| message.skip_msg = 1; |
| `uvm_info(`gfn, $sformatf("\n setting skip msg"), UVM_MEDIUM) |
| end else begin |
| `uvm_fatal(`gfn, |
| $sformatf("\n\t ----| FIRST ITEM DID NOT HAVE MESSAGE START/CONFIG SETTINGS")) |
| end |
| end |
| message.add_start_msg_item(full_item); |
| msg_state = MSG_RUN; |
| end |
| |
| MSG_RUN: begin |
| if (full_item.message_start() || (full_item.start_item && full_item.manual_op)) begin |
| `downcast(msg_clone, message.clone()); |
| msg_fifo.put(msg_clone); |
| message = new(); |
| if (full_item.start_item && full_item.manual_op) begin |
| // only set skip if this is not a real start message |
| message.skip_msg = ~full_item.message_start() || ~full_item.data_in_valid(); |
| end |
| message.add_start_msg_item(full_item); |
| end else begin |
| message.add_data_item(full_item); |
| end |
| end |
| endcase // case (msg_state) |
| end |
| end |
| |
| begin |
| wait (finish_message) |
| `uvm_info(`gfn, $sformatf("\n\t ----| Finish test received adding message item to mg_fifo"), |
| UVM_MEDIUM) |
| `downcast(msg_clone, message.clone()); |
| msg_fifo.put(msg_clone); |
| end |
| |
| begin: check_for_reset |
| forever begin |
| wait (reset_compare); |
| msg_state = MSG_START; |
| message = new(); |
| reset_compare = 0; |
| end |
| end |
| join |
| endtask // rebuild_message |
| |
| |
| virtual task compare(); |
| string txt=""; |
| bit [3:0][31:0] tmp_input; |
| bit [3:0][31:0] tmp_output; |
| forever begin |
| bit operation; |
| aes_message_item msg; |
| msg_fifo.get(msg); |
| |
| if (msg.aes_mode != AES_NONE && !msg.skip_msg) begin |
| msg.alloc_predicted_msg(); |
| |
| //ref-model / opration / chipher mode / IV / key_len / key /data i /data o // |
| operation = msg.aes_operation == AES_ENC ? 1'b0 : |
| msg.aes_operation == AES_DEC ? 1'b1 : 1'b0; |
| c_dpi_aes_crypt_message(cfg.ref_model, operation, msg.aes_mode, msg.aes_iv, |
| msg.aes_keylen, msg.aes_key[0] ^ msg.aes_key[1], |
| msg.input_msg, msg.predicted_msg); |
| |
| `uvm_info(`gfn, $sformatf("\n\t ----| printing MESSAGE %s", msg.convert2string()), |
| UVM_MEDIUM) |
| txt = ""; |
| |
| foreach (msg.input_msg[i]) begin |
| txt = { txt, $sformatf("\n\t %d %h \t %h \t %h \t %b", |
| i, msg.input_msg[i], msg.output_msg[i], msg.predicted_msg[i], msg.output_cleared[i])}; |
| end |
| |
| for (int n =0 ; n < msg.input_msg.size(); n++) begin |
| if ((msg.output_msg[n] != msg.predicted_msg[n]) && ~msg.output_cleared[n]) begin |
| txt = {"\t TEST FAILED MESSAGES DID NOT MATCH \n ", txt}; |
| |
| txt = {txt, |
| $sformatf("\n\n\t ----| ACTUAL OUTPUT DID NOT MATCH PREDICTED OUTPUT |----")}; |
| txt = {txt, |
| $sformatf("\n\t ----| FAILED AT BYTE #%0d \t ACTUAL: 0x%h \t PREDICTED: 0x%h ", |
| n, msg.output_msg[n], msg.predicted_msg[n])}; |
| `uvm_fatal(`gfn, $sformatf(" # %0d \n\t %s \n", good_cnt, txt)) |
| end |
| end |
| `uvm_info(`gfn, $sformatf("\n\t ----| MESSAGE #%0d MATCHED %s |-----", |
| good_cnt, msg.aes_mode.name() ), |
| UVM_MEDIUM) |
| good_cnt++; |
| end else begin |
| if (msg.aes_mode == AES_NONE) begin |
| `uvm_info(`gfn, |
| $sformatf("\n\t ----| MESSAGE #%0d HAS ILLEGAL MODE MESSAGE IGNORED |-----", |
| good_cnt), UVM_MEDIUM) |
| corrupt_cnt++; |
| end |
| if (msg.skip_msg) begin |
| `uvm_info(`gfn, |
| $sformatf("\n\t ----| MESSAGE #%0d was skipped due to start triggered prematurely", |
| good_cnt), UVM_MEDIUM) |
| skipped_cnt++; |
| end |
| end |
| end |
| endtask |
| |
| // TODO get rid of this and do EOP checks in monitor |
| virtual function void phase_ready_to_end(uvm_phase phase); |
| if (phase.get_name() != "run") return; |
| |
| // the message currently being reassembled is should be sent for scoring |
| finish_message = 1; |
| `uvm_info(`gfn, $sformatf("Finish message: %b", finish_message), UVM_MEDIUM) |
| |
| // AES needs this objection - because PHASE READY TO END |
| // is the only way to know that the very last message is now complete |
| phase.raise_objection(this, "need time to finish last item"); |
| fork begin |
| wait_fifo_empty(); |
| phase.drop_objection(this); |
| end |
| join_none |
| endfunction |
| |
| |
| virtual task wait_fifo_empty(); |
| `uvm_info(`gfn, $sformatf("item fifo entries %d", item_fifo.num()), UVM_MEDIUM) |
| `uvm_info(`gfn, $sformatf("rcv_queue entries %d", rcv_item_q.size()), UVM_MEDIUM) |
| `uvm_info(`gfn, $sformatf("msg fifo entries %d", msg_fifo.num()), UVM_MEDIUM) |
| wait (rcv_item_q.size() == 0); |
| wait (item_fifo.num() == 0); |
| wait (msg_fifo.num() == 0); |
| endtask |
| |
| |
| virtual function void reset(string kind = "HARD"); |
| aes_seq_item seq_item; |
| aes_message_item msg_item; |
| super.reset(kind); |
| // reset local fifos queues and variables |
| rcv_item_q.delete(); |
| while (item_fifo.try_get(seq_item)); |
| while (msg_fifo.try_get(msg_item)); |
| |
| skipped_cnt = 0; |
| good_cnt = 0; |
| cfg.split_cnt = 0; |
| // if split is set before reset make sure to cancel |
| input_item.split_item = 0; |
| // reset compare task to start |
| reset_compare = 1; |
| endfunction |
| |
| |
| function void check_phase(uvm_phase phase); |
| string txt = ""; |
| uvm_report_server rpt_srvr; |
| |
| if (cfg.en_scb) begin |
| super.check_phase(phase); |
| `DV_EOT_PRINT_MAILBOX_CONTENTS(aes_message_item, msg_fifo) |
| `DV_EOT_PRINT_MAILBOX_CONTENTS(aes_seq_item, item_fifo) |
| `DV_EOT_PRINT_Q_CONTENTS(aes_seq_item, rcv_item_q) |
| // check that we saw all messages |
| // if there is more than expected check split count |
| if (good_cnt < |
| (cfg.num_messages - cfg.num_corrupt_messages - skipped_cnt)) begin |
| rpt_srvr = uvm_report_server::get_server(); |
| if (rpt_srvr.get_severity_count(UVM_FATAL) |
| + rpt_srvr.get_severity_count(UVM_ERROR) == 0) begin |
| txt = "\n\t ----| NO FAILURES BUT NUMBER OF EXPECTED MESSAGES DOES NOT MATCH ACTUAL"; |
| end else begin |
| txt = "\n\t ----| TEST FAILED"; |
| end |
| |
| txt = { txt, $sformatf(" \n\t ----| Expected:\t %d", cfg.num_messages)}; |
| txt = { txt, $sformatf(" \n\t ----| Seen: \t%d", good_cnt)}; |
| txt = { txt, $sformatf(" \n\t ----| Expected corrupted: \t%d", cfg.num_corrupt_messages)}; |
| txt = { txt, $sformatf(" \n\t ----| Seen corrupted: \t%d", corrupt_cnt)}; |
| txt = { txt, $sformatf(" \n\t ----| Skipped: \t%d", skipped_cnt)}; |
| txt = { txt, $sformatf(" \n\t ----| Split: \t%d", cfg.split_cnt)}; |
| `uvm_fatal(`gfn, $sformatf("%s", txt) ) |
| end |
| if ((good_cnt > (cfg.num_messages - cfg.num_corrupt_messages - skipped_cnt)) |
| && (cfg.split_cnt == 0)) begin |
| txt = " SAW TOO MANY MESSAGES AND NONE WAS SPLIT"; |
| txt = { txt, $sformatf(" \n\t ----| Expected:\t %d", cfg.num_messages)}; |
| txt = { txt, $sformatf(" \n\t ----| Seen: \t%d", good_cnt)}; |
| txt = { txt, $sformatf(" \n\t ----| Expected corrupted: \t%d", cfg.num_corrupt_messages)}; |
| txt = { txt, $sformatf(" \n\t ----| Seen corrupted: \t%d", corrupt_cnt)}; |
| txt = { txt, $sformatf(" \n\t ----| Skipped: \t%d", skipped_cnt)}; |
| txt = { txt, $sformatf(" \n\t ----| Split: \t%d", cfg.split_cnt)}; |
| `uvm_fatal(`gfn, $sformatf("%s", txt)) |
| end |
| end |
| endfunction |
| |
| |
| function void report_phase(uvm_phase phase); |
| uvm_report_server rpt_srvr; |
| string txt=""; |
| |
| super.report_phase(phase); |
| txt = $sformatf("\n\t ----| TEST FINISHED |----"); |
| txt = { txt, $sformatf("\n\t Saw %d Good messages ", good_cnt)}; |
| txt = { txt, $sformatf("\n\t Skipped %d messages " , skipped_cnt)}; |
| txt = { txt, $sformatf("\n\t Split %d messages " , cfg.split_cnt)}; |
| txt = { txt, $sformatf("\n\t Expected %d messages ", cfg.num_messages)}; |
| txt = { txt, $sformatf("\n\t Expected %d corrupted ", cfg.num_corrupt_messages)}; |
| rpt_srvr = uvm_report_server::get_server(); |
| if (rpt_srvr.get_severity_count(UVM_FATAL)+rpt_srvr.get_severity_count(UVM_ERROR)>0) begin |
| `uvm_info(`gfn, $sformatf("%s", cfg.convert2string()), UVM_LOW) |
| txt = { txt,"\n\t---------------------------------------"}; |
| txt = { txt,"\n\t---- TEST FAILED ----"}; |
| txt = { txt,"\n\t---------------------------------------"}; |
| end else begin |
| txt = {txt, "\n\t---------------------------------------"}; |
| txt = { txt,"\n\t---- TEST PASSED ----"}; |
| txt = { txt,"\n\t---------------------------------------"}; |
| end |
| `uvm_info(`gfn, $sformatf("%s", txt), UVM_MEDIUM) |
| |
| endfunction // report_phase |
| endclass |