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
0 commit comments