Merge pull request #3185 from YosysHQ/micko/co_sim

Add co-simulation in sim pass
This commit is contained in:
Miodrag Milanović 2022-02-07 16:36:43 +01:00 committed by GitHub
commit d7f7227ce8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 11555 additions and 23 deletions

View File

@ -594,9 +594,11 @@ $(eval $(call add_include_file,kernel/satgen.h))
$(eval $(call add_include_file,kernel/qcsat.h))
$(eval $(call add_include_file,kernel/ff.h))
$(eval $(call add_include_file,kernel/ffinit.h))
$(eval $(call add_include_file,kernel/fstdata.h))
$(eval $(call add_include_file,kernel/mem.h))
$(eval $(call add_include_file,libs/ezsat/ezsat.h))
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
$(eval $(call add_include_file,libs/fst/fstapi.h))
$(eval $(call add_include_file,libs/sha1/sha1.h))
$(eval $(call add_include_file,libs/json11/json11.hpp))
$(eval $(call add_include_file,passes/fsm/fsmdata.h))
@ -618,7 +620,7 @@ ifneq ($(ABCEXTERNAL),)
kernel/yosys.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
endif
endif
OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o
OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/fstdata.o
kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"'
kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"'
@ -642,6 +644,10 @@ OBJS += libs/minisat/SimpSolver.o
OBJS += libs/minisat/Solver.o
OBJS += libs/minisat/System.o
OBJS += libs/fst/fstapi.o
OBJS += libs/fst/fastlz.o
OBJS += libs/fst/lz4.o
include $(YOSYS_SRC)/frontends/*/Makefile.inc
include $(YOSYS_SRC)/passes/*/Makefile.inc
include $(YOSYS_SRC)/backends/*/Makefile.inc

252
kernel/fstdata.cc Normal file
View File

@ -0,0 +1,252 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2022 Miodrag Milanovic <micko@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/fstdata.h"
USING_YOSYS_NAMESPACE
FstData::FstData(std::string filename) : ctx(nullptr)
{
const std::vector<std::string> g_units = { "s", "ms", "us", "ns", "ps", "fs", "as", "zs" };
ctx = (fstReaderContext *)fstReaderOpen(filename.c_str());
if (!ctx)
log_error("Error opening '%s'\n", filename.c_str());
int scale = (int)fstReaderGetTimescale(ctx);
timescale = pow(10.0, scale);
timescale_str = "";
int unit = 0;
int zeros = 0;
if (scale > 0) {
zeros = scale;
} else {
if ((scale % 3) == 0) {
zeros = (-scale % 3);
unit = (-scale / 3);
} else {
zeros = 3 - (-scale % 3);
unit = (-scale / 3) + 1;
}
}
for (int i=0;i<zeros; i++) timescale_str += "0";
timescale_str += g_units[unit];
extractVarNames();
}
FstData::~FstData()
{
if (ctx)
fstReaderClose(ctx);
}
uint64_t FstData::getStartTime() { return fstReaderGetStartTime(ctx); }
uint64_t FstData::getEndTime() { return fstReaderGetEndTime(ctx); }
fstHandle FstData::getHandle(std::string name) {
if (name_to_handle.find(name) != name_to_handle.end())
return name_to_handle[name];
else
return 0;
};
static std::string remove_spaces(std::string str)
{
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
return str;
}
void FstData::extractVarNames()
{
struct fstHier *h;
intptr_t snum = 0;
while ((h = fstReaderIterateHier(ctx))) {
switch (h->htyp) {
case FST_HT_SCOPE: {
snum++;
std::string fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, (void *)(snum));
scopes.push_back(fst_scope_name);
break;
}
case FST_HT_UPSCOPE: {
fstReaderPopScope(ctx);
snum = fstReaderGetCurrentScopeLen(ctx) ? (intptr_t)fstReaderGetCurrentScopeUserInfo(ctx) : 0;
break;
}
case FST_HT_VAR: {
FstVar var;
var.id = h->u.var.handle;
var.is_alias = h->u.var.is_alias;
var.name = remove_spaces(h->u.var.name);
var.scope = scopes.back();
var.width = h->u.var.length;
vars.push_back(var);
if (!var.is_alias)
handle_to_var[h->u.var.handle] = var;
std::string clean_name;
for(size_t i=0;i<strlen(h->u.var.name);i++)
{
char c = h->u.var.name[i];
if(c==' ') break;
clean_name += c;
}
if (clean_name[0]=='\\')
clean_name = clean_name.substr(1);
//log("adding %s.%s\n",var.scope.c_str(), clean_name.c_str());
name_to_handle[var.scope+"."+clean_name] = h->u.var.handle;
break;
}
}
}
}
static void reconstruct_edges_varlen(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
{
FstData *ptr = (FstData*)user_data;
ptr->reconstruct_edges_callback(pnt_time, pnt_facidx, pnt_value, plen);
}
static void reconstruct_edges(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value)
{
FstData *ptr = (FstData*)user_data;
uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0;
ptr->reconstruct_edges_callback(pnt_time, pnt_facidx, pnt_value, plen);
}
void FstData::reconstruct_edges_callback(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
{
std::string val = std::string((const char *)pnt_value);
std::string prev = last_data[pnt_facidx];
if (pnt_time>=start_time) {
if (prev!="1" && val=="1")
edges.push_back(pnt_time);
if (prev!="0" && val=="0")
edges.push_back(pnt_time);
}
last_data[pnt_facidx] = val;
}
std::vector<uint64_t> FstData::getAllEdges(std::vector<fstHandle> &signal, uint64_t start, uint64_t end)
{
start_time = start;
end_time = end;
last_data.clear();
for(auto &s : signal) {
last_data[s] = "x";
}
edges.clear();
fstReaderSetLimitTimeRange(ctx, start_time, end_time);
fstReaderClrFacProcessMaskAll(ctx);
for(const auto sig : signal)
fstReaderSetFacProcessMask(ctx,sig);
fstReaderIterBlocks2(ctx, reconstruct_edges, reconstruct_edges_varlen, this, nullptr);
return edges;
}
static void reconstruct_clb_varlen_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
{
FstData *ptr = (FstData*)user_data;
ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
}
static void reconstruct_clb_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value)
{
FstData *ptr = (FstData*)user_data;
uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0;
ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
}
void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
{
if (sample_times_ndx >= sample_times.size()) return;
uint64_t time = sample_times[sample_times_ndx];
// if we are past the timestamp
if (pnt_time > time) {
for (auto const& c : last_data)
{
handle_to_data[c.first].push_back(std::make_pair(time,c.second));
size_t index = handle_to_data[c.first].size() - 1;
time_to_index[c.first][time] = index;
}
sample_times_ndx++;
}
// always update last_data
last_data[pnt_facidx] = std::string((const char *)pnt_value);
}
void FstData::reconstructAtTimes(std::vector<fstHandle> &signal, std::vector<uint64_t> time)
{
handle_to_data.clear();
time_to_index.clear();
last_data.clear();
sample_times_ndx = 0;
sample_times = time;
fstReaderSetUnlimitedTimeRange(ctx);
fstReaderClrFacProcessMaskAll(ctx);
for(const auto sig : signal)
fstReaderSetFacProcessMask(ctx,sig);
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
if (time_to_index[signal.back()].count(time.back())==0) {
for (auto const& c : last_data)
{
handle_to_data[c.first].push_back(std::make_pair(time.back(),c.second));
size_t index = handle_to_data[c.first].size() - 1;
time_to_index[c.first][time.back()] = index;
}
}
}
void FstData::reconstructAllAtTimes(std::vector<uint64_t> time)
{
handle_to_data.clear();
time_to_index.clear();
last_data.clear();
sample_times_ndx = 0;
sample_times = time;
fstReaderSetUnlimitedTimeRange(ctx);
fstReaderSetFacProcessMaskAll(ctx);
fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
if (time_to_index[1].count(time.back())==0) {
for (auto const& c : last_data)
{
handle_to_data[c.first].push_back(std::make_pair(time.back(),c.second));
size_t index = handle_to_data[c.first].size() - 1;
time_to_index[c.first][time.back()] = index;
}
}
}
std::string FstData::valueAt(fstHandle signal, uint64_t time)
{
if (handle_to_data.find(signal) == handle_to_data.end())
log_error("Signal id %d not found\n", (int)signal);
auto &data = handle_to_data[signal];
if (time_to_index[signal].count(time)!=0) {
size_t index = time_to_index[signal][time];
return data.at(index).second;
} else {
log_error("No data for signal %d at time %d\n", (int)signal, (int)time);
}
}

81
kernel/fstdata.h Normal file
View File

@ -0,0 +1,81 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2022 Miodrag Milanovic <micko@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef FSTDATA_H
#define FSTDATA_H
#include "kernel/yosys.h"
#include "libs/fst/fstapi.h"
YOSYS_NAMESPACE_BEGIN
struct FstVar
{
fstHandle id;
std::string name;
bool is_alias;
std::string scope;
int width;
};
class FstData
{
public:
FstData(std::string filename);
~FstData();
uint64_t getStartTime();
uint64_t getEndTime();
std::vector<FstVar>& getVars() { return vars; };
void reconstruct_edges_callback(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen);
std::vector<uint64_t> getAllEdges(std::vector<fstHandle> &signal, uint64_t start_time, uint64_t end_time);
void reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen);
void reconstructAtTimes(std::vector<fstHandle> &signal,std::vector<uint64_t> time);
void reconstructAllAtTimes(std::vector<uint64_t> time);
std::string valueAt(fstHandle signal, uint64_t time);
fstHandle getHandle(std::string name);
double getTimescale() { return timescale; }
const char *getTimescaleString() { return timescale_str.c_str(); }
private:
void extractVarNames();
struct fstReaderContext *ctx;
std::vector<std::string> scopes;
std::vector<FstVar> vars;
std::map<fstHandle, FstVar> handle_to_var;
std::map<std::string, fstHandle> name_to_handle;
std::map<fstHandle, std::vector<std::pair<uint64_t, std::string>>> handle_to_data;
std::map<fstHandle, std::string> last_data;
std::map<fstHandle, std::map<uint64_t, size_t>> time_to_index;
std::vector<uint64_t> sample_times;
size_t sample_times_ndx;
double timescale;
std::string timescale_str;
uint64_t start_time;
uint64_t end_time;
std::vector<uint64_t> edges;
};
YOSYS_NAMESPACE_END
#endif

130
libs/fst/block_format.txt Normal file
View File

@ -0,0 +1,130 @@
See fstapi.h for the values for the FST_BL_XXX enums.
===========================================================================
compressed wrapper (typically over whole file)
uint8_t FST_BL_ZWRAPPER
uint64_t section length
uint64_t length of uncompressed data
[zlib compressed data]
===========================================================================
header block
uint8_t FST_BL_HDR
uint64_t section length
uint64_t start time
uint64_t end time
double endian test for "e"
uint64_t memory used by writer
uint64_t scope creation count
uint64_t var creation count
uint64_t max var idcode
uint64_t vc section count
int8_t timescale exponent
[128 bytes] version
[128 bytes] date
===========================================================================
geometry block
uint8_t FST_BL_GEOM
uint64_t section length
uint64_t length of uncompressed geometry data
uint64_t maxhandle
[compressed data]
(length of compressed data is section length - 24)
===========================================================================
hierarchy block
uint8_t FST_BL_HIER
uint64_t section length
uint64_t length of uncompressed hier data
[zlib compressed data]
or
uint8_t FST_BL_HIER_LZ4
uint64_t section length
uint64_t length of uncompressed hier data
[lz4 compressed data]
uint8_t FST_BL_HIER_LZ4DUO
uint64_t section length
uint64_t length of uncompressed hier data
varint length of hier data compressed once with lz4
[lz4 double compressed data]
===========================================================================
dumpon/off block
uint8_t FST_BL_BLACKOUT
uint64_t section length
varint num blackouts (section below is repeated this # times)
[
uint8_t on/off (nonzero = on)
varint delta time
]
===========================================================================
1..n value change blocks:
// header
uint8_t FST_BL_VCDATA (or FST_BL_VCDATA_DYN_ALIAS)
uint64_t section length
uint64_t begin time of section
uint64_t end time of section
uint64_t amount of buffer memory required in reader for full vc traversal
varint maxvalpos (length of uncompressed data)
varint length of compressed data
varint maxhandle associated with this checkpoint data
[compressed data]
---
// value changes
varint maxhandle associated with the value change data
uint8_t pack type ('F' is fastlz, '4' is lz4,
others ['Z'/'!'] are zlib)
varint chain 0 compressed data length (0 = uncompressed)
[compressed data]
...
varint chain n compressed data length (0 = uncompressed)
[compressed data]
---
// index: chain pointer table (from 0..maxhandle-1)
varint if &1 == 1, this is <<1 literal delta
if &1 == 0, this is <<1 RLE count of zeros
if == 0, next varint is handle of prev chain to use,
bit only if FST_BL_VCDATA_DYN_ALIAS or
later VCDATA format
---
uint64_t index length (subtract from here to get index position)
---
[compressed data for time section]
uint64_t uncompressed data length in bytes
uint64_t compressed data length in bytes
uint64_t number of time items
// end of section
===========================================================================

27
libs/fst/config.h Normal file
View File

@ -0,0 +1,27 @@
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
*/
#define HAVE_ALLOCA_H 1
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
#define HAVE_FSEEKO 1
/* Define to 1 if you have the `pthread' library (-lpthread). */
#define HAVE_LIBPTHREAD 1
/* Define to 1 if you have the `realpath' function. */
#define HAVE_REALPATH 1
#if defined(__MINGW32__)
#undef HAVE_ALLOCA_H
#undef HAVE_REALPATH
#endif
#if defined(_MSC_VER)
#undef HAVE_ALLOCA_H
#undef HAVE_REALPATH
#undef HAVE_LIBPTHREAD
#undef HAVE_FSEEKO
#endif
# ifndef __STDC_FORMAT_MACROS
# define __STDC_FORMAT_MACROS 1
# endif

528
libs/fst/fastlz.cc Normal file
View File

@ -0,0 +1,528 @@
/*
FastLZ - lightning-fast lossless compression library
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
SPDX-License-Identifier: MIT
*/
#include "fastlz.h"
#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
/*
* Always check for bound when decompressing.
* Generally it is best to leave it defined.
*/
#define FASTLZ_SAFE
/*
* Give hints to the compiler for branch prediction optimization.
*/
#if defined(__GNUC__) && (__GNUC__ > 2)
#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
#else
#define FASTLZ_EXPECT_CONDITIONAL(c) (c)
#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c)
#endif
/*
* Use inlined functions for supported systems.
*/
#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C)
#define FASTLZ_INLINE inline
#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
#define FASTLZ_INLINE __inline
#else
#define FASTLZ_INLINE
#endif
/*
* Prevent accessing more than 8-bit at once, except on x86 architectures.
*/
#if !defined(FASTLZ_STRICT_ALIGN)
#define FASTLZ_STRICT_ALIGN
#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */
#undef FASTLZ_STRICT_ALIGN
#elif defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__amd64) /* GNU C */
#undef FASTLZ_STRICT_ALIGN
#elif defined(_M_IX86) /* Intel, MSVC */
#undef FASTLZ_STRICT_ALIGN
#elif defined(__386)
#undef FASTLZ_STRICT_ALIGN
#elif defined(_X86_) /* MinGW */
#undef FASTLZ_STRICT_ALIGN
#elif defined(__I86__) /* Digital Mars */
#undef FASTLZ_STRICT_ALIGN
#endif
#endif
/* prototypes */
int fastlz_compress(const void *input, int length, void *output);
int fastlz_compress_level(int level, const void *input, int length, void *output);
int fastlz_decompress(const void *input, int length, void *output, int maxout);
#define MAX_COPY 32
#define MAX_LEN 264 /* 256 + 8 */
#define MAX_DISTANCE 8192
#if !defined(FASTLZ_STRICT_ALIGN)
#define FASTLZ_READU16(p) *((const flzuint16 *)(p))
#else
#define FASTLZ_READU16(p) ((p)[0] | (p)[1] << 8)
#endif
#define HASH_LOG 13
#define HASH_SIZE (1 << HASH_LOG)
#define HASH_MASK (HASH_SIZE - 1)
#define HASH_FUNCTION(v, p) \
{ \
v = FASTLZ_READU16(p); \
v ^= FASTLZ_READU16(p + 1) ^ (v >> (16 - HASH_LOG)); \
v &= HASH_MASK; \
}
#undef FASTLZ_LEVEL
#define FASTLZ_LEVEL 1
#undef FASTLZ_COMPRESSOR
#undef FASTLZ_DECOMPRESSOR
#define FASTLZ_COMPRESSOR fastlz1_compress
#define FASTLZ_DECOMPRESSOR fastlz1_decompress
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length, void *output);
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length, void *output, int maxout);
#include "fastlz.cc"
#undef FASTLZ_LEVEL
#define FASTLZ_LEVEL 2
#undef MAX_DISTANCE
#define MAX_DISTANCE 8191
#define MAX_FARDISTANCE (65535 + MAX_DISTANCE - 1)
#undef FASTLZ_COMPRESSOR
#undef FASTLZ_DECOMPRESSOR
#define FASTLZ_COMPRESSOR fastlz2_compress
#define FASTLZ_DECOMPRESSOR fastlz2_decompress
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length, void *output);
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length, void *output, int maxout);
#include "fastlz.cc"
int fastlz_compress(const void *input, int length, void *output)
{
/* for short block, choose fastlz1 */
if (length < 65536)
return fastlz1_compress(input, length, output);
/* else... */
return fastlz2_compress(input, length, output);
}
int fastlz_decompress(const void *input, int length, void *output, int maxout)
{
/* magic identifier for compression level */
int level = ((*(const flzuint8 *)input) >> 5) + 1;
if (level == 1)
return fastlz1_decompress(input, length, output, maxout);
if (level == 2)
return fastlz2_decompress(input, length, output, maxout);
/* unknown level, trigger error */
return 0;
}
int fastlz_compress_level(int level, const void *input, int length, void *output)
{
if (level == 1)
return fastlz1_compress(input, length, output);
if (level == 2)
return fastlz2_compress(input, length, output);
return 0;
}
#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void *input, int length, void *output)
{
const flzuint8 *ip = (const flzuint8 *)input;
const flzuint8 *ip_bound = ip + length - 2;
const flzuint8 *ip_limit = ip + length - 12;
flzuint8 *op = (flzuint8 *)output;
const flzuint8 *htab[HASH_SIZE];
const flzuint8 **hslot;
flzuint32 hval;
flzuint32 copy;
/* sanity check */
if (FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) {
if (length) {
/* create literal copy only */
*op++ = length - 1;
ip_bound++;
while (ip <= ip_bound)
*op++ = *ip++;
return length + 1;
} else
return 0;
}
/* initializes hash table */
for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
*hslot = ip;
/* we start with literal copy */
copy = 2;
*op++ = MAX_COPY - 1;
*op++ = *ip++;
*op++ = *ip++;
/* main loop */
while (FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) {
const flzuint8 *ref;
flzuint32 distance;
/* minimum match length */
flzuint32 len = 3;
/* comparison starting-point */
const flzuint8 *anchor = ip;
/* check for a run */
#if FASTLZ_LEVEL == 2
if (ip[0] == ip[-1] && FASTLZ_READU16(ip - 1) == FASTLZ_READU16(ip + 1)) {
distance = 1;
/* ip += 3; */ /* scan-build, never used */
ref = anchor - 1 + 3;
goto match;
}
#endif
/* find potential match */
HASH_FUNCTION(hval, ip);
hslot = htab + hval;
ref = htab[hval];
/* calculate distance to the match */
distance = anchor - ref;
/* update hash table */
*hslot = anchor;
/* is this a match? check the first 3 bytes */
if (distance == 0 ||
#if FASTLZ_LEVEL == 1
(distance >= MAX_DISTANCE) ||
#else
(distance >= MAX_FARDISTANCE) ||
#endif
*ref++ != *ip++ || *ref++ != *ip++ || *ref++ != *ip++)
goto literal;
#if FASTLZ_LEVEL == 2
/* far, needs at least 5-byte match */
if (distance >= MAX_DISTANCE) {
if (*ip++ != *ref++ || *ip++ != *ref++)
goto literal;
len += 2;
}
match:
#endif
/* last matched byte */
ip = anchor + len;
/* distance is biased */
distance--;
if (!distance) {
/* zero distance means a run */
flzuint8 x = ip[-1];
while (ip < ip_bound)
if (*ref++ != x)
break;
else
ip++;
} else
for (;;) {
/* safe because the outer check against ip limit */
if (*ref++ != *ip++)
break;
if (*ref++ != *ip++)
break;
if (*ref++ != *ip++)
break;
if (*ref++ != *ip++)
break;
if (*ref++ != *ip++)
break;
if (*ref++ != *ip++)
break;
if (*ref++ != *ip++)
break;
if (*ref++ != *ip++)
break;
while (ip < ip_bound)
if (*ref++ != *ip++)
break;
break;
}
/* if we have copied something, adjust the copy count */
if (copy)
/* copy is biased, '0' means 1 byte copy */
*(op - copy - 1) = copy - 1;
else
/* back, to overwrite the copy count */
op--;
/* reset literal counter */
copy = 0;
/* length is biased, '1' means a match of 3 bytes */
ip -= 3;
len = ip - anchor;
/* encode the match */
#if FASTLZ_LEVEL == 2
if (distance < MAX_DISTANCE) {
if (len < 7) {
*op++ = (len << 5) + (distance >> 8);
*op++ = (distance & 255);
} else {
*op++ = (7 << 5) + (distance >> 8);
for (len -= 7; len >= 255; len -= 255)
*op++ = 255;
*op++ = len;
*op++ = (distance & 255);
}
} else {
/* far away, but not yet in the another galaxy... */
if (len < 7) {
distance -= MAX_DISTANCE;
*op++ = (len << 5) + 31;
*op++ = 255;
*op++ = distance >> 8;
*op++ = distance & 255;
} else {
distance -= MAX_DISTANCE;
*op++ = (7 << 5) + 31;
for (len -= 7; len >= 255; len -= 255)
*op++ = 255;
*op++ = len;
*op++ = 255;
*op++ = distance >> 8;
*op++ = distance & 255;
}
}
#else
if (FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN - 2))
while (len > MAX_LEN - 2) {
*op++ = (7 << 5) + (distance >> 8);
*op++ = MAX_LEN - 2 - 7 - 2;
*op++ = (distance & 255);
len -= MAX_LEN - 2;
}
if (len < 7) {
*op++ = (len << 5) + (distance >> 8);
*op++ = (distance & 255);
} else {
*op++ = (7 << 5) + (distance >> 8);
*op++ = len - 7;
*op++ = (distance & 255);
}
#endif
/* update the hash at match boundary */
HASH_FUNCTION(hval, ip);
htab[hval] = ip++;
HASH_FUNCTION(hval, ip);
htab[hval] = ip++;
/* assuming literal copy */
*op++ = MAX_COPY - 1;
continue;
literal:
*op++ = *anchor++;
ip = anchor;
copy++;
if (FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) {
copy = 0;
*op++ = MAX_COPY - 1;
}
}
/* left-over as literal copy */
ip_bound++;
while (ip <= ip_bound) {
*op++ = *ip++;
copy++;
if (copy == MAX_COPY) {
copy = 0;
*op++ = MAX_COPY - 1;
}
}
/* if we have copied something, adjust the copy length */
if (copy)
*(op - copy - 1) = copy - 1;
else
op--;
#if FASTLZ_LEVEL == 2
/* marker for fastlz2 */
*(flzuint8 *)output |= (1 << 5);
#endif
return op - (flzuint8 *)output;
}
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void *input, int length, void *output, int maxout)
{
const flzuint8 *ip = (const flzuint8 *)input;
const flzuint8 *ip_limit = ip + length;
flzuint8 *op = (flzuint8 *)output;
flzuint8 *op_limit = op + maxout;
flzuint32 ctrl = (*ip++) & 31;
int loop = 1;
do {
const flzuint8 *ref = op;
flzuint32 len = ctrl >> 5;
flzuint32 ofs = (ctrl & 31) << 8;
if (ctrl >= 32) {
#if FASTLZ_LEVEL == 2
flzuint8 code;
#endif
len--;
ref -= ofs;
if (len == 7 - 1)
#if FASTLZ_LEVEL == 1
len += *ip++;
ref -= *ip++;
#else
do {
code = *ip++;
len += code;
} while (code == 255);
code = *ip++;
ref -= code;
/* match from 16-bit distance */
if (FASTLZ_UNEXPECT_CONDITIONAL(code == 255))
if (FASTLZ_EXPECT_CONDITIONAL(ofs == (31 << 8))) {
ofs = (*ip++) << 8;
ofs += *ip++;
ref = op - ofs - MAX_DISTANCE;
}
#endif
#ifdef FASTLZ_SAFE
if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit))
return 0;
if (FASTLZ_UNEXPECT_CONDITIONAL(ref - 1 < (flzuint8 *)output))
return 0;
#endif
if (FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
ctrl = *ip++;
else
loop = 0;
if (ref == op) {
/* optimize copy for a run */
flzuint8 b = ref[-1];
*op++ = b;
*op++ = b;
*op++ = b;
for (; len; --len)
*op++ = b;
} else {
#if !defined(FASTLZ_STRICT_ALIGN)
const flzuint16 *p;
flzuint16 *q;
#endif
/* copy from reference */
ref--;
*op++ = *ref++;
*op++ = *ref++;
*op++ = *ref++;
#if !defined(FASTLZ_STRICT_ALIGN)
/* copy a byte, so that now it's word aligned */
if (len & 1) {
*op++ = *ref++;
len--;
}
/* copy 16-bit at once */
q = (flzuint16 *)op;
op += len;
p = (const flzuint16 *)ref;
for (len >>= 1; len > 4; len -= 4) {
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
}
for (; len; --len)
*q++ = *p++;
#else
for (; len; --len)
*op++ = *ref++;
#endif
}
} else {
ctrl++;
#ifdef FASTLZ_SAFE
if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
return 0;
if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
return 0;
#endif
*op++ = *ip++;
for (--ctrl; ctrl; ctrl--)
*op++ = *ip++;
loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
if (loop)
ctrl = *ip++;
}
} while (FASTLZ_EXPECT_CONDITIONAL(loop));
return op - (flzuint8 *)output;
}
#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */

109
libs/fst/fastlz.h Normal file
View File

@ -0,0 +1,109 @@
/*
FastLZ - lightning-fast lossless compression library
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
SPDX-License-Identifier: MIT
*/
#ifndef FASTLZ_H
#define FASTLZ_H
#include <inttypes.h>
#define flzuint8 uint8_t
#define flzuint16 uint16_t
#define flzuint32 uint32_t
#define FASTLZ_VERSION 0x000100
#define FASTLZ_VERSION_MAJOR 0
#define FASTLZ_VERSION_MINOR 0
#define FASTLZ_VERSION_REVISION 0
#define FASTLZ_VERSION_STRING "0.1.0"
#if defined (__cplusplus)
extern "C" {
#endif
/**
Compress a block of data in the input buffer and returns the size of
compressed block. The size of input buffer is specified by length. The
minimum input buffer size is 16.
The output buffer must be at least 5% larger than the input buffer
and can not be smaller than 66 bytes.
If the input is not compressible, the return value might be larger than
length (input buffer size).
The input buffer and the output buffer can not overlap.
*/
int fastlz_compress(const void* input, int length, void* output);
/**
Decompress a block of compressed data and returns the size of the
decompressed block. If error occurs, e.g. the compressed data is
corrupted or the output buffer is not large enough, then 0 (zero)
will be returned instead.
The input buffer and the output buffer can not overlap.
Decompression is memory safe and guaranteed not to write the output buffer
more than what is specified in maxout.
*/
int fastlz_decompress(const void* input, int length, void* output, int maxout);
/**
Compress a block of data in the input buffer and returns the size of
compressed block. The size of input buffer is specified by length. The
minimum input buffer size is 16.
The output buffer must be at least 5% larger than the input buffer
and can not be smaller than 66 bytes.
If the input is not compressible, the return value might be larger than
length (input buffer size).
The input buffer and the output buffer can not overlap.
Compression level can be specified in parameter level. At the moment,
only level 1 and level 2 are supported.
Level 1 is the fastest compression and generally useful for short data.
Level 2 is slightly slower but it gives better compression ratio.
Note that the compressed data, regardless of the level, can always be
decompressed using the function fastlz_decompress above.
*/
int fastlz_compress_level(int level, const void* input, int length, void* output);
#if defined (__cplusplus)
}
#endif
#endif /* FASTLZ_H */

6546
libs/fst/fstapi.cc Normal file

File diff suppressed because it is too large Load Diff

500
libs/fst/fstapi.h Normal file
View File

@ -0,0 +1,500 @@
/*
* Copyright (c) 2009-2018 Tony Bybell.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
*/
#ifndef FST_API_H
#define FST_API_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#if defined(_MSC_VER)
#include "libs/zlib/zlib.h"
#include <io.h>
#include <process.h>
#define ftruncate _chsize_s
#define unlink _unlink
#define fileno _fileno
#define lseek _lseeki64
#ifdef _WIN64
#define ssize_t __int64
#define SSIZE_MAX 9223372036854775807i64
#else
#define ssize_t long
#define SSIZE_MAX 2147483647L
#endif
#include "stdint.h"
#else
#include <zlib.h>
#include <unistd.h>
#endif
#include <time.h>
#define FST_RDLOAD "FSTLOAD | "
typedef uint32_t fstHandle;
typedef uint32_t fstEnumHandle;
enum fstWriterPackType
{
FST_WR_PT_ZLIB = 0,
FST_WR_PT_FASTLZ = 1,
FST_WR_PT_LZ4 = 2
};
enum fstFileType
{
FST_FT_MIN = 0,
FST_FT_VERILOG = 0,
FST_FT_VHDL = 1,
FST_FT_VERILOG_VHDL = 2,
FST_FT_MAX = 2
};
enum fstBlockType
{
FST_BL_HDR = 0,
FST_BL_VCDATA = 1,
FST_BL_BLACKOUT = 2,
FST_BL_GEOM = 3,
FST_BL_HIER = 4,
FST_BL_VCDATA_DYN_ALIAS = 5,
FST_BL_HIER_LZ4 = 6,
FST_BL_HIER_LZ4DUO = 7,
FST_BL_VCDATA_DYN_ALIAS2 = 8,
FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
FST_BL_SKIP = 255 /* used while block is being written */
};
enum fstScopeType
{
FST_ST_MIN = 0,
FST_ST_VCD_MODULE = 0,
FST_ST_VCD_TASK = 1,
FST_ST_VCD_FUNCTION = 2,
FST_ST_VCD_BEGIN = 3,
FST_ST_VCD_FORK = 4,
FST_ST_VCD_GENERATE = 5,
FST_ST_VCD_STRUCT = 6,
FST_ST_VCD_UNION = 7,
FST_ST_VCD_CLASS = 8,
FST_ST_VCD_INTERFACE = 9,
FST_ST_VCD_PACKAGE = 10,
FST_ST_VCD_PROGRAM = 11,
FST_ST_VHDL_ARCHITECTURE = 12,
FST_ST_VHDL_PROCEDURE = 13,
FST_ST_VHDL_FUNCTION = 14,
FST_ST_VHDL_RECORD = 15,
FST_ST_VHDL_PROCESS = 16,
FST_ST_VHDL_BLOCK = 17,
FST_ST_VHDL_FOR_GENERATE = 18,
FST_ST_VHDL_IF_GENERATE = 19,
FST_ST_VHDL_GENERATE = 20,
FST_ST_VHDL_PACKAGE = 21,
FST_ST_MAX = 21,
FST_ST_GEN_ATTRBEGIN = 252,
FST_ST_GEN_ATTREND = 253,
FST_ST_VCD_SCOPE = 254,
FST_ST_VCD_UPSCOPE = 255
};
enum fstVarType
{
FST_VT_MIN = 0, /* start of vartypes */
FST_VT_VCD_EVENT = 0,
FST_VT_VCD_INTEGER = 1,
FST_VT_VCD_PARAMETER = 2,
FST_VT_VCD_REAL = 3,
FST_VT_VCD_REAL_PARAMETER = 4,
FST_VT_VCD_REG = 5,
FST_VT_VCD_SUPPLY0 = 6,
FST_VT_VCD_SUPPLY1 = 7,
FST_VT_VCD_TIME = 8,
FST_VT_VCD_TRI = 9,
FST_VT_VCD_TRIAND = 10,
FST_VT_VCD_TRIOR = 11,
FST_VT_VCD_TRIREG = 12,
FST_VT_VCD_TRI0 = 13,
FST_VT_VCD_TRI1 = 14,
FST_VT_VCD_WAND = 15,
FST_VT_VCD_WIRE = 16,
FST_VT_VCD_WOR = 17,
FST_VT_VCD_PORT = 18,
FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */
FST_VT_VCD_REALTIME = 20,
FST_VT_GEN_STRING =
21, /* generic string type (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */
FST_VT_SV_BIT = 22,
FST_VT_SV_LOGIC = 23,
FST_VT_SV_INT = 24, /* declare as size = 32 */
FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */
FST_VT_SV_LONGINT = 26, /* declare as size = 64 */
FST_VT_SV_BYTE = 27, /* declare as size = 8 */
FST_VT_SV_ENUM = 28, /* declare as appropriate type range */
FST_VT_SV_SHORTREAL =
29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */
FST_VT_MAX = 29 /* end of vartypes */
};
enum fstVarDir
{
FST_VD_MIN = 0,
FST_VD_IMPLICIT = 0,
FST_VD_INPUT = 1,
FST_VD_OUTPUT = 2,
FST_VD_INOUT = 3,
FST_VD_BUFFER = 4,
FST_VD_LINKAGE = 5,
FST_VD_MAX = 5
};
enum fstHierType
{
FST_HT_MIN = 0,
FST_HT_SCOPE = 0,
FST_HT_UPSCOPE = 1,
FST_HT_VAR = 2,
FST_HT_ATTRBEGIN = 3,
FST_HT_ATTREND = 4,
/* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when fstHier bridges other
formats */
FST_HT_TREEBEGIN = 5,
FST_HT_TREEEND = 6,
FST_HT_MAX = 6
};
enum fstAttrType
{
FST_AT_MIN = 0,
FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */
FST_AT_ARRAY = 1,
FST_AT_ENUM = 2,
FST_AT_PACK = 3,
FST_AT_MAX = 3
};
enum fstMiscType
{
FST_MT_MIN = 0,
FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */
FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */
FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */
FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */
FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
FST_MT_UNKNOWN = 8,
FST_MT_MAX = 8
};
enum fstArrayType
{
FST_AR_MIN = 0,
FST_AR_NONE = 0,
FST_AR_UNPACKED = 1,
FST_AR_PACKED = 2,
FST_AR_SPARSE = 3,
FST_AR_MAX = 3
};
enum fstEnumValueType
{
FST_EV_SV_INTEGER = 0,
FST_EV_SV_BIT = 1,
FST_EV_SV_LOGIC = 2,
FST_EV_SV_INT = 3,
FST_EV_SV_SHORTINT = 4,
FST_EV_SV_LONGINT = 5,
FST_EV_SV_BYTE = 6,
FST_EV_SV_UNSIGNED_INTEGER = 7,
FST_EV_SV_UNSIGNED_BIT = 8,
FST_EV_SV_UNSIGNED_LOGIC = 9,
FST_EV_SV_UNSIGNED_INT = 10,
FST_EV_SV_UNSIGNED_SHORTINT = 11,
FST_EV_SV_UNSIGNED_LONGINT = 12,
FST_EV_SV_UNSIGNED_BYTE = 13,
FST_EV_REG = 14,
FST_EV_TIME = 15,
FST_EV_MAX = 15
};
enum fstPackType
{
FST_PT_NONE = 0,
FST_PT_UNPACKED = 1,
FST_PT_PACKED = 2,
FST_PT_TAGGED_PACKED = 3,
FST_PT_MAX = 3
};
enum fstSupplementalVarType
{
FST_SVT_MIN = 0,
FST_SVT_NONE = 0,
FST_SVT_VHDL_SIGNAL = 1,
FST_SVT_VHDL_VARIABLE = 2,
FST_SVT_VHDL_CONSTANT = 3,
FST_SVT_VHDL_FILE = 4,
FST_SVT_VHDL_MEMORY = 5,
FST_SVT_MAX = 5
};
enum fstSupplementalDataType
{
FST_SDT_MIN = 0,
FST_SDT_NONE = 0,
FST_SDT_VHDL_BOOLEAN = 1,
FST_SDT_VHDL_BIT = 2,
FST_SDT_VHDL_BIT_VECTOR = 3,
FST_SDT_VHDL_STD_ULOGIC = 4,
FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5,
FST_SDT_VHDL_STD_LOGIC = 6,
FST_SDT_VHDL_STD_LOGIC_VECTOR = 7,
FST_SDT_VHDL_UNSIGNED = 8,
FST_SDT_VHDL_SIGNED = 9,
FST_SDT_VHDL_INTEGER = 10,
FST_SDT_VHDL_REAL = 11,
FST_SDT_VHDL_NATURAL = 12,
FST_SDT_VHDL_POSITIVE = 13,
FST_SDT_VHDL_TIME = 14,
FST_SDT_VHDL_CHARACTER = 15,
FST_SDT_VHDL_STRING = 16,
FST_SDT_MAX = 16,
FST_SDT_SVT_SHIFT_COUNT =
10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left after shifting FST_SDT_SVT_SHIFT_COUNT */
FST_SDT_ABS_MAX = ((1 << (FST_SDT_SVT_SHIFT_COUNT)) - 1)
};
struct fstHier
{
unsigned char htyp;
union
{
/* if htyp == FST_HT_SCOPE */
struct fstHierScope
{
unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */
const char *name;
const char *component;
uint32_t name_length; /* strlen(u.scope.name) */
uint32_t component_length; /* strlen(u.scope.component) */
} scope;
/* if htyp == FST_HT_VAR */
struct fstHierVar
{
unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */
unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */
unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */
unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */
unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */
const char *name;
uint32_t length;
fstHandle handle;
uint32_t name_length; /* strlen(u.var.name) */
unsigned is_alias : 1;
} var;
/* if htyp == FST_HT_ATTRBEGIN */
struct fstHierAttr
{
unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */
unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
const char *name;
uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */
uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC +
FST_MT_SOURCESTEM) */
uint32_t name_length; /* strlen(u.attr.name) */
} attr;
} u;
};
struct fstETab
{
char *name;
uint32_t elem_count;
char **literal_arr;
char **val_arr;
};
/*
* writer functions
*/
void fstWriterClose(void *ctx);
void *fstWriterCreate(const char *nam, int use_compressed_hier);
fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits,
const char **literal_arr, const char **val_arr);
/* used for Verilog/SV */
fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, uint32_t len, const char *nam,
fstHandle aliasHandle);
/* future expansion for VHDL and other languages. The variable type, data type, etc map onto
the current Verilog/SV one. The "type" string is optional for a more verbose or custom description */
fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd, uint32_t len, const char *nam,
fstHandle aliasHandle, const char *type, enum fstSupplementalVarType svt,
enum fstSupplementalDataType sdt);
void fstWriterEmitDumpActive(void *ctx, int enable);
void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle);
void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val);
void fstWriterEmitValueChange32(void *ctx, fstHandle handle, uint32_t bits, uint32_t val);
void fstWriterEmitValueChange64(void *ctx, fstHandle handle, uint32_t bits, uint64_t val);
void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle, uint32_t bits, const uint32_t *val);
void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle, uint32_t bits, const uint64_t *val);
void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len);
void fstWriterEmitTimeChange(void *ctx, uint64_t tim);
void fstWriterFlushContext(void *ctx);
int fstWriterGetDumpSizeLimitReached(void *ctx);
int fstWriterGetFseekFailed(void *ctx);
void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype, const char *attrname, uint64_t arg);
void fstWriterSetAttrEnd(void *ctx);
void fstWriterSetComment(void *ctx, const char *comm);
void fstWriterSetDate(void *ctx, const char *dat);
void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes);
void fstWriterSetEnvVar(void *ctx, const char *envvar);
void fstWriterSetFileType(void *ctx, enum fstFileType filetype);
void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ);
void fstWriterSetParallelMode(void *ctx, int enable);
void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */
void fstWriterSetScope(void *ctx, enum fstScopeType scopetype, const char *scopename, const char *scopecomp);
void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath);
void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath);
void fstWriterSetTimescale(void *ctx, int ts);
void fstWriterSetTimescaleFromString(void *ctx, const char *s);
void fstWriterSetTimezero(void *ctx, int64_t tim);
void fstWriterSetUpscope(void *ctx);
void fstWriterSetValueList(void *ctx, const char *vl);
void fstWriterSetVersion(void *ctx, const char *vers);
/*
* reader functions
*/
void fstReaderClose(void *ctx);
void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx);
void fstReaderClrFacProcessMaskAll(void *ctx);
uint64_t fstReaderGetAliasCount(void *ctx);
const char *fstReaderGetCurrentFlatScope(void *ctx);
void *fstReaderGetCurrentScopeUserInfo(void *ctx);
int fstReaderGetCurrentScopeLen(void *ctx);
const char *fstReaderGetDateString(void *ctx);
int fstReaderGetDoubleEndianMatchState(void *ctx);
uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx);
unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx);
uint64_t fstReaderGetEndTime(void *ctx);
int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx);
int fstReaderGetFileType(void *ctx);
int fstReaderGetFseekFailed(void *ctx);
fstHandle fstReaderGetMaxHandle(void *ctx);
uint64_t fstReaderGetMemoryUsedByWriter(void *ctx);
uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx);
uint64_t fstReaderGetScopeCount(void *ctx);
uint64_t fstReaderGetStartTime(void *ctx);
signed char fstReaderGetTimescale(void *ctx);
int64_t fstReaderGetTimezero(void *ctx);
uint64_t fstReaderGetValueChangeSectionCount(void *ctx);
char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf);
uint64_t fstReaderGetVarCount(void *ctx);
const char *fstReaderGetVersionString(void *ctx);
struct fstHier *fstReaderIterateHier(void *ctx);
int fstReaderIterateHierRewind(void *ctx);
int fstReaderIterBlocks(void *ctx,
void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx,
const unsigned char *value),
void *user_callback_data_pointer, FILE *vcdhandle);
int fstReaderIterBlocks2(void *ctx,
void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time,
fstHandle facidx, const unsigned char *value),
void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time,
fstHandle facidx, const unsigned char *value,
uint32_t len),
void *user_callback_data_pointer, FILE *vcdhandle);
void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable);
void *fstReaderOpen(const char *nam);
void *fstReaderOpenForUtilitiesOnly(void);
const char *fstReaderPopScope(void *ctx);
int fstReaderProcessHier(void *ctx, FILE *vcdhandle);
const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info);
void fstReaderResetScope(void *ctx);
void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx);
void fstReaderSetFacProcessMaskAll(void *ctx);
void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time);
void fstReaderSetUnlimitedTimeRange(void *ctx);
void fstReaderSetVcdExtensions(void *ctx, int enable);
/*
* utility functions
*/
int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */
int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len);
int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
struct fstETab *fstUtilityExtractEnumTableFromString(const char *s);
void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */
#ifdef __cplusplus
}
#endif
#endif

1615
libs/fst/lz4.cc Normal file

File diff suppressed because it is too large Load Diff

367
libs/fst/lz4.h Normal file
View File

@ -0,0 +1,367 @@
/*
LZ4 - Fast LZ compression algorithm
Header File
Copyright (C) 2011-2015, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SPDX-License-Identifier: BSD-2-Clause
You can contact the author at :
- LZ4 source repository : https://github.com/Cyan4973/lz4
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
*/
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
/*
* lz4.h provides block compression functions, and gives full buffer control to programmer.
* If you need to generate inter-operable compressed data (respecting LZ4 frame specification),
* and can let the library handle its own memory, please use lz4frame.h instead.
*/
/**************************************
* Version
**************************************/
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
#define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */
#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR * 100 * 100 + LZ4_VERSION_MINOR * 100 + LZ4_VERSION_RELEASE)
int LZ4_versionNumber(void);
/**************************************
* Tuning parameter
**************************************/
/*
* LZ4_MEMORY_USAGE :
* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
* Increasing memory usage improves compression ratio
* Reduced memory usage can improve speed, due to cache effect
* Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
*/
#define LZ4_MEMORY_USAGE 14
/**************************************
* Simple Functions
**************************************/
int LZ4_compress_default(const char *source, char *dest, int sourceSize, int maxDestSize);
int LZ4_decompress_safe(const char *source, char *dest, int compressedSize, int maxDecompressedSize);
/*
LZ4_compress_default() :
Compresses 'sourceSize' bytes from buffer 'source'
into already allocated 'dest' buffer of size 'maxDestSize'.
Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize).
It also runs faster, so it's a recommended setting.
If the function cannot compress 'source' into a more limited 'dest' budget,
compression stops *immediately*, and the function result is zero.
As a consequence, 'dest' content is not valid.
This function never writes outside 'dest' buffer, nor read outside 'source' buffer.
sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE
maxDestSize : full or partial size of buffer 'dest' (which must be already allocated)
return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize)
or 0 if compression fails
LZ4_decompress_safe() :
compressedSize : is the precise full size of the compressed block.
maxDecompressedSize : is the size of destination buffer, which must be already allocated.
return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize)
If destination buffer is not large enough, decoding will stop and output an error code (<0).
If the source stream is detected malformed, the function will stop decoding and return a negative result.
This function is protected against buffer overflow exploits, including malicious data packets.
It never writes outside output buffer, nor reads outside input buffer.
*/
/**************************************
* Advanced Functions
**************************************/
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize) / 255) + 16)
/*
LZ4_compressBound() :
Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
This function is primarily useful for memory allocation purposes (destination buffer size).
Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize)
inputSize : max supported value is LZ4_MAX_INPUT_SIZE
return : maximum output size in a "worst case" scenario
or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE)
*/
int LZ4_compressBound(int inputSize);
/*
LZ4_compress_fast() :
Same as LZ4_compress_default(), but allows to select an "acceleration" factor.
The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
An acceleration value of "1" is the same as regular LZ4_compress_default()
Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1.
*/
int LZ4_compress_fast(const char *source, char *dest, int sourceSize, int maxDestSize, int acceleration);
/*
LZ4_compress_fast_extState() :
Same compression function, just using an externally allocated memory space to store compression state.
Use LZ4_sizeofState() to know how much memory must be allocated,
and allocate it on 8-bytes boundaries (using malloc() typically).
Then, provide it as 'void* state' to compression function.
*/
int LZ4_sizeofState(void);
int LZ4_compress_fast_extState(void *state, const char *source, char *dest, int inputSize, int maxDestSize,
int acceleration);
/*
LZ4_compress_destSize() :
Reverse the logic, by compressing as much data as possible from 'source' buffer
into already allocated buffer 'dest' of size 'targetDestSize'.
This function either compresses the entire 'source' content into 'dest' if it's large enough,
or fill 'dest' buffer completely with as much data as possible from 'source'.
*sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'.
New value is necessarily <= old value.
return : Nb bytes written into 'dest' (necessarily <= targetDestSize)
or 0 if compression fails
*/
int LZ4_compress_destSize(const char *source, char *dest, int *sourceSizePtr, int targetDestSize);
/*
LZ4_decompress_fast() :
originalSize : is the original and therefore uncompressed size
return : the number of bytes read from the source buffer (in other words, the compressed size)
If the source stream is detected malformed, the function will stop decoding and return a negative result.
Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes.
note : This function fully respect memory boundaries for properly formed compressed data.
It is a bit faster than LZ4_decompress_safe().
However, it does not provide any protection against intentionally modified data stream (malicious input).
Use this function in trusted environment only (data to decode comes from a trusted source).
*/
int LZ4_decompress_fast(const char *source, char *dest, int originalSize);
/*
LZ4_decompress_safe_partial() :
This function decompress a compressed block of size 'compressedSize' at position 'source'
into destination buffer 'dest' of size 'maxDecompressedSize'.
The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached,
reducing decompression time.
return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize)
Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.
Always control how many bytes were decoded.
If the source stream is detected malformed, the function will stop decoding and return a negative result.
This function never writes outside of output buffer, and never reads outside of input buffer. It is
therefore protected against malicious data packets
*/
int LZ4_decompress_safe_partial(const char *source, char *dest, int compressedSize, int targetOutputSize,
int maxDecompressedSize);
/***********************************************
* Streaming Compression Functions
***********************************************/
#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE - 3)) + 4)
#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long))
/*
* LZ4_stream_t
* information structure to track an LZ4 stream.
* important : init this structure content before first use !
* note : only allocated directly the structure if you are statically linking LZ4
* If you are using liblz4 as a DLL, please use below construction methods instead.
*/
typedef struct
{
long long table[LZ4_STREAMSIZE_U64];
} LZ4_stream_t;
/*
* LZ4_resetStream
* Use this function to init an allocated LZ4_stream_t structure
*/
void LZ4_resetStream(LZ4_stream_t *streamPtr);
/*
* LZ4_createStream will allocate and initialize an LZ4_stream_t structure
* LZ4_freeStream releases its memory.
* In the context of a DLL (liblz4), please use these methods rather than the static struct.
* They are more future proof, in case of a change of LZ4_stream_t size.
*/
LZ4_stream_t *LZ4_createStream(void);
int LZ4_freeStream(LZ4_stream_t *streamPtr);
/*
* LZ4_loadDict
* Use this function to load a static dictionary into LZ4_stream.
* Any previous data will be forgotten, only 'dictionary' will remain in memory.
* Loading a size of 0 is allowed.
* Return : dictionary size, in bytes (necessarily <= 64 KB)
*/
int LZ4_loadDict(LZ4_stream_t *streamPtr, const char *dictionary, int dictSize);
/*
* LZ4_compress_fast_continue
* Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression
* ratio. Important : Previous data blocks are assumed to still be present and unmodified ! 'dst' buffer must be already
* allocated. If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. If
* not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero.
*/
int LZ4_compress_fast_continue(LZ4_stream_t *streamPtr, const char *src, char *dst, int srcSize, int maxDstSize,
int acceleration);
/*
* LZ4_saveDict
* If previously compressed data block is not guaranteed to remain available at its memory location
* save it into a safer place (char* safeBuffer)
* Note : you don't need to call LZ4_loadDict() afterwards,
* dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue()
* Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error
*/
int LZ4_saveDict(LZ4_stream_t *streamPtr, char *safeBuffer, int dictSize);
/************************************************
* Streaming Decompression Functions
************************************************/
#define LZ4_STREAMDECODESIZE_U64 4
#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
typedef struct
{
unsigned long long table[LZ4_STREAMDECODESIZE_U64];
} LZ4_streamDecode_t;
/*
* LZ4_streamDecode_t
* information structure to track an LZ4 stream.
* init this structure content using LZ4_setStreamDecode or memset() before first use !
*
* In the context of a DLL (liblz4) please prefer usage of construction methods below.
* They are more future proof, in case of a change of LZ4_streamDecode_t size in the future.
* LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure
* LZ4_freeStreamDecode releases its memory.
*/
LZ4_streamDecode_t *LZ4_createStreamDecode(void);
int LZ4_freeStreamDecode(LZ4_streamDecode_t *LZ4_stream);
/*
* LZ4_setStreamDecode
* Use this function to instruct where to find the dictionary.
* Setting a size of 0 is allowed (same effect as reset).
* Return : 1 if OK, 0 if error
*/
int LZ4_setStreamDecode(LZ4_streamDecode_t *LZ4_streamDecode, const char *dictionary, int dictSize);
/*
*_continue() :
These decoding functions allow decompression of multiple blocks in "streaming" mode.
Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB)
In the case of a ring buffers, decoding buffer must be either :
- Exactly same size as encoding buffer, with same update rule (block boundaries at same positions)
In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB).
- Larger than encoding buffer, by a minimum of maxBlockSize more bytes.
maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block.
In which case, encoding and decoding buffers do not need to be synchronized,
and encoding ring buffer can have any size, including small ones ( < 64 KB).
- _At least_ 64 KB + 8 bytes + maxBlockSize.
In which case, encoding and decoding buffers do not need to be synchronized,
and encoding ring buffer can have any size, including larger than decoding buffer.
Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer,
and indicate where it is saved using LZ4_setStreamDecode()
*/
int LZ4_decompress_safe_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *source, char *dest,
int compressedSize, int maxDecompressedSize);
int LZ4_decompress_fast_continue(LZ4_streamDecode_t *LZ4_streamDecode, const char *source, char *dest,
int originalSize);
/*
Advanced decoding functions :
*_usingDict() :
These decoding functions work the same as
a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue()
They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure.
*/
int LZ4_decompress_safe_usingDict(const char *source, char *dest, int compressedSize, int maxDecompressedSize,
const char *dictStart, int dictSize);
int LZ4_decompress_fast_usingDict(const char *source, char *dest, int originalSize, const char *dictStart,
int dictSize);
/**************************************
* Obsolete Functions
**************************************/
/* Deprecate Warnings */
/* Should these warnings messages be a problem,
it is generally possible to disable them,
with -Wno-deprecated-declarations for gcc
or _CRT_SECURE_NO_WARNINGS in Visual for example.
You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */
#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK
#define LZ4_DEPRECATE_WARNING_DEFBLOCK
#define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
#if (LZ4_GCC_VERSION >= 405) || defined(__clang__)
#define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
#elif (LZ4_GCC_VERSION >= 301)
#define LZ4_DEPRECATED(message) __attribute__((deprecated))
#elif defined(_MSC_VER)
#define LZ4_DEPRECATED(message) __declspec(deprecated(message))
#else
#pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler")
#define LZ4_DEPRECATED(message)
#endif
#endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */
/* Obsolete compression functions */
/* These functions are planned to start generate warnings by r131 approximately */
int LZ4_compress(const char *source, char *dest, int sourceSize);
int LZ4_compress_limitedOutput(const char *source, char *dest, int sourceSize, int maxOutputSize);
int LZ4_compress_withState(void *state, const char *source, char *dest, int inputSize);
int LZ4_compress_limitedOutput_withState(void *state, const char *source, char *dest, int inputSize, int maxOutputSize);
int LZ4_compress_continue(LZ4_stream_t *LZ4_streamPtr, const char *source, char *dest, int inputSize);
int LZ4_compress_limitedOutput_continue(LZ4_stream_t *LZ4_streamPtr, const char *source, char *dest, int inputSize,
int maxOutputSize);
/* Obsolete decompression functions */
/* These function names are completely deprecated and must no longer be used.
They are only provided here for compatibility with older programs.
- LZ4_uncompress is the same as LZ4_decompress_fast
- LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe
These function prototypes are now disabled; uncomment them only if you really need them.
It is highly recommended to stop using these prototypes and migrate to maintained ones */
/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */
/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */
/* Obsolete streaming functions; use new streaming interface whenever possible */
LZ4_DEPRECATED("use LZ4_createStream() instead") void *LZ4_create(char *inputBuffer);
LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void);
LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void *state, char *inputBuffer);
LZ4_DEPRECATED("use LZ4_saveDict() instead") char *LZ4_slideInputBuffer(void *state);
/* Obsolete streaming decoding functions */
LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead")
int LZ4_decompress_safe_withPrefix64k(const char *src, char *dst, int compressedSize, int maxDstSize);
LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead")
int LZ4_decompress_fast_withPrefix64k(const char *src, char *dst, int originalSize);
#if defined(__cplusplus)
}
#endif

View File

@ -7,11 +7,20 @@ gitsha="$3"
rm -rf YosysVS-Tpl-v2.zip YosysVS
wget https://yosyshq.net/yosys/nogit/YosysVS-Tpl-v2.zip
wget https://zlib.net/zlib-1.2.11.tar.gz
unzip YosysVS-Tpl-v2.zip
rm -f YosysVS-Tpl-v2.zip
mv YosysVS "$vcxsrc"
tar xvfz zlib-1.2.11.tar.gz
mv YosysVS "$vcxsrc"
mkdir -p "$vcxsrc"/yosys
mkdir -p "$vcxsrc"/yosys/libs/zlib
mv zlib-1.2.11/* "$vcxsrc"/yosys/libs/zlib/.
rm -rf zlib-1.2.11
pushd "$vcxsrc"/yosys
ls libs/zlib/*.c | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' >> ../../srcfiles.txt
popd
{
n=$(grep -B999 '<ItemGroup>' "$vcxsrc"/YosysVS/YosysVS.vcxproj | wc -l)
head -n$n "$vcxsrc"/YosysVS/YosysVS.vcxproj

View File

@ -21,12 +21,49 @@
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/mem.h"
#include "kernel/fstdata.h"
#include <ctime>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
enum class SimulationMode {
sim,
cmp,
gold,
gate,
};
static const std::map<std::string, int> g_units =
{
{ "", -9 }, // default is ns
{ "s", 0 },
{ "ms", -3 },
{ "us", -6 },
{ "ns", -9 },
{ "ps", -12 },
{ "fs", -15 },
{ "as", -18 },
{ "zs", -21 },
};
static double stringToTime(std::string str)
{
if (str=="END") return -1;
char *endptr;
long value = strtol(str.c_str(), &endptr, 10);
if (g_units.find(endptr)==g_units.end())
log_error("Cannot parse '%s', bad unit '%s'\n", str.c_str(), endptr);
if (value < 0)
log_error("Time value '%s' must be positive\n", str.c_str());
return value * pow(10.0, g_units.at(endptr));
}
struct SimShared
{
bool debug = false;
@ -34,6 +71,11 @@ struct SimShared
bool writeback = false;
bool zinit = false;
int rstlen = 1;
FstData *fst = nullptr;
double start_time = 0;
double stop_time = -1;
SimulationMode sim_mode = SimulationMode::sim;
bool cycles_set = false;
};
void zinit(State &v)
@ -51,7 +93,8 @@ void zinit(Const &v)
struct SimInstance
{
SimShared *shared;
std::string scope;
Module *module;
Cell *instance;
@ -92,9 +135,11 @@ struct SimInstance
std::vector<Mem> memories;
dict<Wire*, pair<int, Const>> vcd_database;
dict<Wire*, pair<fstHandle, Const>> fst_database;
dict<Wire*, fstHandle> fst_handles;
SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
shared(shared), module(module), instance(instance), parent(parent), sigmap(module)
SimInstance(SimShared *shared, std::string scope, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
shared(shared), scope(scope), module(module), instance(instance), parent(parent), sigmap(module)
{
log_assert(module);
@ -116,6 +161,13 @@ struct SimInstance
}
}
if ((shared->fst) && !(shared->hide_internal && wire->name[0] == '$')) {
fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
if (id==0 && wire->name.isPublic())
log_warning("Unable to found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)).c_str());
fst_handles[wire] = id;
}
if (wire->attributes.count(ID::init)) {
Const initval = wire->attributes.at(ID::init);
for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
@ -144,7 +196,7 @@ struct SimInstance
Module *mod = module->design->module(cell->type);
if (mod != nullptr) {
dirty_children.insert(new SimInstance(shared, mod, cell, this));
dirty_children.insert(new SimInstance(shared, scope + "." + RTLIL::unescape_id(cell->name), mod, cell, this));
}
for (auto &port : cell->connections()) {
@ -622,14 +674,125 @@ struct SimInstance
for (auto child : children)
child.second->write_vcd_step(f);
}
void write_fst_header(struct fstContext *f)
{
fstWriterSetScope(f, FST_ST_VCD_MODULE, stringf("%s",log_id(name())).c_str(), nullptr);
for (auto wire : module->wires())
{
if (shared->hide_internal && wire->name[0] == '$')
continue;
fstHandle id = fstWriterCreateVar(f, FST_VT_VCD_WIRE, FST_VD_IMPLICIT, GetSize(wire),
stringf("%s%s", wire->name[0] == '$' ? "\\" : "", log_id(wire)).c_str(), 0);
fst_database[wire] = make_pair(id, Const());
}
for (auto child : children)
child.second->write_fst_header(f);
fstWriterSetUpscope(f);
}
void write_fst_step(struct fstContext *f)
{
for (auto &it : fst_database)
{
Wire *wire = it.first;
Const value = get_state(wire);
fstHandle id = it.second.first;
if (it.second.second == value)
continue;
it.second.second = value;
std::stringstream ss;
for (int i = GetSize(value)-1; i >= 0; i--) {
switch (value[i]) {
case State::S0: ss << "0"; break;
case State::S1: ss << "1"; break;
case State::Sx: ss << "x"; break;
default: ss << "z";
}
}
fstWriterEmitValueChange(f, id, ss.str().c_str());
}
for (auto child : children)
child.second->write_fst_step(f);
}
void setInitState(uint64_t time)
{
for (auto &it : ff_database)
{
Cell *cell = it.first;
SigSpec qsig = cell->getPort(ID::Q);
if (qsig.is_wire()) {
IdString name = qsig.as_wire()->name;
fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(name));
if (id==0 && name.isPublic())
log_warning("Unable to found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(name)).c_str());
if (id!=0) {
Const fst_val = Const::from_string(shared->fst->valueAt(id, time));
set_state(qsig, fst_val);
}
}
}
for (auto child : children)
child.second->setInitState(time);
}
bool checkSignals(uint64_t time)
{
bool retVal = false;
for(auto &item : fst_handles) {
if (item.second==0) continue; // Ignore signals not found
Const fst_val = Const::from_string(shared->fst->valueAt(item.second, time));
Const sim_val = get_state(item.first);
if (sim_val.size()!=fst_val.size())
log_error("Signal '%s' size is different in gold and gate.\n", log_id(item.first));
if (shared->sim_mode == SimulationMode::sim) {
// No checks performed when using stimulus
} else if (shared->sim_mode == SimulationMode::gate && !fst_val.is_fully_def()) { // FST data contains X
for(int i=0;i<fst_val.size();i++) {
if (fst_val[i]!=State::Sx && fst_val[i]!=sim_val[i]) {
log_warning("Signal '%s' in file %s in simulation %s\n", log_id(item.first), log_signal(fst_val), log_signal(sim_val));
retVal = true;
break;
}
}
} else if (shared->sim_mode == SimulationMode::gold && !sim_val.is_fully_def()) { // sim data contains X
for(int i=0;i<sim_val.size();i++) {
if (sim_val[i]!=State::Sx && fst_val[i]!=sim_val[i]) {
log_warning("Signal '%s' in file %s in simulation %s\n", log_id(item.first), log_signal(fst_val), log_signal(sim_val));
retVal = true;
break;
}
}
} else {
if (fst_val!=sim_val) {
log_warning("Signal '%s' in file %s in simulation '%s'\n", log_id(item.first), log_signal(fst_val), log_signal(sim_val));
retVal = true;
}
}
}
for (auto child : children)
retVal |= child.second->checkSignals(time);
return retVal;
}
};
struct SimWorker : SimShared
{
SimInstance *top = nullptr;
std::ofstream vcdfile;
struct fstContext *fstfile = nullptr;
pool<IdString> clock, clockn, reset, resetn;
std::string timescale;
std::string sim_filename;
std::string scope;
~SimWorker()
{
@ -638,9 +801,6 @@ struct SimWorker : SimShared
void write_vcd_header()
{
if (!vcdfile.is_open())
return;
vcdfile << stringf("$version %s $end\n", yosys_version_str);
std::time_t t = std::time(nullptr);
@ -660,13 +820,53 @@ struct SimWorker : SimShared
void write_vcd_step(int t)
{
if (!vcdfile.is_open())
return;
vcdfile << stringf("#%d\n", t);
top->write_vcd_step(vcdfile);
}
void write_fst_header()
{
std::time_t t = std::time(nullptr);
fstWriterSetDate(fstfile, asctime(std::localtime(&t)));
fstWriterSetVersion(fstfile, yosys_version_str);
if (!timescale.empty())
fstWriterSetTimescaleFromString(fstfile, timescale.c_str());
fstWriterSetPackType(fstfile, FST_WR_PT_FASTLZ);
fstWriterSetRepackOnClose(fstfile, 1);
top->write_fst_header(fstfile);
}
void write_fst_step(int t)
{
fstWriterEmitTimeChange(fstfile, t);
top->write_fst_step(fstfile);
}
void write_output_header()
{
if (vcdfile.is_open())
write_vcd_header();
if (fstfile)
write_fst_header();
}
void write_output_step(int t)
{
if (vcdfile.is_open())
write_vcd_step(t);
if (fstfile)
write_fst_step(t);
}
void write_output_end()
{
if (fstfile)
fstWriterClose(fstfile);
}
void update()
{
while (1)
@ -705,7 +905,7 @@ struct SimWorker : SimShared
void run(Module *topmod, int numcycles)
{
log_assert(top == nullptr);
top = new SimInstance(this, topmod);
top = new SimInstance(this, scope, topmod);
if (debug)
log("\n===== 0 =====\n");
@ -720,24 +920,25 @@ struct SimWorker : SimShared
update();
write_vcd_header();
write_vcd_step(0);
write_output_header();
write_output_step(0);
for (int cycle = 0; cycle < numcycles; cycle++)
{
if (debug)
log("\n===== %d =====\n", 10*cycle + 5);
else
log("Simulating cycle %d.\n", (cycle*2)+1);
set_inports(clock, State::S0);
set_inports(clockn, State::S1);
update();
write_vcd_step(10*cycle + 5);
write_output_step(10*cycle + 5);
if (debug)
log("\n===== %d =====\n", 10*cycle + 10);
else
log("Simulating cycle %d.\n", cycle+1);
log("Simulating cycle %d.\n", (cycle*2)+2);
set_inports(clock, State::S1);
set_inports(clockn, State::S0);
@ -748,11 +949,132 @@ struct SimWorker : SimShared
}
update();
write_vcd_step(10*cycle + 10);
write_output_step(10*cycle + 10);
}
write_vcd_step(10*numcycles + 2);
write_output_step(10*numcycles + 2);
write_output_end();
if (writeback) {
pool<Module*> wbmods;
top->writeback(wbmods);
}
}
void run_cosim(Module *topmod, int numcycles)
{
log_assert(top == nullptr);
fst = new FstData(sim_filename);
if (scope.empty())
log_error("Scope must be defined for co-simulation.\n");
top = new SimInstance(this, scope, topmod);
std::vector<fstHandle> fst_clock;
for (auto portname : clock)
{
Wire *w = topmod->wire(portname);
if (!w)
log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
if (!w->port_input)
log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
if (id==0)
log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
fst_clock.push_back(id);
}
for (auto portname : clockn)
{
Wire *w = topmod->wire(portname);
if (!w)
log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
if (!w->port_input)
log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
if (id==0)
log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
fst_clock.push_back(id);
}
if (fst_clock.size()==0)
log_error("No clock signals defined for input file\n");
SigMap sigmap(topmod);
std::map<Wire*,fstHandle> inputs;
for (auto wire : topmod->wires()) {
if (wire->port_input) {
fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
if (id==0)
log_error("Unable to find required '%s' signal in file\n",(scope + "." + RTLIL::unescape_id(wire->name)).c_str());
inputs[wire] = id;
}
}
uint64_t startCount = 0;
uint64_t stopCount = 0;
if (start_time==0) {
if (start_time < fst->getStartTime())
log_warning("Start time is before simulation file start time\n");
startCount = fst->getStartTime();
} else if (start_time==-1)
startCount = fst->getEndTime();
else {
startCount = start_time / fst->getTimescale();
if (startCount > fst->getEndTime()) {
startCount = fst->getEndTime();
log_warning("Start time is after simulation file end time\n");
}
}
if (stop_time==0) {
if (stop_time < fst->getStartTime())
log_warning("Stop time is before simulation file start time\n");
stopCount = fst->getStartTime();
} else if (stop_time==-1)
stopCount = fst->getEndTime();
else {
stopCount = stop_time / fst->getTimescale();
if (stopCount > fst->getEndTime()) {
stopCount = fst->getEndTime();
log_warning("Stop time is after simulation file end time\n");
}
}
if (stopCount<startCount) {
log_error("Stop time is before start time\n");
}
auto samples = fst->getAllEdges(fst_clock, startCount, stopCount);
// Limit to number of cycles if provided
if (cycles_set && ((size_t)(numcycles *2) < samples.size()))
samples.erase(samples.begin() + (numcycles*2), samples.end());
// Add setup time (start time)
if (samples.empty() || samples.front()!=startCount)
samples.insert(samples.begin(), startCount);
fst->reconstructAllAtTimes(samples);
bool initial = true;
int cycle = 0;
log("Co-simulation from %lu%s to %lu%s\n", (unsigned long)startCount, fst->getTimescaleString(), (unsigned long)stopCount, fst->getTimescaleString());
for(auto &time : samples) {
log("Co-simulating cycle %d [%lu%s].\n", cycle, (unsigned long)time, fst->getTimescaleString());
for(auto &item : inputs) {
std::string v = fst->valueAt(item.second, time);
top->set_state(item.first, Const::from_string(v));
}
if (initial) {
top->setInitState(time);
initial = false;
}
update();
bool status = top->checkSignals(time);
if (status)
log_error("Signal difference\n");
cycle++;
}
if (writeback) {
pool<Module*> wbmods;
top->writeback(wbmods);
@ -773,6 +1095,9 @@ struct SimPass : public Pass {
log(" -vcd <filename>\n");
log(" write the simulation results to the given VCD file\n");
log("\n");
log(" -fst <filename>\n");
log(" write the simulation results to the given FST file\n");
log("\n");
log(" -clock <portname>\n");
log(" name of top-level clock input\n");
log("\n");
@ -795,14 +1120,41 @@ struct SimPass : public Pass {
log(" include the specified timescale declaration in the vcd\n");
log("\n");
log(" -n <integer>\n");
log(" number of cycles to simulate (default: 20)\n");
log(" number of clock cycles to simulate (default: 20)\n");
log("\n");
log(" -a\n");
log(" include all nets in VCD output, not just those with public names\n");
log(" use all nets in VCD/FST operations, not just those with public names\n");
log("\n");
log(" -w\n");
log(" writeback mode: use final simulation state as new init state\n");
log("\n");
log(" -r\n");
log(" read simulation results file (file formats supported: FST)\n");
log("\n");
log(" -scope\n");
log(" scope of simulation top model\n");
log("\n");
log(" -at <time>\n");
log(" sets start and stop time\n");
log("\n");
log(" -start <time>\n");
log(" start co-simulation in arbitary time (default 0)\n");
log("\n");
log(" -stop <time>\n");
log(" stop co-simulation in arbitary time (default END)\n");
log("\n");
log(" -sim\n");
log(" simulation with stimulus from FST (default)\n");
log("\n");
log(" -sim-cmp\n");
log(" co-simulation expect exact match\n");
log("\n");
log(" -sim-gold\n");
log(" co-simulation, x in simulation can match any value in FST\n");
log("\n");
log(" -sim-gate\n");
log(" co-simulation, x in FST can match any value in simulation\n");
log("\n");
log(" -d\n");
log(" enable debug output\n");
log("\n");
@ -811,6 +1163,7 @@ struct SimPass : public Pass {
{
SimWorker worker;
int numcycles = 20;
bool start_set = false, stop_set = false, at_set = false;
log_header(design, "Executing SIM pass (simulate the circuit).\n");
@ -822,8 +1175,15 @@ struct SimPass : public Pass {
worker.vcdfile.open(vcd_filename.c_str());
continue;
}
if (args[argidx] == "-fst" && argidx+1 < args.size()) {
std::string fst_filename = args[++argidx];
rewrite_filename(fst_filename);
worker.fstfile = (struct fstContext *)fstWriterCreate(fst_filename.c_str(),1);
continue;
}
if (args[argidx] == "-n" && argidx+1 < args.size()) {
numcycles = atoi(args[++argidx].c_str());
worker.cycles_set = true;
continue;
}
if (args[argidx] == "-rstlen" && argidx+1 < args.size()) {
@ -866,9 +1226,55 @@ struct SimPass : public Pass {
worker.zinit = true;
continue;
}
if (args[argidx] == "-r" && argidx+1 < args.size()) {
std::string sim_filename = args[++argidx];
rewrite_filename(sim_filename);
worker.sim_filename = sim_filename;
continue;
}
if (args[argidx] == "-scope" && argidx+1 < args.size()) {
worker.scope = args[++argidx];
continue;
}
if (args[argidx] == "-start" && argidx+1 < args.size()) {
worker.start_time = stringToTime(args[++argidx]);
start_set = true;
continue;
}
if (args[argidx] == "-stop" && argidx+1 < args.size()) {
worker.stop_time = stringToTime(args[++argidx]);
stop_set = true;
continue;
}
if (args[argidx] == "-at" && argidx+1 < args.size()) {
worker.start_time = stringToTime(args[++argidx]);
worker.stop_time = worker.start_time;
at_set = true;
continue;
}
if (args[argidx] == "-sim") {
worker.sim_mode = SimulationMode::sim;
continue;
}
if (args[argidx] == "-sim-cmp") {
worker.sim_mode = SimulationMode::cmp;
continue;
}
if (args[argidx] == "-sim-gold") {
worker.sim_mode = SimulationMode::gold;
continue;
}
if (args[argidx] == "-sim-gate") {
worker.sim_mode = SimulationMode::gate;
continue;
}
break;
}
extra_args(args, argidx, design);
if (at_set && (start_set || stop_set || worker.cycles_set))
log_error("'at' option can only be defined separate of 'start','stop' and 'n'\n");
if (stop_set && worker.cycles_set)
log_error("'stop' and 'n' can only be used exclusively'\n");
Module *top_mod = nullptr;
@ -884,7 +1290,10 @@ struct SimPass : public Pass {
top_mod = mods.front();
}
worker.run(top_mod, numcycles);
if (worker.sim_filename.empty())
worker.run(top_mod, numcycles);
else
worker.run_cosim(top_mod, numcycles);
}
} SimPass;

View File

@ -1,2 +1,4 @@
*.log
run-test.mk
*.vcd
*.fst

79
tests/sat/alu.v Normal file
View File

@ -0,0 +1,79 @@
module alu(
input clk,
input [7:0] A,
input [7:0] B,
input [3:0] operation,
output reg [7:0] result,
output reg CF,
output reg ZF,
output reg SF
);
localparam ALU_OP_ADD /* verilator public_flat */ = 4'b0000;
localparam ALU_OP_SUB /* verilator public_flat */ = 4'b0001;
localparam ALU_OP_ADC /* verilator public_flat */ = 4'b0010;
localparam ALU_OP_SBC /* verilator public_flat */ = 4'b0011;
localparam ALU_OP_AND /* verilator public_flat */ = 4'b0100;
localparam ALU_OP_OR /* verilator public_flat */ = 4'b0101;
localparam ALU_OP_NOT /* verilator public_flat */ = 4'b0110;
localparam ALU_OP_XOR /* verilator public_flat */ = 4'b0111;
localparam ALU_OP_SHL /* verilator public_flat */ = 4'b1000;
localparam ALU_OP_SHR /* verilator public_flat */ = 4'b1001;
localparam ALU_OP_SAL /* verilator public_flat */ = 4'b1010;
localparam ALU_OP_SAR /* verilator public_flat */ = 4'b1011;
localparam ALU_OP_ROL /* verilator public_flat */ = 4'b1100;
localparam ALU_OP_ROR /* verilator public_flat */ = 4'b1101;
localparam ALU_OP_RCL /* verilator public_flat */ = 4'b1110;
localparam ALU_OP_RCR /* verilator public_flat */ = 4'b1111;
reg [8:0] tmp;
always @(posedge clk)
begin
case (operation)
ALU_OP_ADD :
tmp = A + B;
ALU_OP_SUB :
tmp = A - B;
ALU_OP_ADC :
tmp = A + B + { 7'b0000000, CF };
ALU_OP_SBC :
tmp = A - B - { 7'b0000000, CF };
ALU_OP_AND :
tmp = {1'b0, A & B };
ALU_OP_OR :
tmp = {1'b0, A | B };
ALU_OP_NOT :
tmp = {1'b0, ~B };
ALU_OP_XOR :
tmp = {1'b0, A ^ B};
ALU_OP_SHL :
tmp = { A[7], A[6:0], 1'b0};
ALU_OP_SHR :
tmp = { A[0], 1'b0, A[7:1]};
ALU_OP_SAL :
// Same as SHL
tmp = { A[7], A[6:0], 1'b0};
ALU_OP_SAR :
tmp = { A[0], A[7], A[7:1]};
ALU_OP_ROL :
tmp = { A[7], A[6:0], A[7]};
ALU_OP_ROR :
tmp = { A[0], A[0], A[7:1]};
ALU_OP_RCL :
tmp = { A[7], A[6:0], CF};
ALU_OP_RCR :
tmp = { A[0], CF, A[7:1]};
endcase
CF <= tmp[8];
ZF <= tmp[7:0] == 0;
SF <= tmp[7];
result <= tmp[7:0];
end
endmodule

9
tests/sat/grom.ys Normal file
View File

@ -0,0 +1,9 @@
read_verilog grom_computer.v grom_cpu.v alu.v ram_memory.v;
prep -top grom_computer;
sim -clock clk -reset reset -fst grom.fst -vcd grom.vcd -n 80
sim -clock clk -r grom.fst -scope grom_computer -start 25ns -stop 100ns -sim-cmp
sim -clock clk -r grom.fst -scope grom_computer -stop 100ns -sim-gold
sim -clock clk -r grom.fst -scope grom_computer -n 10 -sim-gate

31
tests/sat/grom_computer.v Normal file
View File

@ -0,0 +1,31 @@
module grom_computer
(input clk, // Main Clock
input reset, // reset
output hlt,
output reg[7:0] display_out
);
wire [11:0] addr;
wire [7:0] memory_out;
wire [7:0] memory_in;
wire mem_enable;
wire we;
wire ioreq;
grom_cpu cpu(.clk(clk),.reset(reset),.addr(addr),.data_in(memory_out),.data_out(memory_in),.we(we),.ioreq(ioreq),.hlt(hlt));
assign mem_enable = we & ~ioreq;
ram_memory memory(.clk(clk),.addr(addr),.data_in(memory_in),.we(mem_enable),.data_out(memory_out));
always @(posedge clk)
begin
if(ioreq==1 && we==1)
begin
display_out <= memory_in;
`ifdef DISASSEMBLY
$display("Display output : %h", memory_in);
`endif
end
end
endmodule

747
tests/sat/grom_cpu.v Normal file
View File

@ -0,0 +1,747 @@
module grom_cpu(
input clk,
input reset,
output reg [11:0] addr,
input [7:0] data_in,
output reg [7:0] data_out,
output reg we,
output reg ioreq,
output reg hlt
);
reg[11:0] PC /* verilator public_flat */; // Program counter
reg[7:0] IR /* verilator public_flat */; // Instruction register
reg[7:0] VALUE /* verilator public_flat */; // Temp reg for storing 2nd operand
reg[3:0] CS /* verilator public_flat */; // Code segment regiser
reg[3:0] DS /* verilator public_flat */; // Data segment regiser
reg[11:0] SP /* verilator public_flat */; // Stack pointer regiser
reg[7:0] R[0:3] /* verilator public_flat */; // General purpose registers
reg[11:0] FUTURE_PC /* verilator public_flat */; // PC to jump to
localparam STATE_RESET /*verilator public_flat*/ = 5'b00000;
localparam STATE_FETCH_PREP /*verilator public_flat*/ = 5'b00001;
localparam STATE_FETCH_WAIT /*verilator public_flat*/ = 5'b00010;
localparam STATE_FETCH /*verilator public_flat*/ = 5'b00011;
localparam STATE_EXECUTE /*verilator public_flat*/ = 5'b00100;
localparam STATE_FETCH_VALUE_PREP /*verilator public_flat*/ = 5'b00101;
localparam STATE_FETCH_VALUE /*verilator public_flat*/ = 5'b00110;
localparam STATE_EXECUTE_DBL /*verilator public_flat*/ = 5'b00111;
localparam STATE_LOAD_VALUE /*verilator public_flat*/ = 5'b01000;
localparam STATE_LOAD_VALUE_WAIT /*verilator public_flat*/ = 5'b01001;
localparam STATE_ALU_RESULT_WAIT /*verilator public_flat*/ = 5'b01010;
localparam STATE_ALU_RESULT /*verilator public_flat*/ = 5'b01011;
localparam STATE_PUSH_PC_LOW /*verilator public_flat*/ = 5'b01100;
localparam STATE_JUMP /*verilator public_flat*/ = 5'b01101;
localparam STATE_RET_VALUE_WAIT /*verilator public_flat*/ = 5'b01110;
localparam STATE_RET_VALUE /*verilator public_flat*/ = 5'b01111;
localparam STATE_RET_VALUE_WAIT2 /*verilator public_flat*/ = 5'b10000;
localparam STATE_RET_VALUE2 /*verilator public_flat*/ = 5'b10001;
reg [4:0] state /* verilator public_flat */ = STATE_RESET;
reg [7:0] alu_a /* verilator public_flat */;
reg [7:0] alu_b /* verilator public_flat */;
reg [3:0] alu_op /* verilator public_flat */;
reg [1:0] RESULT_REG /* verilator public_flat */;
wire [7:0] alu_res /* verilator public_flat */;
wire alu_CF /* verilator public_flat */;
wire alu_ZF /* verilator public_flat */;
wire alu_SF /* verilator public_flat */;
reg jump;
alu alu(.clk(clk),.A(alu_a),.B(alu_b),.operation(alu_op),.result(alu_res),.CF(alu_CF),.ZF(alu_ZF),.SF(alu_SF));
always @(posedge clk)
begin
if (reset)
begin
state <= STATE_RESET;
hlt <= 0;
end
else
begin
case (state)
STATE_RESET :
begin
PC <= 12'h000;
state <= STATE_FETCH_PREP;
CS <= 4'h0;
DS <= 4'h0;
R[0] <= 8'h00;
R[1] <= 8'h00;
R[2] <= 8'h00;
R[3] <= 8'h00;
SP <= 12'hfff;
end
STATE_FETCH_PREP :
begin
addr <= PC;
we <= 0;
ioreq <= 0;
state <= STATE_FETCH_WAIT;
end
STATE_FETCH_WAIT :
begin
// Sync with memory due to CLK
state <= (hlt) ? STATE_FETCH_PREP : STATE_FETCH;
end
STATE_FETCH :
begin
IR <= data_in;
PC <= PC + 1;
state <= STATE_EXECUTE;
end
STATE_EXECUTE :
begin
`ifdef DISASSEMBLY
$display(" PC %h R0 %h R1 %h R2 %h R3 %h CS %h DS %h SP %h ALU [%d %d %d]", PC, R[0], R[1], R[2], R[3], CS, DS, SP, alu_CF,alu_SF,alu_ZF);
`endif
if (IR[7])
begin
addr <= PC;
state <= STATE_FETCH_VALUE_PREP;
PC <= PC + 1;
end
else
begin
case(IR[6:4])
3'b000 :
begin
`ifdef DISASSEMBLY
$display("MOV R%d,R%d",IR[3:2],IR[1:0]);
`endif
R[IR[3:2]] <= R[IR[1:0]];
state <= STATE_FETCH_PREP;
end
3'b001 :
begin
alu_a <= R[0]; // first input R0
alu_b <= R[IR[1:0]];
RESULT_REG <= 0; // result in R0
alu_op <= { 2'b00, IR[3:2] };
state <= STATE_ALU_RESULT_WAIT;
`ifdef DISASSEMBLY
case(IR[3:2])
2'b00 : begin
$display("ADD R%d",IR[1:0]);
end
2'b01 : begin
$display("SUB R%d",IR[1:0]);
end
2'b10 : begin
$display("ADC R%d",IR[1:0]);
end
2'b11 : begin
$display("SBC R%d",IR[1:0]);
end
endcase
`endif
end
3'b010 :
begin
alu_a <= R[0]; // first input R0
alu_b <= R[IR[1:0]];
RESULT_REG <= 0; // result in R0
alu_op <= { 2'b01, IR[3:2] };
state <= STATE_ALU_RESULT_WAIT;
`ifdef DISASSEMBLY
case(IR[3:2])
2'b00 : begin
$display("AND R%d",IR[1:0]);
end
2'b01 : begin
$display("OR R%d",IR[1:0]);
end
2'b10 : begin
$display("NOT R%d",IR[1:0]);
end
2'b11 : begin
$display("XOR R%d",IR[1:0]);
end
endcase
`endif
end
3'b011 :
begin
RESULT_REG <= IR[1:0]; // result in REG
// CMP and TEST are not storing result
state <= IR[3] ? STATE_FETCH_PREP : STATE_ALU_RESULT_WAIT;
// CMP and TEST are having first input R0, for INC and DEC is REG
alu_a <= IR[3] ? R[0] : R[IR[1:0]];
// CMP and TEST are having second input REG, for INC and DEC is 1
alu_b <= IR[3] ? R[IR[1:0]] : 8'b00000001;
case(IR[3:2])
2'b00 : begin
`ifdef DISASSEMBLY
$display("INC R%d",IR[1:0]);
`endif
alu_op <= 4'b0001; // ALU_OP_ADD
end
2'b01 : begin
`ifdef DISASSEMBLY
$display("DEC R%d",IR[1:0]);
`endif
alu_op <= 4'b0001; // ALU_OP_SUB
end
2'b10 : begin
`ifdef DISASSEMBLY
$display("CMP R%d",IR[1:0]);
`endif
alu_op <= 4'b0001; // ALU_OP_SUB
end
2'b11 : begin
`ifdef DISASSEMBLY
$display("TST R%d",IR[1:0]);
`endif
alu_op <= 4'b0100; // ALU_OP_AND
end
endcase
end
3'b100 :
begin
if (IR[3]==0)
begin
alu_a <= R[0]; // first input R0
// no 2nd input
RESULT_REG <= 0; // result in R0
alu_op <= { 1'b1, IR[2:0] };
`ifdef DISASSEMBLY
case(IR[2:0])
3'b000 : begin
$display("SHL");
end
3'b001 : begin
$display("SHR");
end
3'b010 : begin
$display("SAL");
end
3'b011 : begin
$display("SAR");
end
3'b100 : begin
$display("ROL");
end
3'b101 : begin
$display("ROR");
end
3'b110 : begin
$display("RCL");
end
3'b111 : begin
$display("RCR");
end
endcase
`endif
state <= STATE_ALU_RESULT_WAIT;
end
else
begin
if (IR[2]==0)
begin
`ifdef DISASSEMBLY
$display("PUSH R%d",IR[1:0]);
`endif
addr <= SP;
we <= 1;
ioreq <= 0;
data_out <= R[IR[1:0]];
SP <= SP - 1;
state <= STATE_FETCH_PREP;
end
else
begin
`ifdef DISASSEMBLY
$display("POP R%d",IR[1:0]);
`endif
addr <= SP + 1;
we <= 0;
ioreq <= 0;
RESULT_REG <= IR[1:0];
SP <= SP + 1;
state <= STATE_LOAD_VALUE_WAIT;
end
end
end
3'b101 :
begin
`ifdef DISASSEMBLY
$display("LOAD R%d,[R%d]", IR[3:2], IR[1:0]);
`endif
addr <= { DS, R[IR[1:0]] };
we <= 0;
ioreq <= 0;
RESULT_REG <= IR[3:2];
state <= STATE_LOAD_VALUE_WAIT;
end
3'b110 :
begin
`ifdef DISASSEMBLY
$display("STORE [R%d],R%d", IR[3:2], IR[1:0]);
`endif
addr <= { DS, R[IR[3:2]] };
we <= 1;
ioreq <= 0;
data_out <= R[IR[1:0]];
state <= STATE_FETCH_PREP;
end
3'b111 :
begin
// Special instuctions
case(IR[3:2])
2'b00 : begin
CS <= R[IR[1:0]][3:0];
state <= STATE_FETCH_PREP;
`ifdef DISASSEMBLY
$display("MOV CS,R%d",IR[1:0]);
`endif
end
2'b01 : begin
DS <= R[IR[1:0]][3:0];
state <= STATE_FETCH_PREP;
`ifdef DISASSEMBLY
$display("MOV DS,R%d",IR[1:0]);
`endif
end
2'b10 : begin
case(IR[1:0])
2'b00 : begin
`ifdef DISASSEMBLY
$display("PUSH CS");
`endif
addr <= SP;
we <= 1;
ioreq <= 0;
data_out <= { 4'b0000, CS};
SP <= SP - 1;
state <= STATE_FETCH_PREP;
end
2'b01 : begin
`ifdef DISASSEMBLY
$display("PUSH DS");
`endif
addr <= SP;
we <= 1;
ioreq <= 0;
data_out <= { 4'b0000, DS};
SP <= SP - 1;
state <= STATE_FETCH_PREP;
end
2'b10 : begin
`ifdef DISASSEMBLY
$display("Unused opcode");
`endif
end
2'b11 : begin
`ifdef DISASSEMBLY
$display("Unused opcode");
`endif
end
endcase
state <= STATE_FETCH_PREP;
end
2'b11 : begin
case(IR[1:0])
2'b00 : begin
`ifdef DISASSEMBLY
$display("Unused opcode");
`endif
state <= STATE_FETCH_PREP;
end
2'b01 : begin
`ifdef DISASSEMBLY
$display("Unused opcode");
`endif
state <= STATE_FETCH_PREP;
end
2'b10 : begin
`ifdef DISASSEMBLY
$display("RET");
`endif
addr <= SP + 1;
we <= 0;
ioreq <= 0;
SP <= SP + 1;
state <= STATE_RET_VALUE_WAIT;
end
2'b11 : begin
hlt <= 1;
`ifdef DISASSEMBLY
$display("HALT");
`endif
state <= STATE_FETCH_PREP;
end
endcase
end
endcase
end
endcase
end
end
STATE_FETCH_VALUE_PREP :
begin
// Sync with memory due to CLK
state <= STATE_FETCH_VALUE;
end
STATE_FETCH_VALUE :
begin
VALUE <= data_in;
state <= STATE_EXECUTE_DBL;
end
STATE_EXECUTE_DBL :
begin
case(IR[6:4])
3'b000 :
begin
if (IR[3]==0)
begin
case(IR[2:0])
3'b000 :
begin
`ifdef DISASSEMBLY
$display("JMP %h ",{ CS, VALUE[7:0] });
`endif
jump = 1;
end
3'b001 :
begin
`ifdef DISASSEMBLY
$display("JC %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_CF==1);
end
3'b010 :
begin
`ifdef DISASSEMBLY
$display("JNC %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_CF==0);
end
3'b011 :
begin
`ifdef DISASSEMBLY
$display("JM %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_SF==1);
end
3'b100 :
begin
`ifdef DISASSEMBLY
$display("JP %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_SF==0);
end
3'b101 :
begin
`ifdef DISASSEMBLY
$display("JZ %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_ZF==1);
end
3'b110 :
begin
`ifdef DISASSEMBLY
$display("JNZ %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_ZF==0);
end
3'b111 :
begin
`ifdef DISASSEMBLY
$display("Unused opcode %h",IR);
`endif
jump = 0;
end
endcase
if (jump)
begin
PC <= { CS, VALUE[7:0] };
addr <= { CS, VALUE[7:0] };
we <= 0;
ioreq <= 0;
end
state <= STATE_FETCH_PREP;
end
else
begin
case(IR[2:0])
3'b000 :
begin
`ifdef DISASSEMBLY
$display("JR %h ", PC + {VALUE[7],VALUE[7],VALUE[7],VALUE[7],VALUE[7:0]} );
`endif
jump = 1;
end
3'b001 :
begin
`ifdef DISASSEMBLY
$display("JRC %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_CF==1);
end
3'b010 :
begin
`ifdef DISASSEMBLY
$display("JRNC %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_CF==0);
end
3'b011 :
begin
`ifdef DISASSEMBLY
$display("JRM %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_SF==1);
end
3'b100 :
begin
`ifdef DISASSEMBLY
$display("JRP %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_SF==0);
end
3'b101 :
begin
`ifdef DISASSEMBLY
$display("JRZ %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_ZF==1);
end
3'b110 :
begin
`ifdef DISASSEMBLY
$display("JRNZ %h ",{CS, VALUE[7:0] });
`endif
jump = (alu_ZF==0);
end
3'b111 :
begin
`ifdef DISASSEMBLY
$display("Unused opcode %h",IR);
`endif
jump = 0;
end
endcase
if (jump)
begin
PC <= PC + {VALUE[7],VALUE[7],VALUE[7],VALUE[7],VALUE[7:0]};
addr <= PC + {VALUE[7],VALUE[7],VALUE[7],VALUE[7],VALUE[7:0]};
we <= 0;
ioreq <= 0;
end
state <= STATE_FETCH_PREP;
end
end
3'b001 :
begin
`ifdef DISASSEMBLY
$display("JUMP %h ",{ IR[3:0], VALUE[7:0] });
`endif
PC <= { IR[3:0], VALUE[7:0] };
addr <= { IR[3:0], VALUE[7:0] };
we <= 0;
ioreq <= 0;
state <= STATE_FETCH_PREP;
end
3'b010 :
begin
`ifdef DISASSEMBLY
$display("CALL %h ",{ IR[3:0], VALUE[7:0] });
`endif
FUTURE_PC <= { IR[3:0], VALUE[7:0] };
addr <= SP;
we <= 1;
ioreq <= 0;
data_out <= { 4'b0000, PC[11:8]};
SP <= SP - 1;
state <= STATE_PUSH_PC_LOW;
end
3'b011 :
begin
`ifdef DISASSEMBLY
$display("MOV SP,%h ",{ IR[3:0], VALUE[7:0] });
`endif
SP <= { IR[3:0], VALUE[7:0] };
state <= STATE_FETCH_PREP;
end
3'b100 :
begin
`ifdef DISASSEMBLY
$display("IN R%d,[0x%h]",IR[1:0], VALUE);
`endif
ioreq <= 1;
we <= 0;
addr <= { 4'b0000, VALUE };
RESULT_REG <= IR[1:0];
state <= STATE_LOAD_VALUE_WAIT;
end
3'b101 :
begin
`ifdef DISASSEMBLY
$display("OUT [0x%h],R%d",VALUE,IR[1:0]);
`endif
ioreq <= 1;
we <= 1;
addr <= { 4'b0000, VALUE };
data_out <= R[IR[1:0]];
state <= STATE_FETCH_PREP;
end
3'b110 :
begin
// Special instuctions
case(IR[1:0])
2'b00 : begin
`ifdef DISASSEMBLY
$display("MOV CS,0x%h",VALUE);
`endif
CS <= VALUE[3:0];
state <= STATE_FETCH_PREP;
end
2'b01 : begin
`ifdef DISASSEMBLY
$display("MOV DS,0x%h",VALUE);
`endif
DS <= VALUE[3:0];
state <= STATE_FETCH_PREP;
end
2'b10 : begin
`ifdef DISASSEMBLY
$display("Unused opcode %h",IR);
`endif
state <= STATE_FETCH_PREP;
end
2'b11 : begin
`ifdef DISASSEMBLY
$display("Unused opcode %h",IR);
`endif
state <= STATE_FETCH_PREP;
end
endcase
end
3'b111 :
begin
case(IR[3:2])
2'b00 : begin
`ifdef DISASSEMBLY
$display("MOV R%d,0x%h",IR[1:0],VALUE);
`endif
R[IR[1:0]] <= VALUE;
state <= STATE_FETCH_PREP;
end
2'b01 : begin
`ifdef DISASSEMBLY
$display("LOAD R%d,[0x%h]",IR[1:0], {DS, VALUE});
`endif
addr <= { DS, VALUE };
we <= 0;
ioreq <= 0;
RESULT_REG <= IR[1:0];
state <= STATE_LOAD_VALUE_WAIT;
end
2'b10 : begin
`ifdef DISASSEMBLY
$display("STORE [0x%h],R%d", {DS, VALUE}, IR[1:0]);
`endif
addr <= { DS, VALUE };
we <= 1;
ioreq <= 0;
data_out <= R[IR[1:0]];
state <= STATE_FETCH_PREP;
end
2'b11 : begin
`ifdef DISASSEMBLY
$display("Unused opcode %h",IR);
`endif
state <= STATE_FETCH_PREP;
end
endcase
end
endcase
end
STATE_LOAD_VALUE_WAIT :
begin
// Sync with memory due to CLK
state <= STATE_LOAD_VALUE;
end
STATE_LOAD_VALUE :
begin
R[RESULT_REG] <= data_in;
we <= 0;
state <= STATE_FETCH_PREP;
end
STATE_ALU_RESULT_WAIT :
begin
state <= STATE_ALU_RESULT;
end
STATE_ALU_RESULT :
begin
R[RESULT_REG] <= alu_res;
state <= STATE_FETCH_PREP;
end
STATE_PUSH_PC_LOW :
begin
addr <= SP;
we <= 1;
ioreq <= 0;
data_out <= PC[7:0];
SP <= SP - 1;
state <= STATE_JUMP;
end
STATE_JUMP :
begin
`ifdef DISASSEMBLY
$display("Jumping to %h",FUTURE_PC);
`endif
PC <= FUTURE_PC;
state <= STATE_FETCH_PREP;
end
STATE_RET_VALUE_WAIT :
begin
// Sync with memory due to CLK
state <= STATE_RET_VALUE;
end
STATE_RET_VALUE :
begin
FUTURE_PC <= { 4'b0000, data_in };
we <= 0;
state <= STATE_RET_VALUE_WAIT2;
addr <= SP + 1;
we <= 0;
ioreq <= 0;
SP <= SP + 1;
end
STATE_RET_VALUE_WAIT2 :
begin
// Sync with memory due to CLK
state <= STATE_RET_VALUE2;
end
STATE_RET_VALUE2 :
begin
FUTURE_PC <= FUTURE_PC | ({ 4'b0000, data_in } << 8);
we <= 0;
state <= STATE_JUMP;
end
default :
begin
state <= STATE_FETCH_PREP;
end
endcase
end
end
endmodule

37
tests/sat/ram_memory.v Normal file
View File

@ -0,0 +1,37 @@
module ram_memory(
input clk,
input [11:0] addr,
input [7:0] data_in,
input we,
output reg [7:0] data_out
);
reg [7:0] store[0:4095] /* verilator public_flat */;
initial
begin
store[0] <= 8'b11100001; // MOV DS,2
store[1] <= 8'b00000010; //
store[2] <= 8'b01010100; // LOAD R1,[R0]
store[3] <= 8'b00110001; // INC R1
store[4] <= 8'b00110001; // INC R1
store[5] <= 8'b01100001; // STORE [R0],R1
store[6] <= 8'b11010001; // OUT [0],R1
store[7] <= 8'b00000000; //
store[8] <= 8'b00110001; // INC R1
store[9] <= 8'b10100001; // CALL 0x100
store[10] <= 8'b00000000; //
store[11] <= 8'b01111111; // HLT
store[256] <= 8'b11010001; // OUT [0],R1
store[257] <= 8'b00000000; //
store[258] <= 8'b01111110; // RET
end
always @(posedge clk)
if (we)
store[addr] <= data_in;
else
data_out <= store[addr];
endmodule

48
tests/sat/sim_counter.ys Normal file
View File

@ -0,0 +1,48 @@
# Create stimulus file
read_verilog <<EOT
module top (clk, reset, cnt);
input clk;
input reset;
output [7:0] cnt;
reg [7:0] cnt;
endmodule
EOT
prep -top top;
sim -clock clk -reset reset -fst stimulus.fst -n 10
design -reset
# Counter implementation
read_verilog <<EOT
module top (clk, reset, cnt);
input clk;
input reset;
output [7:0] cnt;
reg [7:0] cnt;
always @(posedge clk)
if (!reset)
cnt = cnt + 1;
else
cnt = 0;
endmodule
EOT
prep -top top;
# Simulate with stimulus
sim -clock clk -scope top -r stimulus.fst
# Stimulus does not have counter values
# x in FST can match any value in simulation
sim -clock clk -scope top -r stimulus.fst -sim-gate
# Stimulus does not have counter values
# x in simulation can match any value in FST
# so we expect error
logger -expect error "Signal difference" 1
sim -clock clk -scope top -r stimulus.fst -sim-gold