diff --git a/.github/workflows/uvm_ci.yaml b/.github/workflows/uvm_ci.yaml new file mode 100644 index 0000000..b7253e4 --- /dev/null +++ b/.github/workflows/uvm_ci.yaml @@ -0,0 +1,26 @@ +name: Run UVM tests + +on: + push: # This now triggers on pushes to any branch + pull_request: # This now triggers on pull requests to any branch + +jobs: + Extract-Buses: + runs-on: ubuntu-latest + outputs: + IPs: ${{ steps.set-IPs-matrix.outputs.IPs }} + buses: ${{ steps.extract_buses.outputs.buses }} + steps: + - name: Extract Supported Buses + id: extract_buses + uses: efabless/EF_UVM/.github/actions/get-bus@main + - name: Check Output + run: echo ${{ steps.extract_buses.outputs.buses }} + Run-IP-Tests: + uses: efabless/EF_UVM/.github/workflows/run_IP.yaml@main + needs: [Extract-Buses] + with: + test-names: "all_tests" + name: ${{ github.event.repository.name }} + buses: ${{ needs.Extract-Buses.outputs.buses }} + is-ip: true \ No newline at end of file diff --git a/EF_AES.yaml b/EF_AES.yaml index 6f554c0..e44879b 100644 --- a/EF_AES.yaml +++ b/EF_AES.yaml @@ -76,25 +76,30 @@ ports: registers: - name: STATUS - size: 8 + size: 3 mode: r fifo: no offset: 0 bit_access: no - description: "Status register bit 6: ready , bit 7: valid" + description: "Status register bit 0: valid, bit 1: ready, bit 2: key ready" fields: + - name: valid_reg + bit_offset: 0 + bit_width: 1 + read_port: result_valid + description: Result is valid - name: ready_reg - bit_offset: 6 + bit_offset: 1 bit_width: 1 read_port: ready description: Ready to start - - name: valid_reg - bit_offset: 7 + - name: key_ready_reg + bit_offset: 2 bit_width: 1 - read_port: result_valid - description: Result is valid + read_port: key_ready + description: Key is ready - name: CTRL - size: 8 + size: 4 mode: w fifo: no offset: 4 @@ -264,3 +269,6 @@ flags: - name: ready port: ready description: Ready to start +- name: key_ready + port: key_ready + description: Key is ready diff --git a/hdl/rtl/aes_core.v b/hdl/rtl/aes_core.v index 030ffc2..995cd77 100644 --- a/hdl/rtl/aes_core.v +++ b/hdl/rtl/aes_core.v @@ -53,7 +53,8 @@ module aes_core( input wire [127 : 0] block, output wire [127 : 0] result, - output wire result_valid + output wire result_valid, + output wire key_ready ); @@ -89,7 +90,6 @@ module aes_core( reg init_state; wire [127 : 0] round_key; - wire key_ready; reg enc_next; wire [3 : 0] enc_round_nr; diff --git a/hdl/rtl/bus_wrappers/EF_AES_AHBL.v b/hdl/rtl/bus_wrappers/EF_AES_AHBL.v index 531927e..c8a63cf 100644 --- a/hdl/rtl/bus_wrappers/EF_AES_AHBL.v +++ b/hdl/rtl/bus_wrappers/EF_AES_AHBL.v @@ -1,311 +1,246 @@ /* - Copyright 2025 Efabless Corp. + Copyright 2023 secworks - Author: Efabless Corp. (ip_admin@efabless.com) + Author: Joachim Strombergson () - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + This file is auto-generated by wrapper_gen.py on 2023-11-05 - www.apache.org/licenses/LICENSE-2.0 + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. -*/ - -/* THIS FILE IS GENERATED, DO NOT EDIT */ - -`timescale 1ns / 1ps -`default_nettype none - -module EF_AES_AHBL ( - - input wire HCLK, - input wire HRESETn, - input wire HWRITE, - input wire [31:0] HWDATA, - input wire [31:0] HADDR, - input wire [ 1:0] HTRANS, - input wire HSEL, - input wire HREADY, - output wire HREADYOUT, - output wire [31:0] HRDATA, - output wire IRQ - -); - - localparam STATUS_REG_OFFSET = 16'h0000; - localparam CTRL_REG_OFFSET = 16'h0004; - localparam KEY0_REG_OFFSET = 16'h0008; - localparam KEY1_REG_OFFSET = 16'h000C; - localparam KEY2_REG_OFFSET = 16'h0010; - localparam KEY3_REG_OFFSET = 16'h0014; - localparam KEY4_REG_OFFSET = 16'h0018; - localparam KEY5_REG_OFFSET = 16'h001C; - localparam KEY6_REG_OFFSET = 16'h0020; - localparam KEY7_REG_OFFSET = 16'h0024; - localparam BLOCK0_REG_OFFSET = 16'h0028; - localparam BLOCK1_REG_OFFSET = 16'h002C; - localparam BLOCK2_REG_OFFSET = 16'h0030; - localparam BLOCK3_REG_OFFSET = 16'h0034; - localparam RESULT0_REG_OFFSET = 16'h0038; - localparam RESULT1_REG_OFFSET = 16'h003C; - localparam RESULT2_REG_OFFSET = 16'h0040; - localparam RESULT3_REG_OFFSET = 16'h0044; - localparam IM_REG_OFFSET = 16'hFF00; - localparam MIS_REG_OFFSET = 16'hFF04; - localparam RIS_REG_OFFSET = 16'hFF08; - localparam IC_REG_OFFSET = 16'hFF0C; - - reg [0:0] GCLK_REG; - wire clk_g; - - wire clk_gated_en = GCLK_REG[0]; - ef_util_gating_cell clk_gate_cell ( - - // USE_POWER_PINS - .clk(HCLK), - .clk_en(clk_gated_en), - .clk_o(clk_g) - ); - - wire clk = clk_g; - wire reset_n = HRESETn; - - reg last_HSEL, last_HWRITE; - reg [31:0] last_HADDR; - reg [ 1:0] last_HTRANS; - always @(posedge HCLK or negedge HRESETn) begin - if (~HRESETn) begin - last_HSEL <= 1'b0; - last_HADDR <= 1'b0; - last_HWRITE <= 1'b0; - last_HTRANS <= 1'b0; - end else if (HREADY) begin - last_HSEL <= HSEL; - last_HADDR <= HADDR; - last_HWRITE <= HWRITE; - last_HTRANS <= HTRANS; - end - end - wire ahbl_valid = last_HSEL & last_HTRANS[1]; - wire ahbl_we = last_HWRITE & ahbl_valid; - wire ahbl_re = ~last_HWRITE & ahbl_valid; - - wire [1-1:0] encdec; - reg [1-1:0] init; - reg [1-1:0] next; - wire [1-1:0] ready; - wire [256-1:0] key; - wire [1-1:0] keylen; - wire [128-1:0] block; - wire [128-1:0] result; - wire [1-1:0] result_valid; - - // Register Definitions - wire [8-1:0] STATUS_WIRE; - assign STATUS_WIRE[6 : 6] = ready; - assign STATUS_WIRE[7 : 7] = result_valid; - - reg [7:0] CTRL_REG; - assign encdec = CTRL_REG[2 : 2]; - assign keylen = CTRL_REG[3 : 3]; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) CTRL_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == CTRL_REG_OFFSET)) CTRL_REG <= HWDATA[8-1:0]; - - reg [31:0] KEY0_REG; - assign key[31:0] = KEY0_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) KEY0_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == KEY0_REG_OFFSET)) KEY0_REG <= HWDATA[32-1:0]; - - reg [31:0] KEY1_REG; - assign key[63:32] = KEY1_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) KEY1_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == KEY1_REG_OFFSET)) KEY1_REG <= HWDATA[32-1:0]; + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - reg [31:0] KEY2_REG; - assign key[95:64] = KEY2_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) KEY2_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == KEY2_REG_OFFSET)) KEY2_REG <= HWDATA[32-1:0]; - - reg [31:0] KEY3_REG; - assign key[127:96] = KEY3_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) KEY3_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == KEY3_REG_OFFSET)) KEY3_REG <= HWDATA[32-1:0]; - - reg [31:0] KEY4_REG; - assign key[159:128] = KEY4_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) KEY4_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == KEY4_REG_OFFSET)) KEY4_REG <= HWDATA[32-1:0]; - - reg [31:0] KEY5_REG; - assign key[191:160] = KEY5_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) KEY5_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == KEY5_REG_OFFSET)) KEY5_REG <= HWDATA[32-1:0]; - - reg [31:0] KEY6_REG; - assign key[223:192] = KEY6_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) KEY6_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == KEY6_REG_OFFSET)) KEY6_REG <= HWDATA[32-1:0]; - - reg [31:0] KEY7_REG; - assign key[255:224] = KEY7_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) KEY7_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == KEY7_REG_OFFSET)) KEY7_REG <= HWDATA[32-1:0]; - - reg [31:0] BLOCK0_REG; - assign block[31:0] = BLOCK0_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) BLOCK0_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == BLOCK0_REG_OFFSET)) BLOCK0_REG <= HWDATA[32-1:0]; - - reg [31:0] BLOCK1_REG; - assign block[63:32] = BLOCK1_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) BLOCK1_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == BLOCK1_REG_OFFSET)) BLOCK1_REG <= HWDATA[32-1:0]; - - reg [31:0] BLOCK2_REG; - assign block[95:64] = BLOCK2_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) BLOCK2_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == BLOCK2_REG_OFFSET)) BLOCK2_REG <= HWDATA[32-1:0]; - - reg [31:0] BLOCK3_REG; - assign block[127:96] = BLOCK3_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) BLOCK3_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == BLOCK3_REG_OFFSET)) BLOCK3_REG <= HWDATA[32-1:0]; - - reg [31:0] RESULT0_REG; - assign result[31:0] = RESULT0_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) RESULT0_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == RESULT0_REG_OFFSET)) RESULT0_REG <= HWDATA[32-1:0]; - - reg [31:0] RESULT1_REG; - assign result[63:32] = RESULT1_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) RESULT1_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == RESULT1_REG_OFFSET)) RESULT1_REG <= HWDATA[32-1:0]; - - reg [31:0] RESULT2_REG; - assign result[95:64] = RESULT2_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) RESULT2_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == RESULT2_REG_OFFSET)) RESULT2_REG <= HWDATA[32-1:0]; - - reg [31:0] RESULT3_REG; - assign result[127:96] = RESULT3_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) RESULT3_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == RESULT3_REG_OFFSET)) RESULT3_REG <= HWDATA[32-1:0]; - - localparam GCLK_REG_OFFSET = 16'hFF10; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) GCLK_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == GCLK_REG_OFFSET)) GCLK_REG <= HWDATA[1-1:0]; - - reg [ 1:0] IM_REG; - reg [ 1:0] IC_REG; - reg [ 1:0] RIS_REG; +*/ - wire [2-1:0] MIS_REG = RIS_REG & IM_REG; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) IM_REG <= 0; - else if (ahbl_we & (last_HADDR[16-1:0] == IM_REG_OFFSET)) IM_REG <= HWDATA[2-1:0]; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) IC_REG <= 2'b0; - else if (ahbl_we & (last_HADDR[16-1:0] == IC_REG_OFFSET)) IC_REG <= HWDATA[2-1:0]; - else IC_REG <= 2'd0; - wire [0:0] valid = result_valid; +`timescale 1ns/1ns +`default_nettype none - integer _i_; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) RIS_REG <= 0; - else begin - for (_i_ = 0; _i_ < 1; _i_ = _i_ + 1) begin - if (IC_REG[_i_]) RIS_REG[_i_] <= 1'b0; - else if (valid[_i_-0] == 1'b1) RIS_REG[_i_] <= 1'b1; - end - for (_i_ = 1; _i_ < 2; _i_ = _i_ + 1) begin - if (IC_REG[_i_]) RIS_REG[_i_] <= 1'b0; - else if (ready[_i_-1] == 1'b1) RIS_REG[_i_] <= 1'b1; - end - end - assign IRQ = |MIS_REG; - - reg valid_ctrl_wr; - always @(posedge HCLK or negedge HRESETn) - if (~HRESETn) begin - init <= 1'h0; - next <= 1'h0; - valid_ctrl_wr <= 1'b0; - end else if (valid_ctrl_wr) begin - init <= CTRL_REG[0]; - next <= CTRL_REG[1]; - valid_ctrl_wr <= last_HADDR[15:0]==CTRL_REG_OFFSET & ahbl_we; - end else begin - init <= 1'h0; - next <= 1'h0; - valid_ctrl_wr <= last_HADDR[15:0]==CTRL_REG_OFFSET & ahbl_we; - end - aes_core instance_to_wrap ( - .clk(clk), - .reset_n(reset_n), - .encdec(encdec), - .init(init), - .next(next), - .ready(ready), - .key(key), - .keylen(keylen), - .block(block), - .result(result), - .result_valid(result_valid) - ); - assign HRDATA = - (last_HADDR[16-1:0] == STATUS_REG_OFFSET) ? STATUS_WIRE : - (last_HADDR[16-1:0] == CTRL_REG_OFFSET) ? CTRL_REG : - (last_HADDR[16-1:0] == KEY0_REG_OFFSET) ? KEY0_REG : - (last_HADDR[16-1:0] == KEY1_REG_OFFSET) ? KEY1_REG : - (last_HADDR[16-1:0] == KEY2_REG_OFFSET) ? KEY2_REG : - (last_HADDR[16-1:0] == KEY3_REG_OFFSET) ? KEY3_REG : - (last_HADDR[16-1:0] == KEY4_REG_OFFSET) ? KEY4_REG : - (last_HADDR[16-1:0] == KEY5_REG_OFFSET) ? KEY5_REG : - (last_HADDR[16-1:0] == KEY6_REG_OFFSET) ? KEY6_REG : - (last_HADDR[16-1:0] == KEY7_REG_OFFSET) ? KEY7_REG : - (last_HADDR[16-1:0] == BLOCK0_REG_OFFSET) ? BLOCK0_REG : - (last_HADDR[16-1:0] == BLOCK1_REG_OFFSET) ? BLOCK1_REG : - (last_HADDR[16-1:0] == BLOCK2_REG_OFFSET) ? BLOCK2_REG : - (last_HADDR[16-1:0] == BLOCK3_REG_OFFSET) ? BLOCK3_REG : - (last_HADDR[16-1:0] == RESULT0_REG_OFFSET) ? RESULT0_REG : - (last_HADDR[16-1:0] == RESULT1_REG_OFFSET) ? RESULT1_REG : - (last_HADDR[16-1:0] == RESULT2_REG_OFFSET) ? RESULT2_REG : - (last_HADDR[16-1:0] == RESULT3_REG_OFFSET) ? RESULT3_REG : - (last_HADDR[16-1:0] == IM_REG_OFFSET) ? IM_REG : - (last_HADDR[16-1:0] == MIS_REG_OFFSET) ? MIS_REG : - (last_HADDR[16-1:0] == RIS_REG_OFFSET) ? RIS_REG : - (last_HADDR[16-1:0] == GCLK_REG_OFFSET) ? GCLK_REG : +module EF_AES_AHBL #(parameter CLKG=1)( + input wire HCLK, + input wire HRESETn, + input wire [31:0] HADDR, + input wire HWRITE, + input wire [1:0] HTRANS, + input wire HREADY, + input wire HSEL, + input wire [2:0] HSIZE, + input wire [31:0] HWDATA, + output wire [31:0] HRDATA, + output wire HREADYOUT, + output wire IRQ +); + localparam[15:0] STATUS_REG_ADDR = 16'h0000; + localparam[15:0] CTRL_REG_ADDR = 16'h0004; + localparam[15:0] KEY0_REG_ADDR = 16'h0008; + localparam[15:0] KEY1_REG_ADDR = 16'h000c; + localparam[15:0] KEY2_REG_ADDR = 16'h0010; + localparam[15:0] KEY3_REG_ADDR = 16'h0014; + localparam[15:0] KEY4_REG_ADDR = 16'h0018; + localparam[15:0] KEY5_REG_ADDR = 16'h001c; + localparam[15:0] KEY6_REG_ADDR = 16'h0020; + localparam[15:0] KEY7_REG_ADDR = 16'h0024; + localparam[15:0] BLOCK0_REG_ADDR = 16'h0028; + localparam[15:0] BLOCK1_REG_ADDR = 16'h002c; + localparam[15:0] BLOCK2_REG_ADDR = 16'h0030; + localparam[15:0] BLOCK3_REG_ADDR = 16'h0034; + localparam[15:0] RESULT0_REG_ADDR = 16'h0038; + localparam[15:0] RESULT1_REG_ADDR = 16'h003c; + localparam[15:0] RESULT2_REG_ADDR = 16'h0040; + localparam[15:0] RESULT3_REG_ADDR = 16'h0044; + localparam[15:0] IM_REG_ADDR = 16'hFF00; + localparam[15:0] MIS_REG_ADDR = 16'hFF04; + localparam[15:0] RIS_REG_ADDR = 16'hFF08; + localparam[15:0] IC_REG_ADDR = 16'hFF0C; + localparam[15:0] CLKG_REG_ADDR = 16'hFF10; + + reg last_HSEL; + reg [31:0] last_HADDR; + reg last_HWRITE; + reg [1:0] last_HTRANS; + + always@ (posedge HCLK or negedge HRESETn) begin + if (!HRESETn) begin + last_HSEL <= 0; + last_HADDR <= 0; + last_HWRITE <= 0; + last_HTRANS <= 0; + end else if (HREADY) begin + last_HSEL <= HSEL; + last_HADDR <= HADDR; + last_HWRITE <= HWRITE; + last_HTRANS <= HTRANS; + end + end + + reg [7:0] CTRL_REG; + reg [31:0] KEY0_REG; + reg [31:0] KEY1_REG; + reg [31:0] KEY2_REG; + reg [31:0] KEY3_REG; + reg [31:0] KEY4_REG; + reg [31:0] KEY5_REG; + reg [31:0] KEY6_REG; + reg [31:0] KEY7_REG; + reg [31:0] BLOCK0_REG; + reg [31:0] BLOCK1_REG; + reg [31:0] BLOCK2_REG; + reg [31:0] BLOCK3_REG; + reg [2:0] RIS_REG; + reg [2:0] IC_REG; + reg [2:0] IM_REG; + reg init; + reg next; + + wire ready, result_valid, key_ready; + wire[2:0] STATUS_REG = {key_ready, ready, result_valid}; + wire encdec = CTRL_REG[2:2]; + wire keylen = CTRL_REG[3:3]; + wire[255:0] key; + assign key[31:0] = KEY0_REG[31:0]; + assign key[63:32] = KEY1_REG[31:0]; + assign key[95:64] = KEY2_REG[31:0]; + assign key[127:96] = KEY3_REG[31:0]; + assign key[159:128] = KEY4_REG[31:0]; + assign key[191:160] = KEY5_REG[31:0]; + assign key[223:192] = KEY6_REG[31:0]; + assign key[255:224] = KEY7_REG[31:0]; + wire[127:0] block; + assign block[31:0] = BLOCK0_REG[31:0]; + assign block[63:32] = BLOCK1_REG[31:0]; + assign block[95:64] = BLOCK2_REG[31:0]; + assign block[127:96] = BLOCK3_REG[31:0]; + wire[127:0] result; + wire[31:0] RESULT0_REG = result[31:0]; + wire[31:0] RESULT1_REG = result[63:32]; + wire[31:0] RESULT2_REG = result[95:64]; + wire[31:0] RESULT3_REG = result[127:96]; + wire _VALID_FLAG_ = result_valid; + wire _READY_FLAG_ = ready; + wire _KEY_READY_FLAG_ = key_ready; + wire[2:0] MIS_REG = RIS_REG & IM_REG; + wire ahbl_valid = last_HSEL & last_HTRANS[1]; + wire ahbl_we = last_HWRITE & ahbl_valid; + wire ahbl_re = ~last_HWRITE & ahbl_valid; + // wire _clk_ = HCLK; + wire _rst_ = ~HRESETn; + wire gclk; + generate + if(CLKG == 1) begin + reg CLKG_REG; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) CLKG_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==CLKG_REG_ADDR)) CLKG_REG <= HWDATA[1-1:0]; + ef_util_gating_cell clk_gate_cell( + .clk(HCLK), + .clk_en(CLKG_REG), + .clk_o(gclk) + ); + end else + assign gclk = HCLK; + endgenerate + + aes_core inst_to_wrap ( + .clk(gclk), + .reset_n(~_rst_), + .encdec(encdec), + .init(init), + .next(next), + .ready(ready), + .key(key), + .keylen(keylen), + .block(block), + .result(result), + .result_valid(result_valid), + .key_ready(key_ready) + ); + + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) CTRL_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==CTRL_REG_ADDR)) CTRL_REG <= HWDATA[8-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) KEY0_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==KEY0_REG_ADDR)) KEY0_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) KEY1_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==KEY1_REG_ADDR)) KEY1_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) KEY2_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==KEY2_REG_ADDR)) KEY2_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) KEY3_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==KEY3_REG_ADDR)) KEY3_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) KEY4_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==KEY4_REG_ADDR)) KEY4_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) KEY5_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==KEY5_REG_ADDR)) KEY5_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) KEY6_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==KEY6_REG_ADDR)) KEY6_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) KEY7_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==KEY7_REG_ADDR)) KEY7_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) BLOCK0_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==BLOCK0_REG_ADDR)) BLOCK0_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) BLOCK1_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==BLOCK1_REG_ADDR)) BLOCK1_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) BLOCK2_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==BLOCK2_REG_ADDR)) BLOCK2_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) BLOCK3_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==BLOCK3_REG_ADDR)) BLOCK3_REG <= HWDATA[32-1:0]; + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) IM_REG <= 0; else if(ahbl_we & (last_HADDR[15:0]==IM_REG_ADDR)) IM_REG <= HWDATA[2-1:0]; + + always @(posedge HCLK or negedge HRESETn) if(~HRESETn) IC_REG <= 2'b0; else if(ahbl_we & (last_HADDR[15:0]==IC_REG_ADDR)) IC_REG <= HWDATA[2-1:0]; else IC_REG <= 2'd0; + + always @(posedge HCLK or negedge HRESETn) + if(~HRESETn) RIS_REG <= 3'd0; + else begin + if(_VALID_FLAG_) RIS_REG[0] <= 1'b1; else if(IC_REG[0]) RIS_REG[0] <= 1'b0; + if(_READY_FLAG_) RIS_REG[1] <= 1'b1; else if(IC_REG[1]) RIS_REG[1] <= 1'b0; + if(_KEY_READY_FLAG_) RIS_REG[2] <= 1'b1; else if(IC_REG[2]) RIS_REG[2] <= 1'b0; + + end + + reg valid_ctrl_wr; + always @(posedge HCLK or negedge HRESETn) + if (~HRESETn) begin + init <= 1'h0; + next <= 1'h0; + valid_ctrl_wr <= 1'b0; + end else if (valid_ctrl_wr) begin + init <= CTRL_REG[0]; + next <= CTRL_REG[1]; + valid_ctrl_wr <= last_HADDR[15:0]==CTRL_REG_ADDR & ahbl_we; + end else begin + init <= 1'h0; + next <= 1'h0; + valid_ctrl_wr <= last_HADDR[15:0]==CTRL_REG_ADDR & ahbl_we; + end + + assign IRQ = |MIS_REG; + + assign HRDATA = + (last_HADDR[15:0] == CTRL_REG_ADDR) ? CTRL_REG : + (last_HADDR[15:0] == KEY0_REG_ADDR) ? KEY0_REG : + (last_HADDR[15:0] == KEY1_REG_ADDR) ? KEY1_REG : + (last_HADDR[15:0] == KEY2_REG_ADDR) ? KEY2_REG : + (last_HADDR[15:0] == KEY3_REG_ADDR) ? KEY3_REG : + (last_HADDR[15:0] == KEY4_REG_ADDR) ? KEY4_REG : + (last_HADDR[15:0] == KEY5_REG_ADDR) ? KEY5_REG : + (last_HADDR[15:0] == KEY6_REG_ADDR) ? KEY6_REG : + (last_HADDR[15:0] == KEY7_REG_ADDR) ? KEY7_REG : + (last_HADDR[15:0] == BLOCK0_REG_ADDR) ? BLOCK0_REG : + (last_HADDR[15:0] == BLOCK1_REG_ADDR) ? BLOCK1_REG : + (last_HADDR[15:0] == BLOCK2_REG_ADDR) ? BLOCK2_REG : + (last_HADDR[15:0] == BLOCK3_REG_ADDR) ? BLOCK3_REG : + (last_HADDR[15:0] == RIS_REG_ADDR) ? RIS_REG : + (last_HADDR[15:0] == IC_REG_ADDR) ? IC_REG : + (last_HADDR[15:0] == IM_REG_ADDR) ? IM_REG : + (last_HADDR[15:0] == STATUS_REG_ADDR) ? STATUS_REG : + (last_HADDR[15:0] == RESULT0_REG_ADDR) ? RESULT0_REG : + (last_HADDR[15:0] == RESULT1_REG_ADDR) ? RESULT1_REG : + (last_HADDR[15:0] == RESULT2_REG_ADDR) ? RESULT2_REG : + (last_HADDR[15:0] == RESULT3_REG_ADDR) ? RESULT3_REG : + (last_HADDR[15:0] == MIS_REG_ADDR) ? MIS_REG : 32'hDEADBEEF; - assign HREADYOUT = 1'b1; + + assign HREADYOUT = 1'b1; endmodule diff --git a/verify/uvm-python/.gitignore b/verify/uvm-python/.gitignore new file mode 100644 index 0000000..51d311f --- /dev/null +++ b/verify/uvm-python/.gitignore @@ -0,0 +1,13 @@ +*.yalm +*.html +*.pyc +*/__pycache__/ +*.code-workspace +*.log +*.vcd +/sim/ +/coverageReports/ +*.xml +*.gtkw +/EF_UVM/ +IP_Utilities/ \ No newline at end of file diff --git a/verify/uvm-python/Makefile b/verify/uvm-python/Makefile new file mode 100644 index 0000000..4c0182b --- /dev/null +++ b/verify/uvm-python/Makefile @@ -0,0 +1,55 @@ +PLUSARGS += "+UVM_VERBOSITY=UVM_MEDUIM" +TOPLEVEL := top +MODULE ?= top_module +AHB_FILES ?= $(PWD)/../../hdl/rtl/bus_wrappers/EF_AES_AHBL.v +APB_FILES ?= $(PWD)/../../hdl/rtl/bus_wrappers/EF_AES_APB.v +WB_FILES ?= $(PWD)/../../hdl/rtl/bus_wrappers/EF_AES_WB.v +HDL_FILES ?= $(PWD)/../../hdl/rtl/aes_core.v $(PWD)/../../hdl/rtl/aes_decipher_block.v $(PWD)/../../hdl/rtl/aes_encipher_block.v $(PWD)/../../hdl/rtl/aes_inv_sbox.v $(PWD)/../../hdl/rtl/aes_key_mem.v $(PWD)/../../hdl/rtl/aes_sbox.v $(PWD)/../../hdl/rtl/aes.v $(PWD)/../../ip/EF_IP_UTIL/hdl/ef_util_lib.v +VERILOG_SOURCES ?= $(PWD)/top.v $(AHB_FILES) $(APB_FILES) $(WB_FILES) $(HDL_FILES) +RTL_MACROS += "" # Add macros needed +BUS_TYPE ?= APB +ifeq ($(BUS_TYPE),APB) + RTL_MACROS += -DBUS_TYPE_APB + DESIGN_NAME = EF_AES_APB + export CLK_MAKEFILE = PCLK + export RST_MAKEFILE = PRESETn +else ifeq ($(BUS_TYPE),AHB) + RTL_MACROS += -DBUS_TYPE_AHB + DESIGN_NAME = EF_AES_AHBL + export CLK_MAKEFILE = HCLK + export RST_MAKEFILE = HRESETn +else ifeq ($(BUS_TYPE),WISHBONE) + RTL_MACROS += -DBUS_TYPE_WISHBONE + DESIGN_NAME = EF_AES_WB + export CLK_MAKEFILE = clk_i + export RST_MAKEFILE = rst_i +endif +## netlist Gen +GL_MACROS += -DGL -DFUNCTIONAL $(RTL_MACROS) -DUNIT_DELAY=\#1 +PRE_SYS_FILES = $(AHB_FILES) $(APB_FILES) $(WB_FILES) $(HDL_FILES) +PDK_DIR = $(HOME)/.volare/volare/sky130/versions/bdc9412b3e468c102d01b7cf6337be06ec6e9c9a/sky130A/ +PDK_FILES = $(PDK_DIR)/libs.ref/sky130_fd_sc_hd/verilog/primitives.v $(PDK_DIR)/libs.ref/sky130_fd_sc_hd/verilog/sky130_fd_sc_hd.v # get this from openlane logs in the future +POST_SYS_FILES = $(PWD)/top.v $(VIP_FILES) $(PWD)/../../hdl/gl/synthesis/nl/$(DESIGN_NAME).nl.v + +# RTL_MACROS ?= "-DSKIP_WAVE_DUMP" +YAML_FILE = $(PWD)/../../EF_AES.yaml # TODO: update yaml file path +MAKEFLAGS += --no-print-directory + +# List of tests +TESTS := aes_enc_stress_test aes_dec_stress_test aes_enc_dec_stress_test + +# Variable for tag - set this as required +SIM_TAG ?= default_tag + +# Define SIM_PATH variable +SIM_PATH := $(PWD)/sim/$(SIM_TAG) + +# Check and clone EF_UVM repository at the beginning of the Makefile execution + +clone_ef_uvm := $(shell if [ ! -d "EF_UVM" ]; then \ + echo "Cloning the EF_UVM repository..."; \ + git clone https://github.com/efabless/EF_UVM.git; \ +fi;) + + +include EF_UVM/Makefile.test diff --git a/verify/uvm-python/aes_agent/aes_driver.py b/verify/uvm-python/aes_agent/aes_driver.py new file mode 100644 index 0000000..de5c001 --- /dev/null +++ b/verify/uvm-python/aes_agent/aes_driver.py @@ -0,0 +1,29 @@ +from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info, uvm_warning +from uvm.base.uvm_config_db import UVMConfigDb +from uvm.base.uvm_object_globals import UVM_HIGH, UVM_LOW, UVM_MEDIUM +from cocotb.triggers import Timer, ClockCycles, FallingEdge, Event, RisingEdge, First +import cocotb +import random +from EF_UVM.ip_env.ip_agent.ip_driver import ip_driver + + +class aes_driver(ip_driver): + def __init__(self, name="aes_driver", parent=None): + super().__init__(name, parent) + self.tag = name + + async def run_phase(self, phase): + uvm_info(self.tag, "run_phase started", UVM_LOW) + while True: + tr = [] + await self.seq_item_port.get_next_item(tr) + tr = tr[0] + # TODO: Add your code here for driving the IP + uvm_fatal( + self.tag, "please remove this line and write your code for driving here" + ) + # use self.vif. for driving interface signals + self.seq_item_port.item_done() + + +uvm_component_utils(aes_driver) diff --git a/verify/uvm-python/aes_agent/aes_monitor.py b/verify/uvm-python/aes_agent/aes_monitor.py new file mode 100644 index 0000000..f9c4461 --- /dev/null +++ b/verify/uvm-python/aes_agent/aes_monitor.py @@ -0,0 +1,32 @@ +from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info, uvm_error, uvm_warning +from uvm.comps.uvm_monitor import UVMMonitor +from uvm.tlm1.uvm_analysis_port import UVMAnalysisPort +from uvm.base.uvm_config_db import UVMConfigDb +from cocotb.triggers import ( + Timer, + ClockCycles, + FallingEdge, + Event, + RisingEdge, + Combine, + First, +) +from uvm.base.uvm_object_globals import UVM_HIGH, UVM_LOW, UVM_MEDIUM +import cocotb +import math +from EF_UVM.ip_env.ip_agent.ip_monitor import ip_monitor + + +class aes_monitor(ip_monitor): + def __init__(self, name="aes_monitor", parent=None): + super().__init__(name, parent) + + async def run_phase(self, phase): + # TODO: Add logic to monitor the IP + # use self.vif. for monitoring interface signals + # self.monitor_port.write(tr) # this is the port to send the transaction after sampling it + # NOTES: how to create transaction + pass + + +uvm_component_utils(aes_monitor) diff --git a/verify/uvm-python/aes_coverage/aes_coverage.py b/verify/uvm-python/aes_coverage/aes_coverage.py new file mode 100644 index 0000000..a188258 --- /dev/null +++ b/verify/uvm-python/aes_coverage/aes_coverage.py @@ -0,0 +1,29 @@ +from uvm.base.uvm_component import UVMComponent +from uvm.macros import uvm_component_utils +from uvm.tlm1.uvm_analysis_port import UVMAnalysisImp +from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info +from uvm.base.uvm_object_globals import UVM_HIGH, UVM_LOW +from uvm.base.uvm_config_db import UVMConfigDb +from uvm.macros.uvm_tlm_defines import uvm_analysis_imp_decl +from EF_UVM.ip_env.ip_coverage.ip_coverage import ip_coverage + + +class aes_coverage(ip_coverage): + """ + component that initialize the coverage groups and control when to sample the data. + """ + + def __init__(self, name="aes_coverage", parent=None): + super().__init__(name, parent) + + def build_phase(self, phase): + super().build_phase(phase) + # TODO: initialize the class for coverage groups here + + def write(self, tr): + # called when new transaction from ip monitor is received + # TODO: Add sampling logic here + pass + + +uvm_component_utils(aes_coverage) diff --git a/verify/uvm-python/aes_interface/aes_if.py b/verify/uvm-python/aes_interface/aes_if.py new file mode 100644 index 0000000..6253348 --- /dev/null +++ b/verify/uvm-python/aes_interface/aes_if.py @@ -0,0 +1,10 @@ +from uvm.base.sv import sv_if + + +class aes_if(sv_if): + def __init__(self, dut): + # TODO: Add signal need to be seen by the ip monitor and driver in the following format + # bus_map = {: } + # bus_map = {"reset": "rst", ...... } + return + super().__init__(dut, "", bus_map) diff --git a/verify/uvm-python/aes_item/aes_item.py b/verify/uvm-python/aes_item/aes_item.py new file mode 100644 index 0000000..04403f3 --- /dev/null +++ b/verify/uvm-python/aes_item/aes_item.py @@ -0,0 +1,31 @@ +from uvm.seq.uvm_sequence_item import UVMSequenceItem +from uvm.macros import ( + uvm_object_utils_begin, + uvm_object_utils_end, + uvm_field_int, + uvm_object_utils, + uvm_error, + uvm_info, +) +from uvm.base.uvm_object_globals import UVM_ALL_ON, UVM_NOPACK, UVM_HIGH, UVM_MEDIUM +from uvm.base.sv import sv +from EF_UVM.ip_env.ip_item import ip_item + + +class aes_item(ip_item): + def __init__(self, name="aes_item"): + super().__init__(name) + # TODO: Add the variables that defined the item and thier randomization status + + def convert2string(self): + # TODO: return the string representation of the item + return "" + + def do_compare(self, tr): + # method used by scoreboard to compare the items + # TODO: Add logic to compare the item with another passed item + # in the simple case this function should return (self.varaible1 == tr.variable2 and self.varaible2 == tr.variable2 and .. ) + return False + + +uvm_object_utils(aes_item) diff --git a/verify/uvm-python/aes_logger/aes_logger.py b/verify/uvm-python/aes_logger/aes_logger.py new file mode 100644 index 0000000..43c7aa2 --- /dev/null +++ b/verify/uvm-python/aes_logger/aes_logger.py @@ -0,0 +1,21 @@ +from EF_UVM.ip_env.ip_logger.ip_logger import ip_logger +import cocotb +from uvm.macros import uvm_component_utils, uvm_fatal + + +class aes_logger(ip_logger): + def __init__(self, name="aes_logger", parent=None): + super().__init__(name, parent) + self.header = ['Time (ns)'] + self.col_widths = [10] * len(self.header) + + def logger_formatter(self, transaction): + sim_time = f"{cocotb.utils.get_sim_time(units='ns')} ns" + # this called when new transaction is called from ip monitor + # TODO: should return the list of strings by the information in the header with the same order + return [ + sim_time, + ] + + +uvm_component_utils(aes_logger) diff --git a/verify/uvm-python/aes_ref_model/aes_ref_model.py b/verify/uvm-python/aes_ref_model/aes_ref_model.py new file mode 100644 index 0000000..ed27bba --- /dev/null +++ b/verify/uvm-python/aes_ref_model/aes_ref_model.py @@ -0,0 +1,221 @@ +from uvm.base.uvm_component import UVMComponent +from uvm.macros import uvm_component_utils +from uvm.tlm1.uvm_analysis_port import UVMAnalysisImp +from uvm.base.uvm_object_globals import UVM_HIGH, UVM_LOW, UVM_MEDIUM +from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info +from uvm.base.uvm_config_db import UVMConfigDb +from uvm.tlm1.uvm_analysis_port import UVMAnalysisExport +import cocotb +from EF_UVM.ref_model.ref_model import ref_model +from EF_UVM.bus_env.bus_item import bus_item +from cocotb.triggers import Event +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.backends import default_backend + + +class aes_ref_model(ref_model): + """ + The reference model is a crucial element within the top-level verification environment, designed to validate the functionality and performance of both the IP (Intellectual Property) and the bus system. Its primary role is to act as a representative or mimic of the actual hardware components, including the IP and the bus. Key features and functions of the reference model include: + 1) Input Simulation: The reference model is capable of receiving the same inputs that would be provided to the actual IP and bus via connection with the monitors of the bus and IP. + 2) Functional Emulation: It emulates the behavior and responses of the IP and bus under test. By replicating the operational characteristics of these components, the reference model serves as a benchmark for expected performance and behavior. + 3) Output Generation: Upon receiving inputs, the reference model processes them in a manner akin to the real hardware, subsequently generating expected outputs. These outputs are essential for comparison in the verification process. + 4) Interface with Scoreboard: The outputs from the reference model, representing the expected results, are forwarded to the scoreboard. The scoreboard then compares these expected results with the actual outputs from the IP and bus for verification. + 5)Register Abstraction Layer (RAL) Integration: The reference model includes a RAL model that mirrors the register values of the RTL, ensuring synchronization between expected and actual register states. This model facilitates register-level tests and error detection, offering accessible and up-to-date register values for other verification components. It enhances the automation and coverage of register testing, playing a vital role in ensuring the accuracy and comprehensiveness of the verification process. + """ + + def __init__(self, name="aes_ref_model", parent=None): + super().__init__(name, parent) + self.tag = name + self.ris_reg = 0 + self.mis_reg = 0 + self.irq = 0 + self.mis_changed = Event() + self.icr_changed = Event() + self.keys = {"KEY0":0, "KEY1":0, "KEY2":0, "KEY3":0, "KEY4":0, "KEY5":0, "KEY6":0, "KEY7":0} + self.blocks = {"BLOCK0":0, "BLOCK1":0, "BLOCK2":0, "BLOCK3":0} + self.results = {"RESULT0":0, "RESULT1":0, "RESULT2":0, "RESULT3":0} + + def build_phase(self, phase): + super().build_phase(phase) + # Here adding any initialize for user classes for the model + self.keys_address = {} + for key in self.regs.reg_name_to_address.keys(): + if "KEY" in key: + self.keys_address[self.regs.reg_name_to_address[key]] = key + uvm_info(self.tag, "Keys address: " + str(self.keys_address), UVM_LOW) + self.blocks_address = {} + for block in self.regs.reg_name_to_address.keys(): + if "BLOCK" in block: + self.blocks_address[self.regs.reg_name_to_address[block]] = block + uvm_info(self.tag, "Blocks address: " + str(self.blocks_address), UVM_LOW) + self.result_address = {} + for result in self.regs.reg_name_to_address.keys(): + if "RESULT" in result: + self.result_address[self.regs.reg_name_to_address[result]] = result + uvm_info(self.tag, "Results address: " + str(self.result_address), UVM_LOW) + + async def run_phase(self, phase): + await super().run_phase(phase) + # Here add the log to run when simulation starts + + # Checking for interrupts should be run as a concurrent coroutine + await cocotb.start(self.send_irq_tr()) + await cocotb.start(self.clear_ris_reg()) + + def write_bus(self, tr): + # Called when new transaction is received from the bus monitor + # TODO: update the following logic to determine what to do with the received transaction + uvm_info( + self.tag, + " Ref model recieved from bus monitor: " + tr.convert2string(), + UVM_HIGH, + ) + if tr.kind == bus_item.RESET: + self.bus_bus_export.write(tr) + uvm_info("Ref model", "reset from ref model", UVM_LOW) + # TODO: write logic needed when reset is received + self.bus_bus_export.write(tr) + return + if tr.kind == bus_item.WRITE: + # TODO: write logic needed when write transaction is received + # For example, to write the same value to the same resgiter uncomment the following lines + self.regs.write_reg_value(tr.addr, tr.data) + self.bus_bus_export.write(tr) # this is output to the scoreboard + if tr.addr in self.keys_address.keys(): + self.keys[self.keys_address[tr.addr]] = tr.data + elif tr.addr in self.blocks_address.keys(): + self.blocks[self.blocks_address[tr.addr]] = tr.data + elif tr.addr == self.regs.reg_name_to_address["CTRL"]: + # mode + if tr.data & 0b100 == 0b100: + self.mode = "Encipher" + else: + self.mode = "Decipher" + # lenght + if tr.data & 0b1000 == 0b1000: + self.length = 256 + else: + self.length = 128 + # init + if tr.data & 0x1 == 1: + self.keys_frozen = self.keys + # next + if tr.data & 0b10 == 0b10: + self.update_results() + + + # check if the write register is icr , set the icr changed event + if tr.addr == self.regs.reg_name_to_address["icr"] and tr.data != 0: + self.icr_changed.set() + pass + elif tr.kind == bus_item.READ: + # TODO: write logic needed when read transaction is received + # For example, to read the same resgiter uncomment the following lines + data = self.regs.read_reg_value(tr.addr) + td = tr.do_clone() + if tr.addr in self.result_address.keys(): + td.data = self.results[self.result_address[tr.addr]] + elif tr.addr == self.regs.reg_name_to_address["STATUS"] : + pass + else: + td.data = data + self.bus_bus_export.write(td) # this is output to the scoreboard + pass + self.update_interrupt_regs() + + def update_results(self): + if self.length == 128: + key = self.keys_frozen["KEY4"] | self.keys_frozen["KEY5"] << 32 | self.keys_frozen["KEY6"] << 64 | self.keys_frozen["KEY7"] << 96 + uvm_info(self.tag, f"key key key {hex(key)}", UVM_LOW) + key = key.to_bytes(16, byteorder='big') + elif self.length == 256: + key = self.keys_frozen["KEY0"] | self.keys_frozen["KEY1"] << 32 | self.keys_frozen["KEY2"] << 64 | self.keys_frozen["KEY3"] << 96 | self.keys_frozen["KEY4"] << 128 | self.keys_frozen["KEY5"] << 160 | self.keys_frozen["KEY6"] << 192 | self.keys_frozen["KEY7"] << 224 + uvm_info(self.tag, f"key key key {hex(key)}", UVM_LOW) + key = key.to_bytes(32, byteorder='big') + + block = self.blocks["BLOCK0"] | self.blocks["BLOCK1"] << 32 | self.blocks["BLOCK2"] << 64 | self.blocks["BLOCK3"] << 96 + uvm_info(self.tag, f"block block block {hex(block)}", UVM_LOW) + block = block.to_bytes(16, byteorder='big') + cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()) + cryptor = cipher.encryptor() if self.mode == "Encipher" else cipher.decryptor() + cipher_block = cryptor.update(block) + cryptor.finalize() + uvm_info(self.tag, f"Cipher block: {cipher_block.hex().upper()} type = {type(cipher_block)}" , UVM_LOW) + uvm_info(self.tag, f"Cipher block: {hex(int.from_bytes(cipher_block[:4], byteorder='big'))}" , UVM_LOW) + uvm_info(self.tag, f"Cipher block: {hex(int.from_bytes(cipher_block[4:8], byteorder='big'))}" , UVM_LOW) + uvm_info(self.tag, f"Cipher block: {hex(int.from_bytes(cipher_block[8:12], byteorder='big'))}" , UVM_LOW) + uvm_info(self.tag, f"Cipher block: {hex(int.from_bytes(cipher_block[12:16], byteorder='big'))}" , UVM_LOW) + self.results["RESULT0"] = int.from_bytes(cipher_block[12:16], byteorder='big') + self.results["RESULT1"] = int.from_bytes(cipher_block[8:12], byteorder='big') + self.results["RESULT2"] = int.from_bytes(cipher_block[4:8], byteorder='big') + self.results["RESULT3"] = int.from_bytes(cipher_block[:4], byteorder='big') + + def write_ip(self, tr): + # Called when new transaction is received from the ip monitor + # TODO: write what to do when new transaction ip transaction is received + uvm_info( + self.tag, + "Ref model recieved from ip monitor: " + tr.convert2string(), + UVM_HIGH, + ) + + # Update interrupts when a new ip transaction is received + self.set_ris_reg() + self.update_interrupt_regs() + # Here the ref model should predict the transaction and send it to scoreboard + # self.ip_export.write(td) # this is output ro scoreboard + + def set_ris_reg(self): + # TODO: update this function to update the value of 'self.ris_reg' according to the ip transaction + # For example: + # rx_fifo_threshold = self.regs.read_reg_value("RXFIFOT") + # if self.fifo_rx.qsize() > rx_fifo_threshold: + # self.ris_reg |= 0x2 + pass + + async def clear_ris_reg(self): + # This coroutine runs concurrently it waits for icr_changed event then update interrupt registers + while True: + await self.icr_changed.wait() + icr_reg = self.regs.read_reg_value("icr") + mask = ~icr_reg + self.ris_reg = self.ris_reg & mask + self.update_interrupt_regs() + self.regs.write_reg_value("icr", 0, force_write=True) # clear icr register + self.icr_changed.clear() + + def update_interrupt_regs(self): + # This function updates ris and mis with new values and set mis changed event if mis has a new value + self.regs.write_reg_value("ris", self.ris_reg, force_write=True) + im_reg = self.regs.read_reg_value("im") + mis_reg_new = self.ris_reg & im_reg + uvm_info( + self.tag, + f" Update interrupts : im = {im_reg:X}, ris = {self.ris_reg:X}, mis = {mis_reg_new:X}", + UVM_LOW, + ) + if mis_reg_new != self.mis_reg: + self.mis_changed.set() + self.mis_reg = mis_reg_new + self.regs.write_reg_value("mis", self.mis_reg, force_write=True) + + async def send_irq_tr(self): + # This coroutine waits for mis_changed event, create an interrupt transaction, then send it to scoreboard for comparison + # if trg_irq = 1 means that irq changed from low to high, if it is 0, it means irq changed from high to low + while True: + await self.mis_changed.wait() + irq_new = 1 if self.mis_reg else 0 + if irq_new and not self.irq: # irq changed from low to high + self.irq = 1 + tr = bus_irq_item.type_id.create("tr", self) + tr.trg_irq = 1 + self.bus_irq_export.write(tr) + elif not irq_new and self.irq: # irq changed from high to low + self.irq = 0 + tr = bus_irq_item.type_id.create("tr", self) + tr.trg_irq = 0 + self.bus_irq_export.write(tr) + + self.mis_changed.clear() + + +uvm_component_utils(aes_ref_model) diff --git a/verify/uvm-python/aes_seq_lib/aes_config_seq.py b/verify/uvm-python/aes_seq_lib/aes_config_seq.py new file mode 100644 index 0000000..abb1806 --- /dev/null +++ b/verify/uvm-python/aes_seq_lib/aes_config_seq.py @@ -0,0 +1,133 @@ +from uvm.seq import UVMSequence +from uvm.macros.uvm_object_defines import uvm_object_utils +from uvm.macros.uvm_message_defines import uvm_fatal +from uvm.base.uvm_config_db import UVMConfigDb +from EF_UVM.bus_env.bus_seq_lib.bus_seq_base import bus_seq_base +from cocotb.triggers import Timer +from uvm.macros.uvm_sequence_defines import uvm_do_with, uvm_do +import random +from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info, uvm_error +from uvm.base.uvm_object_globals import UVM_LOW + + +class aes_config_seq(bus_seq_base): + # use this sequence write or read from register by the bus interface + # this sequence should be connected to the bus sequencer in the testbench + # you should create as many sequences as you need not only this one + def __init__(self, name="aes_config_seq"): + super().__init__(name) + regs_arr = [] + if not UVMConfigDb.get(self, "", "bus_regs", regs_arr): + uvm_fatal(self.tag, "No json file wrapper regs") + else: + self.regs = regs_arr[0] + self.mode = 0 + self.length = 0 + + + + + async def body(self): + await super().body() + + async def waitReady(self): + self.clear_response_queue() + while True: + rsp = [] + await self.send_req(is_write=False, reg="STATUS") + await self.get_response(rsp) + ris_reg = rsp[0] + uvm_info(self.tag, f"STATUS value{ris_reg}", UVM_LOW) + if ( + ris_reg.data & 0b10 == 0b10 + and ris_reg.addr == self.regs.reg_name_to_address["STATUS"] + ): + break + + async def waitKeyReady(self): + self.clear_response_queue() + while True: + rsp = [] + await self.send_req(is_write=False, reg="STATUS") + await self.get_response(rsp) + ris_reg = rsp[0] + uvm_info(self.tag, f"STATUS value{ris_reg}", UVM_LOW) + if ( + ris_reg.data & 0b100 == 0b100 + and ris_reg.addr == self.regs.reg_name_to_address["STATUS"] + ): + break + + async def waitResultValid(self): + self.clear_response_queue() + while True: + rsp = [] + await self.send_req(is_write=False, reg="STATUS") + await self.get_response(rsp) + ris_reg = rsp[0] + uvm_info(self.tag, f"STATUS value{ris_reg}", UVM_LOW) + if ( + ris_reg.data & 0b1 == 0b1 + and ris_reg.addr == self.regs.reg_name_to_address["STATUS"] + ): + break + + async def write_rand_key(self): + for key in random.sample(["KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7"], k=8): + await self.send_req(is_write=True, reg=key, data_value=random.getrandbits(32)) + + async def write_rand_block(self): + for block in random.sample(["BLOCK0", "BLOCK1", "BLOCK2", "BLOCK3"], k=4): + await self.send_req(is_write=True, reg=block, data_value=random.getrandbits(32)) + + async def read_result(self): + for result in random.sample(["RESULT0", "RESULT1", "RESULT2", "RESULT3"], k=4): + await self.send_req(is_write=False, reg=result) + + async def set_mode(self, is_encipher): + if is_encipher: + self.mode = 1 + value = self.mode << 2 | self.length << 3 + await self.send_req(is_write=True, reg="CTRL", data_condition=lambda data: data == value) + else: + self.mode = 0 + value = self.mode << 2 | self.length << 3 + await self.send_req(is_write=True, reg="CTRL", data_condition=lambda data: data == value) + + async def set_length(self, is_128): + if is_128: + self.length = 0 + value = self.mode << 2 | self.length << 3 + await self.send_req(is_write=True, reg="CTRL", data_condition=lambda data: data == value) + else: + self.length = 1 + value = self.mode << 2 | self.length << 3 + await self.send_req(is_write=True, reg="CTRL", data_condition=lambda data: data == value) + + async def set_init(self): + value = 1 << 0 | self.mode << 2 | self.length << 3 + await self.send_req(is_write=True, reg="CTRL", data_condition=lambda data: data == value) + for _ in range(2): + await self.send_nop() + + async def set_next(self): + value = 1 << 1 | self.mode << 2 | self.length << 3 + await self.send_req(is_write=True, reg="CTRL", data_condition=lambda data: data == value) + for _ in range(2): + await self.send_nop() + + async def update_and_read(self): + # write key + await self.write_rand_key() + # put init + await self.set_init() + await self.waitKeyReady() + # write block + await self.write_rand_block() + await self.set_next() + await self.waitResultValid() + await self.read_result() + for _ in range(40): + await self.send_nop() + +uvm_object_utils(aes_config_seq) \ No newline at end of file diff --git a/verify/uvm-python/aes_seq_lib/aes_stress_dec_seq.py b/verify/uvm-python/aes_seq_lib/aes_stress_dec_seq.py new file mode 100644 index 0000000..1f2eb74 --- /dev/null +++ b/verify/uvm-python/aes_seq_lib/aes_stress_dec_seq.py @@ -0,0 +1,38 @@ +from uvm.seq import UVMSequence +from uvm.macros.uvm_object_defines import uvm_object_utils +from uvm.macros.uvm_message_defines import uvm_fatal +from uvm.base.uvm_config_db import UVMConfigDb +from EF_UVM.bus_env.bus_seq_lib.bus_seq_base import bus_seq_base +from cocotb.triggers import Timer +from uvm.macros.uvm_sequence_defines import uvm_do_with, uvm_do +import random +from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info +from uvm.base.uvm_object_globals import UVM_LOW +from aes_seq_lib.aes_config_seq import aes_config_seq + +class aes_stress_dec_seq(aes_config_seq): + # use this sequence write or read from register by the bus interface + # this sequence should be connected to the bus sequencer in the testbench + # you should create as many sequences as you need not only this one + def __init__(self, name="aes_stress_dec_seq"): + super().__init__(name) + regs_arr = [] + if not UVMConfigDb.get(self, "", "bus_regs", regs_arr): + uvm_fatal(self.tag, "No json file wrapper regs") + else: + self.regs = regs_arr[0] + + async def body(self): + await super().body() + # write key + # put encryption enable + await self.set_mode(is_encipher=False) + for _ in range(random.randint(20, 50)): + await self.set_length(is_128=random.choice([True, False])) + await self.update_and_read() + + + +uvm_object_utils(aes_stress_dec_seq) + + diff --git a/verify/uvm-python/aes_seq_lib/aes_stress_enc_dec_seq.py b/verify/uvm-python/aes_seq_lib/aes_stress_enc_dec_seq.py new file mode 100644 index 0000000..840717e --- /dev/null +++ b/verify/uvm-python/aes_seq_lib/aes_stress_enc_dec_seq.py @@ -0,0 +1,80 @@ +from uvm.seq import UVMSequence +from uvm.macros.uvm_object_defines import uvm_object_utils +from uvm.macros.uvm_message_defines import uvm_fatal +from uvm.base.uvm_config_db import UVMConfigDb +from EF_UVM.bus_env.bus_seq_lib.bus_seq_base import bus_seq_base +from cocotb.triggers import Timer +from uvm.macros.uvm_sequence_defines import uvm_do_with, uvm_do +import random +from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info +from uvm.base.uvm_object_globals import UVM_LOW +from aes_seq_lib.aes_config_seq import aes_config_seq + +class aes_stress_enc_dec_seq(aes_config_seq): + # use this sequence write or read from register by the bus interface + # this sequence should be connected to the bus sequencer in the testbench + # you should create as many sequences as you need not only this one + def __init__(self, name="aes_stress_enc_dec_seq"): + super().__init__(name) + regs_arr = [] + if not UVMConfigDb.get(self, "", "bus_regs", regs_arr): + uvm_fatal(self.tag, "No json file wrapper regs") + else: + self.regs = regs_arr[0] + + async def body(self): + await super().body() + # write key + # put encryption enable + await self.set_length(is_128=random.choice([True, False])) + await self.set_mode(is_encipher=True) + for _ in range(random.randint(10, 20)): + await self.write_rand_key() + await self.set_init() + await self.waitKeyReady() + blocks = {"BLOCK0":random.getrandbits(32), "BLOCK1":random.getrandbits(32), "BLOCK2":random.getrandbits(32), "BLOCK3":random.getrandbits(32)} + await self.set_blocks(blocks) + await self.set_mode(is_encipher=False) + await self.waitReady() + await self.set_blocks(blocks) + await self.set_next() + await self.waitResultValid() + results = await self.read_result_blocks() + uvm_info(self.tag, f"results = {results}", UVM_LOW) + blocks2 = {"BLOCK0": results["RESULT0"], "BLOCK1": results["RESULT1"], "BLOCK2": results["RESULT2"], "BLOCK3": results["RESULT3"]} + await self.set_mode(is_encipher=True) + await self.set_blocks(blocks2) + await self.set_next() + for _ in range(20): # to make sure valid is down + await self.send_nop() + await self.waitResultValid() + results2 = await self.read_result_blocks() + for i in range(4): + if results2[f"RESULT{i}"] != blocks[f"BLOCK{i}"]: + uvm_fatal(self.tag, f"results2 = {results2} != blocks2 = {blocks2}") + + async def set_blocks(self, blocks): + for reg, value in blocks.items(): + await self.send_req(is_write=True, reg=reg, data_value=value) + + async def read_result_blocks(self): + result = {"RESULT0":0, "RESULT1":0, "RESULT2":0, "RESULT3":0} + for reg in result.keys(): + result[reg] = await self.read_result_block(reg) + return result + async def read_result_block(self, reg): + self.clear_response_queue() + while True: + rsp = [] + await self.send_req(is_write=False, reg=reg) + await self.get_response(rsp) + ris_reg = rsp[0] + if ( + ris_reg.addr == self.regs.reg_name_to_address[reg] + ): + break + return ris_reg.data + + + +uvm_object_utils(aes_stress_enc_dec_seq) diff --git a/verify/uvm-python/aes_seq_lib/aes_stress_enc_seq.py b/verify/uvm-python/aes_seq_lib/aes_stress_enc_seq.py new file mode 100644 index 0000000..68e2190 --- /dev/null +++ b/verify/uvm-python/aes_seq_lib/aes_stress_enc_seq.py @@ -0,0 +1,38 @@ +from uvm.seq import UVMSequence +from uvm.macros.uvm_object_defines import uvm_object_utils +from uvm.macros.uvm_message_defines import uvm_fatal +from uvm.base.uvm_config_db import UVMConfigDb +from EF_UVM.bus_env.bus_seq_lib.bus_seq_base import bus_seq_base +from cocotb.triggers import Timer +from uvm.macros.uvm_sequence_defines import uvm_do_with, uvm_do +import random +from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info +from uvm.base.uvm_object_globals import UVM_LOW +from aes_seq_lib.aes_config_seq import aes_config_seq + +class aes_stress_enc_seq(aes_config_seq): + # use this sequence write or read from register by the bus interface + # this sequence should be connected to the bus sequencer in the testbench + # you should create as many sequences as you need not only this one + def __init__(self, name="aes_stress_enc_seq"): + super().__init__(name) + regs_arr = [] + if not UVMConfigDb.get(self, "", "bus_regs", regs_arr): + uvm_fatal(self.tag, "No json file wrapper regs") + else: + self.regs = regs_arr[0] + + async def body(self): + await super().body() + # write key + # put encryption enable + await self.set_mode(is_encipher=True) + for _ in range(random.randint(20, 50)): + await self.set_length(is_128=random.choice([True, False])) + await self.update_and_read() + + + +uvm_object_utils(aes_stress_enc_seq) + + diff --git a/verify/uvm-python/aes_seq_lib/temp.py b/verify/uvm-python/aes_seq_lib/temp.py new file mode 100644 index 0000000..7ad1641 --- /dev/null +++ b/verify/uvm-python/aes_seq_lib/temp.py @@ -0,0 +1,50 @@ +import os +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.backends import default_backend + +# Function to encrypt a single block using AES in ECB mode +def encrypt_aes_ecb(block, key): + cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()) + encryptor = cipher.encryptor() + cipher_text = encryptor.update(block) + encryptor.finalize() + return cipher_text + +# Function to decrypt a single block using AES in ECB mode +def decrypt_aes_ecb(cipher_text, key): + cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()) + decryptor = cipher.decryptor() + decrypted_block = decryptor.update(cipher_text) + decryptor.finalize() + return decrypted_block + +# User Input: Select AES-128 or AES-256 +key_size = int(input("Enter key size (128 or 256): ")) +if key_size not in [128, 256]: + raise ValueError("Invalid key size! Only 128 or 256 are supported.") + +# Generate a random key with the appropriate length +if key_size == 128: + key = 0x2B7E151628AED2A6ABF7158809CF4F3C +elif key_size == 256: + key = os.urandom(32) # 32 bytes for AES-256 + +# Print the generated key in hex format +print(f"Generated Key (Hex): {hex(key)}") + +# Hexadecimal input for block +block_hex = 0x6bc1bee22e409f96e93d7e117393172a +block = block_hex.to_bytes(16, byteorder='big') +key = key.to_bytes(16, byteorder='big') + +# Encrypt the block +cipher_text = encrypt_aes_ecb(block, key) +print(f"Cipher Text (Hex): {cipher_text.hex().upper()}") + +# Decrypt the block +decrypted_block = decrypt_aes_ecb(cipher_text, key) +print(f"Decrypted Block (Hex): {decrypted_block.hex().upper()}") + +# Verify that decryption is correct +if decrypted_block == block: + print("Decryption successful! Original block restored.") +else: + print("Decryption failed. Something went wrong.") diff --git a/verify/uvm-python/test_lib.py b/verify/uvm-python/test_lib.py new file mode 100644 index 0000000..aa81af5 --- /dev/null +++ b/verify/uvm-python/test_lib.py @@ -0,0 +1,139 @@ +import cocotb +from uvm.macros import uvm_component_utils, uvm_fatal, uvm_info +from uvm.base.uvm_config_db import UVMConfigDb +from uvm.base.uvm_object_globals import UVM_LOW +from uvm.base.uvm_globals import run_test +from aes_interface.aes_if import aes_if +from EF_UVM.bus_env.bus_interface.bus_if import ( + bus_apb_if, + bus_irq_if, + bus_ahb_if, + bus_wb_if, +) +from cocotb_coverage.coverage import coverage_db +from cocotb.triggers import Event, First +from EF_UVM.bus_env.bus_regs import bus_regs +from uvm.base import UVMRoot +from EF_UVM.base_test import base_test + +# seqences import +from aes_seq_lib.aes_stress_enc_seq import aes_stress_enc_seq +from aes_seq_lib.aes_stress_dec_seq import aes_stress_dec_seq +from aes_seq_lib.aes_stress_enc_dec_seq import aes_stress_enc_dec_seq + +# override classes +from EF_UVM.ip_env.ip_agent.ip_driver import ip_driver +from aes_agent.aes_driver import aes_driver +from EF_UVM.ip_env.ip_agent.ip_monitor import ip_monitor +from aes_agent.aes_monitor import aes_monitor +from EF_UVM.ref_model.ref_model import ref_model +from aes_ref_model.aes_ref_model import aes_ref_model +from EF_UVM.ip_env.ip_coverage.ip_coverage import ip_coverage +from aes_coverage.aes_coverage import aes_coverage +from EF_UVM.ip_env.ip_logger.ip_logger import ip_logger +from aes_logger.aes_logger import aes_logger + + +@cocotb.test() +async def module_top(dut): + # profiler = cProfile.Profile() + # profiler.enable() + BUS_TYPE = cocotb.plusargs["BUS_TYPE"] + pif = aes_if(dut) + if BUS_TYPE == "APB": + w_if = bus_apb_if(dut) + elif BUS_TYPE == "AHB": + w_if = bus_ahb_if(dut) + elif BUS_TYPE == "WISHBONE": + w_if = bus_wb_if(dut) + else: + uvm_fatal("module_top", f"unknown bus type {BUS_TYPE}") + w_irq_if = bus_irq_if(dut) + UVMConfigDb.set(None, "*", "ip_if", pif) + UVMConfigDb.set(None, "*", "bus_if", w_if) + UVMConfigDb.set(None, "*", "bus_irq_if", w_irq_if) + yaml_file = [] + UVMRoot().clp.get_arg_values("+YAML_FILE=", yaml_file) + yaml_file = yaml_file[0] + regs = bus_regs(yaml_file) + UVMConfigDb.set(None, "*", "bus_regs", regs) + UVMConfigDb.set(None, "*", "irq_exist", regs.get_irq_exist()) + UVMConfigDb.set(None, "*", "collect_coverage", True) + UVMConfigDb.set(None, "*", "disable_logger", False) + test_path = [] + UVMRoot().clp.get_arg_values("+TEST_PATH=", test_path) + test_path = test_path[0] + await run_test() + coverage_db.export_to_yaml(filename=f"{test_path}/coverage.yaml") + # profiler.disable() + # profiler.dump_stats("profile_result.prof") + + +class aes_base_test(base_test): + def __init__(self, name="aes_first_test", parent=None): + BUS_TYPE = cocotb.plusargs["BUS_TYPE"] + super().__init__(name, bus_type=BUS_TYPE, parent=parent) + self.tag = name + + def build_phase(self, phase): + super().build_phase(phase) + # override + self.set_type_override_by_type(ip_driver.get_type(), aes_driver.get_type()) + self.set_type_override_by_type( + ip_monitor.get_type(), aes_monitor.get_type() + ) + self.set_type_override_by_type( + ref_model.get_type(), aes_ref_model.get_type() + ) + self.set_type_override_by_type( + ip_coverage.get_type(), aes_coverage.get_type() + ) + self.set_type_override_by_type(ip_logger.get_type(), aes_logger.get_type()) + + +uvm_component_utils(aes_base_test) + + +class aes_enc_stress_test(aes_base_test): + def __init__(self, name="aes__first_test", parent=None): + super().__init__(name, parent=parent) + self.tag = name + + async def main_phase(self, phase): + uvm_info(self.tag, f"Starting test {self.__class__.__name__}", UVM_LOW) + phase.raise_objection(self, f"{self.__class__.__name__} OBJECTED") + bus_seq = aes_stress_enc_seq("aes_stress_enc_seq") + await bus_seq.start(self.bus_sqr) + phase.drop_objection(self, f"{self.__class__.__name__} drop objection") + +uvm_component_utils(aes_enc_stress_test) + +class aes_dec_stress_test(aes_base_test): + def __init__(self, name="aes__first_test", parent=None): + super().__init__(name, parent=parent) + self.tag = name + + async def main_phase(self, phase): + uvm_info(self.tag, f"Starting test {self.__class__.__name__}", UVM_LOW) + phase.raise_objection(self, f"{self.__class__.__name__} OBJECTED") + bus_seq = aes_stress_dec_seq("aes_stress_dec_seq") + await bus_seq.start(self.bus_sqr) + phase.drop_objection(self, f"{self.__class__.__name__} drop objection") + + +uvm_component_utils(aes_dec_stress_test) + +class aes_enc_dec_stress_test(aes_base_test): + def __init__(self, name="aes__first_test", parent=None): + super().__init__(name, parent=parent) + self.tag = name + + async def main_phase(self, phase): + uvm_info(self.tag, f"Starting test {self.__class__.__name__}", UVM_LOW) + phase.raise_objection(self, f"{self.__class__.__name__} OBJECTED") + bus_seq = aes_stress_enc_dec_seq("aes_stress_enc_dec_seq") + await bus_seq.start(self.bus_sqr) + phase.drop_objection(self, f"{self.__class__.__name__} drop objection") + + +uvm_component_utils(aes_enc_dec_stress_test) diff --git a/verify/uvm-python/top.v b/verify/uvm-python/top.v new file mode 100644 index 0000000..5db3062 --- /dev/null +++ b/verify/uvm-python/top.v @@ -0,0 +1,53 @@ +`timescale 1ns/1ps + +module top(); + reg CLK = 0; + wire RESETn = 1; + wire irq; + // TODO: Add any IP signals here + `ifdef BUS_TYPE_APB + wire [31:0] PADDR; + wire PWRITE; + wire PSEL; + wire PENABLE; + wire [31:0] PWDATA; + wire [31:0] PRDATA; + wire PREADY; + // TODO: initialize the ABP wrapper here + // for example + EF_AES_APB dut(.PCLK(CLK), .PRESETn(RESETn), .PADDR(PADDR), .PWRITE(PWRITE), .PSEL(PSEL), .PENABLE(PENABLE), .PWDATA(PWDATA), .PRDATA(PRDATA), .PREADY(PREADY), .IRQ(irq)); + `endif // BUS_TYPE_APB + `ifdef BUS_TYPE_AHB + wire [31:0] HADDR; + wire HWRITE; + wire HSEL = 0; + wire HREADYOUT; + wire [1:0] HTRANS=0; + wire [31:0] HWDATA; + wire [31:0] HRDATA; + wire HREADY; + // TODO: initialize the AHB wrapper here + // for example + EF_AES_AHBL dut(.HCLK(CLK), .HRESETn(RESETn), .HADDR(HADDR), .HWRITE(HWRITE), .HSEL(HSEL), .HTRANS(HTRANS), .HWDATA(HWDATA), .HRDATA(HRDATA), .HREADY(HREADY),.HREADYOUT(HREADYOUT), .IRQ(irq)); + `endif // BUS_TYPE_AHB + `ifdef BUS_TYPE_WISHBONE + wire [31:0] adr_i; + wire [31:0] dat_i; + wire [31:0] dat_o; + wire [3:0] sel_i; + wire cyc_i; + wire stb_i; + reg ack_o; + // TODO: initialize the Wishbone wrapper here + // for example + EF_AES_WB dut(.clk_i(CLK), .rst_i(~RESETn), .adr_i(adr_i), .dat_i(dat_i), .dat_o(dat_o), .sel_i(sel_i), .cyc_i(cyc_i), .stb_i(stb_i), .ack_o(ack_o), .we_i(we_i), .irq(irq)); + `endif // BUS_TYPE_WISHBONE + // monitor inside signals + `ifndef SKIP_WAVE_DUMP + initial begin + $dumpfile ({"waves.vcd"}); + $dumpvars(0, top); + end + `endif + always #10 CLK = !CLK; // clk generator +endmodule \ No newline at end of file