Skip to content

Commit

Permalink
Merge pull request #11 from kumarrishav14/release-1.0
Browse files Browse the repository at this point in the history
Release 1.0
  • Loading branch information
kumarrishav14 authored Jan 19, 2021
2 parents 8900b3d + 2249568 commit d950b4f
Show file tree
Hide file tree
Showing 18 changed files with 1,627 additions and 2 deletions.
33 changes: 31 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,31 @@
# AXI
Testbench for AXI protocol slave
# AXI

![GitHub release (latest by date)](https://img.shields.io/github/v/release/kumarrishav14/AXI)

VIP for AXI Protocol

## Architecture

![Architecture](images/AXI.png)

## Components

1. Sequence item
2. Sequence - 2 sequence were made as in AXI read and write can happen in parallel.
3. Sequencer - 2 Sequencer were connected to a single driver so that the read and write operation are independent of each other and can happen in parallel
4. Driver - One each in master and slave
5. Monitor - One each in master and slave
6. Scoreboard
7. Environment
8. Test - Comprises of one base test, and 5 directed test cases.
9. TestBench top - Environment can be configured from here
10. Configuration Object:
- env_config - Config object to configure the environment and agents
- test_config - Config object to configure the test.

## How to use

- Download the latest release from below or visit the [release page](https://github.com/kumarrishav14/AXI/releases "Release page") for more old release.
- Copy the contents in a folder.
- Compile *tb_top.sv* in any simulator and simulate *top* module.
- Different test classes can be selected using +UVM_TESTNAME directive.
45 changes: 45 additions & 0 deletions axi_config_objs.svh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import uvm_pkg::*;

/* Configuration object to configure the environment of Test Bench.
Configurable fields:
1. intf: Virtual Interface for the agents
2. active: To set the agent as active or passive */
class env_config extends uvm_object;
`uvm_object_utils(env_config)

// variables
virtual axi_intf#(.D_WIDTH(D_WIDTH), .A_WIDTH(A_WIDTH)) intf;

// Master and Slave are active or passive
uvm_active_passive_enum active = UVM_ACTIVE;

function new(string name = "env_config");
super.new(name);
endfunction //new()
endclass //env_config extends uvm_object

// Configuration object which configures the sequence item generation
class test_config extends uvm_object;
`uvm_object_utils(test_config)

// Vartiables
int no_write_cases = 20;
int no_read_cases = 20;

// Set whether to produce aligned address or unalinged address
// -1: produce both aligned and unaligned randomly
// 0: produce unaligned adresses for all bursts
// 1: produce alligned adress for all bursts
byte isAligned = -1;

// Set the specific burst type for a test
// -1: produce all the burst type randomly
// 0: produce fixed bursts
// 1: produce incr bursts
// 2: produce wrap bursts
byte burst_type = -1;

function new(string name = "test_config");
super.new(name);
endfunction //new()
endclass //test_config extends uvm_object
40 changes: 40 additions & 0 deletions axi_env.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
class axi_env extends uvm_env;
`uvm_component_utils(axi_env)

// Components
axi_master master;
axi_slave slave;
axi_scoreboard scb;

env_config env_cfg;

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

// Function: build_phase
extern function void build_phase(uvm_phase phase);

// Function: connect_phase
extern function void connect_phase(uvm_phase phase);

endclass //axi_env extends uvm_env

function void axi_env::build_phase(uvm_phase phase);
/* note: Do not call super.build_phase() from any class that is extended from an UVM base class! */
/* For more information see UVM Cookbook v1800.2 p.503 */
//super.build_phase(phase);

master = axi_master::type_id::create("master", this);
slave = axi_slave::type_id::create("slave", this);
scb = axi_scoreboard::type_id::create("scb", this);
endfunction: build_phase

function void axi_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);

master.ap.connect(scb.m_ap_imp);
slave.ap.connect(scb.s_ap_imp);
endfunction: connect_phase

110 changes: 110 additions & 0 deletions axi_interface.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
interface axi_intf #(parameter A_WIDTH = 16, D_WIDTH = 16)(input bit clk, bit rstn);
// Write Address
logic [8:0] AWID;
logic [A_WIDTH-1:0] AWADDR;
logic [3:0] AWLEN;
logic [2:0] AWSIZE;
logic [1:0] AWBURST;
logic AWVALID, AWREADY;

// Write Data
logic [8:0] WID;
logic [D_WIDTH-1:0] WDATA;
logic [(D_WIDTH/8)-1:0] WSTRB;
logic WLAST, WVALID, WREADY;

// Write Response
logic [8:0] BID;
logic [1:0] BRESP;
logic BVALID, BREADY;

// Read Address
logic [8:0] ARID;
logic [A_WIDTH-1:0] ARADDR;
logic [3:0] ARLEN;
logic [2:0] ARSIZE;
logic [1:0] ARBURST;
logic ARVALID, ARREADY;

// Read Data
logic [8:0] RID;
logic [D_WIDTH-1:0] RDATA;
logic [1:0] RRESP;
logic RLAST, RVALID, RREADY;

/* Clocking Blocks: 3 CBs are defined as follows
1. m_drv_cb - Clocking block for master driver
2. s_drv_cb - Clocking block for slave driver
3. mon_cb - Clocking block for monitors of both master and slave */
clocking m_drv_cb @(posedge clk);
output AWID, AWADDR, AWLEN, AWSIZE, AWBURST,AWVALID, WID, WDATA, WSTRB, WLAST, WVALID,
BREADY, ARID, ARADDR, ARLEN, ARSIZE, ARBURST, ARVALID, RREADY;
input AWREADY, WREADY, BID, BRESP, BVALID, ARREADY, RID, RDATA, RRESP, RLAST, RVALID;
endclocking

clocking mon_cb @(posedge clk);
input AWID, AWADDR, AWLEN, AWSIZE, AWBURST,AWVALID, WID, WDATA, WSTRB, WLAST, WVALID,
BREADY, ARID, ARADDR, ARLEN, ARSIZE, ARBURST, ARVALID, RREADY;
input AWREADY, WREADY, BID, BRESP, BVALID, ARREADY, RID, RDATA, RRESP, RLAST, RVALID;
endclocking

clocking s_drv_cb @(posedge clk);
input AWID, AWADDR, AWLEN, AWSIZE, AWBURST,AWVALID, WID, WDATA, WSTRB, WLAST, WVALID,
BREADY, ARID, ARADDR, ARLEN, ARSIZE, ARBURST, ARVALID, RREADY;
output AWREADY, WREADY, BID, BRESP, BVALID, ARREADY, RID, RDATA, RRESP, RLAST, RVALID;
endclocking

modport MDRV(clocking m_drv_cb, input rstn);
modport MMON(clocking mon_cb, input rstn);
modport SDRV(clocking s_drv_cb, input rstn);
modport SMON(clocking mon_cb, input rstn);

// *************************************************************************************************
// Assertions
// *************************************************************************************************
// Property to check whether all write address channel remains stable after AWVALID is asserted
property aw_valid;
@(posedge clk) $rose(AWVALID) |-> ( $stable(AWID)
&&$stable(AWADDR)
&&$stable(AWLEN)
&&$stable(AWSIZE)
&&$stable(AWBURST)) throughout AWREADY[->1];
endproperty

// Property to check whether all write address channel remains stable after AWVALID is asserted
property w_valid;
@(posedge clk) $rose(WVALID) |-> ( $stable(WID)
&& $stable(WDATA)
&& $stable(WSTRB)
&& $stable(WLAST)) throughout WREADY[->1];
endproperty

// Property to check whether all write address channel remains stable after AWVALID is asserted
property b_valid;
@(posedge clk) $rose(BVALID) |-> ( $stable(BID)
&& $stable(BRESP)) throughout BREADY[->1];
endproperty

// Property to check whether all write address channel remains stable after AWVALID is asserted
property ar_valid;
@(posedge clk) $rose(ARVALID) |-> ( $stable(ARID)
&&$stable(ARADDR)
&&$stable(ARLEN)
&&$stable(ARSIZE)
&&$stable(ARBURST)) throughout ARREADY[->1];
endproperty

// Property to check whether all write address channel remains stable after AWVALID is asserted
property r_valid;
@(posedge clk) $rose(RVALID) |-> ( $stable(RID)
&& $stable(RDATA)
&& $stable(RRESP)
&& $stable(RLAST)) throughout RREADY[->1];
endproperty

assert property (aw_valid);
assert property (w_valid);
assert property (b_valid);
assert property (ar_valid);
assert property (r_valid);
endinterface //axi_intf
164 changes: 164 additions & 0 deletions axi_m_driver.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
class axi_m_driver extends uvm_driver#(axi_transaction#(D_WIDTH, A_WIDTH));
`uvm_component_utils(axi_m_driver)

// Components
virtual axi_intf#(.D_WIDTH(D_WIDTH), .A_WIDTH(A_WIDTH)).MDRV vif;
uvm_seq_item_pull_port#(REQ, RSP) seq_item_port2;

// Variables
REQ w_trans, r_trans;
bit w_done, r_done;
bit [D_WIDTH-1:0] temp [];
logic AWVALID;

// Methods
extern task drive();
extern task send_write_address();
extern task send_read_address();
extern task send_write_data();
// extern task send_read_data();

function new(string name, uvm_component parent);
super.new(name, parent);
w_done = 1;
r_done = 1;
seq_item_port2 = new("seq_item_port2", this);
endfunction //new()

// Function: build_phase
// extern function void build_phase(uvm_phase phase);

// Function: run_phase
extern task run_phase(uvm_phase phase);

endclass //m_driver extends uvn_driver#(axu)

task axi_m_driver::run_phase(uvm_phase phase);
`uvm_info("DEBUG", "started master driver", UVM_HIGH)
// temp
vif.m_drv_cb.BREADY <= 1;
vif.m_drv_cb.RREADY <= 1;
forever begin
drive();
#1;
end
endtask: run_phase

task axi_m_driver::drive();
if(!vif.rstn) begin
vif.m_drv_cb.AWVALID <= 0;
vif.m_drv_cb.WVALID <= 0;
vif.m_drv_cb.ARVALID <= 0;
return;
end
fork
begin
`uvm_info("DEBUG", $sformatf("w_addr(), w_done = %0d", w_done), UVM_DEBUG)
if(w_done) begin
w_done = 0;
seq_item_port.get_next_item(w_trans);
`uvm_info(get_name(), "Write Packet received in master driver", UVM_LOW)
w_trans.print();
fork
send_write_address();
send_write_data();
join
seq_item_port.item_done();
w_done = 1;
end
end
begin
`uvm_info("DEBUG", $sformatf("r_addr(), r_done = %0d", r_done), UVM_DEBUG)
if(r_done) begin
r_done = 0;
seq_item_port2.get_next_item(r_trans);
`uvm_info(get_name(), "Read Packet received in master driver", UVM_LOW)
r_trans.print();
send_read_address();
seq_item_port2.item_done();
r_done = 1;
end
end
join_none
endtask: drive

task axi_m_driver::send_write_address();
`uvm_info("DEBUG", "Inside send_write_address()", UVM_HIGH)

// Drive all the data
@(vif.m_drv_cb);
vif.m_drv_cb.AWID <= w_trans.id;
vif.m_drv_cb.AWADDR <= w_trans.addr;
vif.m_drv_cb.AWLEN <= w_trans.b_len;
vif.m_drv_cb.AWSIZE <= w_trans.b_size;
vif.m_drv_cb.AWBURST<= w_trans.b_type;
`uvm_info("DEBUG", "Data Driven", UVM_HIGH)

// Wait 1 cycle and drive AWVALID
@(vif.m_drv_cb);
AWVALID = 1;
vif.m_drv_cb.AWVALID<= AWVALID;
`uvm_info("DEBUG", "Asserted AWVALID", UVM_HIGH)

// Wait for AWREADY and deassert AWVALID
@(vif.m_drv_cb);
wait(vif.m_drv_cb.AWREADY);
AWVALID = 0;
vif.m_drv_cb.AWVALID<= AWVALID;
`uvm_info("DEBUG", "Deasserted AWVALID", UVM_HIGH)

// Wait for write data channel to complete transaction
wait(vif.m_drv_cb.BVALID);
endtask: send_write_address

task axi_m_driver::send_write_data();
int len = w_trans.b_len + 1;
temp = new[len];
`uvm_info("DEBUG", "Inside send_write_data()", UVM_HIGH)
foreach ( w_trans.data[i,j] ) begin
temp[i][8*j+:8] = w_trans.data[i][j];
end
wait(AWVALID && vif.m_drv_cb.AWREADY);
`uvm_info("DEBUG", "packed data", UVM_HIGH)
for (int i=0; i<len; i++) begin
`uvm_info("DEBUG", $sformatf("Inside loop: iter %0d", i), UVM_HIGH)
@(vif.m_drv_cb);
vif.m_drv_cb.WID <= w_trans.id;
vif.m_drv_cb.WDATA <= temp[i];
vif.m_drv_cb.WLAST <= (i == len-1) ? 1:0;

// Assert WVALID
@(vif.m_drv_cb);
vif.m_drv_cb.WVALID <= 1;

// Wait for WREADY and deassert WVALID
#1;
wait(vif.m_drv_cb.WREADY);
vif.m_drv_cb.WVALID <= 0;
vif.m_drv_cb.WLAST <= 0;
end
wait(vif.m_drv_cb.BVALID);
endtask: send_write_data


task axi_m_driver::send_read_address();
// Send the read address and control signals
@(vif.m_drv_cb);
vif.m_drv_cb.ARID <= r_trans.id;
vif.m_drv_cb.ARADDR <= r_trans.addr;
vif.m_drv_cb.ARLEN <= r_trans.b_len;
vif.m_drv_cb.ARSIZE <= r_trans.b_size;
vif.m_drv_cb.ARBURST<= r_trans.b_type;

// Assert ARVALID after one clock cycle
@(vif.m_drv_cb);
vif.m_drv_cb.ARVALID<= 1;

// Wait for AWREADY and deassert AWVALID
@(vif.m_drv_cb);
wait(vif.m_drv_cb.ARREADY);
vif.m_drv_cb.ARVALID<= 0;

// Wait for RLAST signal before sending next address
wait(vif.m_drv_cb.RLAST && vif.m_drv_cb.RVALID);
endtask: send_read_address
Loading

0 comments on commit d950b4f

Please sign in to comment.