Skip to content

Commit 78b7a22

Browse files
[top,dv] Integrated AXI4 passive VIP and added AXI scoreboard to the top UVM environment
Signed-off-by: Csaba Kiss <csaba.kiss@semify-eda.com>
1 parent 317515e commit 78b7a22

10 files changed

Lines changed: 682 additions & 1 deletion
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
// Copyright lowRISC contributors (COSMIC project).
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
class top_chip_dv_axi_scoreboard extends uvm_scoreboard;
6+
`uvm_component_utils(top_chip_dv_axi_scoreboard)
7+
8+
axi_addr_range_t mem_map[$];
9+
string default_subordinate_id = "INTERNAL_XBAR_DEFAULT";
10+
11+
// Analysis Implementation Ports
12+
`uvm_analysis_imp_decl(_mgr0_cva6)
13+
`uvm_analysis_imp_decl(_sub0_sram)
14+
`uvm_analysis_imp_decl(_sub1_mailbox)
15+
`uvm_analysis_imp_decl(_sub2_tlcrossbar)
16+
`uvm_analysis_imp_decl(_sub3_dram)
17+
18+
uvm_analysis_imp_mgr0_cva6 #(uvm_sequence_item, top_chip_dv_axi_scoreboard) mgr0_cva6_imp;
19+
uvm_analysis_imp_sub0_sram #(uvm_sequence_item, top_chip_dv_axi_scoreboard) sub0_sram_imp;
20+
uvm_analysis_imp_sub1_mailbox #(uvm_sequence_item, top_chip_dv_axi_scoreboard) sub1_mailbox_imp;
21+
uvm_analysis_imp_sub2_tlcrossbar #(uvm_sequence_item, top_chip_dv_axi_scoreboard) sub2_tlcrossbar_imp;
22+
uvm_analysis_imp_sub3_dram #(uvm_sequence_item, top_chip_dv_axi_scoreboard) sub3_dram_imp;
23+
24+
// Queues to handle out-of-order monitor arrivals
25+
// [SubordinateName][MaskedID]
26+
axi4_vip_item expect_q[string][bit[top_pkg::AxiIdWidth-1:0]][$]; // Manager arrived first
27+
axi4_vip_item actual_q[string][bit[top_pkg::AxiIdWidth-1:0]][$]; // Subordinate arrived first
28+
29+
// External Method Declarations
30+
extern function new(string name, uvm_component parent);
31+
extern virtual function void build_phase(uvm_phase phase);
32+
extern function bit [63:0] get_orig_id(bit [top_pkg::AxiIdWidth-1:0] full_id);
33+
extern function string decode_addr(bit [63:0] addr);
34+
extern virtual function void perform_comparison(axi4_vip_item exp, axi4_vip_item act, string slv);
35+
extern virtual function void write_mgr0_cva6(uvm_sequence_item item);
36+
extern virtual function void check_subordinate_arrival(uvm_sequence_item item, string slv_id);
37+
extern virtual function void write_sub0_sram(uvm_sequence_item tr);
38+
extern virtual function void write_sub1_mailbox(uvm_sequence_item tr);
39+
extern virtual function void write_sub2_tlcrossbar(uvm_sequence_item tr);
40+
extern virtual function void write_sub3_dram(uvm_sequence_item tr);
41+
extern virtual function void check_phase(uvm_phase phase);
42+
43+
endclass : top_chip_dv_axi_scoreboard
44+
45+
//------------------------------------------------------------------------------
46+
// External Method Implementations
47+
//------------------------------------------------------------------------------
48+
49+
function top_chip_dv_axi_scoreboard::new(string name, uvm_component parent);
50+
super.new(name, parent);
51+
mgr0_cva6_imp = new("mgr0_cva6_imp", this);
52+
sub0_sram_imp = new("sub0_sram_imp", this);
53+
sub1_mailbox_imp = new("sub1_mailbox_imp", this);
54+
sub2_tlcrossbar_imp = new("sub2_tlcrossbar_imp", this);
55+
sub3_dram_imp = new("sub3_dram_imp", this);
56+
endfunction : new
57+
58+
function void top_chip_dv_axi_scoreboard::build_phase(uvm_phase phase);
59+
super.build_phase(phase);
60+
61+
// Specific Address Mapping
62+
mem_map.push_back('{"sub0_sram", (top_pkg::SRAMBase), (top_pkg::SRAMBase + top_pkg::SRAMLength - 1)});
63+
mem_map.push_back('{"sub1_mailbox", (top_pkg::MailboxBase), (top_pkg::MailboxBase + top_pkg::MailboxLength - 1)});
64+
mem_map.push_back('{"sub2_tlcrossbar", (top_pkg::TlCrossbarBase), (top_pkg::TlCrossbarBase + top_pkg::TlCrossbarBase - 1)});
65+
mem_map.push_back('{"sub3_dram", (top_pkg::DRAMBase), (top_pkg::DRAMBase + top_pkg::DRAMBase - 1)});
66+
endfunction : build_phase
67+
68+
function bit [top_pkg::AxiIdWidth-1:0] top_chip_dv_axi_scoreboard::get_orig_id(bit [63:0] full_id);
69+
return full_id & ((1 << top_pkg::AxiIdWidth) - 1);
70+
endfunction : get_orig_id
71+
72+
function string top_chip_dv_axi_scoreboard::decode_addr(bit [63:0] addr);
73+
foreach (mem_map[i]) begin
74+
if (addr >= mem_map[i].start_addr && addr <= mem_map[i].end_addr)
75+
return mem_map[i].subordinate_name;
76+
end
77+
return default_subordinate_id;
78+
endfunction : decode_addr
79+
80+
function void top_chip_dv_axi_scoreboard::perform_comparison(axi4_vip_item exp, axi4_vip_item act, string slv);
81+
bit [top_pkg::AxiIdWidth-1:0] mid = get_orig_id((act.dir == AXI_WRITE) ? act.bid : act.rid);
82+
83+
if (act.dir == AXI_WRITE) begin
84+
if (act.awaddr !== exp.awaddr || act.awlen !== exp.awlen ||
85+
act.awsize !== exp.awsize || act.awburst !== exp.awburst) begin
86+
`uvm_error("SCB_ATTR_WR", $sformatf("Write Attribute mismatch on %s ID:%h", slv, mid))
87+
end
88+
89+
if (act.wdata != exp.wdata) begin
90+
`uvm_error("SCB_WDATA", $sformatf("Write Data mismatch on %s ID:%h", slv, mid))
91+
end
92+
93+
if (act.wstrb != exp.wstrb) begin
94+
`uvm_error("SCB_WSTRB", $sformatf("Write Strobe mismatch on %s ID:%h", slv, mid))
95+
end
96+
end else begin
97+
if (act.araddr !== exp.araddr || act.arlen !== exp.arlen ||
98+
act.arsize !== exp.arsize || act.arburst !== exp.arburst) begin
99+
`uvm_error("SCB_ATTR_RD", $sformatf("Read Attribute mismatch on %s ID:%h", slv, mid))
100+
end
101+
102+
if (act.rdata != exp.rdata) begin
103+
`uvm_error("SCB_RDATA", $sformatf("Read Data mismatch on %s ID:%h", slv, mid))
104+
end
105+
106+
if (act.rresp != exp.rresp) begin
107+
`uvm_error("SCB_RRESP", $sformatf("Read Response mismatch on %s ID:%h", slv, mid))
108+
end
109+
end
110+
endfunction : perform_comparison
111+
112+
function void top_chip_dv_axi_scoreboard::write_mgr0_cva6(uvm_sequence_item item);
113+
axi4_vip_item tr;
114+
if (!$cast(tr, item)) begin
115+
`uvm_fatal("TYPE", "Cast failed")
116+
end
117+
118+
begin
119+
bit [63:0] addr = (tr.dir == AXI_WRITE) ? tr.awaddr : tr.araddr;
120+
bit [63:0] id = (tr.dir == AXI_WRITE) ? tr.awid : tr.arid;
121+
string target_slv = decode_addr(addr);
122+
bit [63:0] mid = get_orig_id(id);
123+
124+
if (target_slv == default_subordinate_id) begin
125+
// Decoder error check would go here
126+
end else begin
127+
if (actual_q[target_slv].exists(mid) && actual_q[target_slv][mid].size() > 0) begin
128+
axi4_vip_item act_tr = actual_q[target_slv][mid].pop_front();
129+
perform_comparison(tr, act_tr, target_slv);
130+
if (actual_q[target_slv][mid].size() == 0) actual_q[target_slv].delete(mid);
131+
end else begin
132+
axi4_vip_item exp_tr;
133+
$cast(exp_tr, tr.clone());
134+
expect_q[target_slv][mid].push_back(exp_tr);
135+
end
136+
end
137+
end
138+
endfunction : write_mgr0
139+
140+
function void top_chip_dv_axi_scoreboard::check_subordinate_arrival(uvm_sequence_item item, string slv_id);
141+
axi4_vip_item act;
142+
if (!$cast(act, item)) `uvm_fatal("TYPE", "Cast failed")
143+
144+
begin
145+
bit [63:0] mid = get_orig_id((act.dir == AXI_WRITE) ? act.bid : act.rid);
146+
147+
if (expect_q[slv_id].exists(mid) && expect_q[slv_id][mid].size() > 0) begin
148+
axi4_vip_item exp_tr = expect_q[slv_id][mid].pop_front();
149+
perform_comparison(exp_tr, act, slv_id);
150+
if (expect_q[slv_id][mid].size() == 0) expect_q[slv_id].delete(mid);
151+
end else begin
152+
axi4_vip_item act_tr;
153+
$cast(act_tr, act.clone());
154+
actual_q[slv_id][mid].push_back(act_tr);
155+
end
156+
end
157+
endfunction : check_subordinate_arrival
158+
159+
function void top_chip_dv_axi_scoreboard::write_sub0_sram(uvm_sequence_item tr);
160+
check_subordinate_arrival(tr, "sub0_sram");
161+
endfunction : write_sub0
162+
163+
function void top_chip_dv_axi_scoreboard::write_sub1_mailbox(uvm_sequence_item tr);
164+
check_subordinate_arrival(tr, "sub1_mailbox");
165+
endfunction : write_sub1
166+
167+
function void top_chip_dv_axi_scoreboard::write_sub2_tlcrossbar(uvm_sequence_item tr);
168+
check_subordinate_arrival(tr, "sub2_tlcrossbar");
169+
endfunction : write_sub2
170+
171+
function void top_chip_dv_axi_scoreboard::write_sub3_dram(uvm_sequence_item tr);
172+
check_subordinate_arrival(tr, "sub3_dram");
173+
endfunction : write_sub3
174+
175+
function void top_chip_dv_axi_scoreboard::check_phase(uvm_phase phase);
176+
super.check_phase(phase);
177+
178+
// Check for requests that entered the fabric but never exited
179+
foreach (expect_q[s, i]) begin
180+
if (expect_q[s][i].size() > 0) begin
181+
`uvm_error("SCB_DRAIN_DROP", $sformatf("DROPPED: Master req for %s (ID %h) lost in fabric", s, i))
182+
end
183+
end
184+
185+
// Check for responses that exited the fabric but weren't requested/seen by Master
186+
foreach (actual_q[s, i]) begin
187+
if (actual_q[s][i].size() > 0) begin
188+
`uvm_error("SCB_DRAIN_GHOST", $sformatf("GHOST: Slave %s (ID %h) responded but Master missed it", s, i))
189+
end
190+
end
191+
endfunction : check_phase

hw/top_chip/dv/env/top_chip_dv_env.core

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ filesets:
1111
- lowrisc:dv:dv_utils
1212
- lowrisc:dv:mem_bkdr_util
1313
- lowrisc:dv:uart_agent
14+
- lowrisc:dv:axi4_vip:0.1
1415
- lowrisc:dv:common_ifs
1516
files:
1617
- top_chip_dv_env_pkg.sv
1718
- mem_clear_util.sv: {is_include_file: true}
1819
- top_chip_dv_env_cfg.sv: {is_include_file: true}
1920
- top_chip_dv_env_cov.sv: {is_include_file: true}
21+
- top_chip_dv_axi_scoreboard.sv: {is_include_file: true}
2022
- top_chip_dv_env.sv: {is_include_file: true}
2123
- top_chip_dv_virtual_sequencer.sv: {is_include_file: true}
2224
- seq_lib/top_chip_dv_vseq_list.sv: {is_include_file: true}

hw/top_chip/dv/env/top_chip_dv_env.sv

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ class top_chip_dv_env extends uvm_env;
1212
mem_bkdr_util mem_bkdr_util_h[chip_mem_e];
1313

1414
// Agents
15-
uart_agent m_uart_agent;
15+
uart_agent m_uart_agent;
16+
axi4_vip_env m_mgr_axi[];
17+
axi4_vip_env m_sub_axi[];
18+
19+
top_chip_dv_axi_scoreboard m_axi_scb;
1620

1721
// Standard SV/UVM methods
1822
extern function new(string name="", uvm_component parent=null);
@@ -29,6 +33,9 @@ function top_chip_dv_env::new(string name="", uvm_component parent=null);
2933
endfunction : new
3034

3135
function void top_chip_dv_env::build_phase(uvm_phase phase);
36+
top_pkg::axi_hosts_t axi_mgr_name;
37+
top_pkg::axi_devices_t axi_sub_name;
38+
3239
super.build_phase(phase);
3340

3441
foreach (CHIP_MEM_LIST[i]) begin
@@ -70,6 +77,20 @@ function void top_chip_dv_env::build_phase(uvm_phase phase);
7077
m_uart_agent = uart_agent::type_id::create("m_uart_agent", this);
7178
uvm_config_db#(uart_agent_cfg)::set(this, "m_uart_agent*", "cfg", cfg.m_uart_agent_cfg);
7279

80+
m_mgr_axi = new[NUM_OF_MGR_AXI_IFS];
81+
foreach (m_mgr_axi[i]) begin
82+
axi_mgr_name = top_pkg::axi_hosts_t'(i);
83+
m_mgr_axi[i] = axi4_vip_env::type_id::create(.name($sformatf("m_mgr_axi_%s", axi_mgr_name.name())), .parent(this));
84+
end
85+
86+
m_sub_axi = new[NUM_OF_SUB_AXI_IFS];
87+
foreach (m_sub_axi[i]) begin
88+
axi_sub_name = top_pkg::axi_devices_t'(i);
89+
m_sub_axi[i] = axi4_vip_env::type_id::create(.name($sformatf("m_sub_axi_%s", axi_sub_name.name())), .parent(this));
90+
end
91+
92+
m_axi_scb = top_chip_dv_axi_scoreboard::type_id::create("m_axi_scb", this);
93+
7394
uvm_config_db#(top_chip_dv_env_cfg)::set(this, "", "cfg", cfg);
7495

7596
top_vsqr = top_chip_dv_virtual_sequencer::type_id::create("top_vsqr", this);
@@ -86,6 +107,12 @@ function void top_chip_dv_env::connect_phase(uvm_phase phase);
86107
// Connect monitor output to matching FIFO in the virtual sequencer.
87108
// Allows virtual sequences to check TX items.
88109
m_uart_agent.monitor.tx_analysis_port.connect(top_vsqr.uart_tx_fifo.analysis_export);
110+
111+
m_mgr_axi[top_pkg::CVA6] .m_manager .m_monitor.tx_ap.connect(m_axi_scb.mgr0_cva6_imp);
112+
m_sub_axi[top_pkg::SRAM] .m_subordinate.m_monitor.tx_ap.connect(m_axi_scb.sub0_sram_imp);
113+
m_sub_axi[top_pkg::Mailbox] .m_subordinate.m_monitor.tx_ap.connect(m_axi_scb.sub1_mailbox_imp);
114+
m_sub_axi[top_pkg::TlCrossbar].m_subordinate.m_monitor.tx_ap.connect(m_axi_scb.sub2_tlcrossbar_imp);
115+
m_sub_axi[top_pkg::DRAM] .m_subordinate.m_monitor.tx_ap.connect(m_axi_scb.sub3_dram_imp);
89116
endfunction : connect_phase
90117

91118
task top_chip_dv_env::load_memories();

hw/top_chip/dv/env/top_chip_dv_env_cfg.sv

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class top_chip_dv_env_cfg extends uvm_object;
1515

1616
// External interface agent configs
1717
rand uart_agent_cfg m_uart_agent_cfg;
18+
axi4_vip_cfg m_axi_mgr_cfg[];
19+
axi4_vip_cfg m_axi_sub_cfg[];
1820

1921
`uvm_object_utils_begin(top_chip_dv_env_cfg)
2022
`uvm_object_utils_end

hw/top_chip/dv/env/top_chip_dv_env_pkg.sv

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package top_chip_dv_env_pkg;
99
import mem_bkdr_util_pkg::*;
1010
import sw_test_status_pkg::*;
1111
import uart_agent_pkg::*;
12+
import axi4_vip_pkg::*;
1213

1314
// Macro includes
1415
`include "uvm_macros.svh"
@@ -20,6 +21,21 @@ package top_chip_dv_env_pkg;
2021

2122
typedef chip_mem_e chip_mem_list_t[$];
2223

24+
typedef enum bit[2:0] {
25+
mst0 = 0,
26+
slv0 = 1,
27+
slv1 = 2,
28+
slv2 = 3,
29+
slv3 = 4
30+
} axi_if_t;
31+
32+
// Local Address Map Struct
33+
typedef struct {
34+
string subordinate_name;
35+
bit [63:0] start_addr;
36+
bit [63:0] end_addr;
37+
} axi_addr_range_t;
38+
2339
// Generate the list of all chip_mem_e values, this helps to simplify iterating over them with
2440
// foreach loops.
2541
const chip_mem_list_t CHIP_MEM_LIST = chip_mem_values();
@@ -46,11 +62,16 @@ package top_chip_dv_env_pkg;
4662
parameter bit [31:0] SW_DV_TEST_STATUS_ADDR = SW_DV_START_ADDR + 'h00;
4763
parameter bit [31:0] SW_DV_LOG_ADDR = SW_DV_START_ADDR + 'h04;
4864

65+
// Manual set is necessary
66+
localparam int NUM_OF_MGR_AXI_IFS = 1;
67+
localparam int NUM_OF_SUB_AXI_IFS = 4;
68+
4969
// File includes
5070
`include "mem_clear_util.sv"
5171
`include "top_chip_dv_env_cfg.sv"
5272
`include "top_chip_dv_env_cov.sv"
5373
`include "top_chip_dv_virtual_sequencer.sv"
74+
`include "top_chip_dv_axi_scoreboard.sv"
5475
`include "top_chip_dv_env.sv"
5576
`include "top_chip_dv_vseq_list.sv"
5677
endpackage : top_chip_dv_env_pkg

0 commit comments

Comments
 (0)