1 |
5 |
leonous |
// -*- C++ -*-
|
2 |
|
|
//*************************************************************************
|
3 |
|
|
//
|
4 |
|
|
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
5 |
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
6 |
|
|
// Lesser General Public License or the Perl Artistic License.
|
7 |
|
|
//
|
8 |
|
|
// Verilator is distributed in the hope that it will be useful,
|
9 |
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10 |
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11 |
|
|
// GNU General Public License for more details.
|
12 |
|
|
//
|
13 |
|
|
//=========================================================================
|
14 |
|
|
///
|
15 |
|
|
/// \file
|
16 |
|
|
/// \brief Verilator: Linked against all applications using Verilated source.
|
17 |
|
|
///
|
18 |
|
|
/// This file must be compiled and linked against all objects
|
19 |
|
|
/// created from Verilator.
|
20 |
|
|
///
|
21 |
|
|
/// Code available from: http://www.veripool.org/verilator
|
22 |
|
|
///
|
23 |
|
|
//=========================================================================
|
24 |
|
|
|
25 |
|
|
#include "verilated.h"
|
26 |
|
|
#include <cctype>
|
27 |
|
|
|
28 |
|
|
#define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING
|
29 |
|
|
|
30 |
|
|
//===========================================================================
|
31 |
|
|
// Global variables
|
32 |
|
|
|
33 |
|
|
int Verilated::s_randReset = 0;
|
34 |
|
|
int Verilated::s_debug = 1;
|
35 |
|
|
bool Verilated::s_calcUnusedSigs = false;
|
36 |
|
|
bool Verilated::s_gotFinish = false;
|
37 |
|
|
bool Verilated::s_assertOn = true;
|
38 |
|
|
|
39 |
|
|
//===========================================================================
|
40 |
|
|
// User definable functions
|
41 |
|
|
|
42 |
|
|
#ifndef VL_USER_FINISH // Define this to override this function
|
43 |
|
|
void vl_finish (const char* filename, int linenum, const char* hier) {
|
44 |
|
|
if (0 && hier) {}
|
45 |
|
|
VL_PRINTF("- %s:%d: Verilog $finish\n", filename, linenum);
|
46 |
|
|
if (Verilated::gotFinish()) {
|
47 |
|
|
VL_PRINTF("- %s:%d: Second verilog $finish, exiting\n", filename, linenum);
|
48 |
|
|
exit(0);
|
49 |
|
|
}
|
50 |
|
|
Verilated::gotFinish(true);
|
51 |
|
|
}
|
52 |
|
|
#endif
|
53 |
|
|
|
54 |
|
|
#ifndef VL_USER_STOP // Define this to override this function
|
55 |
|
|
void vl_stop (const char* filename, int linenum, const char* hier) {
|
56 |
|
|
Verilated::gotFinish(true);
|
57 |
|
|
vl_fatal (filename,linenum,hier,"Verilog $stop");
|
58 |
|
|
}
|
59 |
|
|
#endif
|
60 |
|
|
|
61 |
|
|
#ifndef VL_USER_FATAL // Define this to override this function
|
62 |
|
|
void vl_fatal (const char* filename, int linenum, const char* hier, const char* msg) {
|
63 |
|
|
if (0 && hier) {}
|
64 |
|
|
Verilated::gotFinish(true);
|
65 |
|
|
VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg);
|
66 |
|
|
abort();
|
67 |
|
|
}
|
68 |
|
|
#endif
|
69 |
|
|
|
70 |
|
|
//===========================================================================
|
71 |
|
|
// Random reset -- Only called at init time, so don't inline.
|
72 |
|
|
|
73 |
|
|
IData VL_RAND32() {
|
74 |
|
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
75 |
|
|
// Windows doesn't have lrand48(), although Cygwin does.
|
76 |
|
|
return (rand()<<16) ^ rand();
|
77 |
|
|
#else
|
78 |
|
|
return (lrand48()<<16) ^ lrand48();
|
79 |
|
|
#endif
|
80 |
|
|
}
|
81 |
|
|
|
82 |
|
|
IData VL_RANDOM_I(int obits) {
|
83 |
|
|
return VL_RAND32() & VL_MASK_I(obits);
|
84 |
|
|
}
|
85 |
|
|
|
86 |
|
|
QData VL_RANDOM_Q(int obits) {
|
87 |
|
|
QData data = ((QData)VL_RAND32()<<VL_ULL(32)) | (QData)VL_RAND32();
|
88 |
|
|
return data & VL_MASK_Q(obits);
|
89 |
|
|
}
|
90 |
|
|
|
91 |
|
|
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) {
|
92 |
|
|
for (int i=0; i<VL_WORDS_I(obits); i++) {
|
93 |
|
|
if (i<(VL_WORDS_I(obits)-1)) {
|
94 |
|
|
outwp[i] = VL_RAND32();
|
95 |
|
|
} else {
|
96 |
|
|
outwp[i] = VL_RAND32() & VL_MASK_I(obits);
|
97 |
|
|
}
|
98 |
|
|
}
|
99 |
|
|
return outwp;
|
100 |
|
|
}
|
101 |
|
|
|
102 |
|
|
IData VL_RAND_RESET_I(int obits) {
|
103 |
|
|
if (Verilated::randReset()==0) return 0;
|
104 |
|
|
IData data = ~0;
|
105 |
|
|
if (Verilated::randReset()!=1) { // if 2, randomize
|
106 |
|
|
data = VL_RANDOM_I(obits);
|
107 |
|
|
}
|
108 |
|
|
if (obits<32) data &= VL_MASK_I(obits);
|
109 |
|
|
return data;
|
110 |
|
|
}
|
111 |
|
|
|
112 |
|
|
QData VL_RAND_RESET_Q(int obits) {
|
113 |
|
|
if (Verilated::randReset()==0) return 0;
|
114 |
|
|
QData data = VL_ULL(~0);
|
115 |
|
|
if (Verilated::randReset()!=1) { // if 2, randomize
|
116 |
|
|
data = VL_RANDOM_Q(obits);
|
117 |
|
|
}
|
118 |
|
|
if (obits<64) data &= VL_MASK_Q(obits);
|
119 |
|
|
return data;
|
120 |
|
|
}
|
121 |
|
|
|
122 |
|
|
WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) {
|
123 |
|
|
for (int i=0; i<VL_WORDS_I(obits); i++) {
|
124 |
|
|
if (i<(VL_WORDS_I(obits)-1)) {
|
125 |
|
|
outwp[i] = VL_RAND_RESET_I(32);
|
126 |
|
|
} else {
|
127 |
|
|
outwp[i] = VL_RAND_RESET_I(32) & VL_MASK_I(obits);
|
128 |
|
|
}
|
129 |
|
|
}
|
130 |
|
|
return outwp;
|
131 |
|
|
}
|
132 |
|
|
|
133 |
|
|
WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) {
|
134 |
|
|
for (int i=0; i<VL_WORDS_I(obits); i++) outwp[i] = 0;
|
135 |
|
|
return outwp;
|
136 |
|
|
}
|
137 |
|
|
|
138 |
|
|
//===========================================================================
|
139 |
|
|
// Formatting
|
140 |
|
|
|
141 |
|
|
// Do a va_arg returning a quad, assuming input argument is anything less than wide
|
142 |
|
|
#define _VL_VA_ARG_Q(ap, bits) (((bits) <= VL_WORDSIZE) ? va_arg(ap,IData) : va_arg(ap,QData))
|
143 |
|
|
|
144 |
|
|
void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
145 |
|
|
// Format a Verilog $write style format into the output list
|
146 |
|
|
// The format must be pre-processed (and lower cased) by Verilator
|
147 |
|
|
// Arguments are in "width, arg-value (or WDataIn* if wide)" form
|
148 |
|
|
//
|
149 |
|
|
// Note uses a single buffer internally; presumes only one usage per printf
|
150 |
|
|
// Note also assumes variables < 64 are not wide, this assumption is
|
151 |
|
|
// sometimes not true in low-level routines written here in verilated.cpp
|
152 |
|
|
static VL_THREAD char tmp[VL_VALUE_STRING_MAX_WIDTH];
|
153 |
|
|
bool inPct = false;
|
154 |
|
|
bool widthSet = false;
|
155 |
|
|
int width = 0;
|
156 |
|
|
const char* pos = formatp;
|
157 |
|
|
for (; *pos; ++pos) {
|
158 |
|
|
if (!inPct && pos[0]=='%') {
|
159 |
|
|
inPct = true;
|
160 |
|
|
widthSet = false;
|
161 |
|
|
width = 0;
|
162 |
|
|
} else if (!inPct) { // Normal text
|
163 |
|
|
// Fast-forward to next escape and add to output
|
164 |
|
|
const char *ep = pos;
|
165 |
|
|
while (ep[0] && ep[0]!='%') ep++;
|
166 |
|
|
if (ep != pos) {
|
167 |
|
|
output += string(pos, ep-pos);
|
168 |
|
|
pos += ep-pos-1;
|
169 |
|
|
}
|
170 |
|
|
} else { // Format character
|
171 |
|
|
inPct = false;
|
172 |
|
|
char fmt = pos[0];
|
173 |
|
|
switch (fmt) {
|
174 |
|
|
case '0': case '1': case '2': case '3': case '4':
|
175 |
|
|
case '5': case '6': case '7': case '8': case '9':
|
176 |
|
|
inPct = true; // Get more digits
|
177 |
|
|
widthSet = true;
|
178 |
|
|
width = width*10 + (fmt - '0');
|
179 |
|
|
break;
|
180 |
|
|
case '%':
|
181 |
|
|
output += '%';
|
182 |
|
|
break;
|
183 |
|
|
case 'S': { // "C" string
|
184 |
|
|
const char* cstrp = va_arg(ap, const char*);
|
185 |
|
|
output += cstrp;
|
186 |
|
|
break;
|
187 |
|
|
}
|
188 |
|
|
default: {
|
189 |
|
|
// Deal with all read-and-print somethings
|
190 |
|
|
const int lbits = va_arg(ap, int);
|
191 |
|
|
QData ld = 0;
|
192 |
|
|
WDataInP lwp;
|
193 |
|
|
if (lbits <= VL_QUADSIZE) {
|
194 |
|
|
WData qlwp[2];
|
195 |
|
|
ld = _VL_VA_ARG_Q(ap, lbits);
|
196 |
|
|
VL_SET_WQ(qlwp,ld);
|
197 |
|
|
lwp = qlwp;
|
198 |
|
|
} else {
|
199 |
|
|
lwp = va_arg(ap,WDataInP);
|
200 |
|
|
ld = lwp[0];
|
201 |
|
|
if (fmt == 'u' || fmt == 'd') fmt = 'x'; // Not supported, but show something
|
202 |
|
|
}
|
203 |
|
|
int lsb=lbits-1;
|
204 |
|
|
if (widthSet && width==0) while (lsb && !VL_BITISSET_W(lwp,lsb)) lsb--;
|
205 |
|
|
switch (fmt) {
|
206 |
|
|
case 'c': {
|
207 |
|
|
IData charval = ld & 0xff;
|
208 |
|
|
output += charval;
|
209 |
|
|
break;
|
210 |
|
|
}
|
211 |
|
|
case 's':
|
212 |
|
|
for (; lsb>=0; lsb--) {
|
213 |
|
|
lsb = (lsb / 8) * 8; // Next digit
|
214 |
|
|
IData charval = (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xff;
|
215 |
|
|
output += (charval==0)?' ':charval;
|
216 |
|
|
}
|
217 |
|
|
break;
|
218 |
|
|
case 'd': { // Signed decimal
|
219 |
|
|
int digits=sprintf(tmp,"%lld",(vlsint64_t)(VL_EXTENDS_QQ(lbits,lbits,ld)));
|
220 |
|
|
int needmore = width-digits;
|
221 |
|
|
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
|
222 |
|
|
output += tmp;
|
223 |
|
|
break;
|
224 |
|
|
}
|
225 |
|
|
case 'u': { // Unsigned decimal
|
226 |
|
|
int digits=sprintf(tmp,"%llu",ld);
|
227 |
|
|
int needmore = width-digits;
|
228 |
|
|
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
|
229 |
|
|
output += tmp;
|
230 |
|
|
break;
|
231 |
|
|
}
|
232 |
|
|
case 't': { // Time
|
233 |
|
|
int digits;
|
234 |
|
|
if (VL_TIME_MULTIPLIER==1) {
|
235 |
|
|
digits=sprintf(tmp,"%llu",ld);
|
236 |
|
|
} else if (VL_TIME_MULTIPLIER==1000) {
|
237 |
|
|
digits=sprintf(tmp,"%llu.%03llu",
|
238 |
|
|
(QData)(ld/VL_TIME_MULTIPLIER),
|
239 |
|
|
(QData)(ld%VL_TIME_MULTIPLIER));
|
240 |
|
|
} else {
|
241 |
|
|
vl_fatal(__FILE__,__LINE__,"","%%Error: Unsupported VL_TIME_MULTIPLIER");
|
242 |
|
|
}
|
243 |
|
|
int needmore = width-digits;
|
244 |
|
|
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
|
245 |
|
|
output += tmp;
|
246 |
|
|
break;
|
247 |
|
|
}
|
248 |
|
|
case 'b':
|
249 |
|
|
for (; lsb>=0; lsb--) {
|
250 |
|
|
output += ((lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 1) + '0';
|
251 |
|
|
}
|
252 |
|
|
break;
|
253 |
|
|
case 'o':
|
254 |
|
|
for (; lsb>=0; lsb--) {
|
255 |
|
|
lsb = (lsb / 3) * 3; // Next digit
|
256 |
|
|
// Octal numbers may span more than one wide word,
|
257 |
|
|
// so we need to grab each bit separately and check for overrun
|
258 |
|
|
// Octal is rare, so we'll do it a slow simple way
|
259 |
|
|
output += ('0'
|
260 |
|
|
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+0)) ? 1 : 0)
|
261 |
|
|
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+1)) ? 2 : 0)
|
262 |
|
|
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+2)) ? 4 : 0));
|
263 |
|
|
}
|
264 |
|
|
break;
|
265 |
|
|
case 'x':
|
266 |
|
|
for (; lsb>=0; lsb--) {
|
267 |
|
|
lsb = (lsb / 4) * 4; // Next digit
|
268 |
|
|
IData charval = (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xf;
|
269 |
|
|
output += "0123456789abcdef"[charval];
|
270 |
|
|
}
|
271 |
|
|
break;
|
272 |
|
|
default:
|
273 |
|
|
string msg = string("%%Error: Unknown _vl_vsformat code: ")+pos[0]+"\n";
|
274 |
|
|
vl_fatal(__FILE__,__LINE__,"",msg.c_str());
|
275 |
|
|
break;
|
276 |
|
|
} // switch
|
277 |
|
|
}
|
278 |
|
|
} // switch
|
279 |
|
|
}
|
280 |
|
|
}
|
281 |
|
|
}
|
282 |
|
|
|
283 |
|
|
static inline bool _vl_vsss_eof(FILE* fp, int& floc) {
|
284 |
|
|
return fp ? feof(fp) : (floc<0);
|
285 |
|
|
}
|
286 |
|
|
static inline void _vl_vsss_advance(FILE* fp, int& floc) {
|
287 |
|
|
if (fp) fgetc(fp);
|
288 |
|
|
else floc -= 8;
|
289 |
|
|
}
|
290 |
|
|
static inline int _vl_vsss_peek(FILE* fp, int& floc, WDataInP fromp) {
|
291 |
|
|
// Get a character without advancing
|
292 |
|
|
if (fp) {
|
293 |
|
|
int data = fgetc(fp);
|
294 |
|
|
if (data == EOF) return EOF;
|
295 |
|
|
ungetc(data,fp);
|
296 |
|
|
return data;
|
297 |
|
|
} else {
|
298 |
|
|
if (floc < 0) return EOF;
|
299 |
|
|
floc = floc & ~7; // Align to closest character
|
300 |
|
|
int data = (fromp[VL_BITWORD_I(floc)] >> VL_BITBIT_I(floc)) & 0xff;
|
301 |
|
|
return data;
|
302 |
|
|
}
|
303 |
|
|
}
|
304 |
|
|
static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp) {
|
305 |
|
|
while (1) {
|
306 |
|
|
int c = _vl_vsss_peek(fp, floc, fromp);
|
307 |
|
|
if (c==EOF || !isspace(c)) return;
|
308 |
|
|
_vl_vsss_advance(fp, floc);
|
309 |
|
|
}
|
310 |
|
|
}
|
311 |
|
|
static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp,
|
312 |
|
|
char* tmpp, const char* acceptp) {
|
313 |
|
|
// Read into tmp, consisting of characters from acceptp list
|
314 |
|
|
char* cp = tmpp;
|
315 |
|
|
while (1) {
|
316 |
|
|
int c = _vl_vsss_peek(fp, floc, fromp);
|
317 |
|
|
if (c==EOF || isspace(c)) break;
|
318 |
|
|
if (acceptp!=NULL // String - allow anything
|
319 |
|
|
&& NULL==strchr(acceptp, c)) break;
|
320 |
|
|
if (acceptp!=NULL) c = tolower(c); // Non-strings we'll simplify
|
321 |
|
|
*cp++ = c;
|
322 |
|
|
_vl_vsss_advance(fp, floc);
|
323 |
|
|
}
|
324 |
|
|
*cp++ = '\0';
|
325 |
|
|
//VL_PRINTF("\t_read got='%s'\n", tmpp);
|
326 |
|
|
}
|
327 |
|
|
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits, IData ld) {
|
328 |
|
|
for (; nbits && lsb<obits; nbits--, lsb++, ld>>=1) {
|
329 |
|
|
VL_ASSIGNBIT_WI(0, lsb, owp, ld & 1);
|
330 |
|
|
}
|
331 |
|
|
}
|
332 |
|
|
|
333 |
|
|
IData _vl_vsscanf(FILE* fp, // If a fscanf
|
334 |
|
|
int fbits, WDataInP fromp, // Else if a sscanf
|
335 |
|
|
const char* formatp, va_list ap) {
|
336 |
|
|
// Read a Verilog $sscanf/$fscanf style format into the output list
|
337 |
|
|
// The format must be pre-processed (and lower cased) by Verilator
|
338 |
|
|
// Arguments are in "width, arg-value (or WDataIn* if wide)" form
|
339 |
|
|
static VL_THREAD char tmp[VL_VALUE_STRING_MAX_WIDTH];
|
340 |
|
|
int floc = fbits - 1;
|
341 |
|
|
IData got = 0;
|
342 |
|
|
bool inPct = false;
|
343 |
|
|
const char* pos = formatp;
|
344 |
|
|
for (; *pos && !_vl_vsss_eof(fp,floc); ++pos) {
|
345 |
|
|
//VL_PRINTF("_vlscan fmt='%c' floc=%d file='%c'\n", pos[0], floc, _vl_vsss_peek(fp,floc,fromp));
|
346 |
|
|
if (!inPct && pos[0]=='%') {
|
347 |
|
|
inPct = true;
|
348 |
|
|
} else if (!inPct && isspace(pos[0])) { // Format spaces
|
349 |
|
|
while (isspace(pos[1])) pos++;
|
350 |
|
|
_vl_vsss_skipspace(fp,floc,fromp);
|
351 |
|
|
} else if (!inPct) { // Expected Format
|
352 |
|
|
_vl_vsss_skipspace(fp,floc,fromp);
|
353 |
|
|
int c = _vl_vsss_peek(fp,floc,fromp);
|
354 |
|
|
if (c != pos[0]) goto done;
|
355 |
|
|
else _vl_vsss_advance(fp,floc);
|
356 |
|
|
} else { // Format character
|
357 |
|
|
// Skip loading spaces
|
358 |
|
|
inPct = false;
|
359 |
|
|
char fmt = pos[0];
|
360 |
|
|
switch (fmt) {
|
361 |
|
|
case '%': {
|
362 |
|
|
int c = _vl_vsss_peek(fp,floc,fromp);
|
363 |
|
|
if (c != '%') goto done;
|
364 |
|
|
else _vl_vsss_advance(fp,floc);
|
365 |
|
|
break;
|
366 |
|
|
}
|
367 |
|
|
default: {
|
368 |
|
|
// Deal with all read-and-scan somethings
|
369 |
|
|
// Note LSBs are preserved if there's an overflow
|
370 |
|
|
const int obits = va_arg(ap, int);
|
371 |
|
|
int lsb = 0;
|
372 |
|
|
WData qowp[2];
|
373 |
|
|
WDataOutP owp = qowp;
|
374 |
|
|
if (obits > VL_QUADSIZE) {
|
375 |
|
|
owp = va_arg(ap,WDataOutP);
|
376 |
|
|
}
|
377 |
|
|
for (int i=0; i<VL_WORDS_I(obits); i++) owp[i] = 0;
|
378 |
|
|
switch (fmt) {
|
379 |
|
|
case 'c': {
|
380 |
|
|
int c = _vl_vsss_peek(fp,floc,fromp);
|
381 |
|
|
if (c==EOF) goto done;
|
382 |
|
|
else _vl_vsss_advance(fp,floc);
|
383 |
|
|
owp[0] = c;
|
384 |
|
|
break;
|
385 |
|
|
}
|
386 |
|
|
case 's': {
|
387 |
|
|
_vl_vsss_skipspace(fp,floc,fromp);
|
388 |
|
|
_vl_vsss_read(fp,floc,fromp, tmp, NULL);
|
389 |
|
|
if (!tmp[0]) goto done;
|
390 |
|
|
int pos = strlen(tmp)-1;
|
391 |
|
|
for (int i=0; i<obits && pos>=0; pos--) {
|
392 |
|
|
_vl_vsss_setbit(owp,obits,lsb, 8, tmp[pos]); lsb+=8;
|
393 |
|
|
}
|
394 |
|
|
break;
|
395 |
|
|
}
|
396 |
|
|
case 'd': { // Signed decimal
|
397 |
|
|
_vl_vsss_skipspace(fp,floc,fromp);
|
398 |
|
|
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xz?_");
|
399 |
|
|
if (!tmp[0]) goto done;
|
400 |
|
|
vlsint64_t ld;
|
401 |
|
|
sscanf(tmp,"%lld",&ld);
|
402 |
|
|
VL_SET_WQ(owp,ld);
|
403 |
|
|
break;
|
404 |
|
|
}
|
405 |
|
|
case 't': // FALLTHRU // Time
|
406 |
|
|
case 'u': { // Unsigned decimal
|
407 |
|
|
_vl_vsss_skipspace(fp,floc,fromp);
|
408 |
|
|
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xz?_");
|
409 |
|
|
if (!tmp[0]) goto done;
|
410 |
|
|
QData ld;
|
411 |
|
|
sscanf(tmp,"%llu",&ld);
|
412 |
|
|
VL_SET_WQ(owp,ld);
|
413 |
|
|
break;
|
414 |
|
|
}
|
415 |
|
|
case 'b': {
|
416 |
|
|
_vl_vsss_skipspace(fp,floc,fromp);
|
417 |
|
|
_vl_vsss_read(fp,floc,fromp, tmp, "01xz?_");
|
418 |
|
|
if (!tmp[0]) goto done;
|
419 |
|
|
int pos = strlen(tmp)-1;
|
420 |
|
|
for (int i=0; i<obits && pos>=0; pos--) {
|
421 |
|
|
switch(tmp[pos]) {
|
422 |
|
|
case 'x': case 'z': case '?': //FALLTHRU
|
423 |
|
|
case '0': lsb++; break;
|
424 |
|
|
case '1': _vl_vsss_setbit(owp,obits,lsb, 1, 1); lsb++; break;
|
425 |
|
|
case '_': break;
|
426 |
|
|
}
|
427 |
|
|
}
|
428 |
|
|
break;
|
429 |
|
|
}
|
430 |
|
|
case 'o': {
|
431 |
|
|
_vl_vsss_skipspace(fp,floc,fromp);
|
432 |
|
|
_vl_vsss_read(fp,floc,fromp, tmp, "01234567xz?_");
|
433 |
|
|
if (!tmp[0]) goto done;
|
434 |
|
|
int pos = strlen(tmp)-1;
|
435 |
|
|
for (int i=0; i<obits && pos>=0; pos--) {
|
436 |
|
|
switch(tmp[pos]) {
|
437 |
|
|
case 'x': case 'z': case '?': //FALLTHRU
|
438 |
|
|
case '0': lsb+=3; break;
|
439 |
|
|
case '1': _vl_vsss_setbit(owp,obits,lsb, 3, 1); lsb+=3; break;
|
440 |
|
|
case '2': _vl_vsss_setbit(owp,obits,lsb, 3, 2); lsb+=3; break;
|
441 |
|
|
case '3': _vl_vsss_setbit(owp,obits,lsb, 3, 3); lsb+=3; break;
|
442 |
|
|
case '4': _vl_vsss_setbit(owp,obits,lsb, 3, 4); lsb+=3; break;
|
443 |
|
|
case '5': _vl_vsss_setbit(owp,obits,lsb, 3, 5); lsb+=3; break;
|
444 |
|
|
case '6': _vl_vsss_setbit(owp,obits,lsb, 3, 6); lsb+=3; break;
|
445 |
|
|
case '7': _vl_vsss_setbit(owp,obits,lsb, 3, 7); lsb+=3; break;
|
446 |
|
|
case '_': break;
|
447 |
|
|
}
|
448 |
|
|
}
|
449 |
|
|
break;
|
450 |
|
|
}
|
451 |
|
|
case 'x': {
|
452 |
|
|
_vl_vsss_skipspace(fp,floc,fromp);
|
453 |
|
|
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789abcdefxz?_");
|
454 |
|
|
if (!tmp[0]) goto done;
|
455 |
|
|
int pos = strlen(tmp)-1;
|
456 |
|
|
for (int i=0; i<obits && pos>=0; pos--) {
|
457 |
|
|
switch(tmp[pos]) {
|
458 |
|
|
case 'x': case 'z': case '?': //FALLTHRU
|
459 |
|
|
case '0': lsb+=4; break;
|
460 |
|
|
case '1': _vl_vsss_setbit(owp,obits,lsb, 4, 1); lsb+=4; break;
|
461 |
|
|
case '2': _vl_vsss_setbit(owp,obits,lsb, 4, 2); lsb+=4; break;
|
462 |
|
|
case '3': _vl_vsss_setbit(owp,obits,lsb, 4, 3); lsb+=4; break;
|
463 |
|
|
case '4': _vl_vsss_setbit(owp,obits,lsb, 4, 4); lsb+=4; break;
|
464 |
|
|
case '5': _vl_vsss_setbit(owp,obits,lsb, 4, 5); lsb+=4; break;
|
465 |
|
|
case '6': _vl_vsss_setbit(owp,obits,lsb, 4, 6); lsb+=4; break;
|
466 |
|
|
case '7': _vl_vsss_setbit(owp,obits,lsb, 4, 7); lsb+=4; break;
|
467 |
|
|
case '8': _vl_vsss_setbit(owp,obits,lsb, 4, 8); lsb+=4; break;
|
468 |
|
|
case '9': _vl_vsss_setbit(owp,obits,lsb, 4, 9); lsb+=4; break;
|
469 |
|
|
case 'a': _vl_vsss_setbit(owp,obits,lsb, 4, 10); lsb+=4; break;
|
470 |
|
|
case 'b': _vl_vsss_setbit(owp,obits,lsb, 4, 11); lsb+=4; break;
|
471 |
|
|
case 'c': _vl_vsss_setbit(owp,obits,lsb, 4, 12); lsb+=4; break;
|
472 |
|
|
case 'd': _vl_vsss_setbit(owp,obits,lsb, 4, 13); lsb+=4; break;
|
473 |
|
|
case 'e': _vl_vsss_setbit(owp,obits,lsb, 4, 14); lsb+=4; break;
|
474 |
|
|
case 'f': _vl_vsss_setbit(owp,obits,lsb, 4, 15); lsb+=4; break;
|
475 |
|
|
case '_': break;
|
476 |
|
|
}
|
477 |
|
|
}
|
478 |
|
|
break;
|
479 |
|
|
}
|
480 |
|
|
default:
|
481 |
|
|
string msg = string("%%Error: Unknown _vl_vsscanf code: ")+pos[0]+"\n";
|
482 |
|
|
vl_fatal(__FILE__,__LINE__,"",msg.c_str());
|
483 |
|
|
break;
|
484 |
|
|
} // switch
|
485 |
|
|
|
486 |
|
|
got++;
|
487 |
|
|
// Reload data if non-wide (if wide, we put it in the right place directly)
|
488 |
|
|
if (obits <= VL_BYTESIZE) {
|
489 |
|
|
CData* p = va_arg(ap,CData*); *p = owp[0];
|
490 |
|
|
} else if (obits <= VL_SHORTSIZE) {
|
491 |
|
|
SData* p = va_arg(ap,SData*); *p = owp[0];
|
492 |
|
|
} else if (obits <= VL_WORDSIZE) {
|
493 |
|
|
IData* p = va_arg(ap,IData*); *p = owp[0];
|
494 |
|
|
} else if (obits <= VL_QUADSIZE) {
|
495 |
|
|
QData* p = va_arg(ap,QData*); *p = VL_SET_QW(owp);
|
496 |
|
|
}
|
497 |
|
|
}
|
498 |
|
|
} // switch
|
499 |
|
|
}
|
500 |
|
|
}
|
501 |
|
|
done:
|
502 |
|
|
return got;
|
503 |
|
|
}
|
504 |
|
|
|
505 |
|
|
//===========================================================================
|
506 |
|
|
// File I/O
|
507 |
|
|
|
508 |
|
|
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
|
509 |
|
|
int lsb=obits-1;
|
510 |
|
|
bool start=true;
|
511 |
|
|
char* destp = destoutp;
|
512 |
|
|
for (; lsb>=0; lsb--) {
|
513 |
|
|
lsb = (lsb / 8) * 8; // Next digit
|
514 |
|
|
IData charval = (sourcep[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xff;
|
515 |
|
|
if (!start || charval) {
|
516 |
|
|
*destp++ = (charval==0)?' ':charval;
|
517 |
|
|
start = false; // Drop leading 0s
|
518 |
|
|
}
|
519 |
|
|
}
|
520 |
|
|
*destp++ = '\0'; // Terminate
|
521 |
|
|
while (isspace(*(destp-1)) && destp>destoutp) *--destp = '\0'; // Drop trailing spaces
|
522 |
|
|
}
|
523 |
|
|
|
524 |
|
|
void _VL_STRING_TO_VINT(int obits, void* destp, int srclen, const char* srcp) {
|
525 |
|
|
// Convert C string to Verilog format
|
526 |
|
|
int bytes = VL_BYTES_I(obits);
|
527 |
|
|
char* op = ((char*)(destp));
|
528 |
|
|
if (srclen > bytes) srclen = bytes; // Don't overflow destination
|
529 |
|
|
int i;
|
530 |
|
|
for (i=0; i<srclen; i++) { *op++ = srcp[srclen-1-i]; }
|
531 |
|
|
for (; i<bytes; i++) { *op++ = 0; }
|
532 |
|
|
}
|
533 |
|
|
|
534 |
|
|
IData VL_FGETS_IXQ(int obits, void* destp, QData fpq) {
|
535 |
|
|
FILE* fp = VL_CVT_Q_FP(fpq);
|
536 |
|
|
if (VL_UNLIKELY(!fp)) return 0;
|
537 |
|
|
|
538 |
|
|
// The string needs to be padded with 0's in unused spaces in front of
|
539 |
|
|
// any read data. This means we can't know in what location the first
|
540 |
|
|
// character will finally live, so we need to copy. Yuk.
|
541 |
|
|
IData bytes = VL_BYTES_I(obits);
|
542 |
|
|
char buffer[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
543 |
|
|
// V3Emit has static check that bytes < VL_TO_STRING_MAX_WORDS, but be safe
|
544 |
|
|
if (VL_UNLIKELY(bytes > VL_TO_STRING_MAX_WORDS*VL_WORDSIZE)) {
|
545 |
|
|
vl_fatal(__FILE__,__LINE__,"","Internal: fgets buffer overrun");
|
546 |
|
|
}
|
547 |
|
|
|
548 |
|
|
// We don't use fgets, as we must read \0s.
|
549 |
|
|
IData got = 0;
|
550 |
|
|
char* cp = buffer;
|
551 |
|
|
while (got < bytes) {
|
552 |
|
|
int c = getc(fp);
|
553 |
|
|
if (c==EOF) break;
|
554 |
|
|
*cp++ = c; got++;
|
555 |
|
|
if (c=='\n') break;
|
556 |
|
|
}
|
557 |
|
|
|
558 |
|
|
_VL_STRING_TO_VINT(obits, destp, got, buffer);
|
559 |
|
|
return got;
|
560 |
|
|
}
|
561 |
|
|
|
562 |
|
|
QData VL_FOPEN_QI(QData filename, IData mode) {
|
563 |
|
|
IData fnw[2]; VL_SET_WQ(fnw, filename);
|
564 |
|
|
return VL_FOPEN_WI(2, fnw, mode);
|
565 |
|
|
}
|
566 |
|
|
QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
|
567 |
|
|
char filenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
568 |
|
|
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, filenamez, filenamep);
|
569 |
|
|
char modez[5];
|
570 |
|
|
_VL_VINT_TO_STRING(VL_WORDSIZE, modez, &mode);
|
571 |
|
|
return VL_CVT_FP_Q(fopen(filenamez,modez));
|
572 |
|
|
}
|
573 |
|
|
|
574 |
|
|
void VL_WRITEF(const char* formatp, ...) {
|
575 |
|
|
va_list ap;
|
576 |
|
|
va_start(ap,formatp);
|
577 |
|
|
string output;
|
578 |
|
|
_vl_vsformat(output, formatp, ap);
|
579 |
|
|
va_end(ap);
|
580 |
|
|
|
581 |
|
|
// Users can redefine VL_PRINTF if they wish.
|
582 |
|
|
VL_PRINTF("%s", output.c_str());
|
583 |
|
|
}
|
584 |
|
|
|
585 |
|
|
void VL_FWRITEF(QData fpq, const char* formatp, ...) {
|
586 |
|
|
FILE* fp = VL_CVT_Q_FP(fpq);
|
587 |
|
|
if (VL_UNLIKELY(!fp)) return;
|
588 |
|
|
|
589 |
|
|
va_list ap;
|
590 |
|
|
va_start(ap,formatp);
|
591 |
|
|
string output;
|
592 |
|
|
_vl_vsformat(output, formatp, ap);
|
593 |
|
|
va_end(ap);
|
594 |
|
|
|
595 |
|
|
fputs(output.c_str(), fp);
|
596 |
|
|
}
|
597 |
|
|
|
598 |
|
|
IData VL_FSCANF_IX(QData fpq, const char* formatp, ...) {
|
599 |
|
|
FILE* fp = VL_CVT_Q_FP(fpq);
|
600 |
|
|
if (VL_UNLIKELY(!fp)) return 0;
|
601 |
|
|
|
602 |
|
|
va_list ap;
|
603 |
|
|
va_start(ap,formatp);
|
604 |
|
|
IData got = _vl_vsscanf(fp, 0, NULL, formatp, ap);
|
605 |
|
|
va_end(ap);
|
606 |
|
|
return got;
|
607 |
|
|
}
|
608 |
|
|
|
609 |
|
|
IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) {
|
610 |
|
|
IData fnw[2]; VL_SET_WI(fnw, ld);
|
611 |
|
|
|
612 |
|
|
va_list ap;
|
613 |
|
|
va_start(ap,formatp);
|
614 |
|
|
IData got = _vl_vsscanf(NULL, lbits, fnw, formatp, ap);
|
615 |
|
|
va_end(ap);
|
616 |
|
|
return got;
|
617 |
|
|
}
|
618 |
|
|
IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) {
|
619 |
|
|
IData fnw[2]; VL_SET_WQ(fnw, ld);
|
620 |
|
|
|
621 |
|
|
va_list ap;
|
622 |
|
|
va_start(ap,formatp);
|
623 |
|
|
IData got = _vl_vsscanf(NULL, lbits, fnw, formatp, ap);
|
624 |
|
|
va_end(ap);
|
625 |
|
|
return got;
|
626 |
|
|
}
|
627 |
|
|
IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...) {
|
628 |
|
|
va_list ap;
|
629 |
|
|
va_start(ap,formatp);
|
630 |
|
|
IData got = _vl_vsscanf(NULL, lbits, lwp, formatp, ap);
|
631 |
|
|
va_end(ap);
|
632 |
|
|
return got;
|
633 |
|
|
}
|
634 |
|
|
|
635 |
|
|
void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int,
|
636 |
|
|
QData ofilename, void* memp, IData start, IData end) {
|
637 |
|
|
IData fnw[2]; VL_SET_WQ(fnw, ofilename);
|
638 |
|
|
return VL_READMEM_W(hex,width,depth,array_lsb,2, fnw,memp,start,end);
|
639 |
|
|
}
|
640 |
|
|
|
641 |
|
|
void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
642 |
|
|
WDataInP ofilenamep, void* memp, IData start, IData end) {
|
643 |
|
|
char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
644 |
|
|
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep);
|
645 |
|
|
FILE* fp = fopen(ofilenamez, "r");
|
646 |
|
|
if (!fp) {
|
647 |
|
|
// We don't report the Verilog source filename as it slow to have to pass it down
|
648 |
|
|
vl_fatal (ofilenamez, 0, "", "$readmem file not found");
|
649 |
|
|
return;
|
650 |
|
|
}
|
651 |
|
|
// Prep for reading
|
652 |
|
|
IData addr = start;
|
653 |
|
|
int linenum = 1;
|
654 |
|
|
bool innum = false;
|
655 |
|
|
bool ignore_to_eol = false;
|
656 |
|
|
bool ignore_to_cmt = false;
|
657 |
|
|
bool needinc = false;
|
658 |
|
|
bool reading_addr = false;
|
659 |
|
|
int lastc = ' ';
|
660 |
|
|
// Read the data
|
661 |
|
|
// We process a character at a time, as then we don't need to deal
|
662 |
|
|
// with changing buffer sizes dynamically, etc.
|
663 |
|
|
while (1) {
|
664 |
|
|
int c = fgetc(fp);
|
665 |
|
|
if (c==EOF) break;
|
666 |
|
|
//printf("%d: Got '%c' Addr%x IN%d IgE%d IgC%d ninc%d\n", linenum, c, addr, innum, ignore_to_eol, ignore_to_cmt, needinc);
|
667 |
|
|
if (c=='\n') { linenum++; ignore_to_eol=false; if (innum) reading_addr=false; innum=false; }
|
668 |
|
|
else if (c=='\t' || c==' ' || c=='\r' || c=='\f') { if (innum) reading_addr=false; innum=false; }
|
669 |
|
|
// Skip // comments and detect /* comments
|
670 |
|
|
else if (ignore_to_cmt && lastc=='*' && c=='/') {
|
671 |
|
|
ignore_to_cmt = false; if (innum) reading_addr=false; innum=false;
|
672 |
|
|
} else if (!ignore_to_eol && !ignore_to_cmt) {
|
673 |
|
|
if (lastc=='/' && c=='*') { ignore_to_cmt = true; }
|
674 |
|
|
else if (lastc=='/' && c=='/') { ignore_to_eol = true; }
|
675 |
|
|
else if (c=='/') {} // Part of /* or //
|
676 |
|
|
else if (c=='_') {}
|
677 |
|
|
else if (c=='@') { reading_addr = true; innum=false; needinc=false; }
|
678 |
|
|
// Check for hex or binary digits as file format requests
|
679 |
|
|
else if (isxdigit(c)) {
|
680 |
|
|
c = tolower(c);
|
681 |
|
|
int value = (c >= 'a' ? (c-'a'+10) : (c-'0'));
|
682 |
|
|
if (!innum) { // Prep for next number
|
683 |
|
|
if (needinc) { addr++; needinc=false; }
|
684 |
|
|
}
|
685 |
|
|
if (reading_addr) {
|
686 |
|
|
// Decode @ addresses
|
687 |
|
|
if (!innum) addr=0;
|
688 |
|
|
addr = (addr<<4) + value;
|
689 |
|
|
} else {
|
690 |
|
|
needinc = true;
|
691 |
|
|
//printf(" Value width=%d @%x = %c\n", width, addr, c);
|
692 |
|
|
if (addr >= (IData)(depth+array_lsb) || addr < (IData)(array_lsb)) {
|
693 |
|
|
vl_fatal (ofilenamez, linenum, "", "$readmem file address beyond bounds of array");
|
694 |
|
|
} else {
|
695 |
|
|
int entry = addr - array_lsb;
|
696 |
|
|
QData shift = hex ? VL_ULL(4) : VL_ULL(1);
|
697 |
|
|
// Shift value in
|
698 |
|
|
if (width<=8) {
|
699 |
|
|
CData* datap = &((CData*)(memp))[entry];
|
700 |
|
|
if (!innum) { *datap = 0; }
|
701 |
|
|
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
|
702 |
|
|
} else if (width<=16) {
|
703 |
|
|
SData* datap = &((SData*)(memp))[entry];
|
704 |
|
|
if (!innum) { *datap = 0; }
|
705 |
|
|
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
|
706 |
|
|
} else if (width<=VL_WORDSIZE) {
|
707 |
|
|
IData* datap = &((IData*)(memp))[entry];
|
708 |
|
|
if (!innum) { *datap = 0; }
|
709 |
|
|
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
|
710 |
|
|
} else if (width<=VL_QUADSIZE) {
|
711 |
|
|
QData* datap = &((QData*)(memp))[entry];
|
712 |
|
|
if (!innum) { *datap = 0; }
|
713 |
|
|
*datap = ((*datap << (QData)(shift)) + (QData)(value)) & VL_MASK_Q(width);
|
714 |
|
|
} else {
|
715 |
|
|
WDataOutP datap = &((WDataOutP)(memp))[ entry*VL_WORDS_I(width) ];
|
716 |
|
|
if (!innum) { VL_ZERO_RESET_W(width, datap); }
|
717 |
|
|
_VL_SHIFTL_INPLACE_W(width, datap, shift);
|
718 |
|
|
datap[0] |= value;
|
719 |
|
|
}
|
720 |
|
|
if (value>=(1<<shift)) {
|
721 |
|
|
vl_fatal (ofilenamez, linenum, "", "$readmemb (binary) file contains hex characters");
|
722 |
|
|
}
|
723 |
|
|
}
|
724 |
|
|
}
|
725 |
|
|
innum = true;
|
726 |
|
|
}
|
727 |
|
|
else {
|
728 |
|
|
vl_fatal (ofilenamez, linenum, "", "$readmem file syntax error");
|
729 |
|
|
}
|
730 |
|
|
}
|
731 |
|
|
lastc = c;
|
732 |
|
|
}
|
733 |
|
|
if (needinc) { addr++; needinc=false; }
|
734 |
|
|
|
735 |
|
|
// Final checks
|
736 |
|
|
fclose(fp);
|
737 |
|
|
if (end != (IData)(~ VL_ULL(0)) && addr != (end+1)) {
|
738 |
|
|
vl_fatal (ofilenamez, linenum, "", "$readmem file ended before specified ending-address");
|
739 |
|
|
}
|
740 |
|
|
}
|
741 |
|
|
|
742 |
|
|
//===========================================================================
|
743 |
|
|
// Verilated:: Methods
|
744 |
|
|
|
745 |
|
|
const char* Verilated::catName(const char* n1, const char* n2) {
|
746 |
|
|
// Returns new'ed data
|
747 |
|
|
// Used by symbol table creation to make module names
|
748 |
|
|
static char* strp = NULL;
|
749 |
|
|
static int len = -1;
|
750 |
|
|
int newlen = strlen(n1)+strlen(n2)+2;
|
751 |
|
|
if (newlen > len) {
|
752 |
|
|
if (strp) delete [] strp;
|
753 |
|
|
strp = new char[newlen];
|
754 |
|
|
len = newlen;
|
755 |
|
|
}
|
756 |
|
|
strcpy(strp,n1);
|
757 |
|
|
strcat(strp,n2);
|
758 |
|
|
return strp;
|
759 |
|
|
}
|
760 |
|
|
|
761 |
|
|
//===========================================================================
|
762 |
|
|
// VerilatedModule:: Methods
|
763 |
|
|
|
764 |
|
|
VerilatedModule::VerilatedModule(const char* namep)
|
765 |
|
|
: m_namep(strdup(namep)) {
|
766 |
|
|
}
|
767 |
|
|
|
768 |
|
|
VerilatedModule::~VerilatedModule() {
|
769 |
|
|
if (m_namep) free((void*)m_namep); m_namep=NULL;
|
770 |
|
|
}
|
771 |
|
|
|
772 |
|
|
//===========================================================================
|