1 |
12 |
juko |
/*
|
2 |
|
|
* .--------------. .----------------. .------------.
|
3 |
|
|
* | .------------. | .--------------. | .----------. |
|
4 |
|
|
* | | ____ ____ | | | ____ ____ | | | ______ | |
|
5 |
|
|
* | ||_ || _|| | ||_ \ / _|| | | .' ___ || |
|
6 |
|
|
* ___ _ __ ___ _ __ | | | |__| | | | | | \/ | | | |/ .' \_|| |
|
7 |
|
|
* / _ \| '_ \ / _ \ '_ \ | | | __ | | | | | |\ /| | | | || | | |
|
8 |
|
|
* (_) | |_) | __/ | | || | _| | | |_ | | | _| |_\/_| |_ | | |\ `.___.'\| |
|
9 |
|
|
* \___/| .__/ \___|_| |_|| ||____||____|| | ||_____||_____|| | | `._____.'| |
|
10 |
|
|
* | | | | | | | | | | | |
|
11 |
|
|
* |_| | '------------' | '--------------' | '----------' |
|
12 |
|
|
* '--------------' '----------------' '------------'
|
13 |
|
|
*
|
14 |
|
|
* openHMC - An Open Source Hybrid Memory Cube Controller
|
15 |
|
|
* (C) Copyright 2014 Computer Architecture Group - University of Heidelberg
|
16 |
|
|
* www.ziti.uni-heidelberg.de
|
17 |
|
|
* B6, 26
|
18 |
|
|
* 68159 Mannheim
|
19 |
|
|
* Germany
|
20 |
|
|
*
|
21 |
|
|
* Contact: openhmc@ziti.uni-heidelberg.de
|
22 |
|
|
* http://ra.ziti.uni-heidelberg.de/openhmc
|
23 |
|
|
*
|
24 |
|
|
* This source file is free software: you can redistribute it and/or modify
|
25 |
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
26 |
|
|
* the Free Software Foundation, either version 3 of the License, or
|
27 |
|
|
* (at your option) any later version.
|
28 |
|
|
*
|
29 |
|
|
* This source file is distributed in the hope that it will be useful,
|
30 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
31 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
32 |
|
|
* GNU Lesser General Public License for more details.
|
33 |
|
|
*
|
34 |
|
|
* You should have received a copy of the GNU Lesser General Public License
|
35 |
|
|
* along with this source file. If not, see .
|
36 |
|
|
*
|
37 |
|
|
*
|
38 |
|
|
*/
|
39 |
|
|
|
40 |
|
|
//
|
41 |
|
|
//
|
42 |
|
|
// axi4_stream_packet hmc_monitor
|
43 |
|
|
//
|
44 |
|
|
//
|
45 |
|
|
|
46 |
|
|
`ifndef AXI4_STREAM_HMC_MONITOR_SV
|
47 |
|
|
`define AXI4_STREAM_HMC_MONITOR_SV
|
48 |
|
|
|
49 |
|
|
class axi4_stream_hmc_monitor #(parameter DATA_BYTES = 16, parameter TUSER_WIDTH = 16) extends hmc_module_mon ;
|
50 |
|
|
|
51 |
|
|
|
52 |
|
|
int FPW ;
|
53 |
|
|
int HEADERS ;
|
54 |
|
|
int TAILS ;
|
55 |
|
|
int VALIDS ;
|
56 |
|
|
int valids_per_cycle = 0;
|
57 |
|
|
int current_packet_length = 0;
|
58 |
|
|
|
59 |
|
|
bit request = 1;
|
60 |
|
|
|
61 |
|
|
int flit_delay [$];
|
62 |
|
|
|
63 |
|
|
|
64 |
|
|
//-- uvm_analysis_port #(hmc_packet) item_collected_port;
|
65 |
|
|
uvm_analysis_imp #(
|
66 |
|
|
axi4_stream_valid_cycle #(.DATA_BYTES(DATA_BYTES), .TUSER_WIDTH(TUSER_WIDTH)),
|
67 |
|
|
axi4_stream_hmc_monitor #(.DATA_BYTES(DATA_BYTES), .TUSER_WIDTH(TUSER_WIDTH))
|
68 |
|
|
) axi4_port;
|
69 |
|
|
|
70 |
|
|
int n_valids = 0;
|
71 |
|
|
|
72 |
|
|
int headers_seen = 0;
|
73 |
|
|
int tails_seen = 0;
|
74 |
|
|
|
75 |
|
|
|
76 |
|
|
typedef bit [127:0] flit_t;
|
77 |
|
|
flit_t flit_queue[$];
|
78 |
|
|
|
79 |
|
|
int packets_per_cycle = 0;
|
80 |
|
|
|
81 |
|
|
|
82 |
|
|
hmc_packet packet_queue[$];
|
83 |
|
|
|
84 |
|
|
//-- covergroup definition
|
85 |
|
|
|
86 |
|
|
|
87 |
|
|
|
88 |
|
|
|
89 |
|
|
`uvm_component_param_utils(axi4_stream_hmc_monitor #(.DATA_BYTES(DATA_BYTES), .TUSER_WIDTH(TUSER_WIDTH)))
|
90 |
|
|
|
91 |
|
|
|
92 |
|
|
function new ( string name="axi4_stream_hmc_monitor", uvm_component parent );
|
93 |
|
|
super.new(name, parent);
|
94 |
|
|
|
95 |
|
|
axi4_port = new("axi4_port",this);
|
96 |
|
|
|
97 |
|
|
hmc_pkt_cg = new();
|
98 |
|
|
|
99 |
|
|
|
100 |
|
|
endfunction : new
|
101 |
|
|
|
102 |
|
|
function void build_phase(uvm_phase phase);
|
103 |
|
|
super.build_phase(phase);
|
104 |
|
|
FPW = DATA_BYTES/16;//-- convert to variables!
|
105 |
|
|
HEADERS = FPW;
|
106 |
|
|
TAILS = 2*FPW;
|
107 |
|
|
VALIDS = 0;
|
108 |
|
|
endfunction : build_phase
|
109 |
|
|
|
110 |
|
|
//-- Stuff FLITs into a FIFO, separate control signals
|
111 |
|
|
function void collect_flits(input axi4_stream_valid_cycle #(.DATA_BYTES(DATA_BYTES), .TUSER_WIDTH(TUSER_WIDTH)) vc);
|
112 |
|
|
//-- read tuser flags for valid flags
|
113 |
|
|
flit_t tmp_flit;
|
114 |
|
|
flit_t current_flit;
|
115 |
|
|
packets_per_cycle = 0;
|
116 |
|
|
valids_per_cycle =0;
|
117 |
|
|
for (int i = 0; i
|
118 |
|
|
//-- Check if valid
|
119 |
|
|
if (vc.tuser[VALIDS+i] == 1) begin
|
120 |
|
|
valids_per_cycle ++;
|
121 |
|
|
|
122 |
|
|
|
123 |
|
|
|
124 |
|
|
//-- Write 2 flit queue
|
125 |
|
|
for (int b=0; b<128; b++)
|
126 |
|
|
tmp_flit[b] = vc.tdata[128*i+b];
|
127 |
|
|
flit_queue.push_back(tmp_flit);
|
128 |
|
|
|
129 |
|
|
if (vc.tuser[HEADERS+i] == 1'b1) begin
|
130 |
|
|
headers_seen++; //-- Complete hmc_packets to assemble
|
131 |
|
|
packets_per_cycle++;
|
132 |
|
|
flit_delay.push_back(n_valids);
|
133 |
|
|
n_valids = 0;
|
134 |
|
|
end
|
135 |
|
|
//-- Check if tail for complete hmc packet
|
136 |
|
|
if (vc.tuser[TAILS+i] == 1'b1) begin
|
137 |
|
|
tails_seen++; //-- Complete hmc_packets to assemble
|
138 |
|
|
|
139 |
|
|
assert (n_valids == 0)
|
140 |
|
|
else `uvm_fatal(get_type_name(), $psprintf("Non valid flits in pkt detected!"))
|
141 |
|
|
end
|
142 |
|
|
|
143 |
|
|
//-- Check complete hmc packets
|
144 |
|
|
|
145 |
|
|
assert (tails_seen<= headers_seen)
|
146 |
|
|
else `uvm_fatal(get_type_name(), $psprintf("packet is null"))
|
147 |
|
|
|
148 |
|
|
assert (headers_seen <= tails_seen+1)
|
149 |
|
|
else `uvm_fatal(get_type_name(), $psprintf("Packet without Tail detected"))
|
150 |
|
|
|
151 |
|
|
end
|
152 |
|
|
else begin
|
153 |
|
|
n_valids ++;
|
154 |
|
|
end
|
155 |
|
|
|
156 |
|
|
end
|
157 |
15 |
juko |
if(|vc.tuser)
|
158 |
|
|
`uvm_info(get_type_name(),$psprintf("%d header and %d tails available", headers_seen, tails_seen) ,UVM_HIGH)
|
159 |
12 |
juko |
|
160 |
|
|
|
161 |
|
|
|
162 |
|
|
endfunction : collect_flits
|
163 |
|
|
|
164 |
|
|
//-- Use FLITs to form packets
|
165 |
|
|
function void collect_packet();
|
166 |
|
|
|
167 |
|
|
flit_t current_flit;
|
168 |
|
|
bit bitstream[];
|
169 |
|
|
|
170 |
|
|
//-- Assemble 1 hmc packet
|
171 |
|
|
flit_queue_underflow : assert (flit_queue.size() > 0);
|
172 |
|
|
|
173 |
|
|
//-- First flit is always header
|
174 |
|
|
current_flit = flit_queue.pop_front();
|
175 |
|
|
no_length_mismatches_allowed : assert (current_flit[14:11] == current_flit[10:7]); //--check internal hmc_packet length
|
176 |
|
|
current_packet_length = current_flit[10:7];
|
177 |
15 |
juko |
`uvm_info(get_type_name(),$psprintf("packet length %0d ", current_packet_length), UVM_HIGH)
|
178 |
|
|
`uvm_info(get_type_name(),$psprintf("queue size %0d ", flit_queue.size()), UVM_HIGH)
|
179 |
12 |
juko |
flit_queue_underflow2 : assert (flit_queue.size() >= current_packet_length - 1); //--check check hmc_packet complete received
|
180 |
|
|
|
181 |
|
|
|
182 |
|
|
//-- pack flits 2 bitstream
|
183 |
|
|
bitstream = new[current_packet_length*128];
|
184 |
|
|
|
185 |
|
|
//-- Pack first flit
|
186 |
|
|
for (int i=0; i<128; i=i+1)
|
187 |
|
|
bitstream[i] = current_flit[i];
|
188 |
|
|
|
189 |
|
|
//-- Get and pack the remaining flits
|
190 |
|
|
for (int flit=1; flit < current_packet_length; flit ++) begin
|
191 |
|
|
current_flit = flit_queue.pop_front();
|
192 |
|
|
`uvm_info(get_type_name(),$psprintf("pop flit %0d (%0x)", flit, current_flit), UVM_HIGH)
|
193 |
|
|
for (int i=0; i<128; i=i+1) begin
|
194 |
|
|
bitstream[flit*128+i] = current_flit[i];
|
195 |
|
|
end
|
196 |
|
|
end
|
197 |
|
|
|
198 |
|
|
|
199 |
|
|
|
200 |
|
|
|
201 |
|
|
packet = hmc_packet::type_id::create("packet", this);
|
202 |
|
|
void'(packet.unpack(bitstream));
|
203 |
|
|
packet.flit_delay = flit_delay.pop_front();
|
204 |
|
|
|
205 |
|
|
hmc_pkt_cg.sample();
|
206 |
|
|
|
207 |
|
|
//-- assembled a packet
|
208 |
|
|
headers_seen--;
|
209 |
|
|
tails_seen--;
|
210 |
|
|
|
211 |
|
|
if (packet == null) begin
|
212 |
|
|
`uvm_fatal(get_type_name(), $psprintf("packet is null"))
|
213 |
|
|
end
|
214 |
|
|
|
215 |
|
|
packet_queue.push_back(packet);
|
216 |
|
|
|
217 |
|
|
if(packet.get_command_type() == HMC_RESPONSE_TYPE)begin
|
218 |
|
|
`uvm_info("RESPONSE collected",$psprintf("Rsp %0d : %s",rsp_rcvd, packet.command.name()), UVM_LOW)
|
219 |
|
|
rsp_rcvd++;
|
220 |
|
|
end else begin
|
221 |
|
|
`uvm_info("REQUEST collected",$psprintf("Req %0d : %s",req_rcvd, packet.command.name()), UVM_LOW)
|
222 |
|
|
req_rcvd++;
|
223 |
|
|
end
|
224 |
|
|
`uvm_info("AXI4 to HMC Monitor",$psprintf("\n%s", packet.sprint()), UVM_HIGH)
|
225 |
|
|
endfunction : collect_packet
|
226 |
|
|
|
227 |
|
|
function void write(input axi4_stream_valid_cycle #(.DATA_BYTES(DATA_BYTES), .TUSER_WIDTH(TUSER_WIDTH)) vc);
|
228 |
|
|
|
229 |
|
|
|
230 |
|
|
hmc_packet packet;
|
231 |
|
|
|
232 |
|
|
collect_flits(vc);
|
233 |
|
|
|
234 |
15 |
juko |
//`uvm_info(get_type_name(),$psprintf("got %0d tails and %0d flits",tails_seen, flit_queue.size() ), UVM_HIGH)
|
235 |
12 |
juko |
|
236 |
|
|
//-- Convert flit_queue to hmc_packets
|
237 |
|
|
while (tails_seen >0) begin
|
238 |
|
|
collect_packet();
|
239 |
|
|
end
|
240 |
|
|
//-- If flit queue is not empty -> hmc packet striped over 2 axi cycles
|
241 |
|
|
|
242 |
|
|
|
243 |
|
|
while (packet_queue.size()>0) begin
|
244 |
|
|
packet = packet_queue.pop_front();
|
245 |
|
|
//if (packet.command != HMC_ERROR_RESPONSE)
|
246 |
|
|
item_collected_port.write(packet);
|
247 |
|
|
end
|
248 |
|
|
endfunction
|
249 |
|
|
|
250 |
|
|
function void check_phase(uvm_phase phase);
|
251 |
|
|
if (flit_queue.size() >0)
|
252 |
|
|
`uvm_fatal(get_type_name(),$psprintf("flit_queue is not empty: %0d", flit_queue.size()))
|
253 |
|
|
endfunction : check_phase
|
254 |
|
|
endclass : axi4_stream_hmc_monitor
|
255 |
|
|
|
256 |
|
|
`endif // AXI4_STREAM_HMC_MONITOR_SV
|