-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from kumarrishav14/release-1.0
Release 1.0
- Loading branch information
Showing
18 changed files
with
1,627 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.