Compare commits

...
22 Commits
Author SHA1 Message Date
Wilson Snyder 39724eb916 Version bump 2012-09-03 20:03:25 -04:00
Jeremy Bennett 48dddd4ae7 Debug: Use dot label rather than a custom nTITLE node to label the graph. Generate all graph level attributes as attributes of the graph entity. bug555.
Signed-off-by: Wilson Snyder <[email protected]>
2012-08-27 19:02:27 -04:00
Wilson Snyder 9c00fd10de Add --savable to support model save/restore. 2012-08-26 21:19:43 -04:00
Jeremy Bennett 9309d0b00f Commentary on internals.pod, bug554.
Signed-off-by: Wilson Snyder <[email protected]>
2012-08-25 12:47:59 -04:00
Wilson Snyder 038b5d32a3 Commentary 2012-08-25 12:18:06 -04:00
Jeremy Bennett 706920ba19 Tests: t_vpi_var: Fix vector length, bug553.
Signed-off-by: Wilson Snyder <[email protected]>
2012-08-25 12:05:08 -04:00
Jeremy Bennett 39492a0726 Tidy up .gitignore and MANIFEST.SKIP, bug552.
Signed-off-by: Wilson Snyder <[email protected]>
2012-08-25 07:52:07 -04:00
Wilson Snyder df1170fea9 Test 2012-08-23 13:26:12 -04:00
Wilson Snyder f0e1d204fa Fix triangle symbol resolution error broke in 3.840, bug550.
This requires the parse symbol table persist across all parse runs. This is
probably more correct than before, but may result in some fallout if people
relied on data types not being persistant across separately parsed cells.
2012-08-15 21:28:30 -04:00
Wilson Snyder 8ece0a8a5f Create V3ParseSym. No functional change. 2012-08-15 21:14:20 -04:00
Wilson Snyder 1373b81e7c Include: Allow external progs to test command args 2012-08-14 20:37:15 -04:00
Wilson Snyder d3601dd561 Support '{} assignment pattern on structures, part of bug355. 2012-08-12 15:15:21 -04:00
Wilson Snyder f685cf1d0c Fix duplicate begin error broke in 3.840, bug548. 2012-08-10 19:39:18 -04:00
Wilson Snyder d5fcf0c153 Test for bug349 2012-08-08 22:15:07 -04:00
Wilson Snyder 5f9810070d Fix imports under multiple instantiated cells, bug542. 2012-08-08 21:59:17 -04:00
Wilson Snyder 923efa004b New tests 2012-08-07 20:59:34 -04:00
Wilson Snyder 869e8eab3c tests; check package to package refs 2012-08-07 20:37:28 -04:00
Wilson Snyder b51d197117 Fix defparam in generate broke in 3.840, bug543. 2012-08-07 18:24:51 -04:00
Wilson Snyder e4f0a8952c Fix double-deep parameter cell WIDTHs, bug541. 2012-08-02 07:02:57 -04:00
Wilson Snyder 072ee425f4 Fix previous mis-commit 2012-08-02 07:00:12 -04:00
Wilson Snyder a4c2819be2 Commentary 2012-07-31 19:23:19 -04:00
Wilson Snyder 2a274f9c19 Devel version 2012-07-31 18:53:51 -04:00
65 changed files with 2235 additions and 413 deletions
+1
View File
@@ -12,6 +12,7 @@
*.pdf
/Makefile
README
TAGS
autom4te.cache
config.cache
config.status
+17
View File
@@ -3,6 +3,23 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. [by ...]
indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.841 2012/09/03
*** Add --savable to support model save/restore. [Jeremy Bennett]
*** Support '{} assignment pattern on structures, part of bug355.
**** Fix double-deep parameter cell WIDTHs, bug541. [Hiroki Honda]
**** Fix imports under multiple instantiated cells, bug542. [Alex Solomatnikov]
**** Fix defparam in generate broke in 3.840, bug543. [Alex Solomatnikov]
**** Fix duplicate begin error broke in 3.840, bug548. [Alex Solomatnikov]
**** Fix triangle symbol resolution error broke in 3.840, bug550. [Ted Campbell]
* Verilator 3.840 2012/07/31 Beta
** Rewrote tristate handling; supports tri0, tri1, tristate bit selects,
+2
View File
@@ -36,3 +36,5 @@ nodist/
/vc_hdrs.h$
/csrc/
doxygen-doc/.*
TAGS
.*~
+28
View File
@@ -303,6 +303,7 @@ descriptions in the next sections for more information.
--private Debugging; see docs
--psl Enable PSL parsing
--public Debugging; see docs
--savable Enable model save-restore
--sc Create SystemC output
--sp Create SystemPerl output
--stats Create statistics file
@@ -816,6 +817,27 @@ inlining. This will also turn off inlining as if all modules had a
/*verilator public_module*/, unless the module specifically enabled it with
/*verilator inline_module*/.
=item --savable
Enable including save and restore functions in the generated model.
The user code must create a VerilatedSerialize or VerilatedDeserialze
object then calling the << or >> operators on the generated model and any
other data the process needs saved/restored. For example:
void save_model(const char* filenamep) {
VerilatedSave os;
os.open(filenamep);
os << main_time; // user code must save the timestamp, etc
os << *topp;
}
void restore_model(const char* filenamep) {
VerilatedRestore os;
os.open(filenamep);
os >> main_time;
os >> *topp;
}
=item --sc
Specifies SystemC output mode; see also --cc and -sp.
@@ -2374,6 +2396,12 @@ Increment/decrement can only be used as standalone statements or in for
loops. They cannot be used as side effect operators inside more complicate
expressions ("a = b++;").
=item '{} operator
Assignment patterns with order based, default, constant integer (array) or
member identifier (struct/union) keys are supported. Data type keys and
keys which are computed from a constant expression are not supported.
=item cast operator
Casting is supported only between simple scalar types, signed and unsigned,
+1 -1
View File
@@ -4,7 +4,7 @@
# redistribute it and/or modify it under the terms of either the GNU Lesser
# General Public License Version 3 or the Perl Artistic License Version 2.0.
AC_INIT([Verilator],[3.840 2012-07-31])
AC_INIT([Verilator],[3.841 2012-09-03])
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk)
+16 -5
View File
@@ -33,14 +33,10 @@
// Global variables
// Slow path variables
int Verilated::s_randReset = 0;
VerilatedVoidCb Verilated::s_flushCb = NULL;
// Keep below together in one cache line
int Verilated::s_debug = 0;
bool Verilated::s_calcUnusedSigs = false;
bool Verilated::s_gotFinish = false;
bool Verilated::s_assertOn = true;
Verilated::Serialized Verilated::s_s;
VL_THREAD const VerilatedScope* Verilated::t_dpiScopep = NULL;
VL_THREAD const char* Verilated::t_dpiFilename = "";
VL_THREAD int Verilated::t_dpiLineno = 0;
@@ -81,6 +77,17 @@ void vl_fatal (const char* filename, int linenum, const char* hier, const char*
}
#endif
//===========================================================================
// Overall class init
Verilated::Serialized::Serialized() {
s_randReset = 0;
s_debug = 0;
s_calcUnusedSigs = false;
s_gotFinish = false;
s_assertOn = true;
}
//===========================================================================
// Random reset -- Only called at init time, so don't inline.
@@ -1056,6 +1063,10 @@ void Verilated::commandArgs(int argc, const char** argv) {
VerilatedImp::commandArgs(argc,argv);
}
const char* Verilated::commandArgsPlusMatch(const char* prefixp) {
return VerilatedImp::argPlusMatch(prefixp).c_str();
}
void Verilated::scopesDump() {
VerilatedImp::scopesDump();
}
+23 -16
View File
@@ -219,14 +219,18 @@ struct Verilated {
// MEMBERS
private:
// Slow path variables
static int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
static VerilatedVoidCb s_flushCb; ///< Flush callback function
// Fast path
static int s_debug; ///< See accessors... only when VL_DEBUG set
static bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
static bool s_gotFinish; ///< A $finish statement executed
static bool s_assertOn; ///< Assertions are enabled
static struct Serialized { // All these members serialized/deserialized
// Slow path
int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
// Fast path
int s_debug; ///< See accessors... only when VL_DEBUG set
bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
bool s_gotFinish; ///< A $finish statement executed
bool s_assertOn; ///< Assertions are enabled
Serialized();
} s_s;
static VL_THREAD const VerilatedScope* t_dpiScopep; ///< DPI context scope
static VL_THREAD const char* t_dpiFilename; ///< DPI context filename
@@ -241,29 +245,29 @@ public:
/// 0 = Set to zeros
/// 1 = Set all bits to one
/// 2 = Randomize all bits
static void randReset(int val) { s_randReset=val; }
static int randReset() { return s_randReset; } ///< Return randReset value
static void randReset(int val) { s_s.s_randReset=val; }
static int randReset() { return s_s.s_randReset; } ///< Return randReset value
/// Enable debug of internal verilated code
static inline void debug(int level) { s_debug = level; }
static inline void debug(int level) { s_s.s_debug = level; }
#ifdef VL_DEBUG
static inline int debug() { return s_debug; } ///< Return debug value
static inline int debug() { return s_s.s_debug; } ///< Return debug value
#else
static inline int debug() { return 0; } ///< Constant 0 debug, so C++'s optimizer rips up
#endif
/// Enable calculation of unused signals
static void calcUnusedSigs(bool flag) { s_calcUnusedSigs=flag; }
static bool calcUnusedSigs() { return s_calcUnusedSigs; } ///< Return calcUnusedSigs value
static void calcUnusedSigs(bool flag) { s_s.s_calcUnusedSigs=flag; }
static bool calcUnusedSigs() { return s_s.s_calcUnusedSigs; } ///< Return calcUnusedSigs value
/// Did the simulation $finish?
static void gotFinish(bool flag) { s_gotFinish=flag; }
static bool gotFinish() { return s_gotFinish; } ///< Return if got a $finish
static void gotFinish(bool flag) { s_s.s_gotFinish=flag; }
static bool gotFinish() { return s_s.s_gotFinish; } ///< Return if got a $finish
/// Allow traces to at some point be enabled (disables some optimizations)
static void traceEverOn(bool flag) {
if (flag) { calcUnusedSigs(flag); }
}
/// Enable/disable assertions
static void assertOn(bool flag) { s_assertOn=flag; }
static bool assertOn() { return s_assertOn; }
static void assertOn(bool flag) { s_s.s_assertOn=flag; }
static bool assertOn() { return s_s.s_assertOn; }
/// Flush callback for VCD waves
static void flushCb(VerilatedVoidCb cb);
static void flushCall() { if (s_flushCb) (*s_flushCb)(); }
@@ -271,6 +275,7 @@ public:
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs
static void commandArgs(int argc, const char** argv);
static void commandArgs(int argc, char** argv) { commandArgs(argc,(const char**)argv); }
static const char* commandArgsPlusMatch(const char* prefixp);
/// For debugging, print text list of all scope names with
/// dpiImport/Export context. This function may change in future
@@ -292,6 +297,8 @@ public:
static const char* dpiFilenamep() { return t_dpiFilename; }
static int dpiLineno() { return t_dpiLineno; }
static int exportFuncNum(const char* namep);
static size_t serializedSize() { return sizeof(s_s); }
static void* serializedPtr() { return &s_s; }
};
//=========================================================================
+1 -1
View File
@@ -22,7 +22,7 @@
`define _VERILATED_V_ 1
// Hide verilator pragmas from other tools
`ifdef verilator `else
`ifdef VERILATOR `else
`define coverage_block_off
`endif
+3 -1
View File
@@ -55,7 +55,9 @@ class VerilatedImp {
// MEMBERS
static VerilatedImp s_s; ///< Static Singleton; One and only static this
ArgVec m_argVec; ///< Argument list
// Nothing here is save-restored; users expected to re-register appropriately
ArgVec m_argVec; ///< Argument list (NOT save-restored, may want different results)
bool m_argVecLoaded; ///< Ever loaded argument list
UserMap m_userMap; ///< Map of <(scope,userkey), userData>
ScopeNameMap m_nameMap; ///< Map of <scope_name, scope pointer>
+224
View File
@@ -0,0 +1,224 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2001-2012 by Wilson Snyder. This program is free software;
// you can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
//
// This is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
//=============================================================================
///
/// \file
/// \brief C++ Tracing in VCD Format
///
/// AUTHOR: Wilson Snyder
///
//=============================================================================
#include "verilatedos.h"
#include "verilated.h"
#include "verilated_save.h"
#include <fcntl.h>
#include <cerrno>
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h>
#else
# include <unistd.h>
#endif
// CONSTANTS
static const char* VLTSAVE_HEADER_STR = "verilatorsave01\n"; ///< Value of first bytes of each file
static const char* VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
//=============================================================================
//=============================================================================
//=============================================================================
// Searalization
bool VerilatedDeserialize::readDiffers (const void* __restrict datap, size_t size) {
bufferCheck();
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
vluint8_t miss = 0;
while (size--) {
miss |= (*dp++ ^ *m_cp++);
}
return (miss!=0);
}
VerilatedDeserialize& VerilatedDeserialize::readAssert (const void* __restrict datap, size_t size) {
if (VL_UNLIKELY(readDiffers(datap,size))) {
string msg = (string)"Can't deserialize save-restore file as was made from different model";
vl_fatal(filename().c_str(), 0, "", msg.c_str());
close();
}
return *this; // For function chaining
}
void VerilatedSerialize::header() {
VerilatedSerialize& os = *this; // So can cut and paste standard << code below
assert((strlen(VLTSAVE_HEADER_STR) & 7) == 0); // Keep aligned
os.write(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR));
// Verilated doesn't do it itself, as if we're not using save/restore
// it doesn't need to compile this stuff in
os.write(Verilated::serializedPtr(), Verilated::serializedSize());
}
void VerilatedDeserialize::header() {
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
string msg = (string)"Can't deserialize; file has wrong header signature";
vl_fatal(filename().c_str(), 0, "", msg.c_str());
close();
}
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
}
void VerilatedSerialize::trailer() {
VerilatedSerialize& os = *this; // So can cut and paste standard << code below
assert((strlen(VLTSAVE_TRAILER_STR) & 7) == 0); // Keep aligned
os.write(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR));
}
void VerilatedDeserialize::trailer() {
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
string msg = (string)"Can't deserialize; file has wrong end-of-file signature";
vl_fatal(filename().c_str(), 0, "", msg.c_str());
close();
}
}
//=============================================================================
//=============================================================================
//=============================================================================
// Opening/Closing
void VerilatedSave::open (const char* filenamep) {
if (isOpen()) return;
VL_DEBUG_IF(VL_PRINTF("-vltSave: opening save file %s\n",filenamep););
if (filenamep[0]=='|') {
assert(0); // Not supported yet.
} else {
m_fd = ::open (filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK
, 0666);
if (m_fd<0) {
// User code can check isOpen()
m_isOpen = false;
return;
}
}
m_isOpen = true;
m_filename = filenamep;
m_cp = m_bufp;
header();
}
void VerilatedRestore::open (const char* filenamep) {
if (isOpen()) return;
VL_DEBUG_IF(VL_PRINTF("-vltRestore: opening restore file %s\n",filenamep););
if (filenamep[0]=='|') {
assert(0); // Not supported yet.
} else {
m_fd = ::open (filenamep, O_CREAT|O_RDONLY|O_LARGEFILE
, 0666);
if (m_fd<0) {
// User code can check isOpen()
m_isOpen = false;
return;
}
}
m_isOpen = true;
m_filename = filenamep;
m_cp = m_bufp;
m_endp = m_bufp;
header();
}
void VerilatedSave::close () {
if (!isOpen()) return;
trailer();
flush();
m_isOpen = false;
::close(m_fd); // May get error, just ignore it
}
void VerilatedRestore::close () {
if (!isOpen()) return;
trailer();
flush();
m_isOpen = false;
::close(m_fd); // May get error, just ignore it
}
//=============================================================================
// Buffer management
void VerilatedSave::flush() {
if (VL_UNLIKELY(!isOpen())) return;
vluint8_t* wp = m_bufp;
while (1) {
ssize_t remaining = (m_cp - wp);
if (remaining==0) break;
errno = 0;
ssize_t got = ::write (m_fd, wp, remaining);
if (got>0) {
wp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
// write failed, presume error (perhaps out of disk space)
string msg = string(__FUNCTION__)+": "+strerror(errno);
vl_fatal("",0,"",msg.c_str());
close();
break;
}
}
}
m_cp = m_bufp; // Reset buffer
}
void VerilatedRestore::fill() {
if (VL_UNLIKELY(!isOpen())) return;
// Move remaining characters down to start of buffer. (No memcpy, overlaps allowed)
vluint8_t* rp = m_bufp;
for (vluint8_t* sp=m_cp; rp < m_endp;) *rp++ = *sp++; // Overlaps
m_endp = m_bufp + (m_endp - m_cp);
m_cp = m_bufp; // Reset buffer
// Read into buffer starting at m_endp
while (1) {
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
if (remaining==0) break;
errno = 0;
ssize_t got = ::read (m_fd, m_endp, remaining);
if (got>0) {
m_endp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
// write failed, presume error (perhaps out of disk space)
string msg = string(__FUNCTION__)+": "+strerror(errno);
vl_fatal("",0,"",msg.c_str());
close();
break;
}
} else { // got==0, EOF
// Fill buffer from here to end with NULLs so reader's don't need to check eof each character.
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
break;
}
}
}
//=============================================================================
// Serialization of types
+234
View File
@@ -0,0 +1,234 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2012-2012 by Wilson Snyder. This program is free software;
// you can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
//
// This is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
//=============================================================================
///
/// \file
/// \brief Save-restore serialization of verilated modules
///
/// AUTHOR: Wilson Snyder
///
//=============================================================================
#ifndef _VERILATED_SAVE_C_H_
#define _VERILATED_SAVE_C_H_ 1
#include "verilatedos.h"
#include <string>
using namespace std;
//=============================================================================
// VerilatedSerialBase - internal base class for common code between VerilatedSerialize and VerilatedDeserialize
class VerilatedSerialBase {
protected:
// MEMBERS
// For speed, keep m_cp as the first member of this structure
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
bool m_isOpen; ///< True indicates open file/stream
string m_filename;
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
inline static size_t bufferInsertSize() { return 16*1024; }
// CREATORS
VerilatedSerialBase() {
m_isOpen = false;
m_bufp = new vluint8_t [bufferSize()];
m_cp = m_bufp;
}
public:
// CREATORS
virtual ~VerilatedSerialBase() {
close();
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
}
// METHODS
bool isOpen() const { return m_isOpen; }
string filename() const { return m_filename; }
virtual void close() { flush(); }
virtual void flush() {}
};
//=============================================================================
// VerilatedSerialize - convert structures to a stream representation
class VerilatedSerialize : public VerilatedSerialBase {
protected:
virtual void close() { flush(); }
virtual void flush() {}
void header();
void trailer();
public:
// CREATORS
VerilatedSerialize() {}
virtual ~VerilatedSerialize() { close(); }
// METHODS
VerilatedSerialize& bufferCheck() {
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
flush();
}
return *this; // For function chaining
}
inline VerilatedSerialize& write (const void* __restrict datap, size_t size) {
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
while (size) {
bufferCheck();
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
const vluint8_t* __restrict maxp = dp + blk;
while (dp < maxp) *m_cp++ = *dp++;
size -= blk;
}
return *this; // For function chaining
}
};
//=============================================================================
// VerilatedDeserial - load structures from a stream representation
class VerilatedDeserialize : public VerilatedSerialBase {
protected:
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
virtual void fill() = 0;
void header();
void trailer();
public:
// CREATORS
VerilatedDeserialize() {}
virtual ~VerilatedDeserialize() { close(); }
// METHODS
inline VerilatedDeserialize& read (void* __restrict datap, size_t size) {
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
while (size) {
bufferCheck();
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
const vluint8_t* __restrict maxp = dp + blk;
while (dp < maxp) *dp++ = *m_cp++;
size -= blk;
}
return *this; // For function chaining
}
// Read a datum and compare with expected value
bool readDiffers (const void* __restrict datap, size_t size);
VerilatedDeserialize& readAssert (const void* __restrict datap, size_t size);
VerilatedDeserialize& readAssert (vluint64_t data) { return readAssert(&data, sizeof(data)); }
VerilatedDeserialize& bufferCheck() {
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
fill();
}
return *this; // For function chaining
}
};
//=============================================================================
// VerilatedSave - serialize to a file
class VerilatedSave : public VerilatedSerialize {
private:
int m_fd; ///< File descriptor we're writing to
public:
// CREATORS
VerilatedSave() {}
virtual ~VerilatedSave() { close(); }
// METHODS
void open(const char* filenamep); ///< Open the file; call isOpen() to see if errors
void open(const string& filename) { open(filename.c_str()); }
virtual void close();
virtual void flush();
};
//=============================================================================
// VerilatedRestore - deserialize from a file
class VerilatedRestore : public VerilatedDeserialize {
private:
int m_fd; ///< File descriptor we're writing to
public:
// CREATORS
VerilatedRestore() {}
virtual ~VerilatedRestore() { close(); }
// METHODS
void open(const char* filenamep); ///< Open the file; call isOpen() to see if errors
void open(const string& filename) { open(filename.c_str()); }
virtual void close();
virtual void flush() {}
virtual void fill();
};
//=============================================================================
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint64_t& rhs) {
return os.write(&rhs, sizeof(rhs));
}
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint64_t& rhs){
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint32_t& rhs) {
return os.write(&rhs, sizeof(rhs));
}
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint32_t& rhs) {
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint16_t& rhs) {
return os.write(&rhs, sizeof(rhs));
}
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint16_t& rhs) {
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint8_t& rhs) {
return os.write(&rhs, sizeof(rhs));
}
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint8_t& rhs) {
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, bool& rhs) {
return os.write(&rhs, sizeof(rhs));
}
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, bool& rhs) {
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, double& rhs) {
return os.write(&rhs, sizeof(rhs));
}
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, double& rhs) {
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, float& rhs) {
return os.write(&rhs, sizeof(rhs));
}
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, float& rhs) {
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, string& rhs) {
vluint32_t len=rhs.length();
os<<len;
return os.write(rhs.data(), len);
}
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, string& rhs) {
vluint32_t len;
os>>len;
rhs.resize(len);
return os.read((void*)rhs.data(), len);
}
#endif // guard
+173 -35
View File
@@ -14,32 +14,6 @@ the first for reference for developers and debugging problems.
See also the Verilator internals presentation at http://www.veripool.org.
=head1 ADDING A NEW FEATURE
Generally what would you do to add a new feature?
=over 4
File a bug (if there isn't already) so others know what you're working on.
Make a testcase in the test_regress/t/t_EXAMPLE format, see TESTING Below.
If grammar changes are needed, look at the git version of VerilogPerl's
src/VParseGrammar.y, as this grammar supports the full SystemVerilog
language and has a lot of back-and-forth with Verilator's grammar. Copy
the appropriate rules to src/verilog.y and modify the productions.
If a new Ast type is needed, add it to V3AstNodes.h.
Now you can run "test_regress/t/t_{new testcase}.pl --debug" and it'll
probably fail but you'll see a test_regress/obj_dir/t_{newtestcase}/*.tree
file which you can examine to see if the parsing worked. See also the
sections below on debugging.
Modify the later visitor functions to process the new feature as needed.
=back
=head1 CODE FLOWS
=head2 Verilator Flow
@@ -93,6 +67,10 @@ Verilator finally writes the C++ modules.
=head2 Key Classes Used in the Verilator Flow
=over 4
=item C<AstNode>
The AST is represented at the top level by the class C<AstNode>. This abstract
class has derived classes for the individual components (e.g. C<AstGenerate>
for a generate block) or groups of components (e.g. C<AstNodeFTask> for
@@ -119,11 +97,64 @@ are at the top of the tree.
By convention, each function/method uses the variable C<nodep> as a pointer
to the C<AstNode> currently being processed.
=item C<AstNVistor>
The passes are implemented by AST visitor classes (see L</Visitor
Functions>). These are implemented by subclasses of the abstract class,
C<AstNVisitor>. Each pass creates an instance of the visitor class, which
in turn implements a method to perform the pass.
=item C<V3Graph>
A number of passes use graph algorithms, and the class C<V3Graph> is provided
to represent those graphs. Graphs are directed, and algorithms are provided to
manipulate the graphs and to output them in I<GraphViz> dot format (see
L<http://www.graphviz.org/>). C<V3Graph.h> provides documentation of this
class.
=item C<V3GraphVertex>
This is the base class for vertices in a graph. Vertices have an associated
C<fanout>, C<color> and C<rank>, which may be used in algorithms for ordering
the graph. A generic C<user>/C<userp> member variable is also provided.
Virtual methods are provided to specify the name, color, shape and style to be
used in dot output. Typically users provided derived classes from
C<V3GraphVertex> which will reimplement these methods.
Iterators are provided to access in and out edges. Typically these are used in
the form:
for (V3GraphEdge *edgep = vertexp->inBeginp();
edgep;
edgep = edgep->inNextp()) {
=item C<V3GraphEdge>
This is the base class for directed edges between pairs of vertices. Edges
have an associated C<weight> and may also be made C<cutable>. A generic
C<user>/C<userp> member variable is also provided.
Accessors, C<fromp> and C<top> return the "from" and "to" vertices
respectively.
Virtual methods are provided to specify the label, color and style to be
used in dot output. Typically users provided derived classes from
C<V3GraphEdge> which will reimplement these methods.
=item C<V3GraphAlg>
This is the base class for graph algorithms. It implements a C<bool> method,
C<followEdge> which algorithms can use to decide whether an edge is
followed. This method returns true if the graph edge has weight greater than
one and a user function, C<edgeFuncp> (supplied in the constructor) returns
C<true>.
A number of predefined derived algorithm classes and access methods are
provided and documented in C<V3GraphAlg.cpp>.
=back
=head2 Verilated Flow
The evaluation loop outputted by Verilator is designed to allow a single
@@ -178,16 +209,15 @@ TREEOP macro.
The original C++ source code is transformed into C++ code in the C<obj_opt>
and C<obj_dbg> sub-directories (the former for the optimized version of
verilator, the latter for the debug version). So for example C<V3Const.cpp>
Verilator, the latter for the debug version). So for example C<V3Const.cpp>
into C<V3Const__gen.cpp>.
=head2 Visitor Functions
The verilator uses the I<Visitor> design pattern to implement its
refinement and optimization passes. This allows separation of the pass
algorithm from the AST on which it operates. Wikipedia provides an
introduction to the concept at
L<http://en.wikipedia.org/wiki/Visitor_pattern>.
Verilator uses the I<Visitor> design pattern to implement its refinement
and optimization passes. This allows separation of the pass algorithm from
the AST on which it operates. Wikipedia provides an introduction to the
concept at L<http://en.wikipedia.org/wiki/Visitor_pattern>.
As noted above, all visitors are derived classes of C<AstNvisitor>. All
derived classes of C<AstNode> implement the C<accept> method, which takes
@@ -339,7 +369,68 @@ AST.
To write a test see the BUGS section of the Verilator primary manual, and
the documentation in:
test_regress/t/driver.pl --help
test_regress/t/driver.pl --help
Developers will also want to configure with two extra flags:
=over 4
=item --enable-ccwarn
Causes the build to stop on warnings as well as errors. A good way to
ensure no sloppy code gets added, however it can be painful when it comes
to testing, since third party code used in the tests (e.g. SystemC) may not
be warning free.
=item --enable-long-tests
In addition to the standard C, SystemC and SystemPerl tests also run the
tests in the C<test_vcs>, C<test_verilated> and C<test_regress> directories
when using I<make test>. This is disabled by default as SystemC/SystemPerl
installation problems would otherwise falsely indicate a Verilator problem.
=back
When enabling the long tests, some additional PERL modules are needed, which
you can install using cpan.
cpan install Unix::Processors
There are some traps to avoid when running regression tests
=over 4
=item *
The regression tests will assume that you have a version of SystemPerl to
match. Typically if working on Verilator from git, also use SystemPerl from
git.
=item *
When checking the MANIFEST, the test will barf on unexpected code in the
Verilator tree. So make sure to keep any such code outside the tree.
=item *
Not all Linux systems install Perldoc by default. This is needed for the
I<--help> option to Verilator, and also for regression testing. This can be
installed using cpan:
cpan install Pod::Perldoc
Many Linux systems also offer a standard package for this. Red
Hat/Fedora/Centos offer I<perl-Pod-Perldoc>, while Debian/Ubuntu/Linux Mint
offer I<perl-doc>.
=item *
Running regression may exhaust resources on some Linux systems, particularly
file handles and user processes. Increase these to respectively 16,384 and
4,096. The method of doing this is system dependent, but on Fedora Linux it
would require editing the C</etc/security/limits.conf> file as root.
=back
=head1 DEBUGGING
@@ -376,6 +467,9 @@ algorithmic stage. An example:
=over 4
The following summarizes the above example dump, with more detail on each
field in the section below.
"1:2:" indicates the hierarchy of the C<VAR> is the C<op2p> pointer under
the C<MODULE>, which in turn is the C<op1p> pointer under the C<NETLIST>
@@ -439,7 +533,7 @@ Of the form C<< <ennnn> >> or C<< <ennnn#> >> , where C<nnnn> is the number
of the last edit to modify this node. The trailing C<#> indicates the node
has been edited since the last tree dump (which typically means in the last
refinement or optimization pass). GDB can watch for this, see L</Debugging
with GDB> below.
with GDB>.
=item Source file and line
@@ -498,7 +592,7 @@ under gdb and break when an error is hit or the program is about to exit.
You can also use --debug --gdbbt to just backtrace and then exit gdb. To
debug the Verilated executable, use --gdbsim.
If you wish to start verilator under GDB (or another debugger), then you
If you wish to start Verilator under GDB (or another debugger), then you
can use --debug and look at the underlying invocation of verilator_dgb. For
example
@@ -548,6 +642,50 @@ backtrace. You will typically see a frame sequence something like
visit()
...
=head1 ADDING A NEW FEATURE
Generally what would you do to add a new feature?
=over 4
=item 1.
File a bug (if there isn't already) so others know what you're working on.
=item 2.
Make a testcase in the test_regress/t/t_EXAMPLE format, see L<TESTING>.
=item 3.
If grammar changes are needed, look at the git version of VerilogPerl's
src/VParseGrammar.y, as this grammar supports the full SystemVerilog
language and has a lot of back-and-forth with Verilator's grammar. Copy
the appropriate rules to src/verilog.y and modify the productions.
=item 4.
If a new Ast type is needed, add it to V3AstNodes.h.
=back
Now you can run "test_regress/t/t_{new testcase}.pl --debug" and it'll
probably fail but you'll see a test_regress/obj_dir/t_{newtestcase}/*.tree
file which you can examine to see if the parsing worked. See also the
sections above on debugging.
Modify the later visitor functions to process the new feature as needed.
=head2 Adding a new pass
For more substantial changes you may need to add a new pass. The simplest way
to do this is to copy the C<.cpp> and C<.h> files from an existing
pass. You'll need to add a call into your pass from the C<process()> function
in C<src/verilator.cpp>.
To get your pass to build you'll need to add its binary filename to the list
in C<src/Makefile_obj.in> and reconfigure.
=head1 DISTRIBUTION
The latest version is available from L<http://www.veripool.org/>.
+1
View File
@@ -219,6 +219,7 @@ RAW_OBJS = \
V3SplitAs.o \
V3Stats.o \
V3StatsReport.o \
V3String.o \
V3Subst.o \
V3Table.o \
V3Task.o \
+39
View File
@@ -3905,6 +3905,45 @@ struct AstFGetS : public AstNodeBiop {
AstNode* filep() const { return rhsp(); }
};
struct AstPattern : public AstNodeMath {
// Verilog '{a,b,c,d...}
// Parents: AstNodeAssign, AstPattern, ...
// Children: expression, AstPattern, AstPatReplicate
AstPattern(FileLine* fl, AstNode* itemsp) : AstNodeMath(fl) {
addNOp1p(itemsp);
}
ASTNODE_NODE_FUNCS(Pattern, PATTERN)
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; }
virtual string emitC() { V3ERROR_NA; return "";}
virtual string emitSimpleOperator() { V3ERROR_NA; return "";}
virtual bool cleanOut() {V3ERROR_NA; return "";}
virtual int instrCount() const { return widthInstrs(); }
AstNode* itemsp() const { return op1p(); } // op1 = AstPatReplicate, AstPatMember, etc
};
struct AstPatMember : public AstNodeMath {
// Verilog '{a} or '{a{b}}
// Parents: AstPattern
// Children: expression, AstPattern, replication count
private:
bool m_default;
public:
AstPatMember(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* repp) : AstNodeMath(fl) {
setOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); m_default = false; }
ASTNODE_NODE_FUNCS(PatMember, PATMEMBER)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; }
virtual string emitVerilog() { return lhsp()?"%f{%r{%k%l}}":"%l"; }
virtual string emitC() { V3ERROR_NA; return "";}
virtual string emitSimpleOperator() { V3ERROR_NA; return "";}
virtual bool cleanOut() {V3ERROR_NA; return "";}
virtual int instrCount() const { return widthInstrs()*2; }
AstNode* lhsp() const { return op1p(); } // op1 = expression to assign or another AstPattern
AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text)
AstNode* repp() const { return op3p(); } // op3 = replication count, or NULL for count 1
bool isDefault() const { return m_default; }
void isDefault(bool flag) { m_default = flag; }
};
//======================================================================
// SysVerilog assertions
+6 -3
View File
@@ -134,9 +134,11 @@ private:
if (m_unnamedScope=="") m_unnamedScope = ident;
else m_unnamedScope = m_unnamedScope + "__DOT__"+ident;
// Create CellInline for dotted var resolution
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
m_unnamedScope, "__BEGIN__");
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
if (!m_ftaskp) {
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
m_unnamedScope, "__BEGIN__");
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
}
}
@@ -184,6 +186,7 @@ private:
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Inline
if (nodep->user1SetOnce()) return; // Don't double-add text's
if (m_namedScope != "") {
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
+2 -1
View File
@@ -25,6 +25,7 @@
#include <set>
#include "V3Global.h"
#include "V3String.h"
#include "V3Config.h"
//######################################################################
@@ -89,7 +90,7 @@ class V3ConfigIgnores {
it = m_ignFiles.find(filename);
// Make new list for this file of all matches
for (IgnFiles::iterator fnit = m_ignWilds.begin(); fnit != m_ignWilds.end(); ++fnit) {
if (V3Options::wildmatch(filename.c_str(), fnit->first.c_str())) {
if (VString::wildmatch(filename.c_str(), fnit->first.c_str())) {
for (IgnLines::iterator lit = fnit->second.begin(); lit != fnit->second.end(); ++lit) {
it->second.insert(*lit);
}
+94 -2
View File
@@ -29,6 +29,7 @@
#include <algorithm>
#include "V3Global.h"
#include "V3String.h"
#include "V3EmitC.h"
#include "V3EmitCBase.h"
@@ -842,6 +843,7 @@ class EmitCImp : EmitCStmts {
void emitCoverageDecl(AstNodeModule* modp);
void emitCoverageImp(AstNodeModule* modp);
void emitDestructorImp(AstNodeModule* modp);
void emitSavableImp(AstNodeModule* modp);
void emitTextSection(AstType type);
void emitIntFuncDecls(AstNodeModule* modp);
// High level
@@ -1436,7 +1438,7 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
// compatible, and have a common wrapper.
puts("void "+modClassName(m_modp)+"::__vlCoverInsert(uint32_t* countp, bool enable, const char* filenamep, int lineno, int column,\n");
puts( "const char* hierp, const char* pagep, const char* commentp) {\n");
puts( "static uint32_t fake_zero_count = 0;\n");
puts( "static uint32_t fake_zero_count = 0;\n"); // static doesn't need save-restore as constant
puts( "if (!enable) countp = &fake_zero_count;\n"); // Used for second++ instantiation of identical bin
puts( "*countp = 0;\n");
puts( "SP_COVER_INSERT(countp,");
@@ -1459,6 +1461,79 @@ void EmitCImp::emitDestructorImp(AstNodeModule* modp) {
puts("}\n");
}
void EmitCImp::emitSavableImp(AstNodeModule* modp) {
if (v3Global.opt.savable() ) {
puts("\n// Savable\n");
for (int de=0; de<2; ++de) {
string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize";
string funcname = de ? "__Vdeserialize" : "__Vserialize";
string writeread = de ? "read" : "write";
string op = de ? ">>" : "<<";
puts("void "+modClassName(modp)+"::"+funcname+"("+classname+"& os) {\n");
// Place a computed checksum to insure proper structure save/restore formatting
// OK if this hash includes some things we won't dump, since just looking for loading the wrong model
VHashFnv hash;
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstVar* varp = nodep->castVar()) {
hash.hash(varp->name());
hash.hash(varp->dtypep()->width());
}
}
ofp()->printf( "vluint64_t __Vcheckval = VL_ULL(0x%" VL_PRI64 "x);\n",
hash.value());
if (de) {
puts("os.readAssert(__Vcheckval);\n");
} else {
puts("os<<__Vcheckval;\n");
}
// Save all members
if (v3Global.opt.inhibitSim()) puts("os"+op+"__Vm_inhibitSim;\n");
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstVar* varp = nodep->castVar()) {
if (varp->isIO() && modp->isTop() && optSystemC()) {
// System C top I/O doesn't need loading, as the lower level subinst code does it.
}
else if (varp->isParam()) {}
else if (varp->isStatic() && varp->isConst()) {}
else {
int vects = 0;
// This isn't very robust and may need cleanup for other data types
for (AstArrayDType* arrayp=varp->dtypeSkipRefp()->castArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castArrayDType()) {
int vecnum = vects++;
if (arrayp->msb() < arrayp->lsb()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
string ivar = string("__Vi")+cvtToStr(vecnum);
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts("{ int __Vi"+cvtToStr(vecnum)+"="+cvtToStr(0)+";");
puts(" for (; "+ivar+"<"+cvtToStr(arrayp->elementsConst()));
puts("; ++"+ivar+") {\n");
}
if (varp->basicp() && (varp->basicp()->keyword() == AstBasicDTypeKwd::STRING
|| !varp->basicp()->isWide())) {
puts("os"+op+varp->name());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
puts(";\n");
} else {
puts("os."+writeread+"(&"+varp->name());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
puts(",sizeof("+varp->name());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
puts("));\n");
}
for (int v=0; v<vects; ++v) puts( "}}\n");
}
}
}
if (modp->isTop()) { // Save the children
puts( "__VlSymsp->"+funcname+"(os);\n");
}
puts("}\n");
}
}
}
void EmitCImp::emitStaticDecl(AstNodeModule* modp) {
// Need implementation here. Be careful of alignment code; needs to be uniquified
// with module name to avoid multiple symbols.
@@ -1675,8 +1750,12 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
} else {
puts("#include \"verilated.h\"\n");
}
if (v3Global.opt.savable()) {
puts("#include \"verilated_save.h\"\n");
}
if (v3Global.opt.coverage()) {
puts("#include \"SpCoverage.h\"\n");
if (v3Global.opt.savable()) v3error("--coverage and --savable not supported together");
}
if (v3Global.needHInlines()) { // Set by V3EmitCInlines; should have been called before us
puts("#include \""+topClassName()+"__Inlines.h\"\n");
@@ -1842,10 +1921,22 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("static void traceFull ("+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code);\n");
puts("static void traceChg ("+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code);\n");
}
if (v3Global.opt.savable()) {
puts("void __Vserialize(VerilatedSerialize& os);\n");
puts("void __Vdeserialize(VerilatedDeserialize& os);\n");
puts("\n");
}
puts("} VL_ATTR_ALIGNED(64);\n");
puts("} VL_ATTR_ALIGNED(128);\n");
puts("\n");
// Save/restore
if (v3Global.opt.savable() && modp->isTop()) {
puts("inline VerilatedSerialize& operator<<(VerilatedSerialize& os, "+modClassName(modp)+"& rhs) {rhs.__Vserialize(os); return os;}\n");
puts("inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, "+modClassName(modp)+"& rhs) {rhs.__Vdeserialize(os); return os;}\n");
puts("\n");
}
// finish up h-file
if (!optSystemPerl()) {
puts("#endif /*guard*/\n");
@@ -1893,6 +1984,7 @@ void EmitCImp::emitImp(AstNodeModule* modp) {
emitCtorImp(modp);
emitConfigureImp(modp);
emitDestructorImp(modp);
emitSavableImp(modp);
emitCoverageImp(modp);
}
+27 -1
View File
@@ -339,8 +339,13 @@ void EmitCSyms::emitSymHdr() {
puts("\n// METHODS\n");
puts("inline const char* name() { return __Vm_namep; }\n");
puts("inline bool getClearActivity() { bool r=__Vm_activity; __Vm_activity=false; return r;}\n");
if (v3Global.opt.savable() ) {
puts("void __Vserialize(VerilatedSerialize& os);\n");
puts("void __Vdeserialize(VerilatedDeserialize& os);\n");
}
puts("\n");
puts("} VL_ATTR_ALIGNED(64);\n");
puts("\n");
puts("#endif /*guard*/\n");
}
@@ -498,7 +503,28 @@ void EmitCSyms::emitSymImp() {
}
puts("}\n");
puts("\n");
if (v3Global.opt.savable() ) {
puts("\n");
for (int de=0; de<2; ++de) {
string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize";
string funcname = de ? "__Vdeserialize" : "__Vserialize";
string op = de ? ">>" : "<<";
puts("void "+symClassName()+"::"+funcname+"("+classname+"& os) {\n");
puts( "// LOCAL STATE\n");
// __Vm_namep presumably already correct
puts( "os"+op+"__Vm_activity;\n");
puts( "os"+op+"__Vm_didInit;\n");
puts( "// SUBCELL STATE\n");
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
if (!modp->isTop()) {
puts( scopep->nameDotless()+"."+funcname+"(os);\n");
}
}
puts("}\n");
}
}
}
//######################################################################
+3
View File
@@ -80,6 +80,9 @@ public:
if (v3Global.dpi()) {
putMakeClassEntry(of, "verilated_dpi.cpp");
}
if (v3Global.opt.savable()) {
putMakeClassEntry(of, "verilated_save.cpp");
}
if (v3Global.opt.systemPerl()) {
putMakeClassEntry(of, "Sp.cpp"); // Note Sp.cpp includes SpTraceVcdC
}
+3 -2
View File
@@ -29,6 +29,7 @@
#include <algorithm>
#include "V3Global.h"
#include "V3String.h"
#include "V3EmitXml.h"
#include "V3EmitCBase.h"
@@ -64,12 +65,12 @@ class EmitXmlFileVisitor : public EmitCBaseVisitor {
// XML methods
void outputTag(AstNode* nodep, string tag) {
if (tag=="") tag = V3Options::downcase(nodep->typeName());
if (tag=="") tag = VString::downcase(nodep->typeName());
puts("<"+tag+" "+nodep->fileline()->xml());
if (nodep->name()!="") { puts(" name="); putsQuoted(nodep->prettyName()); }
}
void outputChildrenEnd(AstNode* nodep, string tag) {
if (tag=="") tag = V3Options::downcase(nodep->typeName());
if (tag=="") tag = VString::downcase(nodep->typeName());
if (nodep->op1p() || nodep->op2p() || nodep->op3p() || nodep->op4p()) {
puts(">\n");
nodep->iterateChildren(*this);
+4 -4
View File
@@ -275,10 +275,10 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) {
// Header
*logp<<"digraph v3graph {\n";
*logp<<"\trankdir="<<dotRankDir()<<"\n";
*logp<<"\t//size="<<"\"7.5,10\""<<"\n";
*logp<<"\tnTITLE\t[fontsize=20 label=\""<<filename<<"\", shape=box, style=bold, color=black];\n";
*logp<<"\n";
*logp<<"\tgraph\t[label=\""<<filename<<"\",\n";
*logp<<"\t\t labelloc=t, labeljust=l,\n";
*logp<<"\t\t //size="<<"\"7.5,10\","<<"\n";
*logp<<"\t\t rankdir="<<dotRankDir()<<"];\n";
// List of all possible subgraphs
typedef multimap<string,V3GraphVertex*> SubgraphMmap;
+7 -4
View File
@@ -96,6 +96,7 @@ private:
// STATE
V3InFilter* m_filterp; // Parser filter
V3ParseSym* m_parseSymp; // Parser symbol table
// Below state needs to be preserved between each module call.
AstNodeModule* m_modp; // Current module
@@ -202,7 +203,7 @@ private:
// Read-subfile
// If file not found, make AstNotFoundModule, rather than error out.
// We'll throw the error when we know the module will really be needed.
V3Parse parser (v3Global.rootp(), m_filterp);
V3Parse parser (v3Global.rootp(), m_filterp, m_parseSymp);
parser.parseFile(nodep->fileline(), nodep->modName(), false, "");
V3Error::abortIfErrors();
// We've read new modules, grab new pointers to their names
@@ -284,6 +285,7 @@ private:
if (nodep->modp()) {
nodep->iterateChildren(*this);
}
UINFO(4," Link Cell done: "<<nodep<<endl);
}
// Accelerate the recursion
@@ -316,9 +318,10 @@ private:
public:
// CONSTUCTORS
LinkCellsVisitor(AstNetlist* rootp, V3InFilter* filterp)
LinkCellsVisitor(AstNetlist* rootp, V3InFilter* filterp, V3ParseSym* parseSymp)
: m_mods(rootp) {
m_filterp = filterp;
m_parseSymp = parseSymp;
m_modp = NULL;
m_libVertexp = NULL;
m_topVertexp = NULL;
@@ -330,7 +333,7 @@ public:
//######################################################################
// Link class functions
void V3LinkCells::link(AstNetlist* rootp, V3InFilter* filterp) {
void V3LinkCells::link(AstNetlist* rootp, V3InFilter* filterp, V3ParseSym* parseSymp) {
UINFO(4,__FUNCTION__<<": "<<endl);
LinkCellsVisitor visitor (rootp, filterp);
LinkCellsVisitor visitor (rootp, filterp, parseSymp);
}
+2 -1
View File
@@ -26,12 +26,13 @@
#include "V3Ast.h"
class V3InFilter;
class V3ParseSym;
//============================================================================
class V3LinkCells {
public:
static void link(AstNetlist* nodep, V3InFilter* filterp);
static void link(AstNetlist* nodep, V3InFilter* filterp, V3ParseSym* parseSymp);
};
#endif // Guard
+15 -4
View File
@@ -544,6 +544,10 @@ private:
m_statep->insertInline(aboveSymp, m_modSymp, nodep, nodep->name());
}
}
virtual void visit(AstDefParam* nodep, AstNUser*) {
nodep->user1p(m_curSymp);
nodep->iterateChildren(*this);
}
virtual void visit(AstGenerate* nodep, AstNUser*) {
// Begin: ... blocks often replicate under genif/genfor, so simply suppress duplicate checks
// See t_gen_forif.v for an example.
@@ -739,8 +743,7 @@ private:
}
}
m_curSymp->import(srcp, nodep->name());
// No longer needed
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
// No longer needed, but can't delete until any multi-instantiated modules are expanded
}
virtual void visit(AstNode* nodep, AstNUser*) {
@@ -834,14 +837,15 @@ private:
virtual void visit(AstDefParam* nodep, AstNUser*) {
nodep->iterateChildren(*this);
nodep->v3warn(DEFPARAM,"Suggest replace defparam with Verilog 2001 #(."<<nodep->name()<<"(...etc...))");
VSymEnt* foundp = m_statep->getNodeSym(m_modp)->findIdFallback(nodep->path());
VSymEnt* foundp = m_statep->getNodeSym(nodep)->findIdFallback(nodep->path());
AstCell* cellp = foundp->nodep()->castCell();
if (!cellp) {
nodep->v3error("In defparam, cell "<<nodep->path()<<" never declared");
} else {
AstNode* exprp = nodep->rhsp()->unlinkFrBack();
UINFO(9,"Defparam cell "<<nodep->path()<<"."<<nodep->name()
<<" <= "<<exprp<<endl);
<<" attach-to "<<cellp
<<" <= "<<exprp<<endl);
// Don't need to check the name of the defparam exists. V3Param does.
AstPin* pinp = new AstPin (nodep->fileline(),
-1, // Pin# not relevant
@@ -1292,6 +1296,7 @@ private:
<<"'"<<" as a "<<foundp->nodep()->typeName()
<<" but expected a "<<expectWhat);
} else if (m_dotText=="") {
UINFO(7," ErrParseRef curSymp=se"<<(void*)m_curSymp<<" dotSymp=se"<<(void*)m_dotSymp<<endl);
nodep->v3error("Can't find definition of "<<expectWhat
<<": "<<nodep->prettyName());
} else {
@@ -1440,7 +1445,9 @@ private:
nodep->packagep(foundp->packagep());
UINFO(7," Resolved "<<nodep<<endl); // Also prints taskp
} else {
// Note ParseRef has similar error handling/message output
m_statep->preErrorDump();
UINFO(7," ErrFtask curSymp=se"<<(void*)m_curSymp<<" dotSymp=se"<<(void*)dotSymp<<endl);
if (nodep->dotted() == "") {
nodep->v3error("Can't find definition of task/function: "<<nodep->prettyName());
} else {
@@ -1522,6 +1529,10 @@ private:
}
nodep->unlinkFrBack()->deleteTree();
}
virtual void visit(AstPackageImport* nodep, AstNUser*) {
// No longer needed
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
virtual void visit(AstNode* nodep, AstNUser*) {
// Default: Just iterate
nodep->iterateChildren(*this);
+7 -52
View File
@@ -34,6 +34,7 @@
#include <memory>
#include "V3Global.h"
#include "V3String.h"
#include "V3Options.h"
#include "V3Error.h"
#include "V3File.h"
@@ -367,7 +368,7 @@ void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) {
void V3Options::unlinkRegexp(const string& dir, const string& regexp) {
if (DIR* dirp = opendir(dir.c_str())) {
while (struct dirent* direntp = readdir(dirp)) {
if (wildmatch(direntp->d_name, regexp.c_str())) {
if (VString::wildmatch(direntp->d_name, regexp.c_str())) {
string fullname = dir + "/" + string(direntp->d_name);
unlink (fullname.c_str());
}
@@ -433,9 +434,9 @@ string V3Options::getenvSYSTEMC_ARCH() {
#else
struct utsname uts;
uname(&uts);
string sysname = downcase(uts.sysname); // aka 'uname -s'
if (wildmatch(sysname.c_str(), "*solaris*")) { var = "gccsparcOS5"; }
else if (wildmatch(sysname.c_str(), "*cygwin*")) { var ="cygwin"; }
string sysname = VString::downcase(uts.sysname); // aka 'uname -s'
if (VString::wildmatch(sysname.c_str(), "*solaris*")) { var = "gccsparcOS5"; }
else if (VString::wildmatch(sysname.c_str(), "*cygwin*")) { var ="cygwin"; }
else { var = "linux"; }
#endif
setenvStr("SYSTEMC_ARCH", var,"From sysname '"+sysname+"'");
@@ -542,54 +543,6 @@ string V3Options::getenvVERILATOR_ROOT() {
return var;
}
//######################################################################
// Wildcard
// Double procedures, inlined, unrolls loop much better
inline bool V3Options::wildmatchi(const char* s, const char* p) {
for ( ; *p; s++, p++) {
if (*p!='*') {
if (((*s)!=(*p)) && *p != '?')
return false;
}
else {
// Trailing star matches everything.
if (!*++p) return true;
while (wildmatch(s, p) == false)
if (*++s == '\0')
return false;
return true;
}
}
return (*s == '\0');
}
bool V3Options::wildmatch(const char* s, const char* p) {
for ( ; *p; s++, p++) {
if (*p!='*') {
if (((*s)!=(*p)) && *p != '?')
return false;
}
else {
// Trailing star matches everything.
if (!*++p) return true;
while (wildmatchi(s, p) == false)
if (*++s == '\0')
return false;
return true;
}
}
return (*s == '\0');
}
string V3Options::downcase(const string& str) {
string out = str;
for (string::iterator pos = out.begin(); pos != out.end(); ++pos) {
*pos = tolower(*pos);
}
return out;
}
//######################################################################
// V3 Options accessors
@@ -737,6 +690,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profileCFuncs = flag; }
else if ( onoff (sw, "-psl", flag/*ref*/) ) { m_psl = flag; }
else if ( onoff (sw, "-public", flag/*ref*/) ) { m_public = flag; }
else if ( onoff (sw, "-savable", flag/*ref*/) ) { m_savable = flag; }
else if ( !strcmp (sw, "-sc") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = false; }
else if ( onoff (sw, "-skip-identical", flag/*ref*/) ) { m_skipIdentical = flag; }
else if ( !strcmp (sw, "-sp") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = true; }
@@ -1181,6 +1135,7 @@ V3Options::V3Options() {
m_preprocOnly = false;
m_psl = false;
m_public = false;
m_savable = false;
m_skipIdentical = true;
m_stats = false;
m_systemC = false;
+2 -5
View File
@@ -115,6 +115,7 @@ class V3Options {
bool m_profileCFuncs;// main switch: --profile-cfuncs
bool m_psl; // main switch: --psl
bool m_public; // main switch: --public
bool m_savable; // main switch: --savable
bool m_systemC; // main switch: --sc: System C instead of simple C++
bool m_skipIdentical;// main switch: --skip-identical
bool m_systemPerl; // main switch: --sp: System Perl instead of SystemC (m_systemC also set)
@@ -192,7 +193,6 @@ class V3Options {
string parseFileArg(const string& optdir, const string& relfilename);
string filePathCheckOneDir(const string& modname, const string& dirname);
static bool wildmatchi(const char* s, const char* p);
static string getenvStr(const string& envvar, const string& defaultValue);
static void setenvStr(const string& envvar, const string& value, const string& why);
static string getenvSYSTEMPERLGuts();
@@ -223,6 +223,7 @@ class V3Options {
bool systemPerl() const { return m_systemPerl; }
bool usingSystemCLibs() const { return !lintOnly() && (systemPerl() || systemC()); }
bool usingSystemPerlLibs() const { return !lintOnly() && (systemPerl() || coverage()); }
bool savable() const { return m_savable; }
bool skipIdentical() const { return m_skipIdentical; }
bool stats() const { return m_stats; }
bool assertOn() const { return m_assert; } // assertOn as __FILE__ may be defined
@@ -321,10 +322,6 @@ class V3Options {
void parseOptsList (FileLine* fl, const string& optdir, int argc, char** argv);
void parseOptsFile (FileLine* fl, const string& filename, bool rel);
// METHODS (generic string utilities)
static bool wildmatch(const char* s, const char* p);
static string downcase(const string& str);
// METHODS (generic file utilities)
static string filenameFromDirBase (const string& dir, const string& basename);
static string filenameNonDir (const string& filename); ///< Return non-directory part of filename
+9 -7
View File
@@ -76,8 +76,8 @@ private:
LongMap m_longMap; // Hash of very long names to unique identity number
int m_longId;
typedef deque<AstNodeModule*> ModDeque;
ModDeque m_todoModps; // Modules left to process
typedef multimap<int,AstNodeModule*> LevelModMap;
LevelModMap m_todoModps; // Modules left to process
// METHODS
static int debug() {
@@ -125,10 +125,12 @@ private:
}
void visitModules() {
// Loop on all modules left to process
// Hitting a cell adds to the END of this list, so since cells originally exist top->bottom
// we process in top->bottom order too.
// Hitting a cell adds to the appropriate leval of this level-sorted list,
// so since cells originally exist top->bottom we process in top->bottom order too.
while (!m_todoModps.empty()) {
AstNodeModule* nodep = m_todoModps.front(); m_todoModps.pop_front();
LevelModMap::iterator it = m_todoModps.begin();
AstNodeModule* nodep = it->second;
m_todoModps.erase(it);
if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it again
UINFO(4," MOD "<<nodep<<endl);
nodep->iterateChildren(*this);
@@ -147,7 +149,7 @@ private:
UINFO(4," MOD-dead. "<<nodep<<endl); // Marked by LinkDot
} else if (nodep->level() <= 2) { // Haven't added top yet, so level 2 is the top
// Add request to END of modules left to process
m_todoModps.push_back(nodep);
m_todoModps.insert(make_pair(nodep->level(),nodep));
visitModules();
} else if (nodep->user5()) {
UINFO(4," MOD-done "<<nodep<<endl); // Already did it
@@ -443,7 +445,7 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
}
// Now remember to process the child module at the end of the module
m_todoModps.push_back(nodep->modp());
m_todoModps.insert(make_pair(nodep->modp()->level(),nodep->modp()));
}
//######################################################################
+2 -1
View File
@@ -28,6 +28,7 @@
class AstNetlist;
class V3InFilter;
class V3ParseImp;
class V3ParseSym;
//============================================================================
@@ -38,7 +39,7 @@ private:
public:
// CONSTRUCTORS
// We must allow reading multiple files into one parser
V3Parse(AstNetlist* rootp, V3InFilter* filterp);
V3Parse(AstNetlist* rootp, V3InFilter* filterp, V3ParseSym* symp);
~V3Parse();
// METHODS
+2 -2
View File
@@ -159,8 +159,8 @@ void V3ParseImp::lexFile(const string& modname) {
//======================================================================
// V3Parse functions
V3Parse::V3Parse(AstNetlist* rootp, V3InFilter* filterp) {
m_impp = new V3ParseImp (rootp, filterp);
V3Parse::V3Parse(AstNetlist* rootp, V3InFilter* filterp, V3ParseSym* symp) {
m_impp = new V3ParseImp (rootp, filterp, symp);
}
V3Parse::~V3Parse() {
delete m_impp; m_impp = NULL;
+8 -121
View File
@@ -25,7 +25,7 @@
#include "V3Error.h"
#include "V3Global.h"
#include "V3Parse.h"
#include "V3SymTable.h"
#include "V3ParseSym.h"
#include <deque>
class V3Lexer;
@@ -75,6 +75,7 @@ struct V3ParseBisonYYSType {
AstNodeVarRef* varnodep;
AstPackage* packagep;
AstParseRef* parserefp;
AstPatMember* patmemberp;
AstPin* pinp;
AstRange* rangep;
AstSenTree* sentreep;
@@ -85,132 +86,18 @@ struct V3ParseBisonYYSType {
#define YYSTYPE V3ParseBisonYYSType
//######################################################################
// Symbol table for parsing
class V3ParseSym {
// TYPES
typedef vector<VSymEnt*> SymStack;
private:
// MEMBERS
static int s_anonNum; // Number of next anonymous object (parser use only)
VSymGraph m_syms; // Graph of symbol tree
VSymEnt* m_symTableNextId; // Symbol table for next lexer lookup (parser use only)
VSymEnt* m_symCurrentp; // Active symbol table for additions/lookups
SymStack m_sympStack; // Stack of upper nodes with pending symbol tables
private:
// METHODS
static VSymEnt* getTable(AstNode* nodep) {
if (!nodep->user4p()) nodep->v3fatalSrc("Current symtable not found");
return nodep->user4p()->castSymEnt();
}
public:
VSymEnt* nextId() const { return m_symTableNextId; }
VSymEnt* symCurrentp() const { return m_symCurrentp; }
VSymEnt* symRootp() const { return m_syms.rootp(); }
VSymEnt* findNewTable(AstNode* nodep) {
if (!nodep->user4p()) {
VSymEnt* symsp = new VSymEnt(&m_syms, nodep);
nodep->user4p(symsp);
}
return getTable(nodep);
}
void nextId(AstNode* entp) {
if (entp) {
UINFO(9,"symTableNextId under "<<entp<<"-"<<entp->type().ascii()<<endl);
m_symTableNextId = getTable(entp);
}
else {
UINFO(9,"symTableNextId under NULL"<<endl);
m_symTableNextId = NULL;
}
}
void reinsert(AstNode* nodep, VSymEnt* parentp=NULL) {
reinsert(nodep, parentp, nodep->name());
}
void reinsert(AstNode* nodep, VSymEnt* parentp, string name) {
if (!parentp) parentp = symCurrentp();
if (name == "") { // New name with space in name so can't collide with users
name = string(" anon") + nodep->type().ascii() + cvtToStr(++s_anonNum);
}
parentp->reinsert(name, findNewTable(nodep));
}
void pushNew(AstNode* nodep) { pushNewUnder(nodep, NULL); }
void pushNewUnder(AstNode* nodep, VSymEnt* parentp) {
if (!parentp) parentp = symCurrentp();
VSymEnt* symp = findNewTable(nodep); // Will set user4p, which is how we connect table to node
symp->fallbackp(parentp);
reinsert(nodep, parentp);
pushScope(symp);
}
void pushScope(VSymEnt* symp) {
m_sympStack.push_back(symp);
m_symCurrentp = symp;
}
void popScope(AstNode* nodep) {
if (symCurrentp()->nodep() != nodep) {
if (debug()) { showUpward(); dump(cout,"-mism: "); }
nodep->v3fatalSrc("Symbols suggest ending "<<symCurrentp()->nodep()->prettyTypeName()
<<" but parser thinks ending "<<nodep->prettyTypeName());
return;
}
m_sympStack.pop_back();
if (m_sympStack.empty()) { nodep->v3fatalSrc("symbol stack underflow"); return; }
m_symCurrentp = m_sympStack.back();
}
void showUpward () {
UINFO(1,"ParseSym Stack:\n");
for (SymStack::reverse_iterator it=m_sympStack.rbegin(); it!=m_sympStack.rend(); ++it) {
VSymEnt* symp = *it;
UINFO(1,"\t"<<symp->nodep()<<endl);
}
UINFO(1,"ParseSym Current: "<<symCurrentp()->nodep()<<endl);
}
void dump(ostream& os, const string& indent="") {
m_syms.dump(os,indent);
}
AstNode* findEntUpward (const string& name) {
// Lookup the given string as an identifier, return type of the id, scanning upward
return symCurrentp()->findIdFallback(name)->nodep();
}
void import(AstNode* packagep, const string& id_or_star) {
// Import from package::id_or_star to this
VSymEnt* symp = getTable(packagep);
if (!symp) { // Internal problem, because we earlier found pkg to label it an ID__aPACKAGE
packagep->v3fatalSrc("Import package not found");
return;
}
// Walk old sym table and reinsert into current table
// We let V3LinkDot report the error instead of us
symCurrentp()->import(symp, id_or_star);
}
public:
// CREATORS
V3ParseSym(AstNetlist* rootp)
: m_syms(rootp) {
s_anonNum = 0; // Number of next anonymous object
pushScope(findNewTable(rootp));
m_symTableNextId = NULL;
m_symCurrentp = symCurrentp();
}
~V3ParseSym() {}
};
//######################################################################
class V3ParseImp {
// MEMBERS
AstNetlist* m_rootp; // Root of the design
V3InFilter* m_filterp; // Reading filter
V3ParseSym* m_symp; // Symbol table
V3Lexer* m_lexerp; // Current FlexLexer
static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based
FileLine* m_fileline; // Filename/linenumber currently active
V3ParseSym m_sym; // Symbol table
bool m_inCellDefine; // Inside a `celldefine
bool m_inLibrary; // Currently reading a library vs. regular file
int m_inBeginKwd; // Inside a `begin_keywords
@@ -307,14 +194,14 @@ public:
size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf,max_size); }
//==== Symbol tables
V3ParseSym* symp() { return &m_sym; }
V3ParseSym* symp() { return m_symp; }
public:
// CREATORS
V3ParseImp(AstNetlist* rootp, V3InFilter* filterp)
: m_filterp(filterp), m_sym(rootp) {
V3ParseImp(AstNetlist* rootp, V3InFilter* filterp, V3ParseSym* parserSymp)
: m_rootp(rootp), m_filterp(filterp), m_symp(parserSymp) {
m_fileline = NULL;
m_rootp = rootp; m_lexerp = NULL;
m_lexerp = NULL;
m_inCellDefine = false;
m_inLibrary = false;
m_inBeginKwd = 0;
+145
View File
@@ -0,0 +1,145 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Common header between parser and lex
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2009-2012 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3PARSESYM_H_
#define _V3PARSESYM_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3Global.h"
#include "V3SymTable.h"
#include <deque>
//######################################################################
// Symbol table for parsing
class V3ParseSym {
// TYPES
typedef vector<VSymEnt*> SymStack;
private:
// MEMBERS
static int s_anonNum; // Number of next anonymous object (parser use only)
VSymGraph m_syms; // Graph of symbol tree
VSymEnt* m_symTableNextId; // Symbol table for next lexer lookup (parser use only)
VSymEnt* m_symCurrentp; // Active symbol table for additions/lookups
SymStack m_sympStack; // Stack of upper nodes with pending symbol tables
private:
// METHODS
static VSymEnt* getTable(AstNode* nodep) {
if (!nodep->user4p()) nodep->v3fatalSrc("Current symtable not found");
return nodep->user4p()->castSymEnt();
}
public:
VSymEnt* nextId() const { return m_symTableNextId; }
VSymEnt* symCurrentp() const { return m_symCurrentp; }
VSymEnt* symRootp() const { return m_syms.rootp(); }
VSymEnt* findNewTable(AstNode* nodep) {
if (!nodep->user4p()) {
VSymEnt* symsp = new VSymEnt(&m_syms, nodep);
nodep->user4p(symsp);
}
return getTable(nodep);
}
void nextId(AstNode* entp) {
if (entp) {
UINFO(9,"symTableNextId under "<<entp<<"-"<<entp->type().ascii()<<endl);
m_symTableNextId = getTable(entp);
}
else {
UINFO(9,"symTableNextId under NULL"<<endl);
m_symTableNextId = NULL;
}
}
void reinsert(AstNode* nodep, VSymEnt* parentp=NULL) {
reinsert(nodep, parentp, nodep->name());
}
void reinsert(AstNode* nodep, VSymEnt* parentp, string name) {
if (!parentp) parentp = symCurrentp();
if (name == "") { // New name with space in name so can't collide with users
name = string(" anon") + nodep->type().ascii() + cvtToStr(++s_anonNum);
}
parentp->reinsert(name, findNewTable(nodep));
}
void pushNew(AstNode* nodep) { pushNewUnder(nodep, NULL); }
void pushNewUnder(AstNode* nodep, VSymEnt* parentp) {
if (!parentp) parentp = symCurrentp();
VSymEnt* symp = findNewTable(nodep); // Will set user4p, which is how we connect table to node
symp->fallbackp(parentp);
reinsert(nodep, parentp);
pushScope(symp);
}
void pushScope(VSymEnt* symp) {
m_sympStack.push_back(symp);
m_symCurrentp = symp;
}
void popScope(AstNode* nodep) {
if (symCurrentp()->nodep() != nodep) {
if (debug()) { showUpward(); dump(cout,"-mism: "); }
nodep->v3fatalSrc("Symbols suggest ending "<<symCurrentp()->nodep()->prettyTypeName()
<<" but parser thinks ending "<<nodep->prettyTypeName());
return;
}
m_sympStack.pop_back();
if (m_sympStack.empty()) { nodep->v3fatalSrc("symbol stack underflow"); return; }
m_symCurrentp = m_sympStack.back();
}
void showUpward () {
UINFO(1,"ParseSym Stack:\n");
for (SymStack::reverse_iterator it=m_sympStack.rbegin(); it!=m_sympStack.rend(); ++it) {
VSymEnt* symp = *it;
UINFO(1,"\t"<<symp->nodep()<<endl);
}
UINFO(1,"ParseSym Current: "<<symCurrentp()->nodep()<<endl);
}
void dump(ostream& os, const string& indent="") {
m_syms.dump(os,indent);
}
AstNode* findEntUpward (const string& name) {
// Lookup the given string as an identifier, return type of the id, scanning upward
return symCurrentp()->findIdFallback(name)->nodep();
}
void import(AstNode* packagep, const string& id_or_star) {
// Import from package::id_or_star to this
VSymEnt* symp = getTable(packagep);
if (!symp) { // Internal problem, because we earlier found pkg to label it an ID__aPACKAGE
packagep->v3fatalSrc("Import package not found");
return;
}
// Walk old sym table and reinsert into current table
// We let V3LinkDot report the error instead of us
symCurrentp()->import(symp, id_or_star);
}
public:
// CREATORS
V3ParseSym(AstNetlist* rootp)
: m_syms(rootp) {
s_anonNum = 0; // Number of next anonymous object
pushScope(findNewTable(rootp));
m_symTableNextId = NULL;
m_symCurrentp = symCurrentp();
}
~V3ParseSym() {}
};
#endif // Guard
+72
View File
@@ -0,0 +1,72 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Options parsing
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2012 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3String.h"
//######################################################################
// Wildcard
// Double procedures, inlined, unrolls loop much better
inline bool VString::wildmatchi(const char* s, const char* p) {
for ( ; *p; s++, p++) {
if (*p!='*') {
if (((*s)!=(*p)) && *p != '?')
return false;
}
else {
// Trailing star matches everything.
if (!*++p) return true;
while (wildmatch(s, p) == false)
if (*++s == '\0')
return false;
return true;
}
}
return (*s == '\0');
}
bool VString::wildmatch(const char* s, const char* p) {
for ( ; *p; s++, p++) {
if (*p!='*') {
if (((*s)!=(*p)) && *p != '?')
return false;
}
else {
// Trailing star matches everything.
if (!*++p) return true;
while (wildmatchi(s, p) == false)
if (*++s == '\0')
return false;
return true;
}
}
return (*s == '\0');
}
string VString::downcase(const string& str) {
string out = str;
for (string::iterator pos = out.begin(); pos != out.end(); ++pos) {
*pos = tolower(*pos);
}
return out;
}
+91
View File
@@ -0,0 +1,91 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: String manipulation
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2012 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3STRING_H_
#define _V3STRING_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include <string>
//######################################################################
// VString - String manipulation
class VString {
static bool wildmatchi(const char* s, const char* p);
public:
// METHODS (generic string utilities)
static bool wildmatch(const char* s, const char* p);
static string downcase(const string& str);
};
//######################################################################
// Compute FNV1a (Fowler/Noll/Vo) hashes
// See http://www.isthe.com/chongo/tech/comp/fnv/index.html
// Algorithmic basis for these functions was in the public domain, by chongo <Landon Curt Noll>
class VHashFnv {
enum { FNV1_64_INIT = 0xcbf29ce484222325ULL }; // Initial value
vluint64_t m_hash;
inline void hashC(uint8_t c) {
m_hash ^= c;
// Below is faster than m_hash *= 0x100000001b3ULL;
m_hash += ((m_hash << 1) + (m_hash << 4) + (m_hash << 5)
+ (m_hash << 7) + (m_hash << 8) + (m_hash << 40));
}
public:
VHashFnv() : m_hash(FNV1_64_INIT) {}
~VHashFnv() {}
vluint64_t value() const { return m_hash; }
VHashFnv& hash(const void* bufp, size_t len) { // Memory
const uint8_t* bp = (const uint8_t*)bufp;
const uint8_t* be = bp + len;
while (bp < be) hashC((vluint64_t)*bp++);
return *this;
}
VHashFnv& hash(const char* strp) { // String
const uint8_t* sp = (const uint8_t*)strp;
while (*sp) hashC((vluint64_t)*sp++);
return *this;
}
VHashFnv& hash(const string& str) { return hash(str.c_str()); }
VHashFnv& hash(vluint64_t n) {
hashC(n>>0); hashC(n>>8); hashC(n>>16); hashC(n>>24);
hashC(n>>32); hashC(n>>40); hashC(n>>48); hashC(n>>56);
return *this;
}
VHashFnv& hash(uint32_t n) {
hashC(n>>0); hashC(n>>8); hashC(n>>16); hashC(n>>24);
return *this;
}
VHashFnv& hash(uint16_t n) {
hashC(n>>0); hashC(n>>8);
return *this;
}
VHashFnv& hash(uint8_t n) { hashC(n); return *this; }
VHashFnv& hash(int n) { hashC((vluint64_t)n); return *this; }
};
//######################################################################
#endif // guard
+13 -2
View File
@@ -53,7 +53,7 @@ private:
VSymEnt* m_parentp; // Table that created this table, dot notation needed to resolve into it
AstPackage* m_packagep; // Package node is in (for V3LinkDot, unused here)
string m_symPrefix; // String to prefix symbols with (for V3LinkDot, unused here)
#if 0 // debug
#ifdef VL_DEBUG
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel("V3LinkDot.cpp");
@@ -87,7 +87,18 @@ public:
// METHODS
VSymEnt(VSymGraph* graphp, AstNode* nodep); // Below
~VSymEnt() {}
~VSymEnt() {
// Change links so we coredump if used
#ifdef VL_DEBUG
m_nodep = (AstNode*)1;
m_fallbackp = (VSymEnt*)1;
m_parentp = (VSymEnt*)1;
m_packagep = (AstPackage*)1;
#endif
}
#if defined(VL_DEBUG) && !defined(VL_LEAK_CHECKS)
void operator delete(void* objp, size_t size) {} // For testing, leak so above destructor 1 assignments work
#endif
void fallbackp(VSymEnt* entp) { m_fallbackp = entp; }
void parentp(VSymEnt* entp) { m_parentp = entp; }
VSymEnt* parentp() const { return m_parentp; }
+1 -1
View File
@@ -666,7 +666,7 @@ private:
// We could use 64-bits of a MD5/SHA hash rather than a string here,
// but the compare is only done on first call then memoized, so it's not worth optimizing.
string stmt;
stmt += "static int __Vfuncnum = -1;\n";
stmt += "static int __Vfuncnum = -1;\n"; // Static doesn't need save-restore as if below will re-fill proper value
// First time init (faster than what the compiler does if we did a singleton
stmt += "if (VL_UNLIKELY(__Vfuncnum==-1)) { __Vfuncnum = Verilated::exportFuncNum(\""+nodep->cname()+"\"); }\n";
// If the find fails, it will throw an error
+2 -1
View File
@@ -36,6 +36,7 @@
#include <vector>
#include "V3Global.h"
#include "V3String.h"
#include "V3Undriven.h"
#include "V3Ast.h"
@@ -135,7 +136,7 @@ public:
bool unusedMatch(AstVar* nodep) {
const char* regexpp = v3Global.opt.unusedRegexp().c_str();
if (!regexpp || !*regexpp) return false;
return V3Options::wildmatch(nodep->prettyName().c_str(), regexpp);
return VString::wildmatch(nodep->prettyName().c_str(), regexpp);
}
void reportViolations() {
// Combine bits into overall state
+147 -20
View File
@@ -119,6 +119,7 @@ private:
AstFunc* m_funcp; // Current function
AstInitial* m_initialp; // Current initial block
AstAttrOf* m_attrp; // Current attribute
AstNodeDType* m_assDTypep; // Assign LHS data type for assignment pattern
bool m_doGenerate; // Do errors later inside generate statement
// CLASSES
@@ -995,6 +996,126 @@ private:
pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstPattern* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return;
UINFO(9,"PATTERN "<<nodep<<endl);
AstNodeDType* oldAssDTypep = m_assDTypep;
{
if (!m_assDTypep) nodep->v3error("Unsupported/Illegal: Assignment pattern not underneath an assignment");
m_assDTypep = m_assDTypep->skipRefp();
UINFO(9," adtypep "<<m_assDTypep<<endl);
nodep->dtypep(m_assDTypep);
if (AstNodeClassDType* classp = m_assDTypep->castNodeClassDType()) {
// Due to "default" and tagged patterns, we need to determine
// which member each AstPatMember corresponds to before we can
// determine the dtypep for that PatMember's value, and then
// width the initial value appropriately.
typedef map<AstMemberDType*,AstPatMember*> PatMap;
PatMap patmap;
AstPatMember* defaultp = NULL;
{
AstMemberDType* memp = classp->membersp();
AstPatMember* patp = nodep->itemsp()->castPatMember();
for (; memp || patp; ) {
// Determine replication count, and replicate initial value as widths need to be individually determined
if (patp) {
int times = visitPatMemberRep(patp);
for (int i=1; i<times; i++) {
AstNode* newp = patp->cloneTree(false);
patp->addNextHere(newp);
// This loop will see the new elements as part of nextp()
}
if (patp->keyp()) {
if (AstText* textp = patp->keyp()->castText()) {
memp = classp->findMember(textp->text());
if (!memp) {
patp->keyp()->v3error("Assignment pattern key '"<<textp->text()<<"' not found as member");
continue;
}
} else {
patp->keyp()->v3error("Assignment pattern key not supported/understood: "<<patp->keyp()->prettyTypeName());
}
}
}
if (patp && patp->isDefault()) {
if (defaultp) nodep->v3error("Multiple '{ default: } clauses");
defaultp = patp;
} else if (memp && !patp) {
// Missing init elements, warn below
memp=NULL; patp=NULL; break;
} else if (!memp && patp) { patp->v3error("Assignment pattern contains too many elements");
memp=NULL; patp=NULL; break;
} else {
patmap.insert(make_pair(memp, patp));
}
// Next
if (memp) memp = memp->nextp()->castMemberDType();
if (patp) patp = patp->nextp()->castPatMember();
}
}
AstNode* newp = NULL;
for (AstMemberDType* memp = classp->membersp(); memp; memp=memp->nextp()->castMemberDType()) {
PatMap::iterator it = patmap.find(memp);
AstPatMember* newpatp = NULL;
AstPatMember* patp = NULL;
if (it == patmap.end()) {
if (defaultp) {
newpatp = defaultp->cloneTree(false);
patp = newpatp;
}
else {
patp->v3error("Assignment pattern missed initializing elements: "<<memp->prettyTypeName());
}
} else {
patp = it->second;
}
// Determine initial values
m_assDTypep = memp;
patp->dtypep(memp);
patp->accept(*this,WidthVP(patp->width(),patp->width(),BOTH).p());
// Convert to concat for now
if (!newp) newp = patp->lhsp()->unlinkFrBack();
else {
AstConcat* concatp = new AstConcat(patp->fileline(), newp, patp->lhsp()->unlinkFrBack());
newp = concatp;
newp->dtypeSetLogicSized(concatp->lhsp()->width()+concatp->rhsp()->width(),
concatp->lhsp()->width()+concatp->rhsp()->width(),
nodep->dtypep()->numeric());
}
if (newpatp) pushDeletep(newpatp);
}
if (newp) nodep->replaceWith(newp);
else nodep->v3error("Assignment pattern with no members");
pushDeletep(nodep); nodep = NULL; // Deletes defaultp also, if present
} else {
nodep->v3error("Unsupported: Assignment pattern applies against non struct/union: "<<m_assDTypep->prettyTypeName());
}
}
m_assDTypep = oldAssDTypep;
}
virtual void visit(AstPatMember* nodep, AstNUser* vup) {
if (!nodep->dtypep()) nodep->v3fatalSrc("Pattern member type not assigned by AstPattern visitor");
if (!m_assDTypep) nodep->v3error("Unsupported/Illegal: Assignment pattern member not underneath an assignment");
nodep->lhsp()->dtypeFrom(nodep);
nodep->iterateChildren(*this,WidthVP(nodep->dtypep()->width(),nodep->dtypep()->width(),BOTH).p());
widthCheck(nodep,"LHS",nodep->lhsp(),nodep->width(),nodep->width());
}
int visitPatMemberRep(AstPatMember* nodep) {
uint32_t times = 1;
if (nodep->repp()) { // else repp()==NULL shorthand for rep count 1
nodep->repp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
checkCvtUS(nodep->repp());
V3Const::constifyParamsEdit(nodep->repp()); // repp may change
AstConst* constp = nodep->repp()->castConst();
if (!constp) { nodep->v3error("Replication value isn't a constant."); times=0; }
else times = constp->toUInt();
if (times==0) { nodep->v3error("Pattern replication value of 0 is not legal."); times=1; }
nodep->repp()->unlinkFrBackWithNext()->deleteTree(); // Done with replicate before cloning
}
return times;
}
virtual void visit(AstPslClocked* nodep, AstNUser*) {
nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
nodep->sensesp()->iterateAndNext(*this);
@@ -1077,27 +1198,32 @@ private:
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// TOP LEVEL NODE
//if (debug()) nodep->dumpTree(cout," AssignPre: ");
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
if (!nodep->lhsp()->dtypep()) nodep->v3fatalSrc("How can LHS be untyped?");
if (!nodep->lhsp()->dtypep()->widthSized()) nodep->v3fatalSrc("How can LHS be unsized?");
if (!nodep->lhsp()->isDouble() && nodep->rhsp()->isDouble()) {
spliceCvtS(nodep->rhsp(), false); // Round RHS
} else if (nodep->lhsp()->isDouble() && !nodep->rhsp()->isDouble()) {
spliceCvtD(nodep->rhsp());
AstNodeDType* oldAssDTypep = m_assDTypep;
{
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (!nodep->lhsp()->dtypep()) nodep->v3fatalSrc("How can LHS be untyped?");
if (!nodep->lhsp()->dtypep()->widthSized()) nodep->v3fatalSrc("How can LHS be unsized?");
m_assDTypep = nodep->lhsp()->dtypep();
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
if (!nodep->lhsp()->isDouble() && nodep->rhsp()->isDouble()) {
spliceCvtS(nodep->rhsp(), false); // Round RHS
} else if (nodep->lhsp()->isDouble() && !nodep->rhsp()->isDouble()) {
spliceCvtD(nodep->rhsp());
}
int awidth = nodep->lhsp()->width();
if (awidth==0) {
awidth = nodep->rhsp()->width(); // Parameters can propagate by unsized assignment
}
nodep->rhsp()->iterateAndNext(*this,WidthVP(awidth,awidth,FINAL).p());
nodep->dtypeFrom(nodep->lhsp());
nodep->dtypeChgWidth(awidth,awidth); // We know the assign will truncate, so rather
// than using "width" and have the optimizer truncate the result, we do
// it using the normal width reduction checks.
//UINFO(0,"aw "<<awidth<<" w"<<nodep->rhsp()->width()<<" m"<<nodep->rhsp()->widthMin()<<endl);
widthCheck(nodep,"Assign RHS",nodep->rhsp(),awidth,awidth);
//if (debug()) nodep->dumpTree(cout," AssignOut: ");
}
int awidth = nodep->lhsp()->width();
if (awidth==0) {
awidth = nodep->rhsp()->width(); // Parameters can propagate by unsized assignment
}
nodep->rhsp()->iterateAndNext(*this,WidthVP(awidth,awidth,FINAL).p());
nodep->dtypeFrom(nodep->lhsp());
nodep->dtypeChgWidth(awidth,awidth); // We know the assign will truncate, so rather
// than using "width" and have the optimizer truncate the result, we do
// it using the normal width reduction checks.
//UINFO(0,"aw "<<awidth<<" w"<<nodep->rhsp()->width()<<" m"<<nodep->rhsp()->widthMin()<<endl);
widthCheck(nodep,"Assign RHS",nodep->rhsp(),awidth,awidth);
//if (debug()) nodep->dumpTree(cout," AssignOut: ");
m_assDTypep = oldAssDTypep;
}
virtual void visit(AstSFormatF* nodep, AstNUser*) {
// Excludes NodeDisplay, see below
@@ -2200,6 +2326,7 @@ public:
m_funcp = NULL;
m_initialp = NULL;
m_attrp = NULL;
m_assDTypep = NULL;
m_doGenerate = doGenerate;
}
AstNode* mainAcceptEdit(AstNode* nodep) {
+4 -2
View File
@@ -70,6 +70,7 @@
#include "V3Order.h"
#include "V3Param.h"
#include "V3Parse.h"
#include "V3ParseSym.h"
#include "V3PreShell.h"
#include "V3Premit.h"
#include "V3Scope.h"
@@ -111,8 +112,9 @@ void V3Global::readFiles() {
AstUser4InUse inuser4;
V3InFilter filter (v3Global.opt.pipeFilter());
V3ParseSym parseSyms (v3Global.rootp()); // Symbol table must be common across all parsing
V3Parse parser (v3Global.rootp(), &filter);
V3Parse parser (v3Global.rootp(), &filter, &parseSyms);
// Read top module
for (V3StringList::const_iterator it = v3Global.opt.vFiles().begin();
it != v3Global.opt.vFiles().end(); ++it) {
@@ -135,7 +137,7 @@ void V3Global::readFiles() {
if (!v3Global.opt.preprocOnly()) {
// Resolve all modules cells refer to
V3LinkCells::link(v3Global.rootp(), &filter);
V3LinkCells::link(v3Global.rootp(), &filter, &parseSyms);
}
}
+66 -1
View File
@@ -2188,6 +2188,71 @@ caseCondList<nodep>: // IEEE: part of case_item
| caseCondList ',' expr { $$ = $1;$1->addNext($3); }
;
patternNoExpr<nodep>: // IEEE: pattern **Excluding Expr*
'.' id/*variable*/ { $1->v3error("Unsupported: '{} tagged patterns"); $$=NULL; }
| yP_DOTSTAR { $1->v3error("Unsupported: '{} tagged patterns"); $$=NULL; }
// // IEEE: "expr" excluded; expand in callers
// // "yTAGGED id [expr]" Already part of expr
//UNSUP yTAGGED id/*member_identifier*/ patternNoExpr { $1->v3error("Unsupported: '{} tagged patterns"); $$=NULL; }
// // "yP_TICKBRA patternList '}'" part of expr under assignment_pattern
;
patternList<nodep>: // IEEE: part of pattern
patternOne { $$ = $1; }
| patternList ',' patternOne { $$ = $1->addNextNull($3); }
;
patternOne<nodep>: // IEEE: part of pattern
expr { $$ = new AstPatMember($1->fileline(),$1,NULL,NULL); }
| expr '{' argsExprList '}' { $$ = new AstPatMember($2,$3,NULL,$1); }
| patternNoExpr { $$ = $1; }
;
patternMemberList<nodep>: // IEEE: part of pattern and assignment_pattern
patternMemberOne { $$ = $1; }
| patternMemberList ',' patternMemberOne { $$ = $1->addNextNull($3); }
;
patternMemberOne<patmemberp>: // IEEE: part of pattern and assignment_pattern
patternKey ':' expr { $$ = new AstPatMember($2,$3,$1,NULL); }
| patternKey ':' patternNoExpr { $2->v3error("Unsupported: '{} .* patterns"); $$=NULL; }
// // From assignment_pattern_key
| yDEFAULT ':' expr { $$ = new AstPatMember($2,$3,NULL,NULL); $$->isDefault(true); }
| yDEFAULT ':' patternNoExpr { $2->v3error("Unsupported: '{} .* patterns"); $$=NULL; }
;
patternKey<nodep>: // IEEE: merge structure_pattern_key, array_pattern_key, assignment_pattern_key
// // IEEE: structure_pattern_key
// // id/*member*/ is part of constExpr below
//UNSUP constExpr { $$ = $1; }
// // IEEE: assignment_pattern_key
//UNSUP simple_type { $1->v3error("Unsupported: '{} with data type as key"); $$=$1; }
// // simple_type reference looks like constExpr
// // Verilator:
// // The above expressions cause problems because "foo" may be a constant identifier
// // (if array) or a reference to the "foo"member (if structure)
// // So for now we only allow a true constant number, or a identifier which we treat as a structure member name
yaINTNUM { $$ = new AstConst($<fl>1,*$1); }
| yaFLOATNUM { $$ = new AstConst($<fl>1,AstConst::RealDouble(),$1); }
| yaID__ETC { $$ = new AstText($<fl>1,*$1); }
;
assignment_pattern<nodep>: // ==IEEE: assignment_pattern
// This doesn't match the text of the spec. I think a : is missing, or example code needed
// yP_TICKBRA constExpr exprList '}' { $$="'{"+$2+" "+$3"}"; }
// // "'{ const_expression }" is same as patternList with one entry
// // From patternNoExpr
// // also IEEE: "''{' expression { ',' expression } '}'"
// // matches since patternList includes expr
yP_TICKBRA patternList '}' { $$ = new AstPattern($1,$2); }
// // From patternNoExpr
// // also IEEE "''{' structure_pattern_key ':' ...
// // also IEEE "''{' array_pattern_key ':' ...
| yP_TICKBRA patternMemberList '}' { $$ = new AstPattern($1,$2); }
// // IEEE: Not in grammar, but in VMM
| yP_TICKBRA '}' { $1->v3error("Unsupported: Empty '{}"); $$=NULL; }
;
// "datatype id = x {, id = x }" | "yaId = x {, id=x}" is legal
for_initialization<nodep>: // ==IEEE: for_initialization + for_variable_declaration + extra terminating ";"
// // IEEE: for_variable_declaration
@@ -2705,7 +2770,7 @@ exprOkLvalue<nodep>: // expression that's also OK to use as a variable_lvalue
// // We allow more here than the spec requires
//UNSUP ~l~exprScope assignment_pattern { UNSUP }
//UNSUP data_type assignment_pattern { UNSUP }
//UNSUP assignment_pattern { UNSUP }
| assignment_pattern { $$ = $1; }
//
//UNSUP streaming_concatenation { UNSUP }
;
+50 -3
View File
@@ -476,6 +476,7 @@ sub compile_vlt_flags {
$self->{sc} = 1 if ($checkflags =~ /-sc\b/);
$self->{sp} = 1 if ($checkflags =~ /-sp\b/);
$self->{trace} = 1 if ($opt_trace || $checkflags =~ /-trace\b/);
$self->{savable} = 1 if ($checkflags =~ /-savable\b/);
$self->{coverage} = 1 if ($checkflags =~ /-coverage\b/);
my @verilator_flags = @{$param{verilator_flags}};
@@ -963,15 +964,39 @@ sub _make_main {
print $fh "#include \"systemc.h\"\n" if $self->sc;
print $fh "#include \"systemperl.h\"\n" if $self->sp;
print $fh "#include \"verilated_vcd_c.h\"\n" if $self->{trace} && !$self->sp;
print $fh "#include \"verilated_save.h\"\n" if $self->{savable};
print $fh "#include \"SpTraceVcd.h\"\n" if $self->{trace} && $self->sp;
print $fh "$VM_PREFIX * topp;\n";
if (!$self->sc_or_sp) {
print $fh "unsigned int main_time = false;\n";
print $fh "vluint64_t main_time = false;\n";
print $fh "double sc_time_stamp () {\n";
print $fh " return main_time;\n";
print $fh "}\n";
}
if ($self->{savable}) {
$fh->print("\n");
$fh->print("void save_model(const char* filenamep) {\n");
$fh->print(" VL_PRINTF(\"Saving model to '%s'\\n\", filenamep);\n");
$fh->print(" VerilatedSave os;\n");
$fh->print(" os.open(filenamep);\n");
$fh->print(" os << main_time;\n");
$fh->print(" os << *topp;\n");
$fh->print(" os.close();\n");
$fh->print("}\n");
$fh->print("\n");
$fh->print("void restore_model(const char* filenamep) {\n");
$fh->print(" VL_PRINTF(\"Restoring model from '%s'\\n\", filenamep);\n");
$fh->print(" VerilatedRestore os;\n");
$fh->print(" os.open(filenamep);\n");
$fh->print(" os >> main_time;\n");
$fh->print(" os >> *topp;\n");
$fh->print(" os.close();\n");
$fh->print("}\n");
}
#### Main
if ($self->sc_or_sp) {
print $fh "extern int sc_main(int argc, char **argv);\n";
print $fh "int sc_main(int argc, char **argv) {\n";
@@ -1017,9 +1042,24 @@ sub _make_main {
$fh->print("#endif\n");
}
print $fh " ${set}fastclk = false;\n" if $self->{inputs}{fastclk};
print $fh " ${set}clk = false;\n" if $self->{inputs}{clk};
if ($self->{savable}) {
$fh->print(" const char* save_time_strp = Verilated::commandArgsPlusMatch(\"save_time=\");\n");
$fh->print(" const char* save_restore_strp = Verilated::commandArgsPlusMatch(\"save_restore=\");\n");
$fh->print(" unsigned int save_time = !save_time_strp[0] ? 0 : atoi(save_time_strp+strlen(\"+save_time=\"));\n");
$fh->print(" unsigned int save_restore = !save_restore_strp[0] ? 0 : 1;\n");
}
if ($self->{savable}) {
$fh->print(" if (save_restore) {\n");
$fh->print(" restore_model(\"$self->{obj_dir}/saved.vltsv\");\n");
$fh->print(" } else {\n");
} else {
$fh->print(" {\n");
}
print $fh " ${set}fastclk = false;\n" if $self->{inputs}{fastclk};
print $fh " ${set}clk = false;\n" if $self->{inputs}{clk};
_print_advance_time($self, $fh, 10);
print $fh " }\n";
print $fh " while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {\n";
for (my $i=0; $i<5; $i++) {
@@ -1032,6 +1072,13 @@ sub _make_main {
print $fh " ${set}clk=!${set}clk;\n";
$action = 1;
}
if ($self->{savable}) {
$fh->print(" if (sc_time_stamp() == save_time && save_time) {\n");
$fh->print(" save_model(\"$self->{obj_dir}/saved.vltsv\");\n");
$fh->print(" printf(\"Exiting after save_model\\n\");\n");
$fh->print(" exit(0);\n");
$fh->print(" }\n");
}
_print_advance_time($self, $fh, 1, $action);
}
print $fh " }\n";
+38 -38
View File
@@ -39,24 +39,24 @@ module t (/*AUTOARG*/
// big endian
always @ (posedge clk)
if (cnt[1:0]==2'd0) begin
// initialize to defaults (all bits 1'bx)
if (cnt[30:2]== 0) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 1) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 2) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 3) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 4) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 5) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 6) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 7) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 8) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 9) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==10) array_bg <= {WA{ {WB{1'bx}} }};
// initialize to defaults (all bits 1'b0)
if (cnt[30:2]== 0) array_bg <= '0;
else if (cnt[30:2]== 1) array_bg <= '0;
else if (cnt[30:2]== 2) array_bg <= '0;
else if (cnt[30:2]== 3) array_bg <= '0;
else if (cnt[30:2]== 4) array_bg <= '0;
else if (cnt[30:2]== 5) array_bg <= '0;
else if (cnt[30:2]== 6) array_bg <= '0;
else if (cnt[30:2]== 7) array_bg <= '0;
else if (cnt[30:2]== 8) array_bg <= '0;
else if (cnt[30:2]== 9) array_bg <= '0;
else if (cnt[30:2]==10) array_bg <= '0;
end else if (cnt[1:0]==2'd1) begin
// write data into whole or part of the array using literals
if (cnt[30:2]== 0) begin end
else if (cnt[30:2]== 1) array_bg <= '{ 3 ,2 ,1, 0 };
else if (cnt[30:2]== 2) array_bg <= '{0:4, 1:5, 2:6, 3:7};
else if (cnt[30:2]== 3) array_bg <= '{default:13};
else if (cnt[30:2]== 2) array_bg <= '{default:13};
else if (cnt[30:2]== 3) array_bg <= '{0:4, 1:5, 2:6, 3:7};
else if (cnt[30:2]== 4) array_bg <= '{2:15, default:13};
else if (cnt[30:2]== 5) array_bg <= '{WA { {WB/2 {2'b10}} }};
else if (cnt[30:2]== 6) array_bg <= '{WA { {3'b101, {WB/2-1{2'b10}}} }};
@@ -66,40 +66,40 @@ module t (/*AUTOARG*/
else if (cnt[30:2]==10) array_bg <= '{cnt+0, cnt+1, cnt+2, cnt+3};
end else if (cnt[1:0]==2'd2) begin
// chack array agains expected value
if (cnt[30:2]== 0) begin if (array_bg !== 16'bxxxxxxxxxxxxxxxx) begin $display("%b", array_bg); $stop(); end end
if (cnt[30:2]== 0) begin if (array_bg !== 16'b0000000000000000) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 1) begin if (array_bg !== 16'b0011001000010000) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 2) begin if (array_bg !== 16'b0111011001010100) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 3) begin if (array_bg !== 16'b1101110111011101) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 2) begin if (array_bg !== 16'b1101110111011101) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 3) begin if (array_bg !== 16'b0111011001010100) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 4) begin if (array_bg !== 16'b1101111111011101) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 5) begin if (array_bg !== 16'b1010101010101010) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 6) begin if (array_bg !== 16'b0110011001100110) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 7) begin if (array_bg !== 16'b0010001000100010) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 8) begin if (array_bg !== 16'b10101010xxxxxxxx) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 9) begin if (array_bg !== 16'bxxxxxxxx10101010) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 8) begin if (array_bg !== 16'b1010101000000000) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]== 9) begin if (array_bg !== 16'b0000000010101010) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==10) begin if (array_bg !== 16'b1001101010111100) begin $display("%b", array_bg); $stop(); end end
end
// little endian
always @ (posedge clk)
if (cnt[1:0]==2'd0) begin
// initialize to defaults (all bits 1'bx)
if (cnt[30:2]== 0) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 1) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 2) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 3) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 4) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 5) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 6) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 7) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 8) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]== 9) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==10) array_lt <= {WA{ {WB{1'bx}} }};
// initialize to defaults (all bits 1'b0)
if (cnt[30:2]== 0) array_lt <= '0;
else if (cnt[30:2]== 1) array_lt <= '0;
else if (cnt[30:2]== 2) array_lt <= '0;
else if (cnt[30:2]== 3) array_lt <= '0;
else if (cnt[30:2]== 4) array_lt <= '0;
else if (cnt[30:2]== 5) array_lt <= '0;
else if (cnt[30:2]== 6) array_lt <= '0;
else if (cnt[30:2]== 7) array_lt <= '0;
else if (cnt[30:2]== 8) array_lt <= '0;
else if (cnt[30:2]== 9) array_lt <= '0;
else if (cnt[30:2]==10) array_lt <= '0;
end else if (cnt[1:0]==2'd1) begin
// write data into whole or part of the array using literals
if (cnt[30:2]== 0) begin end
else if (cnt[30:2]== 1) array_lt <= '{ 3 ,2 ,1, 0 };
else if (cnt[30:2]== 2) array_lt <= '{3:4, 2:5, 1:6, 0:7};
else if (cnt[30:2]== 3) array_lt <= '{default:13};
else if (cnt[30:2]== 2) array_lt <= '{default:13};
else if (cnt[30:2]== 3) array_lt <= '{3:4, 2:5, 1:6, 0:7};
else if (cnt[30:2]== 4) array_lt <= '{1:15, default:13};
else if (cnt[30:2]== 5) array_lt <= '{WA { {WB/2 {2'b10}} }};
else if (cnt[30:2]== 6) array_lt <= '{WA { {3'b101, {WB/2-1{2'b10}}} }};
@@ -109,16 +109,16 @@ module t (/*AUTOARG*/
else if (cnt[30:2]==10) array_lt <= '{cnt+0, cnt+1, cnt+2, cnt+3};
end else if (cnt[1:0]==2'd2) begin
// chack array agains expected value
if (cnt[30:2]== 0) begin if (array_lt !== 16'bxxxxxxxxxxxxxxxx) begin $display("%b", array_lt); $stop(); end end
if (cnt[30:2]== 0) begin if (array_lt !== 16'b0000000000000000) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 1) begin if (array_lt !== 16'b0011001000010000) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 2) begin if (array_lt !== 16'b0111011001010100) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 3) begin if (array_lt !== 16'b1101110111011101) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 2) begin if (array_lt !== 16'b1101110111011101) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 3) begin if (array_lt !== 16'b0111011001010100) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 4) begin if (array_lt !== 16'b1101111111011101) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 5) begin if (array_lt !== 16'b1010101010101010) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 6) begin if (array_lt !== 16'b0110011001100110) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 7) begin if (array_lt !== 16'b0010001000100010) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 8) begin if (array_lt !== 16'b10101010xxxxxxxx) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 9) begin if (array_lt !== 16'bxxxxxxxx10101010) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 8) begin if (array_lt !== 16'b1010101000000000) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]== 9) begin if (array_lt !== 16'b0000000010101010) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==10) begin if (array_lt !== 16'b1001101010111100) begin $display("%b", array_lt); $stop(); end end
end
+42 -42
View File
@@ -39,17 +39,17 @@ module t (/*AUTOARG*/
// big endian
always @ (posedge clk)
if (cnt[1:0]==2'd0) begin
// initialize to defaaults (all bits to x)
if (cnt[30:2]==0) array_bg <= {WA *WB{1'bx} };
else if (cnt[30:2]==1) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==2) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==3) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==4) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==5) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==6) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==7) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==8) array_bg <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==9) array_bg <= {WA{ {WB{1'bx}} }};
// initialize to defaaults (all bits to 0)
if (cnt[30:2]==0) array_bg <= '0;
else if (cnt[30:2]==1) array_bg <= '0;
else if (cnt[30:2]==2) array_bg <= '0;
else if (cnt[30:2]==3) array_bg <= '0;
else if (cnt[30:2]==4) array_bg <= '0;
else if (cnt[30:2]==5) array_bg <= '0;
else if (cnt[30:2]==6) array_bg <= '0;
else if (cnt[30:2]==7) array_bg <= '0;
else if (cnt[30:2]==8) array_bg <= '0;
else if (cnt[30:2]==9) array_bg <= '0;
end else if (cnt[1:0]==2'd1) begin
// write value to array
if (cnt[30:2]==0) begin end
@@ -64,19 +64,19 @@ module t (/*AUTOARG*/
else if (cnt[30:2]==9) array_bg [WA -1 ][WB -1 ] <= {1 *1 +0{1'b1}};
end else if (cnt[1:0]==2'd2) begin
// check array value
if (cnt[30:2]==0) begin if (array_bg !== 64'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) begin $display("%b", array_bg); $stop(); end end
if (cnt[30:2]==0) begin if (array_bg !== 64'b0000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==1) begin if (array_bg !== 64'b1111111111111111111111111111111111111111111111111111111111111111) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==2) begin if (array_bg !== 64'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx11111111111111111111111111111111) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==3) begin if (array_bg !== 64'b11111111111111111111111111111111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==4) begin if (array_bg !== 64'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx11111111) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==5) begin if (array_bg !== 64'b11111111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==6) begin if (array_bg !== 64'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1111) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==7) begin if (array_bg !== 64'b1111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==8) begin if (array_bg !== 64'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==9) begin if (array_bg !== 64'b1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==2) begin if (array_bg !== 64'b0000000000000000000000000000000011111111111111111111111111111111) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==3) begin if (array_bg !== 64'b1111111111111111111111111111111100000000000000000000000000000000) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==4) begin if (array_bg !== 64'b0000000000000000000000000000000000000000000000000000000011111111) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==5) begin if (array_bg !== 64'b1111111100000000000000000000000000000000000000000000000000000000) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==6) begin if (array_bg !== 64'b0000000000000000000000000000000000000000000000000000000000001111) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==7) begin if (array_bg !== 64'b1111000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==8) begin if (array_bg !== 64'b0000000000000000000000000000000000000000000000000000000000000001) begin $display("%b", array_bg); $stop(); end end
else if (cnt[30:2]==9) begin if (array_bg !== 64'b1000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_bg); $stop(); end end
end else if (cnt[1:0]==2'd3) begin
// read value from array (not a very good test for now)
if (cnt[30:2]==0) begin if (array_bg !== {WA *WB {1'bx}}) $stop(); end
if (cnt[30:2]==0) begin if (array_bg !== {WA *WB {1'b0}}) $stop(); end
else if (cnt[30:2]==1) begin if (array_bg !== {WA *WB +0{1'b1}}) $stop(); end
else if (cnt[30:2]==2) begin if (array_bg [WA/2-1:0 ] !== {WA/2*WB +0{1'b1}}) $stop(); end
else if (cnt[30:2]==3) begin if (array_bg [WA -1:WA/2] !== {WA/2*WB +0{1'b1}}) $stop(); end
@@ -91,17 +91,17 @@ module t (/*AUTOARG*/
// little endian
always @ (posedge clk)
if (cnt[1:0]==2'd0) begin
// initialize to defaaults (all bits to x)
if (cnt[30:2]==0) array_lt <= {WA *WB{1'bx} };
else if (cnt[30:2]==1) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==2) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==3) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==4) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==5) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==6) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==7) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==8) array_lt <= {WA{ {WB{1'bx}} }};
else if (cnt[30:2]==9) array_lt <= {WA{ {WB{1'bx}} }};
// initialize to defaaults (all bits to 0)
if (cnt[30:2]==0) array_lt <= '0;
else if (cnt[30:2]==1) array_lt <= '0;
else if (cnt[30:2]==2) array_lt <= '0;
else if (cnt[30:2]==3) array_lt <= '0;
else if (cnt[30:2]==4) array_lt <= '0;
else if (cnt[30:2]==5) array_lt <= '0;
else if (cnt[30:2]==6) array_lt <= '0;
else if (cnt[30:2]==7) array_lt <= '0;
else if (cnt[30:2]==8) array_lt <= '0;
else if (cnt[30:2]==9) array_lt <= '0;
end else if (cnt[1:0]==2'd1) begin
// write value to array
if (cnt[30:2]==0) begin end
@@ -116,19 +116,19 @@ module t (/*AUTOARG*/
else if (cnt[30:2]==9) array_lt [ WA -1][ WB -1] <= {1 *1 +0{1'b1}};
end else if (cnt[1:0]==2'd2) begin
// check array value
if (cnt[30:2]==0) begin if (array_lt !== 64'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) begin $display("%b", array_lt); $stop(); end end
if (cnt[30:2]==0) begin if (array_lt !== 64'b0000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==1) begin if (array_lt !== 64'b1111111111111111111111111111111111111111111111111111111111111111) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==2) begin if (array_lt !== 64'b11111111111111111111111111111111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==3) begin if (array_lt !== 64'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx11111111111111111111111111111111) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==4) begin if (array_lt !== 64'b11111111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==5) begin if (array_lt !== 64'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx11111111) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==6) begin if (array_lt !== 64'b1111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==7) begin if (array_lt !== 64'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1111) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==8) begin if (array_lt !== 64'b1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==9) begin if (array_lt !== 64'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==2) begin if (array_lt !== 64'b1111111111111111111111111111111100000000000000000000000000000000) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==3) begin if (array_lt !== 64'b0000000000000000000000000000000011111111111111111111111111111111) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==4) begin if (array_lt !== 64'b1111111100000000000000000000000000000000000000000000000000000000) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==5) begin if (array_lt !== 64'b0000000000000000000000000000000000000000000000000000000011111111) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==6) begin if (array_lt !== 64'b1111000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==7) begin if (array_lt !== 64'b0000000000000000000000000000000000000000000000000000000000001111) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==8) begin if (array_lt !== 64'b1000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_lt); $stop(); end end
else if (cnt[30:2]==9) begin if (array_lt !== 64'b0000000000000000000000000000000000000000000000000000000000000001) begin $display("%b", array_lt); $stop(); end end
end else if (cnt[1:0]==2'd3) begin
// read value from array (not a very good test for now)
if (cnt[30:2]==0) begin if (array_lt !== {WA *WB {1'bx}}) $stop(); end
if (cnt[30:2]==0) begin if (array_lt !== {WA *WB {1'b0}}) $stop(); end
else if (cnt[30:2]==1) begin if (array_lt !== {WA *WB +0{1'b1}}) $stop(); end
else if (cnt[30:2]==2) begin if (array_lt [0 :WA/2-1] !== {WA/2*WB +0{1'b1}}) $stop(); end
else if (cnt[30:2]==3) begin if (array_lt [WA/2:WA -1] !== {WA/2*WB +0{1'b1}}) $stop(); end
+4 -2
View File
@@ -97,7 +97,8 @@ void t_embed_child_io_eval (unsigned char clk,
VL_DEBUG_IF(VL_PRINTF(" t_embed1_child_io_eval\n"); );
Vt_embed1_child* __modelp = __get_modelp();
VL_DEBUG_IF(VL_PRINTF("[%0ld] in clk=%x b=%x V=%x R=%x\n",
VL_TIME_Q(), clk, bit_in, vec_in[0], is_ref););
(long int) (VL_TIME_Q()), clk, bit_in, vec_in[0],
is_ref););
__modelp->clk = clk;
__modelp->bit_in = bit_in;
__modelp->vec_in = vec_in[0];
@@ -119,5 +120,6 @@ void t_embed_child_io_eval (unsigned char clk,
wide_out[3] = __modelp->wide_out[3];
*did_init_out = __modelp->did_init_out;
VL_DEBUG_IF(VL_PRINTF("[%0ld] out b=%x V=%x DI=%x\n",
VL_TIME_Q(), *bit_out, *vec_out, *did_init_out););
(long int)(VL_TIME_Q()), *bit_out, *vec_out,
*did_init_out););
}
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
v_flags2 => ["--lint-only --inline-mult 1"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
);
ok(1);
1;
+28
View File
@@ -0,0 +1,28 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Wilson Snyder.
module init;
task t1;
reg ba,bb,bc,bd,be,bf,bg,bh,bi,bj,bk,bl,bm,bn,bo,bp,bq,br,bs,bt,bu,bv,bw,bx,by,bz;
reg ca,cb,cc,cd,ce,cf,cg,ch,ci,cj,ck,cl,cm,cn,co,cp,cq,cr,cs,ct,cu,cv,cw,cx,cy,cz;
reg da,db,dc,dd,de,df,dg,dh,di,dj,dk,dl,dm,dn, dp,dq,dr,ds,dt,du,dv,dw,dx,dy,dz;
begin : READER
$display ("Time: %0t Instance: %m", $time);
end
endtask
task t2;
reg ba,bb,bc,bd,be,bf,bg,bh,bi,bj,bk,bl,bm,bn,bo,bp,bq,br,bs,bt,bu,bv,bw,bx,by,bz;
begin : READER
$display ("Time: %0t Instance: %m", $time);
end
endtask
endmodule
module test();
init u_ram1();
init u_ram2();
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+43
View File
@@ -0,0 +1,43 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
parameter PAR = 3;
wire [31:0] o1a,o1b;
m1 #(0) m1a(.o(o1a));
m1 #(1) m1b(.o(o1b));
always @ (posedge clk) begin
if (o1a != 8) $stop;
if (o1b != 4) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
module m1 (output wire [31:0] o);
parameter W = 0;
generate
if (W == 0) begin
m2 m2 (.o(o));
defparam m2.PAR2 = 8;
end
else begin
m2 m2 (.o(o));
defparam m2.PAR2 = 4;
end
endgenerate
endmodule
module m2 (output wire [31:0] o);
parameter PAR2 = 10;
assign o = PAR2;
endmodule
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug517");
# Compile time only test
compile (
);
ok(1);
1;
+72
View File
@@ -0,0 +1,72 @@
// DESCRIPTION: Verilator: Test generate index usage.
//
// The code illustrates a problem in Verilator's handling of constant
// expressions inside generate indexes.
//
// This is a regression test against issue 517.
//
// **If you do not wish for your code to be released to the public
// please note it here, otherwise:**
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Jeremy Bennett.
`define START 8
`define SIZE 4
`define END (`START + `SIZE)
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [`END-1:0] y;
wire [`END-1:0] x;
foo foo_i (.y (y),
.x (x),
.clk (clk));
always @(posedge clk) begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule // t
module foo(output wire [`END-1:0] y,
input wire [`END-1:0] x,
input wire clk);
function peek_bar;
peek_bar = bar_inst[`START].i_bar.r; // this is ok
peek_bar = bar_inst[`START + 1].i_bar.r; // this fails, should not.
endfunction
genvar g;
generate
for (g = `START; g < `END; g = g + 1) begin: bar_inst
bar i_bar(.x (x[g]),
.y (y[g]),
.clk (clk));
end
endgenerate
endmodule : foo
module bar(output wire y,
input wire x,
input wire clk);
reg r = 0;
assign y = r;
always @(posedge clk) begin
r = x ? ~x : y;
end
endmodule : bar
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
expect=>quotemeta(
q{created tag with scope = top.v.tag
created tag with scope = top.v.b.gen[0].tag
created tag with scope = top.v.b.gen[1].tag
mod a has scope = top.v
mod a has tag = top.v.tag
mod b has scope = top.v.b
mod b has tag = top.v.tag
mod c has scope = top.v.b.gen[0].c
mod c has tag = top.v.b.gen[0].tag
mod c has scope = top.v.b.gen[1].c
mod c has tag = top.v.b.gen[1].tag
*-* All Finished *-*}),
);
ok(1);
1;
+84
View File
@@ -0,0 +1,84 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Wilson Snyder.
/* Acceptable answer 1
created tag with scope = top.t.tag
created tag with scope = top.t.b.gen[0].tag
created tag with scope = top.t.b.gen[1].tag
mod a has scope = top.t
mod a has tag = top.t.tag
mod b has scope = top.t.b
mod b has tag = top.t.tag
mod c has scope = top.t.b.gen[0].c
mod c has tag = top.t.b.gen[0].tag
mod c has scope = top.t.b.gen[1].c
mod c has tag = top.t.b.gen[1].tag
*/
/* Acceptable answer 2
created tag with scope = top.t.tag
created tag with scope = top.t.b.gen[0].tag
created tag with scope = top.t.b.gen[1].tag
mod a has scope = top.t
mod a has tag = top.t.tag
mod b has scope = top.t.b
mod b has tag = top.t.tag
mod c has scope = top.t.b.gen[0].c
mod c has tag = top.t.tag
mod c has scope = top.t.b.gen[1].c
mod c has tag = top.t.tag
*/
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
tag tag ();
b b ();
always @ (t.cyc) begin
if (t.cyc == 2) $display("mod a has scope = %m");
if (t.cyc == 2) $display("mod a has tag = %0s", tag.scope);
end
always @(posedge clk) begin
cyc <= cyc + 1;
if (cyc==99) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module b ();
genvar g;
generate
for (g=0; g<2; g++) begin : gen
tag tag ();
c c ();
end
endgenerate
always @ (t.cyc) begin
if (t.cyc == 3) $display("mod b has scope = %m");
if (t.cyc == 3) $display("mod b has tag = %0s", tag.scope);
end
endmodule
module c ();
always @ (t.cyc) begin
if (t.cyc == 4) $display("mod c has scope = %m");
if (t.cyc == 4) $display("mod c has tag = %0s", tag.scope);
end
endmodule
module tag ();
bit [100*8-1:0] scope;
initial begin
$sformat(scope,"%m");
$display("created tag with scope = %0s",scope);
end
endmodule
+9
View File
@@ -53,6 +53,11 @@ module t (/*AUTOARG*/
// verilator lint_on WIDTH
end
reg signed [32:0] bug349;
initial
begin
end
integer i;
initial begin
if ((-1 >>> 3) != -1) $stop; // Decimals are signed
@@ -81,6 +86,10 @@ module t (/*AUTOARG*/
i = -'sd12 /3; if (i !== 32'hfffffffc) $stop;
i = -4'sd12 /3; if (i !== 32'h00000001) $stop;
// verilator lint_on WIDTH
// verilator lint_off WIDTH
bug349 = 4'sb1111 - 1'b1;
if (bug349 != 32'he) $stop;
end
function signed [15:0] copy_signed;
+1 -1
View File
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
v_flags => ["--lint-only"],
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
'%Error: t/t_mem_packed_assign_bad.v:\d+: Unsupported: Assignment between packed arrays of different dimensions
+5
View File
@@ -9,6 +9,9 @@ package functions;
function real abs (real num);
abs = (num <0) ? -num : num;
endfunction
function real neg (real num);
return -abs(num); // Check package funcs can call package funcs
endfunction
endpackage
module t ();
@@ -19,6 +22,8 @@ module t ();
initial begin
if (abs(-2.1) != 2.1) $stop;
if (abs(2.2) != 2.2) $stop;
if (neg(-2.1) != -2.1) $stop;
if (neg(2.2) != -2.2) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
+2
View File
@@ -19,7 +19,9 @@ module t ();
// synthesis translate on
localparam LP_PACK_AND_MOD = 20;
initial begin
// verilator lint_off STMTDLY
#10;
// verilator lint_on STMTDLY
if (LP_PACK_AND_MOD != 20) $stop;
check_param();
$write("*-* All Finished *-*\n");
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
# Compile only
ok(1);
1;
+68
View File
@@ -0,0 +1,68 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
package defs;
function automatic integer max;
input integer a;
input integer b;
max = (a > b) ? a : b;
endfunction
function automatic integer log2;
input integer value;
value = value >> 1;
for (log2 = 0; value > 0; log2 = log2 + 1)
value = value >> 1;
endfunction
function automatic integer ceil_log2;
input integer value;
value = value - 1;
for (ceil_log2 = 0; value > 0; ceil_log2 = ceil_log2 + 1)
value = value >> 1;
endfunction
endpackage
module sub();
import defs::*;
parameter RAND_NUM_MAX = "";
localparam DATA_RANGE = RAND_NUM_MAX + 1;
localparam DATA_WIDTH = ceil_log2(DATA_RANGE);
localparam WIDTH = max(4, ceil_log2(DATA_RANGE + 1));
endmodule
module t(/*AUTOARG*/
// Inputs
clk
);
import defs::*;
parameter WHICH = 0;
parameter MAX_COUNT = 10;
localparam MAX_EXPONENT = log2(MAX_COUNT);
localparam EXPONENT_WIDTH = ceil_log2(MAX_EXPONENT + 1);
input clk;
generate
if (WHICH == 1)
begin : which_true
sub sub_true();
defparam sub_true.RAND_NUM_MAX = MAX_EXPONENT;
end
else
begin : which_false
sub sub_false();
defparam sub_false.RAND_NUM_MAX = MAX_COUNT;
end
endgenerate
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2 => ["--lint-only"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
);
ok(1);
1;
+29
View File
@@ -0,0 +1,29 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use.
// bug541
module t(clk,odata);
input clk;
output [7:0] odata;
paramtest_DFFRE #(1) dffre0(clk,odata[7]);
paramtest_WRAP #(7) dffe0(clk,odata[6:0]);
endmodule
module paramtest_WRAP(clk,q);
parameter W=1;
input clk;
output [W-1:0] q;
paramtest_DFFRE #(W) dffre0(clk,q);
endmodule
module paramtest_DFFRE(clk,q);
parameter W=1;
parameter [W-1:0] INIT={W{1'b0}};
input clk;
output [W-1:0] q;
reg [W-1:0] q;
always @(posedge clk) begin
q <= INIT;
end
endmodule
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
v_flags2 => ["--savable"],
save_time => 500,
);
execute (
check_finished=>0,
all_run_flags => ['+save_time=500'],
);
-r "$Self->{obj_dir}/saved.vltsv" or $Self->error("Saved.vltsv not created\n");
execute (
all_run_flags => ['+save_restore=1'],
check_finished=>1,
);
ok(1);
1;
+77
View File
@@ -0,0 +1,77 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
/*verilator no_inline_module*/ // So we'll get hiearachy we can test
input clk;
sub sub (/*AUTOINST*/
// Inputs
.clk (clk));
endmodule
module sub (/*AUTOARG*/
// Inputs
clk
);
input clk;
/*verilator no_inline_module*/ // So we'll get hiearachy we can test
integer cyc=0;
reg [127:0] save128;
reg [47:0] save48;
reg [1:0] save2;
reg [255:0] cycdone; // Make sure each cycle executes exactly once
reg [31:0] vec[2:1][2:1];
real r;
string s,s2;
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d\n",$time, cyc);
`endif
cyc <= cyc + 1;
if (cycdone[cyc[7:0]]) $stop;
cycdone[cyc[7:0]] <= '1;
if (cyc==0) begin
// Setup
save128 <= 128'hc77bb9b3784ea0914afe43fb79d7b71e;
save48 <= 48'h4afe43fb79d7;
save2 <= 2'b10;
vec[1][1] <= 32'h0101;
vec[1][2] <= 32'h0102;
vec[2][1] <= 32'h0201;
vec[2][2] <= 32'h0202;
r <= 1.234;
s <= "hello";
end
if (cyc==1) begin
if ($test$plusargs("save_restore")!=0) begin
// Don't allow the restored model to run from time 0, it must run from a restore
$write("%%Error: didn't really restore\n");
$stop;
end
end
else if (cyc==99) begin
if (save128 !== 128'hc77bb9b3784ea0914afe43fb79d7b71e) $stop;
if (save48 !== 48'h4afe43fb79d7) $stop;
if (save2 !== 2'b10) $stop;
if (cycdone !== {{(256-99){1'b0}}, {99{1'b1}}}) $stop;
if (vec[1][1] !== 32'h0101) $stop;
if (vec[1][2] !== 32'h0102) $stop;
if (vec[2][1] !== 32'h0201) $stop;
if (vec[2][2] !== 32'h0202) $stop;
if (r != 1.234) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
+15 -8
View File
@@ -15,6 +15,11 @@ module t;
bit b0;
} b4_t;
typedef struct packed { // [3:0]
b4_t x1;
b4_t x0;
} b4x2_t;
typedef union packed { // [3:0]
bit [3:0] quad0;
b4_t quad1;
@@ -60,7 +65,6 @@ module t;
if (arr[1].four !== 4'b1010) $stop;
//
// Initialization
`ifndef VERILATOR // UNSUPPORTED
begin
b4_t q = '{1'b1, 1'b1, 1'b0, 1'b0};
if (q != 4'b1100) $stop;
@@ -74,18 +78,21 @@ module t;
if (q != 4'b1111) $stop;
end
begin
b4_t q = '{b0:1'b1, b2:1'b1, b3:1'b1, b1:1'b0};
if (q != 4'b1101) $stop;
b4x2_t m = '{4'b1001, '{1'b1, 1'b0, 1'b1, 1'b1}};
if (m != 8'b10011011) $stop;
end
begin
b4_t q = '{default:1'b1};
if (q != 4'b1111) $stop;
q.b1 = 0;
if (q != 4'b1101) $stop;
{q.b3,q.b2} = 2'b10;
if (q != 4'b1001) $stop;
end
`endif
begin
b4_t q = '{b0:1'b1, b2:1'b1, b3:1'b1, b1:1'b0};
if (q != 4'b1101) $stop;
end
begin
b4_t q = '{b2:1'b0, default:1'b1};
if (q != 4'b1011) $stop;
end
$write("*-* All Finished *-*\n");
$finish;
@@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug355");
compile (
);
+22 -18
View File
@@ -48,26 +48,28 @@ module t (/*AUTOARG*/
// big endian
always @ (posedge clk)
if (cnt[1:0]==2'd0) begin
// initialize to defaults (all bits 1'bx)
if (cnt[30:2]==0) struct_bg <= {WS{1'bx}};
else if (cnt[30:2]==1) struct_bg <= {WS{1'bx}};
else if (cnt[30:2]==2) struct_bg <= {WS{1'bx}};
else if (cnt[30:2]==3) struct_bg <= {WS{1'bx}};
else if (cnt[30:2]==4) struct_bg <= {WS{1'bx}};
else if (cnt[30:2]==5) struct_bg <= {WS{1'bx}};
else if (cnt[30:2]==6) struct_bg <= {WS{1'bx}};
// initialize to defaults (all bits 1'b0)
if (cnt[30:2]==0) struct_bg <= '0;
else if (cnt[30:2]==1) struct_bg <= '0;
else if (cnt[30:2]==2) struct_bg <= '0;
else if (cnt[30:2]==3) struct_bg <= '0;
else if (cnt[30:2]==4) struct_bg <= '0;
else if (cnt[30:2]==5) struct_bg <= '0;
else if (cnt[30:2]==6) struct_bg <= '0;
end else if (cnt[1:0]==2'd1) begin
// write data into whole or part of the array using literals
if (cnt[30:2]==0) begin end
else if (cnt[30:2]==1) struct_bg <= '{0 ,1 , 2, 3};
else if (cnt[30:2]==2) struct_bg <= '{e0:1, e1:2, e2:3, e3:4};
else if (cnt[30:2]==3) struct_bg <= '{e3:6, e2:4, e1:2, e0:0};
// verilator lint_off WIDTH
else if (cnt[30:2]==4) struct_bg <= '{default:13};
else if (cnt[30:2]==5) struct_bg <= '{e2:8'haa, default:1};
else if (cnt[30:2]==6) struct_bg <= '{cnt+0 ,cnt+1 , cnt+2, cnt+3};
// verilator lint_on WIDTH
end else if (cnt[1:0]==2'd2) begin
// chack array agains expected value
if (cnt[30:2]==0) begin if (struct_bg !== 15'bx_xx_xxxx_xxxxxxxx) begin $display("%b", struct_bg); $stop(); end end
if (cnt[30:2]==0) begin if (struct_bg !== 15'b0_00_0000_00000000) begin $display("%b", struct_bg); $stop(); end end
else if (cnt[30:2]==1) begin if (struct_bg !== 15'b0_01_0010_00000011) begin $display("%b", struct_bg); $stop(); end end
else if (cnt[30:2]==2) begin if (struct_bg !== 15'b1_10_0011_00000100) begin $display("%b", struct_bg); $stop(); end end
else if (cnt[30:2]==3) begin if (struct_bg !== 15'b0_10_0100_00000110) begin $display("%b", struct_bg); $stop(); end end
@@ -79,26 +81,28 @@ module t (/*AUTOARG*/
// little endian
always @ (posedge clk)
if (cnt[1:0]==2'd0) begin
// initialize to defaults (all bits 1'bx)
if (cnt[30:2]==0) struct_lt <= {WS{1'bx}};
else if (cnt[30:2]==1) struct_lt <= {WS{1'bx}};
else if (cnt[30:2]==2) struct_lt <= {WS{1'bx}};
else if (cnt[30:2]==3) struct_lt <= {WS{1'bx}};
else if (cnt[30:2]==4) struct_lt <= {WS{1'bx}};
else if (cnt[30:2]==5) struct_lt <= {WS{1'bx}};
else if (cnt[30:2]==6) struct_lt <= {WS{1'bx}};
// initialize to defaults (all bits 1'b0)
if (cnt[30:2]==0) struct_lt <= '0;
else if (cnt[30:2]==1) struct_lt <= '0;
else if (cnt[30:2]==2) struct_lt <= '0;
else if (cnt[30:2]==3) struct_lt <= '0;
else if (cnt[30:2]==4) struct_lt <= '0;
else if (cnt[30:2]==5) struct_lt <= '0;
else if (cnt[30:2]==6) struct_lt <= '0;
end else if (cnt[1:0]==2'd1) begin
// write data into whole or part of the array using literals
if (cnt[30:2]==0) begin end
else if (cnt[30:2]==1) struct_lt <= '{0 ,1 , 2, 3};
else if (cnt[30:2]==2) struct_lt <= '{e0:1, e1:2, e2:3, e3:4};
else if (cnt[30:2]==3) struct_lt <= '{e3:6, e2:4, e1:2, e0:0};
// verilator lint_off WIDTH
else if (cnt[30:2]==4) struct_lt <= '{default:13};
else if (cnt[30:2]==5) struct_lt <= '{e2:8'haa, default:1};
else if (cnt[30:2]==6) struct_lt <= '{cnt+0 ,cnt+1 , cnt+2, cnt+3};
// verilator lint_on WIDTH
end else if (cnt[1:0]==2'd2) begin
// chack array agains expected value
if (cnt[30:2]==0) begin if (struct_lt !== 15'bx_xx_xxxx_xxxxxxxx) begin $display("%b", struct_lt); $stop(); end end
if (cnt[30:2]==0) begin if (struct_lt !== 15'b0_00_0000_00000000) begin $display("%b", struct_lt); $stop(); end end
else if (cnt[30:2]==1) begin if (struct_lt !== 15'b0_01_0010_00000011) begin $display("%b", struct_lt); $stop(); end end
else if (cnt[30:2]==2) begin if (struct_lt !== 15'b1_10_0011_00000100) begin $display("%b", struct_lt); $stop(); end end
else if (cnt[30:2]==3) begin if (struct_lt !== 15'b0_10_0100_00000110) begin $display("%b", struct_lt); $stop(); end end
+3 -3
View File
@@ -281,7 +281,7 @@ int _mon_check_quad() {
CHECK_RESULT_NZ(vh2);
s_vpi_value v;
t_vpi_vecval vv; bzero(&vv,sizeof(vv));
t_vpi_vecval vv[2]; bzero(&vv,sizeof(vv));
s_vpi_time t;
t.type = vpiSimTime;
@@ -294,13 +294,13 @@ int _mon_check_quad() {
CHECK_RESULT_NZ(vhidx2);
v.format = vpiVectorVal;
v.value.vector = &vv;
v.value.vector = vv;
v.value.vector[1].aval = 0x12819213UL;
v.value.vector[0].aval = 0xabd31a1cUL;
vpi_put_value(vhidx2, &v, &t, vpiNoDelay);
v.format = vpiVectorVal;
v.value.vector = &vv;
v.value.vector = vv;
v.value.vector[1].aval = 0x1c77bb9bUL;
v.value.vector[0].aval = 0x3784ea09UL;
vpi_put_value(vhidx3, &v, &t, vpiNoDelay);