ALU - Verification With UVM
ALU - Verification With UVM
with
Arithmetic and Logic Unit Verification with UVM
Design Specifications
Port Descriptions
The ALU operation is selected using a 4-bit ALU_Sel input. The following table maps
the ALU_Sel values to the corresponding operations:
ALU_Sel Operation
4’b0000 A+B
4’b0001 A-B
4’b0010 A*B
4’b0011 A/B
4’b0100 - 4’b1111 Reserved
Notes
• Ensure that Input A is always greater than or equal to Input B for proper
functionality.
• The ALU does not support back-to-back transactions; a cycle must be left
between operations.
ALU TB ARCHITECTURE
Design
//--------------------------------------------------------
//ALU Design
//--------------------------------------------------------
/*
ALU Arithmetic and Logic Operations
----------------------------------------------------------------------
|ALU_Sel| ALU Operation
----------------------------------------------------------------------
| 0000 | ALU_Out = A + B;
----------------------------------------------------------------------
| 0001 | ALU_Out = A - B;
----------------------------------------------------------------------
| 0010 | ALU_Out = A * B;
----------------------------------------------------------------------
| 0011 | ALU_Out = A / B;
----------------------------------------------------------------------
*/
module alu(
input clock,
input reset,
input [7:0] A,B, // ALU 8-bit Inputs
input [3:0] ALU_Sel,// ALU Selection
output reg [7:0] ALU_Out, // ALU 8-bit Output
output bit CarryOut // Carry Out Flag
);
endmodule
Testbench
`timescale 1ns/1ns
import uvm_pkg::*;
`include "uvm_macros.svh"
//--------------------------------------------------------
//Include Files
//--------------------------------------------------------
`include "interface.sv"
`include "sequence_item.sv"
`include "sequence.sv"
`include "sequencer.sv"
`include "driver.sv"
`include "monitor.sv"
`include "agent.sv"
`include "scoreboard.sv"
`include "env.sv"
`include "test.sv"
module top;
//--------------------------------------------------------
//Instantiation
//--------------------------------------------------------
logic clock;
alu_interface intf(.clock(clock));
alu dut(
.clock(intf.clock),
.reset(intf.reset),
.A(intf.a),
.B(intf.b),
.ALU_Sel(intf.op_code),
.ALU_Out(intf.result),
.CarryOut(intf.carry_out)
);
//--------------------------------------------------------
//Interface Setting
//--------------------------------------------------------
initial begin
uvm_config_db #(virtual alu_interface)::set(null, "*", "vif", intf );
end
//--------------------------------------------------------
//Start The Test
//--------------------------------------------------------
initial begin
run_test("alu_test");
end
//--------------------------------------------------------
//Clock Generation
//--------------------------------------------------------
initial begin
clock = 0;
#5;
forever begin
clock = ~clock;
#2;
end
end
//--------------------------------------------------------
//Maximum Simulation Time
//--------------------------------------------------------
initial begin
#5000;
$display("Sorry! Ran out of clock cycles!");
$finish();
end
//--------------------------------------------------------
//Generate Waveforms
//--------------------------------------------------------
initial begin
$dumpfile("d.vcd");
$dumpvars();
end
endmodule: top
Interface
interface alu_interface(input logic clock);
logic reset;
logic [7:0] a, b;
logic [3:0] op_code;
logic [7:0] result;
bit carry_out;
endinterface: alu_interface
Test
class alu_test extends uvm_test;
`uvm_component_utils(alu_test)
alu_env env;
alu_base_sequence reset_seq;
alu_test_sequence test_seq;
//--------------------------------------------------------
//Constructor
//--------------------------------------------------------
function new(string name = "alu_test", uvm_component parent);
super.new(name, parent);
`uvm_info("TEST_CLASS", "Inside Constructor!", UVM_HIGH)
endfunction: new
//--------------------------------------------------------
//Build Phase
//--------------------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("TEST_CLASS", "Build Phase!", UVM_HIGH)
endfunction: build_phase
//--------------------------------------------------------
//Connect Phase
//--------------------------------------------------------
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("TEST_CLASS", "Connect Phase!", UVM_HIGH)
endfunction: connect_phase
//--------------------------------------------------------
//Run Phase
//--------------------------------------------------------
task run_phase (uvm_phase phase);
super.run_phase(phase);
`uvm_info("TEST_CLASS", "Run Phase!", UVM_HIGH)
phase.raise_objection(this);
//reset_seq
reset_seq = alu_base_sequence::type_id::create("reset_seq");
reset_seq.start(env.agnt.seqr);
#10;
repeat(100) begin
//test_seq
test_seq = alu_test_sequence::type_id::create("test_seq");
test_seq.start(env.agnt.seqr);
#10;
end
phase.drop_objection(this);
endtask: run_phase
endclass: alu_test
Environment
class alu_env extends uvm_env;
`uvm_component_utils(alu_env)
alu_agent agnt;
alu_scoreboard scb;
//--------------------------------------------------------
//Constructor
//--------------------------------------------------------
function new(string name = "alu_env", uvm_component parent);
super.new(name, parent);
`uvm_info("ENV_CLASS", "Inside Constructor!", UVM_HIGH)
endfunction: new
//--------------------------------------------------------
//Build Phase
//--------------------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("ENV_CLASS", "Build Phase!", UVM_HIGH)
endfunction: build_phase
//--------------------------------------------------------
//Connect Phase
//--------------------------------------------------------
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("ENV_CLASS", "Connect Phase!", UVM_HIGH)
agnt.mon.monitor_port.connect(scb.scoreboard_port);
endfunction: connect_phase
//--------------------------------------------------------
//Run Phase
//--------------------------------------------------------
task run_phase (uvm_phase phase);
super.run_phase(phase);
endtask: run_phase
endclass: alu_env
Agent
class alu_agent extends uvm_agent;
`uvm_component_utils(alu_agent)
alu_driver drv;
alu_monitor mon;
alu_sequencer seqr;
//--------------------------------------------------------
//Constructor
//--------------------------------------------------------
function new(string name = "alu_agent", uvm_component parent);
super.new(name, parent);
`uvm_info("AGENT_CLASS", "Inside Constructor!", UVM_HIGH)
endfunction: new
//--------------------------------------------------------
//Build Phase
//--------------------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("AGENT_CLASS", "Build Phase!", UVM_HIGH)
drv = alu_driver::type_id::create("drv", this);
mon = alu_monitor::type_id::create("mon", this);
seqr = alu_sequencer::type_id::create("seqr", this);
endfunction: build_phase
//--------------------------------------------------------
//Connect Phase
//--------------------------------------------------------
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("AGENT_CLASS", "Connect Phase!", UVM_HIGH)
drv.seq_item_port.connect(seqr.seq_item_export);
endfunction: connect_phase
//--------------------------------------------------------
//Run Phase
//--------------------------------------------------------
task run_phase (uvm_phase phase);
super.run_phase(phase);
endtask: run_phase
endclass: alu_agent
Driver
class alu_driver extends uvm_driver#(alu_sequence_item);
`uvm_component_utils(alu_driver)
//--------------------------------------------------------
//Constructor
//--------------------------------------------------------
function new(string name = "alu_driver", uvm_component parent);
super.new(name, parent);
`uvm_info("DRIVER_CLASS", "Inside Constructor!", UVM_HIGH)
endfunction: new
//--------------------------------------------------------
//Build Phase
//--------------------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("DRIVER_CLASS", "Build Phase!", UVM_HIGH)
if(!(uvm_config_db #(virtual alu_interface)::get(this, "*", "vif", vif)))
begin
`uvm_error("DRIVER_CLASS", "Failed to get VIF from config DB!")
end
endfunction: build_phase
//--------------------------------------------------------
//Connect Phase
//--------------------------------------------------------
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("DRIVER_CLASS", "Connect Phase!", UVM_HIGH)
endfunction: connect_phase
//--------------------------------------------------------
//Run Phase
//--------------------------------------------------------
task run_phase (uvm_phase phase);
super.run_phase(phase);
`uvm_info("DRIVER_CLASS", "Inside Run Phase!", UVM_HIGH)
forever begin
item = alu_sequence_item::type_id::create("item");
seq_item_port.get_next_item(item);
drive(item);
seq_item_port.item_done();
end
endtask: run_phase
//--------------------------------------------------------
//[Method] Drive
//--------------------------------------------------------
task drive(alu_sequence_item item);
@(posedge vif.clock);
vif.reset <= item.reset;
vif.a <= item.a;
vif.b <= item.b;
vif.op_code <= item.op_code;
endtask: drive
endclass: alu_driver
Monitor
class alu_monitor extends uvm_monitor;
`uvm_component_utils(alu_monitor)
//--------------------------------------------------------
//Constructor
//--------------------------------------------------------
function new(string name = "alu_monitor", uvm_component parent);
super.new(name, parent);
`uvm_info("MONITOR_CLASS", "Inside Constructor!", UVM_HIGH)
endfunction: new
//--------------------------------------------------------
//Build Phase
//--------------------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("MONITOR_CLASS", "Build Phase!", UVM_HIGH)
endfunction: build_phase
//--------------------------------------------------------
//Connect Phase
//--------------------------------------------------------
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("MONITOR_CLASS", "Connect Phase!", UVM_HIGH)
endfunction: connect_phase
//--------------------------------------------------------
//Run Phase
//--------------------------------------------------------
task run_phase (uvm_phase phase);
super.run_phase(phase);
`uvm_info("MONITOR_CLASS", "Inside Run Phase!", UVM_HIGH)
forever begin
item = alu_sequence_item::type_id::create("item");
wait(!vif.reset);
//sample inputs
@(posedge vif.clock);
item.a = vif.a;
item.b = vif.b;
item.op_code = vif.op_code;
//sample output
@(posedge vif.clock);
item.result = vif.result;
endtask: run_phase
endclass: alu_monitor
Sequencer
class alu_sequencer extends uvm_sequencer#(alu_sequence_item);
`uvm_component_utils(alu_sequencer)
//--------------------------------------------------------
//Constructor
//--------------------------------------------------------
function new(string name = "alu_sequencer", uvm_component parent);
super.new(name, parent);
`uvm_info("SEQR_CLASS", "Inside Constructor!", UVM_HIGH)
endfunction: new
//--------------------------------------------------------
//Build Phase
//--------------------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("SEQR_CLASS", "Build Phase!", UVM_HIGH)
endfunction: build_phase
//--------------------------------------------------------
//Connect Phase
//--------------------------------------------------------
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("SEQR_CLASS", "Connect Phase!", UVM_HIGH)
endfunction: connect_phase
endclass: alu_sequencer
Sequence Item
class alu_sequence_item extends uvm_sequence_item;
`uvm_object_utils(alu_sequence_item)
//--------------------------------------------------------
//Instantiation
//--------------------------------------------------------
rand logic reset;
rand logic [7:0] a, b;
rand logic [3:0] op_code;
//--------------------------------------------------------
//Default Constraints
//--------------------------------------------------------
constraint input1_c {a inside {[10:20]};}
constraint input2_c {b inside {[1:10]};}
constraint op_code_c {op_code inside {0,1,2,3};}
//--------------------------------------------------------
//Constructor
//--------------------------------------------------------
function new(string name = "alu_sequence_item");
super.new(name);
endfunction: new
endclass: alu_sequence_item
Sequence
class alu_base_sequence extends uvm_sequence;
`uvm_object_utils(alu_base_sequence)
alu_sequence_item reset_pkt;
//--------------------------------------------------------
//Constructor
//--------------------------------------------------------
function new(string name= "alu_base_sequence");
super.new(name);
`uvm_info("BASE_SEQ", "Inside Constructor!", UVM_HIGH)
endfunction
//--------------------------------------------------------
//Body Task
//--------------------------------------------------------
task body();
`uvm_info("BASE_SEQ", "Inside body task!", UVM_HIGH)
reset_pkt = alu_sequence_item::type_id::create("reset_pkt");
start_item(reset_pkt);
reset_pkt.randomize() with {reset==1;};
finish_item(reset_pkt);
endtask: body
endclass: alu_base_sequence
alu_sequence_item item;
//--------------------------------------------------------
//Constructor
//--------------------------------------------------------
function new(string name= "alu_test_sequence");
super.new(name);
`uvm_info("TEST_SEQ", "Inside Constructor!", UVM_HIGH)
endfunction
//--------------------------------------------------------
//Body Task
//--------------------------------------------------------
task body();
`uvm_info("TEST_SEQ", "Inside body task!", UVM_HIGH)
item = alu_sequence_item::type_id::create("item");
start_item(item);
item.randomize() with {reset==0;};
finish_item(item);
endtask: body
endclass: alu_test_sequence
Scoreboard
class alu_scoreboard extends uvm_test;
`uvm_component_utils(alu_scoreboard)
alu_sequence_item transactions[$];
//--------------------------------------------------------
//Constructor
//--------------------------------------------------------
function new(string name = "alu_scoreboard", uvm_component parent);
super.new(name, parent);
`uvm_info("SCB_CLASS", "Inside Constructor!", UVM_HIGH)
endfunction: new
//--------------------------------------------------------
//Build Phase
//--------------------------------------------------------
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("SCB_CLASS", "Build Phase!", UVM_HIGH)
endfunction: build_phase
//--------------------------------------------------------
//Connect Phase
//--------------------------------------------------------
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("SCB_CLASS", "Connect Phase!", UVM_HIGH)
endfunction: connect_phase
//--------------------------------------------------------
//Write Method
//--------------------------------------------------------
function void write(alu_sequence_item item);
transactions.push_back(item);
endfunction: write
//--------------------------------------------------------
//Run Phase
//--------------------------------------------------------
task run_phase (uvm_phase phase);
super.run_phase(phase);
`uvm_info("SCB_CLASS", "Run Phase!", UVM_HIGH)
forever begin
/*
// get the packet
// generate expected value
// compare it with actual value
// score the transactions accordingly
*/
alu_sequence_item curr_trans;
wait((transactions.size() != 0));
curr_trans = transactions.pop_front();
compare(curr_trans);
end
endtask: run_phase
//--------------------------------------------------------
//Compare : Generate Expected Result and Compare with Actual
//--------------------------------------------------------
task compare(alu_sequence_item curr_trans);
logic [7:0] expected;
logic [7:0] actual;
case(curr_trans.op_code)
0: begin //A + B
expected = curr_trans.a + curr_trans.b;
end
1: begin //A - B
expected = curr_trans.a - curr_trans.b;
end
2: begin //A * B
expected = curr_trans.a * curr_trans.b;
end
3: begin //A / B
expected = curr_trans.a / curr_trans.b;
end
endcase
actual = curr_trans.result;
endtask: compare
endclass: alu_scoreboard