0% found this document useful (0 votes)
300 views17 pages

ALU - Verification With UVM

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
300 views17 pages

ALU - Verification With UVM

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

Verification

with
Arithmetic and Logic Unit Verification with UVM

Design Specifications

1. Clocking and Reset:


o The design is clocked.
o Reset type is Active High (Reset occurs when the value is 1).
2. Operation Cycle:
o Input is provided on the current cycle.
o The Design Under Test (DUT) outputs the result in the next cycle.
o Back-to-back transactions are not supported.
3. Supported Operations:
o The ALU supports four operations: ADD, SUB, MULT, and DIV.
o Input A must always be greater than or equal to Input B.

Port Descriptions

Port Name Type Property Size


Clock Input Wire 1 bit
Reset Input Wire 1 bit
A Input Wire 8 bits
B Input Wire 8 bits
ALU_Sel Input Wire 4 bits
ALU_Out Output Reg 8 bits
CarryOut Output Bit 1 bit
ALU Operation Selection

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
);

reg [7:0] ALU_Result;


wire [8:0] tmp;

assign tmp = {1'b0,A} + {1'b0,B};

always @(posedge clock or posedge reset) begin


if(reset) begin
ALU_Out <= 8'd0;
CarryOut <= 1'd0;
end
else begin
ALU_Out <= ALU_Result;
CarryOut <= tmp[8];
end
end

always @(*) //introduce a bug here, A B sensitivity only, change ALU_Sel


during
begin
case(ALU_Sel)
4'b0000: // Addition
ALU_Result = A + B ;
4'b0001: // Subtraction
ALU_Result = A - B ;
4'b0010: // Multiplication
ALU_Result = A * B;
4'b0011: // Division
ALU_Result = A/B;
default: ALU_Result = 8'hAC ; // Give out random BAD value
endcase
end

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)

env = alu_env::type_id::create("env", this);

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)

agnt = alu_agent::type_id::create("agnt", this);


scb = alu_scoreboard::type_id::create("scb", this);

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)

virtual alu_interface vif;


alu_sequence_item item;

//--------------------------------------------------------
//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)

virtual alu_interface vif;


alu_sequence_item item;

uvm_analysis_port #(alu_sequence_item) monitor_port;

//--------------------------------------------------------
//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)

monitor_port = new("monitor_port", this);

if(!(uvm_config_db #(virtual alu_interface)::get(this, "*", "vif", vif)))


begin
`uvm_error("MONITOR_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("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;

// send item to scoreboard


monitor_port.write(item);
end

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;

logic [7:0] result; //output


bit carry_out; // output

//--------------------------------------------------------
//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

class alu_test_sequence extends alu_base_sequence;


`uvm_object_utils(alu_test_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)

uvm_analysis_imp #(alu_sequence_item, alu_scoreboard) scoreboard_port;

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)

scoreboard_port = new("scoreboard_port", this);

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;

if(actual != expected) begin


`uvm_error("COMPARE", $sformatf("Transaction failed! ACT=%d, EXP=%d",
actual, expected))
end
else begin
// Note: Can display the input and op_code as well if you want to see
what's happening
`uvm_info("COMPARE", $sformatf("Transaction Passed! ACT=%d, EXP=%d",
actual, expected), UVM_LOW)
end

endtask: compare

endclass: alu_scoreboard

You might also like