core-v-verif系列之cv32e40p UVM环境介绍<14>

UVM环境介绍
HEAD commitID: 1f968ef

1. tb/core/tb_riscv/riscv_random_interrupt_generator.sv


//
//                                                                                                          //
// Author:                              Francesco Minervini - [email protected]                      //
//                                                                                                          //
// Additional contributions by:         Davide Schiavone - [email protected]                          //
// Design Name:                         Interrupt generator                                                 //
// Project Name:                        RI5CY, Zeroriscy                                                    //
// Language:                            SystemVerilog                                                       //
//                                                                                                          //
// Description:                         Send interrupt request to core choosing one option between:         //
//                                      - Random;                                                           //
//                                      - Standard;                                                         //
//                                      - PC value-triggering                                               //
//                                                                                                          //
//
//import riscv_defines::*;
import perturbation_defines::*;

module riscv_random_interrupt_generator
`ifndef VERILATOR
  import uvm_pkg::*;
  `include "uvm_macros.svh"
`endif
(
    input logic           rst_ni,
    input logic           clk_i,
    input logic           irq_i,
    input logic   [4:0]   irq_id_i,
    input logic           irq_ack_i,
    output logic          irq_o,
    output logic  [4:0]   irq_id_o,
    output logic          irq_ack_o,
    input logic  [31:0]   irq_mode_i,
    input logic  [31:0]   irq_min_cycles_i,
    input logic  [31:0]   irq_max_cycles_i,
    input logic  [31:0]   irq_min_id_i,
    input logic  [31:0]   irq_max_id_i,
    output logic [31:0]   irq_act_id_o,
    output logic          irq_id_we_o,
    input logic  [31:0]   irq_pc_id_i,
    input logic  [31:0]   irq_pc_trig_i
);

`ifndef VERILATOR
class rand_irq_cycles;
    rand int n;
endclass : rand_irq_cycles

class rand_irq_id;
    rand int n;
endclass : rand_irq_id

logic [31:0] irq_mode_q;
logic        irq_random;
logic  [4:0] irq_id_random;
logic        irq_ack_random;
logic        irq_monitor;
logic  [4:0] irq_id_monitor;
logic        irq_ack_monitor;

assign irq_ack_o = irq_ack_i;

always_ff @(posedge clk_i or negedge rst_ni)
begin
    if(~rst_ni) begin
        irq_mode_q <= 0;
    end else begin
        irq_mode_q <= irq_mode_i;
    end
end

always_comb
begin
    unique case (irq_mode_q)
        RANDOM:
        begin
         irq_o     = irq_random;
         irq_id_o  = irq_id_random;
        end

        PC_TRIG:
        begin
         irq_o     = irq_monitor;
         irq_id_o  = irq_id_monitor;
        end

        default:
        begin
         irq_o     = irq_i;
         irq_id_o  = irq_id_i;
        end
    endcase
end

//Random Process
initial
begin
    automatic rand_irq_cycles wait_cycles = new();
    automatic rand_irq_id value = new();
    int rs,i, min_irq_cycles, max_irq_cycles, min_irq_id, max_irq_id;
    irq_random = 1'b0;
    irq_id_random  = '0;

    while(1) begin

        irq_random    = 1'b0;
        irq_id_random = '0;

        @(posedge clk_i);

        wait(irq_mode_q == RANDOM);
        min_irq_id     = irq_min_id_i;
        max_irq_id     = irq_max_id_i;
        min_irq_cycles = irq_min_cycles_i;
        max_irq_cycles = irq_max_cycles_i;

        rs = 0; // "randomize success"
        rs = value.randomize() with{
   
            n >= min_irq_id;
            n <= max_irq_id;
        };
        if (!rs) `uvm_error("RISCV_RANDOM_INTERRUPT_GENERATOR", "Randomization failure on value.randomize()")

        rs = wait_cycles.randomize() with{
   
            n >= min_irq_cycles;
            n <= max_irq_cycles;
        };
        if (!rs) `uvm_error("RISCV_RANDOM_INTERRUPT_GENERATOR", "Randomization failure on wait_cycles.randomize()")

        while(wait_cycles.n != 0) begin
            @(posedge clk_i);
            wait_cycles.n--;
        end

        irq_id_random = value.n;
        irq_random    = 1'b1;
        irq_act_id_o  = value.n;
        @(posedge clk_i);
        //we don't care about the ack in this mode
        for(i=0; i<max_irq_cycles; i++) begin
            @(posedge clk_i);
        end
    end // while(1)
end


//Monitor Process
initial
begin
    irq_monitor    = 1'b0;
    irq_id_monitor = '0;
    wait(irq_mode_q == PC_TRIG);
    wait(irq_pc_id_i == irq_pc_trig_i);
    irq_monitor    = 1'b1;
    irq_id_monitor = irq_min_id_i;
    while(irq_ack_i != 1'b1) begin
        @(posedge clk_i);   //Keep the request high until the acknowledge is received
    end
    @(posedge clk_i);
    irq_monitor    = 1'b0;
    irq_id_monitor = '0;
end

initial
begin
    while(1) begin
        irq_id_we_o = 1'b0;
        wait(irq_ack_i == 1'b1);
        irq_id_we_o = 1'b1;   //Give the write enable to store the core response
        @(posedge clk_i);
    end
end

`endif //VERILATOR
endmodule

riscv_random_interrupt_generator.sv 是一个 SystemVerilog 文件,用于实现一个随机中断生成器模块,该模块可根据不同的模式向核心发送中断请求。

1. 版权声明

// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.

此部分声明了文件的版权归属以及使用该文件需遵循的 Solderpad Hardware License 0.51。

2. 模块概述

//
//                                                                                                          //
// Author:                              Francesco Minervini - [email protected]                      //
//                                                                                                          //
// Additional contributions by:         Davide Schiavone - [email protected]                          //
// Design Name:                         Interrupt generator                                                 //
// Project Name:                        RI5CY, Zeroriscy                                                    //
// Language:                            SystemVerilog                                                       //
//                                                                                                          //
// Description:                         Send interrupt request to core choosing one option between:         //
//                                      - Random;                                                           //
//                                      - Standard;                                                         //
//                                      - PC value-triggering                                               //
//                                                                                                          //
//

这部分注释提供了模块的基本信息,包括作者、设计名称、项目名称、使用的语言以及模块的功能描述,即可以在随机、标准和 PC 值触发三种模式下向核心发送中断请求。

3. 包导入

import perturbation_defines::*;

导入 perturbation_defines 包,该包可能定义了一些与扰动相关的常量、类型等。

4. 模块定义

module riscv_random_interrupt_generator
`ifndef VERILATOR
  import uvm_pkg::*;
  `include "uvm_macros.svh"
`endif
(
    input logic           rst_ni,
    input logic           clk_i,
    input logic           irq_i,
    input logic   [4:0]   irq_id_i,
    input logic           irq_ack_i,
    output logic          irq_o,
    output logic  [4:0]   irq_id_o,
    output logic          irq_ack_o,
    input logic  [31:0]   irq_mode_i,
    input logic  [31:0]   irq_min_cycles_i,
    input logic  [31:0]   irq_max_cycles_i,
    input logic  [31:0]   irq_min_id_i,
    input logic  [31:0]   irq_max_id_i,
    output logic [31:0]   irq_act_id_o,
    output logic          irq_id_we_o,
    input logic  [31:0]   irq_pc_id_i,
    input logic  [31:0]   irq_pc_trig_i
);
  • 模块名为 riscv_random_interrupt_generator
  • ifndef VERILATOR 条件编译块用于在非 Verilator 仿真环境下导入 UVM 包和相关宏文件。
  • 模块的端口包括:
    • 时钟和复位信号:rst_ni(异步低电平复位)、clk_i(时钟信号)。
    • 中断输入信号:irq_i(外部中断请求)、irq_id_i(外部中断 ID)、irq_ack_i(中断确认信号)。
    • 中断输出信号:irq_o(输出中断请求)、irq_id_o(输出中断 ID)、irq_ack_o(输出中断确认)。
    • 配置信号:irq_mode_i(中断模式)、irq_min_cycles_i(最小中断周期)、irq_max_cycles_i(最大中断周期)、irq_min_id_i(最小中断 ID)、irq_max_id_i(最大中断 ID)。
    • 其他信号:irq_act_id_o(实际中断 ID)、irq_id_we_o(中断 ID 写使能)、irq_pc_id_i(PC 值)、irq_pc_trig_i(PC 触发值)。

5. 随机类定义

`ifndef VERILATOR
class rand_irq_cycles;
    rand int n;
endclass : rand_irq_cycles

class rand_irq_id;
    rand int n;
endclass : rand_irq_id

定义了两个随机类 rand_irq_cyclesrand_irq_id,分别用于生成随机的中断周期和中断 ID。

6. 内部信号定义

logic [31:0] irq_mode_q;
logic        irq_random;
logic  [4:0] irq_id_random;
logic        irq_ack_random;
logic        irq_monitor;
logic  [4:0] irq_id_monitor;
logic        irq_ack_monitor;

定义了一些内部信号,用于存储中断模式、随机中断信息和监控中断信息。

7. 信号赋值

assign irq_ack_o = irq_ack_i;

将输入的中断确认信号 irq_ack_i 直接赋值给输出的中断确认信号 irq_ack_o

8. 中断模式寄存器

always_ff @(posedge clk_i or negedge rst_ni)
begin
    if(~rst_ni) begin
        irq_mode_q <= 0;
    end else begin
        irq_mode_q <= irq_mode_i;
    end
end

使用一个同步寄存器 irq_mode_q 来存储中断模式 irq_mode_i,在复位时将其清零。

9. 中断模式选择

always_comb
begin
    unique case (irq_mode_q)
        RANDOM:
        begin
         irq_o     = irq_random;
         irq_id_o  = irq_id_random;
        end

        PC_TRIG:
        begin
         irq_o     = irq_monitor;
         irq_id_o  = irq_id_monitor;
        end

        default:
        begin
         irq_o     = irq_i;
         irq_id_o  = irq_id_i;
        end
    endcase
end

根据 irq_mode_q 的值选择不同的中断输出:

  • irq_mode_qRANDOM 时,输出随机中断信息。
  • irq_mode_qPC_TRIG 时,输出 PC 触发的中断信息。
  • 其他情况,输出外部输入的中断信息。

10. 随机中断生成过程

initial
begin
    automatic rand_irq_cycles wait_cycles = new();
    automatic rand_irq_id value = new();
    int rs,i, min_irq_cycles, max_irq_cycles, min_irq_id, max_irq_id;
    irq_random = 1'b0;
    irq_id_random  = '0;

    while(1) begin

        irq_random    = 1'b0;
        irq_id_random = '0;

        @(posedge clk_i);

        wait(irq_mode_q == RANDOM);
        min_irq_id     = irq_min_id_i;
        max_irq_id     = irq_max_id_i;
        min_irq_cycles = irq_min_cycles_i;
        max_irq_cycles = irq_max_cycles_i;

        rs = 0; // "randomize success"
        rs = value.randomize() with{
            n >= min_irq_id;
            n <= max_irq_id;
        };
        if (!rs) `uvm_error("RISCV_RANDOM_INTERRUPT_GENERATOR", "Randomization failure on value.randomize()")

        rs = wait_cycles.randomize() with{
            n >= min_irq_cycles;
            n <= max_irq_cycles;
        };
        if (!rs) `uvm_error("RISCV_RANDOM_INTERRUPT_GENERATOR", "Randomization failure on wait_cycles.randomize()")

        while(wait_cycles.n != 0) begin
            @(posedge clk_i);
            wait_cycles.n--;
        end

        irq_id_random = value.n;
        irq_random    = 1'b1;
        irq_act_id_o  = value.n;
        @(posedge clk_i);
        //we don't care about the ack in this mode
        for(i=0; i
  • 该过程在 irq_mode_qRANDOM 时生成随机中断。
  • 使用 rand_irq_cyclesrand_irq_id 类生成随机的中断周期和中断 ID。
  • 等待随机生成的周期数后,发出中断请求,并将中断 ID 输出。

11. PC 触发中断生成过程

initial
begin
    irq_monitor    = 1'b0;
    irq_id_monitor = '0;
    wait(irq_mode_q == PC_TRIG);
    wait(irq_pc_id_i == irq_pc_trig_i);
    irq_monitor    = 1'b1;
    irq_id_monitor = irq_min_id_i;
    while(irq_ack_i != 1'b1) begin
        @(posedge clk_i);   //Keep the request high until the acknowledge is received
    end
    @(posedge clk_i);
    irq_monitor    = 1'b0;
    irq_id_monitor = '0;
end
  • 该过程在 irq_mode_qPC_TRIG 时工作。
  • irq_pc_id_i 等于 irq_pc_trig_i 时,发出中断请求,并将中断 ID 设置为 irq_min_id_i
  • 保持中断请求高电平,直到收到中断确认信号。

12. 中断 ID 写使能过程

initial
begin
    while(1) begin
        irq_id_we_o = 1'b0;
        wait(irq_ack_i == 1'b1);
        irq_id_we_o = 1'b1;   //Give the write enable to store the core response
        @(posedge clk_i);
    end
end
  • 该过程在收到中断确认信号 irq_ack_i 时,将中断 ID 写使能信号 irq_id_we_o 置为高电平,用于存储核心的响应。

13. 模块结束

`endif //VERILATOR
endmodule

结束模块定义,endif 对应前面的 ifndef VERILATOR

总结

该模块实现了一个可配置的随机中断生成器,支持随机、标准和 PC 值触发三种中断模式。通过不同的过程根据配置生成相应的中断请求,并处理中断确认信号。在随机模式下,使用随机类生成随机的中断周期和中断 ID;在 PC 触发模式下,根据 PC 值触发中断。同时,提供了中断 ID 写使能信号用于存储核心的响应。

2. tb/core/tb_riscv/riscv_random_stall.sv


//
//                                                                                                              //
// Author:                      Andreas Traber - [email protected]                                        //
//                                                                                                              //
// Additional contributions by: Francesco Minervini - [email protected]                                  //
//                              Davide Schiavone    - [email protected]                                   //
// Design Name:                 Perturbation Unit                                                               //
// Project Name:                RI5CY, Zeroriscy                                                                //
// Language:                    SystemVerilog                                                                   //
//                                                                                                              //
// Description:                 Introduce stalls on core standard execution for both data and instructions      //
//                                                                                                              //
//

//import riscv_defines::*;
import perturbation_defines::*;

module riscv_random_stall

 #(
    parameter MAX_STALL_N    = 1,
              RAM_ADDR_WIDTH = 32,
              DATA_WIDTH     = 32
  )

(
    input logic                             clk_i,
    input logic                             rst_ni,
    //grant from memory
    input logic                             grant_mem_i,
    input logic                             rvalid_mem_i,
    input logic [DATA_WIDTH-1:0]            rdata_mem_i,

    output logic                            grant_core_o,
    output logic                            rvalid_core_o,
    output logic [DATA_WIDTH-1:0]           rdata_core_o,

    input logic                             req_core_i,
    output logic                            req_mem_o,

    input logic  [RAM_ADDR_WIDTH-1:0]       addr_core_i,
    output logic [RAM_ADDR_WIDTH-1:0]       addr_mem_o,

    input logic [DATA_WIDTH-1:0]            wdata_core_i,
    output logic [DATA_WIDTH-1:0]           wdata_mem_o,

    input logic                             we_core_i,
    output logic                            we_mem_o,

    input logic [3:0]                       be_core_i,
    output logic [3:0]                      be_mem_o,

    input logic [31:0]                      stall_mode_i,
    input logic [31:0]                      max_stall_i,
    input logic [31:0]                      gnt_stall_i,
    input logic [31:0]                      valid_stall_i
);
`ifndef VERILATOR
logic req_per_q, grant_per_q, rvalid_per_q;

typedef struct {
   
     logic [31:0]                  addr;
     logic                         we;
     logic [ 3:0]                  be;
     logic [DATA_WIDTH

你可能感兴趣的:(core-v-verif)