Comparar commits

...

Nenhum commit em comum. 'master' e 'main' tem histórias completamente diferentes.
master ... main

10 arquivos alterados com 341 adições e 2 exclusões
Visão dividida
  1. BIN
      AXI_wave.png
  2. +0
    -2
      README.md
  3. +22
    -0
      axi_agent.sv
  4. +46
    -0
      axi_cov.sv
  5. +126
    -0
      axi_drv.sv
  6. +12
    -0
      axi_env.sv
  7. +43
    -0
      axi_seq_lib.sv
  8. +8
    -0
      axi_sqr.sv
  9. +43
    -0
      axi_tx.sv
  10. +41
    -0
      top.sv

BIN
AXI_wave.png Ver arquivo

Antes Depois
Largura: 1920  |  Altura: 1080  |  Tamanho: 491 KiB

+ 0
- 2
README.md Ver arquivo

@@ -1,2 +0,0 @@
# AXI3


+ 22
- 0
axi_agent.sv Ver arquivo

@@ -0,0 +1,22 @@
class axi_agent extends uvm_agent;
axi_drv drv;
axi_sqr sqr;
axi_mon mon;
axi_cov cov;
`uvm_component_utils_begin(axi_agent)// factory registration
`NEW_COMP
function void build_phase(uvm_phase phase);
super.build_phase(phase);
mon = axi_mon::type_id::create("mon", this);
drv =axi_drv::type_id::create("drv", this);// creating from factory
sqr = axi_sqr::type_id::create("sqr", this);
cov = axi_cov::type_id::create("cov", this);
end
endfunction
function void connect_phase(uvm_phase phase);
drv.seq_item_port.connect(sqr.seq_item_export);
mon.ap_port.connect(cov.analysis_export);
end
endfunction
endclass

+ 46
- 0
axi_cov.sv Ver arquivo

@@ -0,0 +1,46 @@
class axi_cov extends uvm_subscriber#(axi_tx);
axi_tx tx;
`uvm_component_utils(axi_cov)

covergroup axi_cg;
ADDR_CP : coverpoint tx.addr {
option.auto_bin_max = 8;
}
WR_RD_CP : coverpoint tx.wr_rd{
bins WR = {1'b1};
bins RD = {1'b0};
}
BURST_TYPE_CP : coverpoint tx.burst_type {
bins FIXED = {FIXED};
bins WRAP = {WRAP};
bins INCR = {INCR};
}
RESP_CP : coverpoint tx.resp {
bins OKAY = {OKAY};
bins EXOKAY = {EXOKAY};
bins SLVERR = {SLVERR};
bins DECERR = {DECERR};
}
ADDR_CP_X_WR_RD_CP : cross ADDR_CP, WR_RD_CP;
ADDR_CP_X_BURST_TYPE_CP : cross ADDR_CP, BURST_TYPE_CP;
ADDR_CP_X_RESP_CP : cross ADDR_CP, RESP_CP;
WR_RD_CP_X_BURST_TYPE_CP : cross WR_RD_CP, BURST_TYPE_CP;
WR_RD_CP_X_RESP_CP : cross WR_RD_CP, RESP_CP;
BURST_TYPE_CP_X_RESP_CP : cross BURST_TYPE_CP, RESP_CP;
endgroup

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

function void write(T t);
$cast(tx, t);
$display("time : %0t", $time);
tx.print();
axi_cg.sample();
endfunction

endclass



+ 126
- 0
axi_drv.sv Ver arquivo

@@ -0,0 +1,126 @@
class axi_drv extends uvm_driver#(axi_tx);
virtual axi_intf vif;
`uvm_component_utils(axi_drv)
`NEW_COMP

function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual axi_intf)::get(this, "", "vif", vif)) begin
`uvm_error("CONFG_DB", "Not able to get axi intf handle")
end
endfunction

task run_phase(uvm_phase phase);
@(negedge vif.arst);//waiting for release the reset
forever begin
seq_item_port.get_next_item(req);
req.print();
drive_tx(req);
seq_item_port.item_done();
end
endtask

task drive_tx(axi_tx tx);
if (tx.wr_rd == 1) begin
write_addr(tx);
write_data(tx);
write_resp(tx);
end
if (tx.wr_rd == 0) begin
read_addr(tx);
read_data(tx);
end
endtask

task write_addr(axi_tx tx);
`uvm_info("AXI_TX", "write_addr", UVM_MEDIUM);
//Master drives all write address channel signals (aw), it will drive at the posedge of clock
@(vif.mst_cb);
vif.mst_cb.awaddr <= tx.addr;
vif.mst_cb.awlen <= tx.burst_len;
vif.mst_cb.awsize <= tx.burst_size;
vif.mst_cb.awburst <= tx.burst_type;
vif.mst_cb.awid <= tx.txid;
vif.mst_cb.awvalid <= 1'b1;
wait (vif.mst_cb.awready == 1'b1);
@(vif.mst_cb);
vif.mst_cb.awaddr <= 0;
vif.mst_cb.awlen <= 0;
vif.mst_cb.awsize <= 0;
vif.mst_cb.awburst <= 0;
vif.mst_cb.awid <= 0;
vif.mst_cb.awvalid <= 0;
endtask

task write_data(axi_tx tx);
`uvm_info("AXI_TX", "write_data", UVM_MEDIUM);
for (int i = 0; i <= tx.burst_len; i++) begin
@(vif.mst_cb)
vif.mst_cb.wdata <= tx.dataQ.pop_front();
vif.mst_cb.wstrb <= 4'b1111; //need to be updated as per the burst size
vif.mst_cb.wvalid <= 1'b1;
vif.mst_cb.wid <= tx.txid;
//wlast=1 will be in last beat
if(i == tx.burst_len) vif.mst_cb.wlast <= 1'b1;
else vif.mst_cb.wlast <= 0;
wait(vif.mst_cb.wready == 1'b1);
end
//once data beats are done, then reset all signals to 0
@(vif.mst_cb);
vif.mst_cb.wvalid <= 0;
vif.mst_cb.wlast <= 0;
vif.mst_cb.wdata <= 0;
vif.mst_cb.wstrb <= 0;
vif.mst_cb.wid <= 0;
endtask

task write_resp(axi_tx tx);
bit bvalid_f = 0;
//`uvm_info("AXI_TX", "write_resp", UVM_MEDIUM);
//write response is initiated by slave
while (bvalid_f == 0) begin
@(vif.mst_cb);
bvalid_f = vif.mst_cb.bvalid;
end
vif.mst_cb.bready <= 1'b1;
@(vif.mst_cb);
vif.mst_cb.bready <= 1'b0;
endtask

task read_addr(axi_tx tx);
`uvm_info("AXI_TX", "read_addr", UVM_MEDIUM);
@(vif.mst_cb);
vif.mst_cb.araddr <= tx.addr;
vif.mst_cb.arlen <= tx.burst_len;
vif.mst_cb.arsize <= tx.burst_size;
vif.mst_cb.arburst <= tx.burst_type;
vif.mst_cb.arid <= tx.txid;
vif.mst_cb.arvalid <= 1'b1;
wait (vif.mst_cb.arready == 1'b1);
@(vif.mst_cb);
vif.mst_cb.araddr <= 0;
vif.mst_cb.arlen <= 0;
vif.mst_cb.arsize <= 0;
vif.mst_cb.arburst <= 0;
vif.mst_cb.arid <= 0;
vif.mst_cb.arvalid <= 0;
endtask

task read_data(axi_tx tx);
bit rvalid_f = 0;
`uvm_info("AXI_TX", "read_data", UVM_MEDIUM);
//since read data is happening multiple times, then handshaking should do multiple times
for (int i = 0; i <= tx.burst_len; i++) begin
rvalid_f = 0;
while (rvalid_f == 0) begin
@(vif.mst_cb);
rvalid_f = vif.mst_cb.rvalid;
vif.mst_cb.rready <= 1'b1;
end
end
@(vif.mst_cb);
vif.mst_cb.rready <= 1'b0;
endtask
endclass


+ 12
- 0
axi_env.sv Ver arquivo

@@ -0,0 +1,12 @@
class axi_env extends uvm_env;
axi_agent magent;
`uvm_component_utils(axi_env);// factory registration
`NEW_COMP
function void build_phase(uvm_phase phase);
super.build_phase(phase);
magent = axi_agent::type_id::create("magent", this);
uvm_config_db#(int)::set(this, "magent", "mst_slv_f", `MSTR);
endfunction
endclass

+ 43
- 0
axi_seq_lib.sv Ver arquivo

@@ -0,0 +1,43 @@
//base sequence : things common to all sequence
class axi_base_seq extends uvm_sequence #(axi_tx);
uvm_phase phase;
`uvm_object_utils(axi_base_seq)
`NEW_OBJ
task pre_body();
//raise objection
phase = get_starting_phase();
if (phase !=null) begin
phase.raise_objection(this);
phase.phase_done.set_drain_time(this,100);
end
endtask
task post_body();
//drop objection
if (phase !=null) begin
phase.drop_objection(this);
end
endtask
endclass

//functional sequence: things specific to current sequence
class axi_wr_rd_seq extends axi_base_seq;
axi_tx tx;
axi_tx txQ[$];
`uvm_object_utils(axi_wr_rd_seq)
`NEW_OBJ
task body();
//write/read to same loc
repeat(1) begin
`uvm_do_with (req, {req.wr_rd==1;});
tx = new req; //shallow copy
txQ.push_back(tx);
end
//read_tx
repeat(1) begin
tx = txQ.pop_front();
`uvm_do_with (req, {req.wr_rd==0; req.burst_len ==tx.burst_len; req.addr == tx.addr;});
end
endtask
endclass



+ 8
- 0
axi_sqr.sv Ver arquivo

@@ -0,0 +1,8 @@
class axi_sqr extends uvm_sequencer #(axi_tx);
`uvm_component_utils(axi_sqr)
`NEW_COMP
function void build_phase(uvm_phase phase);
super.build_phase (phase);
endfunction

endclass

+ 43
- 0
axi_tx.sv Ver arquivo

@@ -0,0 +1,43 @@
class axi_tx extends uvm_sequence_item;
rand bit wr_rd;
rand bit [`ADDR_WIDTH-1:0] addr;
rand bit [`WIDTH-1:0] dataQ[$]; //to support burst of data
rand bit [3:0] burst_len;
rand bit [2:0] burst_size;
rand burst_type_t burst_type;
rand bit [3:0] txid;
bit [1:0] resp;
bit [31:0] wrap_lower, wrap_upper;
int tx_size;
`uvm_object_utils_begin(axi_tx)
`uvm_field_int(addr, UVM_ALL_ON|UVM_NOPACK);
`uvm_field_queue_int(dataQ, UVM_ALL_ON|UVM_NOPACK);
`uvm_field_int(wr_rd, UVM_ALL_ON|UVM_NOPACK);
`uvm_field_int(burst_len, UVM_ALL_ON|UVM_NOPACK);
`uvm_field_int(burst_size, UVM_ALL_ON|UVM_NOPACK);
`uvm_field_enum(burst_type_t, burst_type, UVM_ALL_ON|UVM_NOPACK);
`uvm_field_int(txid, UVM_ALL_ON|UVM_NOPACK);
`uvm_field_int(wrap_lower, UVM_ALL_ON|UVM_NOPACK);
`uvm_field_int(wrap_upper, UVM_ALL_ON|UVM_NOPACK);
`uvm_object_utils_end
`NEW_OBJ
function void post_randomize();
if (burst_type == WRAP) begin
tx_size = (burst_len+1) * (2**burst_size);
wrap_lower = addr - (addr%tx_size);
wrap_upper = wrap_lower + tx_size - 1;
end
endfunction
//constraint
constraint dataQ_c{
dataQ.size() == burst_len+1;
}
constraint burst_type_c{
burst_type != RSVD_BT;
}
constraint wrap_aligned_c{
(burst_type) == WRAP -> (addr%(2**burst_size)==0);
}
endclass


+ 41
- 0
top.sv Ver arquivo

@@ -0,0 +1,41 @@
`include "uvm_pkg.sv"
import uvm_pkg ::*;
`include "uvm_macros.svh"
`define WIDTH 32
`define DEPTH 64
`define ADDR_WIDTH $clog2(`DEPTH)
`include "axi_tx.sv"
`include "axi_seq_lib.sv"
`include "axi_sqr.sv"
`include "axi_drv.sv"
`include "axi_mon.sv"
`include "axi_cov.sv"
`include "axi_agent.sv"
`include "axi_env.sv"
module top;
reg clk, rst;
axi_intf pif(clk,rst);
axi_env env = new();
initial begin
clk = 0;
forever #5 clk = ~clk;
end
initial begin
rst = 1;
repeat(2) @(posedge clk);
rst = 0;
// #1000;
// $finish;
end
initial begin
run_test("axi_wr_rd_test");
end
//initial begin
// $dumpvars();
// $dumpfile("1.vcd");
//end
endmodule

Carregando…
Cancelar
Salvar