一个加法器的验证

1.DUT

module alu_top (
    input   wire            clk_i,
    input   wire            rst_i,
    input   wire    [31:0]  dataA_i,
    input   wire    [31:0]  dataB_i,
    input   wire    [ 2:0]  ALUCtrl_i,     // Operation code
    output  logic   [31:0]  ALUResult_o,
    output  logic           Zero_o
);

reg [31:0] temp_alu_result;
reg temp_zero;

always @(*) begin
    if (rst_i == 1'b1) begin
        temp_alu_result =  32'b0;
        temp_zero      =   1'b0;
    end else begin
        case (ALUCtrl_i)
            3'b010: // ADD
            begin
                temp_alu_result = dataA_i + dataB_i;
            end

            3'b110: // SUB
            begin
                temp_alu_result = dataA_i - dataB_i;
            end

            3'b000: // AND
            begin
                temp_alu_result = dataA_i & dataB_i;
            end

            3'b001: // OR
            begin
                temp_alu_result = dataA_i | dataB_i;
            end

            3'b011: // XOR
            begin
                temp_alu_result = dataA_i ^ dataB_i;
            end

            3'b100: // NOR
            begin
                temp_alu_result = ~(dataA_i | dataB_i);
            end

            3'b111: // SLT
            begin
                if ((dataA_i - dataB_i) < 0)
                    temp_alu_result = 32'b1;
                else
                    temp_alu_result = 32'b0;
            end

            default:
            begin
                temp_alu_result =  32'b0;
                temp_zero      =   1'b0;
            end
        endcase

        // The zero signal is mainly used by the branch
        if (temp_alu_result == 32'b0) begin
            temp_zero = 1'b1;
        end else begin
            temp_zero = 1'b0;
        end
    end // NOT reset

end // always

always @(posedge clk_i or posedge rst_i) begin
    if (rst_i == 1'b1) begin
        ALUResult_o <= 32'b0;
        Zero_o <= 1'b1;
    end else begin
        ALUResult_o <= temp_alu_result;
        Zero_o <= temp_zero;
    end
end // always

endmodule : alu_top

2.transaction

`ifndef ALU_BASE_SEQ_ITEM__SV
`define ALU_BASE_SEQ_ITEM__SV

class alu_base_seq_item extends uvm_sequence_item;

    rand bit [31:0] dataA_i;
    rand bit [31:0] dataB_i;
    randc bit [ 2:0] ALUCtrl_i;
    bit [31:0] ALUResult_o;
    bit        Zero_o;

    rand int wait_cycles;

    `uvm_object_utils_begin(alu_base_seq_item)
        `uvm_field_int(dataA_i, UVM_DEFAULT)
        `uvm_field_int(dataB_i, UVM_DEFAULT)
        `uvm_field_int(ALUCtrl_i, UVM_DEFAULT)
        `uvm_field_int(ALUResult_o, UVM_DEFAULT)
        `uvm_field_int(Zero_o, UVM_DEFAULT)
    `uvm_object_utils_end

    //------------------------------------------
    // Constraints
    //------------------------------------------
    constraint delay_loops {wait_cycles inside {[0:5]};}
    constraint valid_alu_op {ALUCtrl_i inside {3'b000, 3'b001, 3'b010, 3'b011, 3'b100, 3'b110, 3'b111};}

    function new (string name = "alu_base_seq_item");
        super.new(name);
    endfunction: new

endclass: alu_base_seq_item

`endif

3.sequence

`ifndef ALU_BASE_SEQ__SV
`define ALU_BASE_SEQ__SV

class alu_base_seq extends uvm_sequence#(alu_base_seq_item);
    `uvm_object_utils(alu_base_seq)

    // Each sequence has a random number of operations.
    // There is a constraint to keep the number reasonable.
    rand int unsigned num_of_ops;
    constraint num_of_ops_con {num_of_ops inside {[16:24]};}

    function new(string name = "alu_base_seq");
        super.new(name);
    endfunction: new

    // This task generates a sequence of transactions.
    task body();
        alu_base_seq_item m_alu_base_seq_item_h;
        repeat (num_of_ops) begin
            m_alu_base_seq_item_h = alu_base_seq_item::type_id::create(.name("m_alu_base_seq_item_h"));
            start_item(m_alu_base_seq_item_h);
            if (!m_alu_base_seq_item_h.randomize()) begin
                `uvm_error("m_alu_base_seq_item_h", "Randomize failed.");
            end
            finish_item(m_alu_base_seq_item_h);
        end
    endtask: body
endclass: alu_base_seq
`endif

 4.sequencer

直接使用参数化的uvm_sequencer

5.interface

`ifndef ALU_IF__SV
`define ALU_IF__SV

interface alu_if (input bit clk);

    // ALU signals
    logic [31:0] dataA_i, dataB_i, ALUResult_o;
    logic [2:0]  ALUCtrl_i;
    logic rst_i, Zero_o;

endinterface : alu_if

`endif

6.driver

`ifndef ALU_DRIVER__SV
`define ALU_DRIVER__SV

class alu_driver extends uvm_driver#(alu_base_seq_item);
    `uvm_component_utils(alu_driver)

    virtual alu_if m_alu_vif_h;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction: new

    // In the build phase, the driver is connected to the virtual interface.
    // The DUT is also connected to the same interface.
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        assert(uvm_config_db#(virtual alu_if)::get
        (.cntxt(this), .inst_name(""), .field_name("alu_if"), .value(m_alu_vif_h)));
    endfunction: build_phase

    task run_phase(uvm_phase phase);
        alu_base_seq_item m_req_h;

        m_alu_vif_h.dataA_i   <= 32'b0;
        m_alu_vif_h.dataB_i   <= 32'b0;
        m_alu_vif_h.ALUCtrl_i <= 3'b0;

        // Generate a reset sequence.
        // FIXME: Move this to the pre-run phase.
        m_alu_vif_h.rst_i     <= 1'b1;
        repeat (2) @(posedge m_alu_vif_h.clk);
        m_alu_vif_h.rst_i     <= 1'b0;
        // Keep receiving the next transaction from the sequence until you run out.
        // Drive each transaction on the interface as per the protocol.

        // In the alu_agent, the seq_item_port of the alu_driver is hooked up to the
        // seq_item_export port on the sequencer (alu_base_seq_item).
        // The alu_driver accepts alu_transactions with the get_next_item function.

        // Sample timing diagram
        //          ___     ___     ___
        // CLK  ___|   |___|   |___|   |___
        //
        // INP  _______########------------
        //
        // OUT  -------------------#####----
        forever begin
            seq_item_port.get_next_item(m_req_h);

            `uvm_info("DRIVER_START:", $sformatf("DATA:: dataA_i: %32x, dataB_i: %32x, ALU_OP: %3b", m_req_h.dataA_i, m_req_h.dataB_i, m_req_h.ALUCtrl_i), UVM_DEBUG)
            @(negedge m_alu_vif_h.clk);
            m_alu_vif_h.dataA_i   = m_req_h.dataA_i;
            m_alu_vif_h.dataB_i   = m_req_h.dataB_i;
            m_alu_vif_h.ALUCtrl_i = m_req_h.ALUCtrl_i;
            @(negedge m_alu_vif_h.clk);
            m_alu_vif_h.dataA_i   = 32'bz;
            m_alu_vif_h.dataB_i   = 32'bz;
            m_alu_vif_h.ALUCtrl_i = 3'bz;
            `uvm_info("DRIVER_DONE:", $sformatf("DATA:: dataA_i: %32x, dataB_i: %32x, ALU_OP: %3b", m_alu_vif_h.dataA_i, m_alu_vif_h.dataB_i, m_alu_vif_h.ALUCtrl_i), UVM_DEBUG)
            `uvm_info("DRIVER_WAIT:", $sformatf("Waiting for %1d cycles", m_req_h.wait_cycles), UVM_DEBUG)
            repeat (m_req_h.wait_cycles) @(negedge m_alu_vif_h.clk);
            seq_item_port.item_done();
        end // forever
    endtask: run_phase
endclass: alu_driver
`endif

7.monitor

`ifndef ALU_MONITOR__SV
`define ALU_MONITOR__SV

class alu_monitor extends uvm_monitor;
    `uvm_component_utils(alu_monitor)

    virtual alu_if m_alu_vif_h;
    uvm_analysis_port #(alu_base_seq_item) m_analysis_port_h;

    function new (string name, uvm_component parent);
        super.new(name, parent);
    endfunction: new

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        m_analysis_port_h = new("m_analysis_port_h", this);
    endfunction: build_phase

    function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        assert(uvm_config_db#(virtual alu_if)::get
        (.cntxt(this), .inst_name(""), .field_name("alu_if"), .value(m_alu_vif_h)));
    endfunction: connect_phase

    task run_phase(uvm_phase phase);
        alu_base_seq_item m_req_h = alu_base_seq_item::type_id::create("monitor_m_req_h");
        alu_base_seq_item m_req_clone_h;
        @(negedge m_alu_vif_h.rst_i);
        forever begin
            @(posedge m_alu_vif_h.clk);
            m_req_h.dataA_i  = m_alu_vif_h.dataA_i;
            m_req_h.dataB_i  = m_alu_vif_h.dataB_i;
            m_req_h.ALUCtrl_i = m_alu_vif_h.ALUCtrl_i;
            `uvm_info("MONITOR:", $sformatf("DATA:: dataA_i: %32x, dataB_i: %32x, ALU_OP: %3b", m_req_h.dataA_i, m_req_h.dataB_i, m_req_h.ALUCtrl_i), UVM_DEBUG)
            @(posedge m_alu_vif_h.clk);
            m_req_h.ALUResult_o = m_alu_vif_h.ALUResult_o;
            m_req_h.Zero_o = m_alu_vif_h.Zero_o;
            `uvm_info("MONITOR:", $sformatf("RESULT:: ALUResult_o: %32x, Zero_o: %1x", m_req_h.ALUResult_o, m_req_h.Zero_o), UVM_DEBUG)
            $cast(m_req_clone_h, m_req_h.clone());
            m_analysis_port_h.write(m_req_clone_h);
        end // forever
    endtask: run_phase
endclass: alu_monitor
`endif

8.agent

`ifndef ALU_AGENT__SV
`define ALU_AGENT__SV

class alu_agent extends uvm_agent;
    `uvm_component_utils(alu_agent)

    uvm_analysis_port #(alu_base_seq_item) m_analysis_port_h;
    uvm_sequencer #(alu_base_seq_item)     m_sequencer_h;
    alu_driver                             m_driver_h;
    alu_monitor                            m_monitor_h;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction: new

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);

        // Monitor should always be present.
        m_monitor_h = alu_monitor::type_id::create("m_monitor_h", this);

        // Analysis port should always be present.
        m_analysis_port_h = new("m_analysis_port_h", this);

        // Only build the driver and sequencer if agent is active.
        m_driver_h = alu_driver::type_id::create("m_driver_h", this);
        m_sequencer_h = uvm_sequencer#(alu_base_seq_item)::type_id::create("m_sequencer_h", this);

    endfunction: build_phase

    virtual function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        m_monitor_h.m_analysis_port_h.connect(m_analysis_port_h);

        // Only connect the driver and the sequencer if agent is active.
        m_driver_h.seq_item_port.connect(m_sequencer_h.seq_item_export);
    endfunction: connect_phase
endclass: alu_agent
`endif

9.monitor

`ifndef SCOREBOARD__SV
`define SCOREBOARD__SV
class scoreboard extends uvm_component;

    `uvm_component_utils(scoreboard)

    uvm_tlm_analysis_fifo #(alu_base_seq_item) m_alu_fifo_h;

    function new(string name = "scoreboard", uvm_component parent = null);
        super.new(name, parent);
    endfunction: new

    function void build_phase(uvm_phase phase);
        m_alu_fifo_h = new("m_alu_fifo_h", this);
    endfunction: build_phase

    task run_phase(uvm_phase phase);

        alu_base_seq_item alu_op;
        bit [31:0] expALUResult_o;
        bit        expZero_o;
        forever begin
            m_alu_fifo_h.get(alu_op);
            `uvm_info("SCOREBOARD:", $sformatf("DATA:: alu_op.dataA_i: %32x, alu_op.dataB_i: %32x, ALU_OP: %3b", alu_op.dataA_i, alu_op.dataB_i, alu_op.ALUCtrl_i), UVM_NONE)

            case (alu_op.ALUCtrl_i)
                3'b010: // ADD
                begin
                    expALUResult_o = alu_op.dataA_i + alu_op.dataB_i;
                end

                3'b110: // SUB
                begin
                    expALUResult_o = alu_op.dataA_i - alu_op.dataB_i;
                end

                3'b000: // AND
                begin
                    expALUResult_o = alu_op.dataA_i & alu_op.dataB_i;
                end

                3'b001: // OR
                begin
                    expALUResult_o = alu_op.dataA_i | alu_op.dataB_i;
                end

                3'b011: // XOR
                begin
                    expALUResult_o = alu_op.dataA_i ^ alu_op.dataB_i;
                end

                3'b100: // NOR
                begin
                    expALUResult_o = ~(alu_op.dataA_i | alu_op.dataB_i);
                end

                3'b111: // SLT
                begin
                    if ((alu_op.dataA_i - alu_op.dataB_i) < 0)
                        expALUResult_o = 32'b1;
                    else
                        expALUResult_o = 32'b0;
                end

                default:
                begin
                    expALUResult_o =  32'b0;
                    expZero_o      =   1'b0;
                end
            endcase
            // The zero signal is mainly used by the branch
            if (expALUResult_o == 32'b0) begin
                expZero_o = 1'b1;
            end else begin
                expZero_o = 1'b0;
            end

            `uvm_info("SCOREBOARD:", $sformatf("DATA:: alu_op.ALUResult_o: %32x, expALUResult_o: %32x, alu_op.Zero_o: %1b, expZero_o: %1b", alu_op.ALUResult_o, expALUResult_o, alu_op.Zero_o, expZero_o), UVM_NONE)
            if(alu_op.ALUResult_o == expALUResult_o && alu_op.Zero_o == expZero_o) begin
                `uvm_info("SCOREBOARD:", $sformatf("CHECK_OK"), UVM_NONE)
            end else begin
                `uvm_error("SCOREBOARD:", $sformatf("CHECK_FAILED"))
            end

        end // forever
    endtask: run_phase

endclass: scoreboard
`endif

 10.env

`ifndef ENV__SV
`define ENV__SV

class alu_env extends uvm_env;

    `uvm_component_utils(alu_env)

    alu_agent m_alu_agent_h;
    scoreboard m_scoreboard_h;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction: new

    function void build_phase(uvm_phase phase);
        m_alu_agent_h = alu_agent::type_id::create("m_alu_agent_h", this);
        m_scoreboard_h = scoreboard::type_id::create("m_scoreboard_h", this);
    endfunction: build_phase

    function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        m_alu_agent_h.m_analysis_port_h.connect(m_scoreboard_h.m_alu_fifo_h.analysis_export);
    endfunction: connect_phase

endclass: alu_env
`endif

 11.testcase

`ifndef ALU_BASE_TEST__SV
`define ALU_BASE_TEST__SV

class alu_base_test extends uvm_test;
    `uvm_component_utils(alu_base_test)

    alu_env m_alu_env_h;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction: new

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        m_alu_env_h = alu_env::type_id::create(.name("m_alu_env_h"), .parent(this));
    endfunction: build_phase

    task run_phase(uvm_phase phase);
        alu_base_seq m_alu_seq_h;

        // Raise objection so the test will not end. Dropping it will end the test.
        phase.raise_objection(.obj(this));
        m_alu_seq_h = alu_base_seq::type_id::create(.name("m_alu_seq_h"));
        assert(m_alu_seq_h.randomize());
        `uvm_info("alu_base_test",{"\n", m_alu_seq_h.sprint()}, UVM_LOW)

        // Set the generated sequence on the sequencer port of the agent.
        // The driver will pick up a transaction each and driver it.
        m_alu_seq_h.start(m_alu_env_h.m_alu_agent_h.m_sequencer_h);
        #10ns;
        phase.drop_objection(.obj(this));
    endtask: run_phase
endclass: alu_base_test
`endif

12.testbench

`ifndef TB_TOP__SV
`define TB_TOP__SV

import uvm_pkg::*;
`include "uvm_macros.svh"

module top;

reg clk;

// Interface to connect the ALU agent with the DUT
alu_if    m_alu_if_h (clk);

// DUT connections
alu_top DUT (
    .clk_i(clk),
    .rst_i(m_alu_if_h.rst_i),
    .dataA_i(m_alu_if_h.dataA_i),
    .dataB_i(m_alu_if_h.dataB_i),
    .ALUCtrl_i(m_alu_if_h.ALUCtrl_i),
    .ALUResult_o(m_alu_if_h.ALUResult_o),
    .Zero_o(m_alu_if_h.Zero_o)
);

// Clock generator
initial begin
    clk = 0;
    #5ns;
    forever #5ns clk = !clk;
end

// Set the interface to the DUT to be used by UVM TB.
initial begin
    uvm_config_db#(virtual alu_if)::set(null, "*", "alu_if", m_alu_if_h);
    run_test();
end

endmodule: top
`endif

 

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个使用Vivado和Verilog语言实现的四位二进制加法器的示例: 首先,创建一个新的工程并打开Vivado。 1. 在Vivado主界面,选择"Create Project"创建一个新工程。 2. 在"Project Name"字段输入工程的名称,选择一个合适的位置来保存工程文件,然后点击"Next"。 3. 在"Default Part"页面选择你使用的FPGA器件,然后点击"Next"。 4. 在"Project Type"页面选择"RTL Project",然后点击"Next"。 5. 在"Add Sources"页面,点击"Create File"创建一个新的Verilog文件。 6. 输入文件名(例如,binary_adder.v)并点击"OK"。 7. 打开创建的Verilog文件,并输入以下代码: ```verilog module BinaryAdder( input wire [3:0] A, input wire [3:0] B, output wire [3:0] Sum ); wire [3:0] carry; assign Sum[0] = A[0] ^ B[0]; assign carry[0] = A[0] & B[0]; assign Sum[1] = A[1] ^ B[1] ^ carry[0]; assign carry[1] = (A[1] & B[1]) | (carry[0] & (A[1] ^ B[1])); assign Sum[2] = A[2] ^ B[2] ^ carry[1]; assign carry[2] = (A[2] & B[2]) | (carry[1] & (A[2] ^ B[2])); assign Sum[3] = A[3] ^ B[3] ^ carry[2]; assign carry[3] = (A[3] & B[3]) | (carry[2] & (A[3] ^ B[3])); endmodule ``` 在上述代码,BinaryAdder模块实现一个四位的二进制加法器。它接受两个四位输入(A和B),并输出一个四位结果(Sum)。 8. 保存Verilog文件并返回到Vivado界面。 9. 在Vivado界面,点击"Run Simulation"来运行仿真,验证二进制加法器的功能。 以上是一个简单的四位二进制加法器的示例。你可以根据需要进行修改和扩展。完成后,你可以综合和实现该设计,然后将其下载到目标FPGA器件进行验证

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值