aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile35
-rw-r--r--README18
-rw-r--r--backends/verilog/verilog_backend.cc24
-rw-r--r--frontends/ast/ast.cc82
-rw-r--r--frontends/ast/ast.h9
-rw-r--r--frontends/ast/genrtlil.cc27
-rw-r--r--frontends/ast/simplify.cc25
-rw-r--r--frontends/verilog/lexer.l4
-rw-r--r--frontends/verilog/parser.y2
-rw-r--r--frontends/verilog/verilog_frontend.cc10
-rw-r--r--kernel/driver.cc180
-rw-r--r--kernel/register.cc10
-rw-r--r--kernel/register.h9
-rw-r--r--kernel/rtlil.cc19
-rw-r--r--kernel/rtlil.h2
-rw-r--r--kernel/select.cc36
-rw-r--r--kernel/show.cc160
-rw-r--r--libs/subcircuit/subcircuit.cc15
-rw-r--r--libs/svgviewer/.gitignore5
-rw-r--r--libs/svgviewer/files/bubbles.svg215
-rw-r--r--libs/svgviewer/files/cubic.svg77
-rw-r--r--libs/svgviewer/files/spheres.svg72
-rw-r--r--libs/svgviewer/main.cpp66
-rw-r--r--libs/svgviewer/mainwindow.cpp192
-rw-r--r--libs/svgviewer/mainwindow.h85
-rw-r--r--libs/svgviewer/svgview.cpp188
-rw-r--r--libs/svgviewer/svgview.h83
-rw-r--r--libs/svgviewer/svgviewer.desktop11
-rw-r--r--libs/svgviewer/svgviewer.pro33
-rw-r--r--libs/svgviewer/svgviewer.qrc6
-rw-r--r--passes/dfflibmap/Makefile.inc6
-rw-r--r--passes/fsm/fsm_export.cc48
-rw-r--r--passes/hierarchy/hierarchy.cc17
-rw-r--r--passes/opt/opt_const.cc6
-rw-r--r--passes/opt/opt_share.cc49
-rw-r--r--passes/submod/submod.cc136
-rw-r--r--passes/techmap/techmap.cc275
-rw-r--r--techlibs/Makefile.inc2
-rw-r--r--techlibs/simlib.v9
-rw-r--r--tests/k68_vltor/changes.diff12
-rw-r--r--tests/k68_vltor/clone.sh6
-rw-r--r--tests/k68_vltor/run.sh30
-rw-r--r--tests/simple/always01.v10
-rw-r--r--tests/simple/always02.v13
-rw-r--r--tests/simple/always03.v22
-rw-r--r--tests/simple/arrays01.v16
-rw-r--r--tests/simple/forgen01.v20
-rw-r--r--tests/simple/forgen02.v30
-rw-r--r--tests/simple/process.v19
-rwxr-xr-xtests/tools/vcdcd.pl20
51 files changed, 2182 insertions, 267 deletions
diff --git a/.gitignore b/.gitignore
index 4576d54d6..191b95992 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ qtcreator.config
qtcreator.creator
qtcreator.creator.user
Makefile.conf
-filterlib
yosys
yosys-config
+yosys-filterlib
+yosys-svgviewer
diff --git a/Makefile b/Makefile
index b20d17712..e1b8bac16 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,10 @@ CONFIG := clang-debug
# CONFIG := gcc-debug
# CONFIG := release
+ENABLE_TCL := 1
+ENABLE_QT4 := 1
+ENABLE_GPROF := 0
+
OBJS = kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/select.o kernel/show.o
OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o
@@ -12,6 +16,7 @@ OBJS += libs/sha1/sha1.o
OBJS += libs/subcircuit/subcircuit.o
GENFILES =
+EXTRA_TARGETS =
TARGETS = yosys yosys-config
all: top-all
@@ -37,12 +42,26 @@ CXX = gcc
CXXFLAGS += -std=gnu++0x -march=native -O3 -DNDEBUG
endif
+ifeq ($(ENABLE_TCL),1)
+CXXFLAGS += -I/usr/include/tcl8.5 -DYOSYS_ENABLE_TCL
+LDLIBS += -ltcl8.5
+endif
+
+ifeq ($(ENABLE_GPROF),1)
+CXXFLAGS += -pg
+LDFLAGS += -pg
+endif
+
+ifeq ($(ENABLE_QT4),1)
+TARGETS += yosys-svgviewer
+endif
+
include frontends/*/Makefile.inc
include passes/*/Makefile.inc
include backends/*/Makefile.inc
include techlibs/Makefile.inc
-top-all: $(TARGETS)
+top-all: $(TARGETS) $(EXTRA_TARGETS)
yosys: $(OBJS)
$(CXX) -o yosys $(LDFLAGS) $(OBJS) $(LDLIBS)
@@ -51,18 +70,22 @@ yosys-config: yosys-config.in
sed 's,@CXX@,$(CXX),; s,@CXXFLAGS@,$(CXXFLAGS),; s,@LDFLAGS@,$(LDFLAGS),; s,@LDLIBS@,$(LDLIBS),;' < yosys-config.in > yosys-config
chmod +x yosys-config
+yosys-svgviewer: libs/svgviewer/*.h libs/svgviewer/*.cpp
+ cd libs/svgviewer && qmake-qt4 && make
+ cp libs/svgviewer/svgviewer yosys-svgviewer
+
test: yosys
cd tests/simple && bash run-test.sh
cd tests/hana && bash run-test.sh
cd tests/asicworld && bash run-test.sh
-install: yosys
- install yosys /usr/local/bin/yosys
- install yosys-config /usr/local/bin/yosys-config
+install: $(TARGETS)
+ install $(TARGETS) /usr/local/bin/
clean:
rm -f $(OBJS) $(GENFILES) $(TARGETS)
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d
+ test ! -f libs/svgviewer/Makefile || make -C libs/svgviewer distclean
mrproper: clean
git clean -xdf
@@ -86,6 +109,10 @@ config-gcc-debug: clean
config-release: clean
echo 'CONFIG := release' > Makefile.conf
+config-gprof: clean
+ echo 'CONFIG := release' > Makefile.conf
+ echo 'ENABLE_GPROF := 1' >> Makefile.conf
+
-include libs/*/*.d
-include frontends/*/*.d
-include passes/*/*.d
diff --git a/README b/README
index ab9fcd612..a4a218636 100644
--- a/README
+++ b/README
@@ -88,9 +88,13 @@ some simple optimizations:
yosys> proc; opt
-display design netlist using 'gv' as postscript viewer:
+display design netlist using the yosys svg viewer:
- yosys> show -viewer gv
+ yosys> show
+
+the same thing using 'gv' as postscript viewer:
+
+ yosys> show -format ps -viewer gv
translating netlist to gate logic and perform some simple optimizations:
@@ -205,6 +209,12 @@ Verilog Attributes and non-standard features
temporary variable within an always block. This is mostly used internally
by yosys to synthesize verilog functions and access arrays.
+- The "placeholder" attribute on modules is used to mark empty stub modules
+ that have the same ports as the real thing but do not contain information
+ on the internal configuration. This modules are only used by the synthesis
+ passes to identify input and output ports of cells. The verilog backend
+ also does not output placeholder modules on default.
+
- In addition to the (* ... *) attribute syntax, yosys supports
the non-standard {* ... *} attribute syntax to set default attributes
for everything that comes after the {* ... *} statement. (Reset
@@ -240,8 +250,8 @@ TODOs / Open Bugs
- Actually use range information on parameters
- Add brief source code documentation to most passes and kernel code
- Implement mux-to-tribuf pass and rebalance mixed mux/tribuf trees
- - Add commands 'delete' (remove objects) and 'attr' (get, set and remove attributes)
- - TCL and Python interfaces to frontends, passes, backends and RTLIL
+ - Add 'edit' command for changing the design (delete, add, modify objects)
+ - Improve TCL support and add 'list' command for inspecting the design from TCL
- Additional internal cell types: $pla and $lut
- Support for registering designs (as collection of modules) to CellTypes
- Smarter resource sharing pass (add MUXes and get rid of duplicated cells)
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index a4713cb0a..04a3c7643 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -923,6 +923,11 @@ struct VerilogBackend : public Backend {
log(" without this option all internal cells are converted to verilog\n");
log(" expressions.\n");
log("\n");
+ log(" -placeholders\n");
+ log(" usually modules with the 'placeholder' attribute are ignored. with\n");
+ log(" this option set only the modules with the 'placeholder' attribute\n");
+ log(" are written to the output file.\n");
+ log("\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
@@ -933,6 +938,8 @@ struct VerilogBackend : public Backend {
attr2comment = false;
noexpr = false;
+ bool placeholders = false;
+
reg_ct.clear();
reg_ct.setup_stdcells_mem();
reg_ct.cell_types.insert("$sr");
@@ -958,16 +965,21 @@ struct VerilogBackend : public Backend {
noexpr = true;
continue;
}
+ if (arg == "-placeholders") {
+ placeholders = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
- for (auto it = design->modules.begin(); it != design->modules.end(); it++) {
- log("Dumping module `%s'.\n", it->first.c_str());
- if (it != design->modules.begin())
- fprintf(f, "\n");
- dump_module(f, "", it->second);
- }
+ for (auto it = design->modules.begin(); it != design->modules.end(); it++)
+ if ((it->second->attributes.count("\\placeholder") > 0) == placeholders) {
+ if (it != design->modules.begin())
+ fprintf(f, "\n");
+ log("Dumping module `%s'.\n", it->first.c_str());
+ dump_module(f, "", it->second);
+ }
reg_ct.clear();
}
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index d35ea4171..2c552ea22 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -46,11 +46,12 @@ namespace AST {
// instanciate global variables (private API)
namespace AST_INTERNAL {
- bool flag_dump_ast, flag_dump_ast_diff, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg;
+ bool flag_dump_ast, flag_dump_ast_diff, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
RTLIL::SigSpec *genRTLIL_subst_from = NULL;
RTLIL::SigSpec *genRTLIL_subst_to = NULL;
+ RTLIL::SigSpec ignoreThisSignalsInInitial;
AstNode *current_top_block, *current_block, *current_block_child;
AstModule *current_module;
}
@@ -122,6 +123,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_CELL)
X(AST_PRIMITIVE)
X(AST_ALWAYS)
+ X(AST_INITIAL)
X(AST_BLOCK)
X(AST_ASSIGN_EQ)
X(AST_ASSIGN_LE)
@@ -417,6 +419,14 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
}
break;
+ case AST_INITIAL:
+ fprintf(f, "%s" "initial\n", indent.c_str());
+ for (auto child : children) {
+ if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
+ child->dumpVlog(f, indent + " ");
+ }
+ break;
+
case AST_POSEDGE:
case AST_NEGEDGE:
case AST_EDGE:
@@ -679,10 +689,25 @@ static AstModule* process_module(AstNode *ast)
log("--- END OF AST DUMP ---\n");
}
+ if (flag_lib) {
+ std::vector<AstNode*> new_children;
+ for (auto child : ast->children) {
+ if (child->type == AST_WIRE && (child->is_input || child->is_output))
+ new_children.push_back(child);
+ else
+ delete child;
+ }
+ ast->children.swap(new_children);
+ ast->attributes["\\placeholder"] = AstNode::mkconst_int(0, false, 0);
+ }
+
current_module = new AstModule;
current_module->ast = NULL;
current_module->name = ast->str;
current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
+
+ ignoreThisSignalsInInitial = RTLIL::SigSpec();
+
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
@@ -697,19 +722,30 @@ static AstModule* process_module(AstNode *ast)
}
for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i];
- if (node->type != AST_WIRE && node->type != AST_MEMORY)
+ if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
node->genRTLIL();
}
+ ignoreThisSignalsInInitial.sort_and_unify();
+
+ for (size_t i = 0; i < ast->children.size(); i++) {
+ AstNode *node = ast->children[i];
+ if (node->type == AST_INITIAL)
+ node->genRTLIL();
+ }
+
+ ignoreThisSignalsInInitial = RTLIL::SigSpec();
+
current_module->ast = ast_before_simplify;
current_module->nolatches = flag_nolatches;
current_module->nomem2reg = flag_nomem2reg;
current_module->mem2reg = flag_mem2reg;
+ current_module->lib = flag_lib;
return current_module;
}
// create AstModule instances for all modules in the AST tree and add them to 'design'
-void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast, bool dump_ast_diff, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg)
+void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast, bool dump_ast_diff, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib)
{
current_ast = ast;
flag_dump_ast = dump_ast;
@@ -718,6 +754,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast, bool dump_
flag_nolatches = nolatches;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
+ flag_lib = lib;
assert(current_ast->type == AST_DESIGN);
for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++) {
@@ -747,8 +784,10 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
flag_nolatches = nolatches;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
+ flag_lib = lib;
use_internal_line_num();
+ std::string para_info;
std::vector<unsigned char> hash_data;
hash_data.insert(hash_data.end(), name.begin(), name.end());
hash_data.push_back(0);
@@ -762,9 +801,10 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
continue;
para_counter++;
std::string para_id = child->str;
- if (parameters.count(child->str) > 0) {
+ if (parameters.count(para_id) > 0) {
log("Parameter %s = %s\n", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[child->str])));
rewrite_parameter:
+ para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
child->delete_children();
child->children.push_back(AstNode::mkconst_bits(parameters[para_id].bits, false));
hash_data.insert(hash_data.end(), child->str.begin(), child->str.end());
@@ -774,10 +814,8 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
parameters.erase(para_id);
continue;
}
- char buf[100];
- snprintf(buf, 100, "$%d", para_counter);
- if (parameters.count(buf) > 0) {
- para_id = buf;
+ para_id = stringf("$%d", para_counter);
+ if (parameters.count(para_id) > 0) {
log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
goto rewrite_parameter;
}
@@ -785,17 +823,26 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
if (parameters.size() > 0)
log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), name.c_str());
- unsigned char hash[20];
- unsigned char *hash_data2 = new unsigned char[hash_data.size()];
- for (size_t i = 0; i < hash_data.size(); i++)
- hash_data2[i] = hash_data[i];
- sha1::calc(hash_data2, hash_data.size(), hash);
- delete[] hash_data2;
+ std::string modname;
+
+ if (para_info.size() > 60)
+ {
+ unsigned char hash[20];
+ unsigned char *hash_data2 = new unsigned char[hash_data.size()];
+ for (size_t i = 0; i < hash_data.size(); i++)
+ hash_data2[i] = hash_data[i];
+ sha1::calc(hash_data2, hash_data.size(), hash);
+ delete[] hash_data2;
- char hexstring[41];
- sha1::toHexString(hash, hexstring);
+ char hexstring[41];
+ sha1::toHexString(hash, hexstring);
- std::string modname = "$paramod$" + std::string(hexstring) + "$" + name;
+ modname = "$paramod$" + std::string(hexstring) + name;
+ }
+ else
+ {
+ modname = "$paramod" + name + para_info;
+ }
if (design->modules.count(modname) == 0) {
new_ast->str = modname;
@@ -821,6 +868,7 @@ void AstModule::update_auto_wires(std::map<RTLIL::IdString, int> auto_sizes)
flag_nolatches = nolatches;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
+ flag_lib = lib;
use_internal_line_num();
for (auto it = auto_sizes.begin(); it != auto_sizes.end(); it++) {
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index d65851acd..acf10f9ad 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -103,6 +103,7 @@ namespace AST
AST_CELL,
AST_PRIMITIVE,
AST_ALWAYS,
+ AST_INITIAL,
AST_BLOCK,
AST_ASSIGN_EQ,
AST_ASSIGN_LE,
@@ -189,13 +190,13 @@ namespace AST
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
- void process(RTLIL::Design *design, AstNode *ast, bool dump_ast = false, bool dump_ast_diff = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false, bool mem2reg = false);
+ void process(RTLIL::Design *design, AstNode *ast, bool dump_ast = false, bool dump_ast_diff = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false, bool mem2reg = false, bool lib = false);
// parametric modules are supported directly by the AST library
// therfore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
- bool nolatches, nomem2reg, mem2reg;
+ bool nolatches, nomem2reg, mem2reg, lib;
virtual ~AstModule();
virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
virtual void update_auto_wires(std::map<RTLIL::IdString, int> auto_sizes);
@@ -217,10 +218,10 @@ namespace AST
namespace AST_INTERNAL
{
// internal state variables
- extern bool flag_dump_ast, flag_dump_ast_diff, flag_nolatches, flag_nomem2reg, flag_mem2reg;
+ extern bool flag_dump_ast, flag_dump_ast_diff, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib;
extern AST::AstNode *current_ast, *current_ast_mod;
extern std::map<std::string, AST::AstNode*> current_scope;
- extern RTLIL::SigSpec *genRTLIL_subst_from, *genRTLIL_subst_to;
+ extern RTLIL::SigSpec *genRTLIL_subst_from, *genRTLIL_subst_to, ignoreThisSignalsInInitial;
extern AST::AstNode *current_top_block, *current_block, *current_block_child;
extern AST::AstModule *current_module;
struct ProcessGenerator;
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 0654db2df..cb57bbab7 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -183,7 +183,9 @@ struct AST_INTERNAL::ProcessGenerator
{
// input and output structures
AstNode *always;
+ RTLIL::SigSpec skipSyncSignals;
RTLIL::Process *proc;
+ const RTLIL::SigSpec &outputSignals;
// This always points to the RTLIL::CaseRule beeing filled at the moment
RTLIL::CaseRule *current_case;
@@ -205,7 +207,7 @@ struct AST_INTERNAL::ProcessGenerator
// map helps generating nice numbered names for all this temporary signals.
std::map<RTLIL::Wire*, int> new_temp_count;
- ProcessGenerator(AstNode *always) : always(always)
+ ProcessGenerator(AstNode *always, RTLIL::SigSpec skipSyncSignalsArg = RTLIL::SigSpec()) : always(always), skipSyncSignals(skipSyncSignalsArg), outputSignals(subst_lvalue_from)
{
// generate process and simple root case
proc = new RTLIL::Process;
@@ -310,6 +312,7 @@ struct AST_INTERNAL::ProcessGenerator
case AST_COND:
case AST_ALWAYS:
+ case AST_INITIAL:
for (auto child : ast->children)
if (child->type == AST_BLOCK)
collect_lvalues(reg, child, type_eq, type_le, false);
@@ -334,9 +337,9 @@ struct AST_INTERNAL::ProcessGenerator
reg.sort_and_unify();
}
- // remove all assignments to the given signal pattern in a case and all its children
- // when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this
- // function is acalled to clean up the first two assignments as they are overwritten by
+ // remove all assignments to the given signal pattern in a case and all its children.
+ // e.g. when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this
+ // function is called to clean up the first two assignments as they are overwritten by
// the third assignment.
void removeSignalFromCaseTree(RTLIL::SigSpec pattern, RTLIL::CaseRule *cs)
{
@@ -350,8 +353,10 @@ struct AST_INTERNAL::ProcessGenerator
// add an assignment (aka "action") but split it up in chunks. this way huge assignments
// are avoided and the generated $mux cells have a more "natural" size.
- void addChunkActions(std::vector<RTLIL::SigSig> &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue, bool noSyncToUndef = false)
+ void addChunkActions(std::vector<RTLIL::SigSig> &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue, bool inSyncRule = false)
{
+ if (inSyncRule)
+ lvalue.remove2(skipSyncSignals, &rvalue);
assert(lvalue.width == rvalue.width);
lvalue.optimize();
rvalue.optimize();
@@ -360,7 +365,7 @@ struct AST_INTERNAL::ProcessGenerator
for (size_t i = 0; i < lvalue.chunks.size(); i++) {
RTLIL::SigSpec lhs = lvalue.chunks[i];
RTLIL::SigSpec rhs = rvalue.extract(offset, lvalue.chunks[i].width);
- if (noSyncToUndef && lvalue.chunks[i].wire && lvalue.chunks[i].wire->attributes.count("\\nosync"))
+ if (inSyncRule && lvalue.chunks[i].wire && lvalue.chunks[i].wire->attributes.count("\\nosync"))
rhs = RTLIL::SigSpec(RTLIL::State::Sx, rhs.width);
actions.push_back(RTLIL::SigSig(lhs, rhs));
offset += lhs.width;
@@ -456,7 +461,7 @@ struct AST_INTERNAL::ProcessGenerator
} else if (node->type == AST_BLOCK) {
processAst(node);
} else if (!generated_default_case)
- current_case->compare.push_back(node->genWidthRTLIL(sw->signal.width));
+ current_case->compare.push_back(node->genWidthRTLIL(sw->signal.width, &subst_rvalue_from, &subst_rvalue_to));
}
sw->cases.push_back(current_case);
current_case = backup_case;
@@ -528,6 +533,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint)
case AST_LOCALPARAM:
case AST_GENVAR:
case AST_GENFOR:
+ case AST_GENBLOCK:
case AST_GENIF:
break;
@@ -1015,6 +1021,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint)
case AST_ALWAYS: {
AstNode *always = this->clone();
ProcessGenerator generator(always);
+ ignoreThisSignalsInInitial.append(generator.outputSignals);
+ delete always;
+ } break;
+
+ case AST_INITIAL: {
+ AstNode *always = this->clone();
+ ProcessGenerator generator(always, ignoreThisSignalsInInitial);
delete always;
} break;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 887b62f2c..bf0f9e63f 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -182,6 +182,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
break;
if (type == AST_GENIF && i >= 1)
break;
+ if (type == AST_GENBLOCK)
+ break;
if (type == AST_PREFIX && i >= 1)
break;
while (did_something_here && i < children.size()) {
@@ -194,7 +196,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
current_block = this;
current_block_child = children[i];
}
- if (type == AST_ALWAYS && children[i]->type == AST_BLOCK)
+ if ((type == AST_ALWAYS || type == AST_INITIAL) && children[i]->type == AST_BLOCK)
current_top_block = children[i];
did_something_here = children[i]->simplify(const_fold_here, at_zero, in_lvalue_here, stage);
if (did_something_here)
@@ -409,6 +411,21 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
did_something = true;
}
+ // simplify unconditional generate block
+ if (type == AST_GENBLOCK && children.size() != 0)
+ {
+ if (!str.empty()) {
+ std::map<std::string, std::string> name_map;
+ expand_genblock(std::string(), str + ".", name_map);
+ }
+
+ for (size_t i = 0; i < children.size(); i++)
+ current_ast_mod->children.push_back(children[i]);
+
+ children.clear();
+ did_something = true;
+ }
+
// simplify generate-if blocks
if (type == AST_GENIF && children.size() != 0)
{
@@ -434,7 +451,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
if (!buf->str.empty()) {
std::map<std::string, std::string> name_map;
- buf->expand_genblock(std::string(), buf->str, name_map);
+ buf->expand_genblock(std::string(), buf->str + ".", name_map);
}
for (size_t i = 0; i < buf->children.size(); i++)
@@ -877,10 +894,8 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
return;
}
- if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL) && name_map.count(str) > 0) {
+ if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL) && name_map.count(str) > 0)
str = name_map[str];
- return;
- }
std::map<std::string, std::string> backup_name_map;
diff --git a/frontends/verilog/lexer.l b/frontends/verilog/lexer.l
index a269c072a..f899191bb 100644
--- a/frontends/verilog/lexer.l
+++ b/frontends/verilog/lexer.l
@@ -184,7 +184,7 @@ supply1 { return TOK_SUPPLY1; }
"$signed" { return TOK_TO_SIGNED; }
"$unsigned" { return TOK_TO_UNSIGNED; }
-[a-zA-Z_$][a-zA-Z0-9_$]* {
+[a-zA-Z_$][a-zA-Z0-9_\.$]* {
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
return TOK_ID;
}
@@ -233,6 +233,8 @@ supply1 { return TOK_SUPPLY1; }
"<=" { return OP_LE; }
">=" { return OP_GE; }
+"===" { return OP_EQ; }
+
/* "~&" { return OP_NAND; } */
/* "~|" { return OP_NOR; } */
"~^" { return OP_XNOR; }
diff --git a/frontends/verilog/parser.y b/frontends/verilog/parser.y
index 9caa236f8..22af178e8 100644
--- a/frontends/verilog/parser.y
+++ b/frontends/verilog/parser.y
@@ -607,7 +607,7 @@ always_stmt:
ast_stack.pop_back();
} |
attr TOK_INITIAL {
- AstNode *node = new AstNode(AST_ALWAYS);
+ AstNode *node = new AstNode(AST_INITIAL);
append_attr(node, $1);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index f4a8c79fa..f9731cbc2 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -89,6 +89,9 @@ struct VerilogFrontend : public Frontend {
log(" -nopp\n");
log(" do not run the pre-processor\n");
log("\n");
+ log(" -lib\n");
+ log(" only create empty placeholder modules\n");
+ log("\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
@@ -100,6 +103,7 @@ struct VerilogFrontend : public Frontend {
bool flag_mem2reg = false;
bool flag_ppdump = false;
bool flag_nopp = false;
+ bool flag_lib = false;
frontend_verilog_yydebug = false;
log_header("Executing Verilog-2005 frontend.\n");
@@ -144,6 +148,10 @@ struct VerilogFrontend : public Frontend {
flag_nopp = true;
continue;
}
+ if (arg == "-lib") {
+ flag_lib = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
@@ -173,7 +181,7 @@ struct VerilogFrontend : public Frontend {
frontend_verilog_yyparse();
frontend_verilog_yylex_destroy();
- AST::process(design, current_ast, flag_dump_ast, flag_dump_ast_diff, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg);
+ AST::process(design, current_ast, flag_dump_ast, flag_dump_ast_diff, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib);
if (!flag_nopp)
fclose(fp);
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 1dddefdcb..3de16e724 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -20,13 +20,26 @@
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
+#include <string.h>
+#include <unistd.h>
+#include <dlfcn.h>
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/log.h"
-#include <string.h>
-#include <unistd.h>
-#include <dlfcn.h>
+
+bool fgetline(FILE *f, std::string &buffer)
+{
+ buffer = "";
+ char block[4096];
+ while (1) {
+ if (fgets(block, 4096, f) == NULL)
+ return false;
+ buffer += block;
+ if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r'))
+ return true;
+ }
+}
static void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command)
{
@@ -50,9 +63,13 @@ static void run_frontend(std::string filename, std::string command, RTLIL::Desig
f = fopen(filename.c_str(), "r");
if (f == NULL)
log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
- char buffer[4096];
- while (fgets(buffer, 4096, f) != NULL) {
- Pass::call(design, buffer);
+ std::string command;
+ while (fgetline(f, command)) {
+ Pass::call(design, command);
+ design->check();
+ }
+ if (!command.empty()) {
+ Pass::call(design, command);
design->check();
}
if (filename != "-")
@@ -132,10 +149,13 @@ static char **readline_completion(const char *text, int start, int)
return NULL;
}
-static const char *create_prompt(RTLIL::Design *design)
+static const char *create_prompt(RTLIL::Design *design, int recursion_counter)
{
static char buffer[100];
- std::string str = "\nyosys";
+ std::string str = "\n";
+ if (recursion_counter > 1)
+ str += stringf("(%d) ", recursion_counter);
+ str += "yosys";
if (!design->selected_active_module.empty())
str += stringf(" [%s]", design->selected_active_module.c_str());
if (!design->selection_stack.back().full_selection) {
@@ -151,26 +171,29 @@ static const char *create_prompt(RTLIL::Design *design)
static void shell(RTLIL::Design *design)
{
- static bool recursion_detect = false;
+ static int recursion_counter = 0;
- if (recursion_detect) {
- log("Already in interactive shell.\n");
- return;
- }
-
- recursion_detect = true;
+ recursion_counter++;
log_cmd_error_throw = true;
rl_readline_name = "yosys";
rl_attempted_completion_function = readline_completion;
char *command = NULL;
- while ((command = readline(create_prompt(design))) != NULL)
+ while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
{
if (command[strspn(command, " \t\r\n")] == 0)
continue;
add_history(command);
+ char *p = command + strspn(command, " \t\r\n");
+ if (!strncmp(p, "exit", 4)) {
+ p += 4;
+ p += strspn(p, " \t\r\n");
+ if (*p == 0)
+ break;
+ }
+
try {
assert(design->selection_stack.size() == 1);
Pass::call(design, command);
@@ -180,8 +203,10 @@ static void shell(RTLIL::Design *design)
log_reset_stack();
}
}
+ if (command == NULL)
+ printf("exit\n");
- recursion_detect = false;
+ recursion_counter--;
log_cmd_error_throw = false;
}
@@ -216,7 +241,7 @@ struct ShellPass : public Pass {
log("This command is the default action if nothing else has been specified\n");
log("on the command line.\n");
log("\n");
- log("Press Ctrl-D to leave the interactive shell.\n");
+ log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
@@ -225,6 +250,82 @@ struct ShellPass : public Pass {
}
} ShellPass;
+struct ScriptPass : public Pass {
+ ScriptPass() : Pass("script", "execute commands from script file") { }
+ virtual void help() {
+ log("\n");
+ log(" script <filename>\n");
+ log("\n");
+ log("This command executes the yosys commands in the specified file.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ if (args.size() < 2)
+ log_cmd_error("Missing script file.\n");
+ if (args.size() > 2)
+ extra_args(args, 1, design, false);
+ run_frontend(args[1], "script", design, NULL);
+ }
+} ScriptPass;
+
+#ifdef YOSYS_ENABLE_TCL
+struct TclPass : public Pass {
+ TclPass() : Pass("tcl", "execute a TCL script file") { }
+ virtual void help() {
+ log("\n");
+ log(" tcl <filename>\n");
+ log("\n");
+ log("This command executes the tcl commands in the specified file.\n");
+ log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
+ log("\n");
+ log("The tcl command 'yosys -import' can be used to import all yosys\n");
+ log("commands directly as tcl commands to the tcl shell. The yosys\n");
+ log("command 'proc' is wrapped using the tcl command 'procs' in order\n");
+ log("to avoid a name collision with the tcl builting command 'proc'.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ if (args.size() < 2)
+ log_cmd_error("Missing script file.\n");
+ if (args.size() > 2)
+ extra_args(args, 1, design, false);
+ if (Tcl_EvalFile(yosys_tcl, args[1].c_str()) != TCL_OK)
+ log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_tcl));
+ }
+} TclPass;
+
+static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
+{
+ std::vector<std::string> args;
+ for (int i = 1; i < argc; i++)
+ args.push_back(argv[i]);
+
+ if (args.size() >= 1 && args[0] == "-import") {
+ for (auto &it : REGISTER_INTERN::pass_register) {
+ std::string tcl_command_name = it.first;
+ if (tcl_command_name == "proc")
+ tcl_command_name = "procs";
+ Tcl_CmdInfo info;
+ if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
+ log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
+ } else {
+ std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
+ Tcl_Eval(interp, tcl_script.c_str());
+ }
+ }
+ return TCL_OK;
+ }
+
+ if (args.size() == 1) {
+ Pass::call(yosys_tcl_design, args[0]);
+ return TCL_OK;
+ }
+
+ Pass::call(yosys_tcl_design, args);
+ return TCL_OK;
+}
+#endif
+
int main(int argc, char **argv)
{
std::string frontend_command = "auto";
@@ -233,10 +334,16 @@ int main(int argc, char **argv)
std::vector<void*> loaded_modules;
std::string output_filename = "";
std::string scriptfile = "";
+ bool scriptfile_tcl = false;
bool got_output_filename = false;
+#ifdef YOSYS_ENABLE_TCL
+ yosys_tcl = Tcl_CreateInterp();
+ Tcl_CreateCommand(yosys_tcl, "yosys", tcl_yosys_cmd, NULL, NULL);
+#endif
+
int opt;
- while ((opt = getopt(argc, argv, "Sm:f:b:o:p:l:qts:")) != -1)
+ while ((opt = getopt(argc, argv, "Sm:f:b:o:p:l:qts:c:")) != -1)
{
switch (opt)
{
@@ -284,10 +391,15 @@ int main(int argc, char **argv)
break;
case 's':
scriptfile = optarg;
+ scriptfile_tcl = false;
+ break;
+ case 'c':
+ scriptfile = optarg;
+ scriptfile_tcl = true;
break;
default:
fprintf(stderr, "\n");
- fprintf(stderr, "Usage: %s [-S] [-q] [-t] [-l logfile] [-o <outfile>] [-f <frontend>] [-s <scriptfile>]\n", argv[0]);
+ fprintf(stderr, "Usage: %s [-S] [-q] [-t] [-l logfile] [-o <outfile>] [-f <frontend>] [{-s|-c} <scriptfile>]\n", argv[0]);
fprintf(stderr, " %*s[-p <pass> [-p ..]] [-b <backend>] [-m <module_file>] [<infile> [..]]\n", int(strlen(argv[0])+1), "");
fprintf(stderr, "\n");
fprintf(stderr, " -q\n");
@@ -311,6 +423,9 @@ int main(int argc, char **argv)
fprintf(stderr, " -s scriptfile\n");
fprintf(stderr, " execute the commands in the script file\n");
fprintf(stderr, "\n");
+ fprintf(stderr, " -c tcl_scriptfile\n");
+ fprintf(stderr, " execute the commands in the tcl script file (see 'help tcl' for details)\n");
+ fprintf(stderr, "\n");
fprintf(stderr, " -p command\n");
fprintf(stderr, " execute the commands\n");
fprintf(stderr, "\n");
@@ -366,6 +481,10 @@ int main(int argc, char **argv)
design->selection_stack.push_back(RTLIL::Selection());
log_push();
+#ifdef YOSYS_ENABLE_TCL
+ yosys_tcl_design = design;
+#endif
+
if (optind == argc && passes_commands.size() == 0 && scriptfile.empty()) {
if (!got_output_filename)
backend_command = "";
@@ -375,8 +494,17 @@ int main(int argc, char **argv)
while (optind < argc)
run_frontend(argv[optind++], frontend_command, design, output_filename == "-" ? &backend_command : NULL);
- if (!scriptfile.empty())
- run_frontend(scriptfile, "script", design, output_filename == "-" ? &backend_command : NULL);
+ if (!scriptfile.empty()) {
+ if (scriptfile_tcl) {
+#ifdef YOSYS_ENABLE_TCL
+ if (Tcl_EvalFile(yosys_tcl, scriptfile.c_str()) != TCL_OK)
+ log_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_tcl));
+#else
+ log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n");
+#endif
+ } else
+ run_frontend(scriptfile, "script", design, output_filename == "-" ? &backend_command : NULL);
+ }
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
run_pass(*it, design);
@@ -386,6 +514,10 @@ int main(int argc, char **argv)
delete design;
+#ifdef YOSYS_ENABLE_TCL
+ yosys_tcl_design = NULL;
+#endif
+
log("\nREADY.\n");
log_pop();
@@ -400,6 +532,10 @@ int main(int argc, char **argv)
for (auto mod : loaded_modules)
dlclose(mod);
+#ifdef YOSYS_ENABLE_TCL
+ Tcl_DeleteInterp(yosys_tcl);
+#endif
+
return 0;
}
diff --git a/kernel/register.cc b/kernel/register.cc
index 1dd608754..bfd51feb1 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -27,6 +27,11 @@
using namespace REGISTER_INTERN;
#define MAX_REG_COUNT 1000
+#ifdef YOSYS_ENABLE_TCL
+Tcl_Interp *yosys_tcl = NULL;
+RTLIL::Design *yosys_tcl_design = NULL;
+#endif
+
namespace REGISTER_INTERN
{
int raw_register_count = 0;
@@ -109,9 +114,6 @@ void Pass::cmd_error(const std::vector<std::string> &args, size_t argidx, std::s
msg.c_str(), command_text.c_str(), error_pos, "");
}
-// implemented in kernel/select.cc
-extern void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, RTLIL::Design *design);
-
void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Design *design, bool select)
{
for (; argidx < args.size(); argidx++)
@@ -124,7 +126,7 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig
if (!select)
cmd_error(args, argidx, "Extra argument.");
- handle_extra_select_args(this, args, argidx, design);
+ handle_extra_select_args(this, args, argidx, args.size(), design);
break;
}
cmd_log_args(args);
diff --git a/kernel/register.h b/kernel/register.h
index a817d8c64..2f664e7c1 100644
--- a/kernel/register.h
+++ b/kernel/register.h
@@ -26,6 +26,12 @@
#include <vector>
#include <map>
+#ifdef YOSYS_ENABLE_TCL
+#include <tcl.h>
+extern Tcl_Interp *yosys_tcl;
+extern RTLIL::Design *yosys_tcl_design;
+#endif
+
struct Pass
{
std::string pass_name, short_help;
@@ -77,6 +83,9 @@ struct Backend : Pass
static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args);
};
+// implemented in kernel/select.cc
+extern void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design);
+
namespace REGISTER_INTERN {
extern int raw_register_count;
extern bool raw_register_done;
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index c97e2e455..b0dcfe428 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -18,6 +18,7 @@
*/
#include "kernel/rtlil.h"
+#include "kernel/log.h"
#include <assert.h>
#include <algorithm>
@@ -257,13 +258,12 @@ RTLIL::Module::~Module()
RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, std::map<RTLIL::IdString, RTLIL::Const>)
{
- assert(!"Called derive() from module base class.");
- abort();
+ log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
}
void RTLIL::Module::update_auto_wires(std::map<RTLIL::IdString, int>)
{
- assert(!"Called update_auto_wires() from module base class.");
+ log_error("Module `%s' has automatic wires bu no HDL backend to handle it!\n", id2cstr(name));
}
size_t RTLIL::Module::count_id(RTLIL::IdString id)
@@ -566,7 +566,7 @@ void RTLIL::SigSpec::optimize()
check();
}
-static bool compare_sigchunks(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b)
+bool RTLIL::SigChunk::compare(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b)
{
if (a.wire != b.wire) {
if (a.wire == NULL || b.wire == NULL)
@@ -583,14 +583,21 @@ static bool compare_sigchunks(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b
return a.data.bits < b.data.bits;
}
+void RTLIL::SigSpec::sort()
+{
+ expand();
+ std::sort(chunks.begin(), chunks.end(), RTLIL::SigChunk::compare);
+ optimize();
+}
+
void RTLIL::SigSpec::sort_and_unify()
{
expand();
- std::sort(chunks.begin(), chunks.end(), compare_sigchunks);
+ std::sort(chunks.begin(), chunks.end(), RTLIL::SigChunk::compare);
for (size_t i = 1; i < chunks.size(); i++) {
RTLIL::SigChunk &ch1 = chunks[i-1];
RTLIL::SigChunk &ch2 = chunks[i];
- if (!compare_sigchunks(ch1, ch2) && !compare_sigchunks(ch2, ch1)) {
+ if (!RTLIL::SigChunk::compare(ch1, ch2) && !RTLIL::SigChunk::compare(ch2, ch1)) {
chunks.erase(chunks.begin()+i);
width -= chunks[i].width;
i--;
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index a0d7a1a37..fe88182fa 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -277,6 +277,7 @@ struct RTLIL::SigChunk {
bool operator <(const RTLIL::SigChunk &other) const;
bool operator ==(const RTLIL::SigChunk &other) const;
bool operator !=(const RTLIL::SigChunk &other) const;
+ static bool compare(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b);
};
struct RTLIL::SigSpec {
@@ -291,6 +292,7 @@ struct RTLIL::SigSpec {
SigSpec(RTLIL::State bit, int width = 1);
void expand();
void optimize();
+ void sort();
void sort_and_unify();
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;
diff --git a/kernel/select.cc b/kernel/select.cc
index a6e675c88..fa1c3db02 100644
--- a/kernel/select.cc
+++ b/kernel/select.cc
@@ -346,8 +346,18 @@ static void select_op_expand(RTLIL::Design *design, std::string arg, char mode)
size_t endpos = arg.find(':', pos);
if (endpos == std::string::npos)
endpos = arg.size();
- if (int(endpos) > pos)
- limits.insert(RTLIL::escape_id(arg.substr(pos, endpos-pos)));
+ if (int(endpos) > pos) {
+ std::string str = arg.substr(pos, endpos-pos);
+ if (str[0] == '@') {
+ str = RTLIL::escape_id(str.substr(1));
+ if (design->selection_vars.count(str) > 0) {
+ for (auto i1 : design->selection_vars.at(str).selected_members)
+ for (auto i2 : i1.second)
+ limits.insert(i2);
+ }
+ } else
+ limits.insert(RTLIL::escape_id(str));
+ }
pos = endpos;
}
}
@@ -471,7 +481,8 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
select_op_expand(design, arg, 'o');
} else
log_cmd_error("Unknown selection operator '%s'.\n", arg.c_str());
- select_filter_active_mod(design, work_stack.back());
+ if (work_stack.size() >= 1)
+ select_filter_active_mod(design, work_stack.back());
return;
}
@@ -585,20 +596,27 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
select_filter_active_mod(design, work_stack.back());
}
-// used in kernel/register.cc
-void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, RTLIL::Design *design)
+// used in kernel/register.cc and maybe other locations, extern decl. in register.h
+void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design)
{
work_stack.clear();
- for (; argidx < args.size(); argidx++) {
- if (args[argidx].substr(0, 1) == "-")
- pass->cmd_error(args, argidx, "Unexpected option in selection arguments.");
+ for (; argidx < args_size; argidx++) {
+ if (args[argidx].substr(0, 1) == "-") {
+ if (pass != NULL)
+ pass->cmd_error(args, argidx, "Unexpected option in selection arguments.");
+ else
+ log_cmd_error("Unexpected option in selection arguments.");
+ }
select_stmt(design, args[argidx]);
}
while (work_stack.size() > 1) {
select_op_union(design, work_stack.front(), work_stack.back());
work_stack.pop_back();
}
- design->selection_stack.push_back(work_stack.back());
+ if (work_stack.size() > 0)
+ design->selection_stack.push_back(work_stack.back());
+ else
+ design->selection_stack.push_back(RTLIL::Selection(false));
}
struct SelectPass : public Pass {
diff --git a/kernel/show.cc b/kernel/show.cc
index 321d9e2e0..fd703dd53 100644
--- a/kernel/show.cc
+++ b/kernel/show.cc
@@ -36,7 +36,7 @@ struct ShowWorker
std::map<RTLIL::IdString, int> autonames;
int single_idx_count;
- struct net_conn { std::set<std::string> in, out; int bits; };
+ struct net_conn { std::set<std::string> in, out; int bits; std::string color; };
std::map<std::string, net_conn> net_conn_map;
FILE *f;
@@ -47,6 +47,9 @@ struct ShowWorker
bool stretchIO;
int page_counter;
+ const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections;
+ const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections;
+
uint32_t xorshift32(uint32_t x) {
x ^= x << 13;
x ^= x >> 17;
@@ -61,6 +64,40 @@ struct ShowWorker
return stringf("colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", currentColor%8+1);
}
+ std::string nextColor(std::string presetColor)
+ {
+ if (presetColor.empty())
+ return nextColor();
+ return presetColor;
+ }
+
+ std::string nextColor(RTLIL::SigSpec sig, std::string defaultColor)
+ {
+ sig.sort_and_unify();
+ for (auto &c : sig.chunks) {
+ if (c.wire != NULL)
+ for (auto &s : color_selections)
+ if (s.second.selected_members.count(module->name) > 0 && s.second.selected_members.at(module->name).count(c.wire->name) > 0)
+ return stringf("color=\"%s\", fontcolor=\"%d\"", s.first.c_str(), s.first.c_str());
+ }
+ return defaultColor;
+ }
+
+ std::string nextColor(RTLIL::SigSig &conn, std::string defaultColor)
+ {
+ return nextColor(conn.first, nextColor(conn.second, defaultColor));
+ }
+
+ std::string nextColor(RTLIL::SigSpec &sig)
+ {
+ return nextColor(sig, nextColor());
+ }
+
+ std::string nextColor(RTLIL::SigSig &conn)
+ {
+ return nextColor(conn, nextColor());
+ }
+
std::string widthLabel(int bits)
{
if (bits <= 1)
@@ -145,10 +182,12 @@ struct ShowWorker
label_string += stringf("<s%d> %d:%d - %d:%d |", i, pos, pos-c.width+1, c.offset+c.width-1, c.offset);
net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i));
net_conn_map[net].bits = c.width;
+ net_conn_map[net].color = nextColor(c, net_conn_map[net].color);
} else {
label_string += stringf("<s%d> %d:%d - %d:%d |", i, c.offset+c.width-1, c.offset, pos, pos-c.width+1);
net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i));
net_conn_map[net].bits = c.width;
+ net_conn_map[net].color = nextColor(c, net_conn_map[net].color);
}
pos -= c.width;
}
@@ -158,9 +197,9 @@ struct ShowWorker
if (!port.empty()) {
currentColor = xorshift32(currentColor);
if (driver)
- code += stringf("%s:e -> x%d:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", port.c_str(), idx, nextColor().c_str(), widthLabel(sig.width).c_str());
+ code += stringf("%s:e -> x%d:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", port.c_str(), idx, nextColor(sig).c_str(), widthLabel(sig.width).c_str());
else
- code += stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", idx, port.c_str(), nextColor().c_str(), widthLabel(sig.width).c_str());
+ code += stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", idx, port.c_str(), nextColor(sig).c_str(), widthLabel(sig.width).c_str());
}
if (node != NULL)
*node = stringf("x%d", idx);
@@ -173,6 +212,7 @@ struct ShowWorker
else
net_conn_map[net].out.insert(port);
net_conn_map[net].bits = sig.width;
+ net_conn_map[net].color = nextColor(sig, net_conn_map[net].color);
}
if (node != NULL)
*node = net;
@@ -202,8 +242,9 @@ struct ShowWorker
if (it.second->port_input || it.second->port_output)
shape = "octagon";
if (it.first[0] == '\\') {
- fprintf(f, "n%d [ shape=%s, label=\"%s\" ];\n",
- id2num(it.first), shape, escape(it.first));
+ fprintf(f, "n%d [ shape=%s, label=\"%s\", %s, fontcolor=\"black\" ];\n",
+ id2num(it.first), shape, escape(it.first),
+ nextColor(RTLIL::SigSpec(it.second), "color=\"black\"").c_str());
if (it.second->port_input)
all_sources.insert(stringf("n%d", id2num(it.first)));
else if (it.second->port_output)
@@ -294,10 +335,12 @@ struct ShowWorker
if (left_node[0] == 'x' && right_node[0] == 'x') {
currentColor = xorshift32(currentColor);
- fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node.c_str(), right_node.c_str(), nextColor().c_str(), widthLabel(conn.first.width).c_str());
+ fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node.c_str(), right_node.c_str(), nextColor(conn).c_str(), widthLabel(conn.first.width).c_str());
} else {
net_conn_map[right_node].bits = conn.first.width;
+ net_conn_map[right_node].color = nextColor(conn, net_conn_map[right_node].color);
net_conn_map[left_node].bits = conn.first.width;
+ net_conn_map[left_node].color = nextColor(conn, net_conn_map[left_node].color);
if (left_node[0] == 'x') {
net_conn_map[right_node].in.insert(left_node);
} else if (right_node[0] == 'x') {
@@ -315,7 +358,7 @@ struct ShowWorker
currentColor = xorshift32(currentColor);
if (wires_on_demand.count(it.first) > 0) {
if (it.second.in.size() == 1 && it.second.out.size() == 1) {
- fprintf(f, "%s:e -> %s:w [%s, %s];\n", it.second.in.begin()->c_str(), it.second.out.begin()->c_str(), nextColor().c_str(), widthLabel(it.second.bits).c_str());
+ fprintf(f, "%s:e -> %s:w [%s, %s];\n", it.second.in.begin()->c_str(), it.second.out.begin()->c_str(), nextColor(it.second.color).c_str(), widthLabel(it.second.bits).c_str());
continue;
}
if (it.second.in.size() == 0 || it.second.out.size() == 0)
@@ -324,16 +367,19 @@ struct ShowWorker
fprintf(f, "%s [ shape=point ];\n", it.first.c_str());
}
for (auto &it2 : it.second.in)
- fprintf(f, "%s:e -> %s:w [%s, %s];\n", it2.c_str(), it.first.c_str(), nextColor().c_str(), widthLabel(it.second.bits).c_str());
+ fprintf(f, "%s:e -> %s:w [%s, %s];\n", it2.c_str(), it.first.c_str(), nextColor(it.second.color).c_str(), widthLabel(it.second.bits).c_str());
for (auto &it2 : it.second.out)
- fprintf(f, "%s:e -> %s:w [%s, %s];\n", it.first.c_str(), it2.c_str(), nextColor().c_str(), widthLabel(it.second.bits).c_str());
+ fprintf(f, "%s:e -> %s:w [%s, %s];\n", it.first.c_str(), it2.c_str(), nextColor(it.second.color).c_str(), widthLabel(it.second.bits).c_str());
}
fprintf(f, "};\n");
}
- ShowWorker(FILE *f, RTLIL::Design *design, std::vector<RTLIL::Design*> &libs, uint32_t colorSeed, bool genWidthLabels, bool stretchIO) :
- f(f), design(design), currentColor(colorSeed), genWidthLabels(genWidthLabels), stretchIO(stretchIO)
+ ShowWorker(FILE *f, RTLIL::Design *design, std::vector<RTLIL::Design*> &libs, uint32_t colorSeed, bool genWidthLabels, bool stretchIO,
+ const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections,
+ const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections) :
+ f(f), design(design), currentColor(colorSeed), genWidthLabels(genWidthLabels), stretchIO(stretchIO),
+ color_selections(color_selections), label_selections(label_selections)
{
ct.setup_internals();
ct.setup_internals_mem();
@@ -352,8 +398,12 @@ struct ShowWorker
if (!design->selected_module(module->name))
continue;
if (design->selected_whole_module(module->name)) {
+ if (module->attributes.count("\\placeholder") > 0) {
+ log("Skipping placeholder module %s.\n", id2cstr(module->name));
+ continue;
+ } else
if (module->cells.empty() && module->connections.empty()) {
- log("Skipping skeletton module %s.\n", id2cstr(module->name));
+ log("Skipping empty module %s.\n", id2cstr(module->name));
continue;
} else
log("Dumping module %s to page %d.\n", id2cstr(module->name), ++page_counter);
@@ -373,10 +423,14 @@ struct ShowPass : public Pass {
log(" show [options] [selection]\n");
log("\n");
log("Create a graphviz DOT file for the selected part of the design and compile it\n");
- log("to a postscript file.\n");
+ log("to a graphics file (usually SVG or PostScript).\n");
+ log("\n");
+ log(" -viewer <viewer>\n");
+ log(" Run the specified command with the graphics file as parameter.\n");
log("\n");
- log(" -viewer <command>\n");
- log(" Also run the specified command with the postscript file as parameter.\n");
+ log(" -format <format>\n");
+ log(" Generate a graphics file in the specified format.\n");
+ log(" Usually <format> is 'svg' or 'ps'.\n");
log("\n");
log(" -lib <verilog_or_ilang_file>\n");
log(" Use the specified library file for determining whether cell ports are\n");
@@ -386,6 +440,11 @@ struct ShowPass : public Pass {
log(" -prefix <prefix>\n");
log(" generate <prefix>.dot and <prefix>.ps instead of yosys-show.{dot,ps}\n");
log("\n");
+ log(" -color <color> <wire>\n");
+ log(" assign the specified color to the specified wire. The object can be\n");
+ log(" a single selection wildcard expressions or a saved set of objects in\n");
+ log(" the @<name> syntax (see \"help select\" for details).\n");
+ log("\n");
log(" -colors <seed>\n");
log(" Randomly assign colors to the wires. The integer argument is the seed\n");
log(" for the random number generator. Change the seed value if the colored\n");
@@ -398,7 +457,11 @@ struct ShowPass : public Pass {
log(" stretch the graph so all inputs are on the left side and all outputs\n");
log(" (including inout ports) are on the right side.\n");
log("\n");
- log("The generated output files are `yosys-show.dot' and `yosys-show.ps'.\n");
+ log("When no <format> is specified, SVG is used. When no <format> and <viewer> is\n");
+ log("specified, 'yosys-svgviewer' is used to display the schematic.\n");
+ log("\n");
+ log("The generated output files are 'yosys-show.dot' and 'yosys-show.<format>',\n");
+ log("unless another prefix is specified using -prefix <prefix>.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
@@ -406,6 +469,10 @@ struct ShowPass : public Pass {
log_header("Generating Graphviz representation of design.\n");
log_push();
+ std::vector<std::pair<std::string, RTLIL::Selection>> color_selections;
+ std::vector<std::pair<std::string, RTLIL::Selection>> label_selections;
+
+ std::string format;
std::string viewer_exe;
std::string prefix = "yosys-show";
std::vector<std::string> libfiles;
@@ -430,10 +497,32 @@ struct ShowPass : public Pass {
prefix = args[++argidx];
continue;
}
+ if (arg == "-color" && argidx+2 < args.size()) {
+ std::pair<std::string, RTLIL::Selection> data;
+ data.first = args[++argidx], argidx++;
+ handle_extra_select_args(this, args, argidx, argidx+1, design);
+ data.second = design->selection_stack.back();
+ design->selection_stack.pop_back();
+ color_selections.push_back(data);
+ continue;
+ }
+ if (arg == "-label" && argidx+2 < args.size() && false) {
+ std::pair<std::string, RTLIL::Selection> data;
+ data.first = args[++argidx], argidx++;
+ handle_extra_select_args(this, args, argidx, argidx+1, design);
+ data.second = design->selection_stack.back();
+ design->selection_stack.pop_back();
+ label_selections.push_back(data);
+ continue;
+ }
if (arg == "-colors" && argidx+1 < args.size()) {
colorSeed = atoi(args[++argidx].c_str());
continue;
}
+ if (arg == "-format" && argidx+1 < args.size()) {
+ format = args[++argidx];
+ continue;
+ }
if (arg == "-width") {
flag_width= true;
continue;
@@ -446,6 +535,20 @@ struct ShowPass : public Pass {
}
extra_args(args, argidx, design);
+ if (format != "ps") {
+ int modcount = 0;
+ for (auto &mod_it : design->modules) {
+ if (mod_it.second->attributes.count("\\placeholder") > 0)
+ continue;
+ if (mod_it.second->cells.empty() && mod_it.second->connections.empty())
+ continue;
+ if (design->selected_module(mod_it.first))
+ modcount++;
+ }
+ if (modcount > 1)
+ log_cmd_error("For formats different than 'ps' only one module must be selected.\n");
+ }
+
for (auto filename : libfiles) {
FILE *f = fopen(filename.c_str(), "rt");
if (f == NULL)
@@ -460,33 +563,42 @@ struct ShowPass : public Pass {
log_header("Continuing show pass.\n");
std::string dot_file = stringf("%s.dot", prefix.c_str());
- std::string ps_file = stringf("%s.ps", prefix.c_str());
+ std::string out_file = stringf("%s.%s", prefix.c_str(), format.empty() ? "svg" : format.c_str());
log("Writing dot description to `%s'.\n", dot_file.c_str());
FILE *f = fopen(dot_file.c_str(), "w");
- if (f == NULL)
+ if (f == NULL) {
+ for (auto lib : libs)
+ delete lib;
log_cmd_error("Can't open dot file `%s' for writing.\n", dot_file.c_str());
- ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_stretch);
+ }
+ ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_stretch, color_selections, label_selections);
fclose(f);
+ for (auto lib : libs)
+ delete lib;
+
if (worker.page_counter == 0)
log_cmd_error("Nothing there to show.\n");
- std::string cmd = stringf("dot -Tps -o '%s' '%s'", ps_file.c_str(), dot_file.c_str());
+ std::string cmd = stringf("dot -T%s -o '%s' '%s'", format.empty() ? "svg" : format.c_str(), out_file.c_str(), dot_file.c_str());
log("Exec: %s\n", cmd.c_str());
if (system(cmd.c_str()) != 0)
log_cmd_error("Shell command failed!\n");
if (!viewer_exe.empty()) {
- cmd = stringf("%s '%s' &", viewer_exe.c_str(), ps_file.c_str());
+ cmd = stringf("%s '%s' &", viewer_exe.c_str(), out_file.c_str());
+ log("Exec: %s\n", cmd.c_str());
+ if (system(cmd.c_str()) != 0)
+ log_cmd_error("Shell command failed!\n");
+ } else
+ if (format.empty()) {
+ cmd = stringf("fuser -s '%s' || yosys-svgviewer '%s' &", out_file.c_str(), out_file.c_str());
log("Exec: %s\n", cmd.c_str());
if (system(cmd.c_str()) != 0)
log_cmd_error("Shell command failed!\n");
}
- for (auto lib : libs)
- delete lib;
-
log_pop();
}
} ShowPass;
diff --git a/libs/subcircuit/subcircuit.cc b/libs/subcircuit/subcircuit.cc
index 6ee2a0fcc..b4e74be6b 100644
--- a/libs/subcircuit/subcircuit.cc
+++ b/libs/subcircuit/subcircuit.cc
@@ -1124,6 +1124,21 @@ class SubCircuit::SolverWorker
while (prunePortmapCandidates(portmapCandidates, enumerationMatrix, needle, haystack)) { }
+ if (verbose) {
+ my_printf("\nPortmapper results:\n");
+ for (int j = 0; j < int(enumerationMatrix.size()); j++) {
+ my_printf("%5d: %s\n", j, needle.graph.nodes[j].nodeId.c_str());
+ int variantCounter = 0;
+ for (auto &i2 : portmapCandidates.at(j)) {
+ my_printf("%*s variant %2d:", 6, "", variantCounter++);
+ int mapCounter = 0;
+ for (auto &i3 : i2)
+ my_printf("%s %s -> %s", mapCounter++ ? "," : "", i3.first.c_str(), i3.second.c_str());
+ my_printf("\n");
+ }
+ }
+ }
+
for (int j = 0; j < int(enumerationMatrix.size()); j++) {
if (portmapCandidates[j].size() == 0) {
if (verbose) {
diff --git a/libs/svgviewer/.gitignore b/libs/svgviewer/.gitignore
new file mode 100644
index 000000000..b92d91f8b
--- /dev/null
+++ b/libs/svgviewer/.gitignore
@@ -0,0 +1,5 @@
+Makefile
+moc_mainwindow.cpp
+moc_svgview.cpp
+qrc_svgviewer.cpp
+svgviewer
diff --git a/libs/svgviewer/files/bubbles.svg b/libs/svgviewer/files/bubbles.svg
new file mode 100644
index 000000000..51730124a
--- /dev/null
+++ b/libs/svgviewer/files/bubbles.svg
@@ -0,0 +1,215 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg width="20cm" height="15cm" viewBox="0 0 800 600"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink/"
+ baseProfile="tiny" version="1.2">
+ <title>Spheres</title>
+ <desc>Semi-transparent bubbles on a colored background.</desc>
+ <defs>
+ <!-- Create radial gradients for each bubble. -->
+ <radialGradient id="blueBubble" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" stop-opacity="1" />
+ <stop offset="25%" stop-color="#cdcdff" stop-opacity=".65" />
+ <stop offset="100%" stop-color="#cdaacd" stop-opacity=".75" />
+ </radialGradient>
+ <radialGradient id="redBubble" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" stop-opacity="1" />
+ <stop offset="25%" stop-color="#ffcdcd" stop-opacity=".65" />
+ <stop offset="100%" stop-color="#bbbb99" stop-opacity=".75" />
+ </radialGradient>
+ <radialGradient id="greenBubble" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" stop-opacity="1" />
+ <stop offset="25%" stop-color="#cdffcd" stop-opacity=".65" />
+ <stop offset="100%" stop-color="#99aaaa" stop-opacity=".75" />
+ </radialGradient>
+ <radialGradient id="yellowBubble" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" stop-opacity="1" />
+ <stop offset="25%" stop-color="#ffffcd" stop-opacity=".65" />
+ <stop offset="100%" stop-color="#bbbbaa" stop-opacity=".75" />
+ </radialGradient>
+ <radialGradient id="background" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="400" fx="250" fy="250">
+ <stop offset="0%" stop-color="#ffffee" />
+ <stop offset="100%" stop-color="#ccccaa" />
+ </radialGradient>
+ <linearGradient id="surface" gradientUnits="userSpaceOnUse"
+ x1="-100" y1="200" x2="400" y2="200">
+ <stop offset="0%" stop-color="#ffffcc" />
+ <stop offset="100%" stop-color="#bbbb88" />
+ </linearGradient>
+
+ <!-- Create radial gradients for each circle to make them look like
+ spheres. -->
+ <radialGradient id="blueSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="blue" />
+ <stop offset="100%" stop-color="#222244" />
+ </radialGradient>
+ <radialGradient id="redSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="red" />
+ <stop offset="100%" stop-color="#442222" />
+ </radialGradient>
+ <radialGradient id="greenSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="green" />
+ <stop offset="100%" stop-color="#113311" />
+ </radialGradient>
+ <radialGradient id="yellowSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="yellow" />
+ <stop offset="100%" stop-color="#444422" />
+ </radialGradient>
+ <radialGradient id="shadowGrad" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="50">
+ <stop offset="0%" stop-color="black" stop-opacity="1.0" />
+ <stop offset="100%" stop-color="black" stop-opacity="0.0" />
+ </radialGradient>
+
+ <!-- Define a shadow for each sphere. -->
+ <circle id="shadow" fill="url(#shadowGrad)" cx="0" cy="0" r="100" />
+ <g id="bubble">
+ <circle fill="black" cx="0" cy="0" r="50" />
+ <circle fill="#a6ce39" cx="0" cy="0" r="33" />
+ <path fill="black" d="M 37,50 L 50,37 L 12,-1 L 22,-11 L 10,-24 L -24,10
+ L -11,22 L -1,12 Z" />
+ <circle cx="0" cy="0" r="100" />
+ </g>
+ </defs>
+ <g>
+ <rect fill="url(#background)" x="0" y="0" width="800" height="600" />
+ </g>
+
+ <g transform="translate(200,700)">
+ <use xlink:href="#bubble" fill="url(#blueBubble)" />
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="1s" dur="10s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(315,700)">
+ <g transform="scale(0.5,0.5)">
+ <use xlink:href="#bubble" fill="url(#redBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="3s" dur="7s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(80,700)">
+ <g transform="scale(0.65,0.65)">
+ <use xlink:href="#bubble" fill="url(#greenBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="5s" dur="9s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(255,700)">
+ <g transform="scale(0.3,0.3)">
+ <use xlink:href="#bubble" fill="url(#yellowBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="2s" dur="6s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(565,700)">
+ <g transform="scale(0.4,0.4)">
+ <use xlink:href="#bubble" fill="url(#blueBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="4s" dur="8s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(715,700)">
+ <g transform="scale(0.6,0.6)">
+ <use xlink:href="#bubble" fill="url(#redBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="1s" dur="4s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(645,700)">
+ <g transform="scale(0.375,0.375)">
+ <use xlink:href="#bubble" fill="url(#greenBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="0s" dur="11s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(555,700)">
+ <g transform="scale(0.9,0.9)">
+ <use xlink:href="#bubble" fill="url(#yellowBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="3s" dur="7.5s" fill="freeze" repeatCount="indefinite" />
+ </g>
+
+ <g transform="translate(360,700)">
+ <g transform="scale(0.5,0.5)">
+ <use xlink:href="#bubble" fill="url(#blueBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="3s" dur="6s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(215,700)">
+ <g transform="scale(0.45,0.45)">
+ <use xlink:href="#bubble" fill="url(#redBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="5.5s" dur="7s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(420,700)">
+ <g transform="scale(0.75,0.75)">
+ <use xlink:href="#bubble" fill="url(#greenBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="1s" dur="9s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(815,700)">
+ <g transform="scale(0.6,0.6)">
+ <use xlink:href="#bubble" fill="url(#yellowBubble)" />
+ </g>
+ <animateTransform attributeName="transform" type="translate" additive="sum"
+ values="0,0; 0,-800" begin="2s" dur="9.5s" fill="freeze" repeatCount="indefinite" />
+ </g>
+
+ <g transform="translate(225,375)" >
+ <g transform="scale(1.0,0.5)" >
+ <path d="M 0 0 L 350 0 L 450 450 L -100 450 z"
+ fill="url(#surface)" stroke="none" />
+ </g>
+ </g>
+ <g transform="translate(200,0)" >
+ <g transform="translate(200,490) scale(2.0,1.0) rotate(45)" >
+ <rect fill="#a6ce39" x="-69" y="-69" width="138" height="138" />
+ <circle fill="black" cx="0" cy="0" r="50" />
+ <circle fill="#a6ce39" cx="0" cy="0" r="33" />
+ <path fill="black" d="M 37,50 L 50,37 L 12,-1 L 22,-11 L 10,-24 L -24,10
+ L -11,22 L -1,12 Z" />
+ <animateTransform attributeName="transform" type="rotate" additive="sum" values="0; 360"
+ begin="0s" dur="10s" fill="freeze" repeatCount="indefinite" />
+ </g>
+ <g transform="translate(200,375)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#blueSphere)" cx="0" cy="0" r="100" />
+ </g>
+ <g transform="translate(315,440)">
+ <g transform="scale(0.5,0.5)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#redSphere)" cx="0" cy="0" r="100" />
+ </g>
+ </g>
+ <g transform="translate(80,475)">
+ <g transform="scale(0.65,0.65)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#greenSphere)" cx="0" cy="0" r="100" />
+ </g>
+ </g>
+ <g transform="translate(255,525)">
+ <g transform="scale(0.3,0.3)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#yellowSphere)" cx="0" cy="0" r="100" />
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/libs/svgviewer/files/cubic.svg b/libs/svgviewer/files/cubic.svg
new file mode 100644
index 000000000..492bb72b8
--- /dev/null
+++ b/libs/svgviewer/files/cubic.svg
@@ -0,0 +1,77 @@
+<?xml version="1.0" standalone="no"?>
+<svg width="10cm" height="10cm" viewBox="0 0 1000 1000"
+ xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny">
+ <title>Example cubic02 - cubic Bezier commands in path data</title>
+ <desc>Picture showing examples of "C" and "S" commands,
+ along with annotations showing the control points
+ and end points</desc>
+
+ <rect fill="none" stroke="blue" stroke-width="1" x="1" y="1" width="998" height="998" />
+
+ <!-- Path 1 -->
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="100,200 100,100" />
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="400,100 400,200" />
+ <path fill="none" stroke="red" stroke-width="5" d="M100,200 C100,100 400,100 400,200" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="100" cy="200" r="10" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="400" cy="200" r="10" />
+ <circle class="CtlPoint" cx="100" cy="100" r="10" />
+ <circle class="CtlPoint" cx="400" cy="100" r="10" />
+ <text text-anchor="middle" font-size="22" font-family="Verdana" x="250" y="275">M100,200 C100,100 400,100 400,200</text>
+
+ <!-- Path 2 -->
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="100,500 25,400" />
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="475,400 400,500" />
+ <path fill="none" stroke="red" stroke-width="5" d="M100,500 C25,400 475,400 400,500" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="100" cy="500" r="10" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="400" cy="500" r="10" />
+ <circle fill="#888888" stroke="none" cx="25" cy="400" r="10" />
+ <circle fill="#888888" stroke="none" cx="475" cy="400" r="10" />
+ <text text-anchor="middle" font-size="22" font-family="Verdana" x="250" y="575">M100,500 C25,400 475,400 400,500</text>
+
+ <!-- Path 3 -->
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="100,800 175,700" />
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="325,700 400,800" />
+ <path fill="none" stroke="red" stroke-width="5" d="M100,800 C175,700 325,700 400,800" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="100" cy="800" r="10" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="400" cy="800" r="10" />
+ <circle fill="#888888" stroke="none" cx="175" cy="700" r="10" />
+ <circle fill="#888888" stroke="none" cx="325" cy="700" r="10" />
+ <text text-anchor="middle" font-size="22" font-family="Verdana" x="250" y="875">M100,800 C175,700 325,700 400,800</text>
+
+ <!-- Path 4 -->
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="600,200 675,100" />
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="975,100 900,200" />
+ <path fill="none" stroke="red" stroke-width="5" d="M600,200 C675,100 975,100 900,200" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="600" cy="200" r="10" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="900" cy="200" r="10" />
+ <circle fill="#888888" stroke="none" cx="675" cy="100" r="10" />
+ <circle fill="#888888" stroke="none" cx="975" cy="100" r="10" />
+ <text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="275">M600,200 C675,100 975,100 900,200</text>
+
+ <!-- Path 5 -->
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="600,500 600,350" />
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="900,650 900,500" />
+ <path fill="none" stroke="red" stroke-width="5" d="M600,500 C600,350 900,650 900,500" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="600" cy="500" r="10" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="900" cy="500" r="10" />
+ <circle fill="#888888" stroke="none" cx="600" cy="350" r="10" />
+ <circle fill="#888888" stroke="none" cx="900" cy="650" r="10" />
+ <text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="575">M600,500 C600,350 900,650 900,500</text>
+
+ <!-- Path 6 (C and S command) -->
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="600,800 625,700" />
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="725,700 750,800" />
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="750,800 775,900" />
+ <polyline fill="none" stroke="#888888" stroke-width="2" points="875,900 900,800" />
+ <path fill="none" stroke="red" stroke-width="5" d="M600,800 C625,700 725,700 750,800
+ S875,900 900,800" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="600" cy="800" r="10" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="750" cy="800" r="10" />
+ <circle fill="none" stroke="#888888" stroke-width="2" cx="900" cy="800" r="10" />
+ <circle fill="#888888" stroke="none" cx="625" cy="700" r="10" />
+ <circle fill="#888888" stroke="none" cx="725" cy="700" r="10" />
+ <circle fill="#888888" stroke="none" cx="875" cy="900" r="10" />
+ <circle fill="none" stroke="blue" stroke-width="4" cx="775" cy="900" r="9" />
+ <text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="945">M600,800 C625,700 725,700 750,800</text>
+ <text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="975">S875,900 900,800</text>
+</svg>
diff --git a/libs/svgviewer/files/spheres.svg b/libs/svgviewer/files/spheres.svg
new file mode 100644
index 000000000..b23164bce
--- /dev/null
+++ b/libs/svgviewer/files/spheres.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" standalone="no"?>
+<svg width="8cm" height="8cm" viewBox="0 0 400 400"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink/"
+ baseProfile="tiny" version="1.2">
+ <title>Spheres</title>
+ <desc>Gradient filled spheres with different colors.</desc>
+ <defs>
+ <!-- Create radial gradients for each circle to make them look like
+ spheres. -->
+ <radialGradient id="blueSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="blue" />
+ <stop offset="100%" stop-color="#222244" />
+ </radialGradient>
+ <radialGradient id="redSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="red" />
+ <stop offset="100%" stop-color="#442222" />
+ </radialGradient>
+ <radialGradient id="greenSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="green" />
+ <stop offset="100%" stop-color="#113311" />
+ </radialGradient>
+ <radialGradient id="yellowSphere" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="-50">
+ <stop offset="0%" stop-color="white" />
+ <stop offset="75%" stop-color="yellow" />
+ <stop offset="100%" stop-color="#444422" />
+ </radialGradient>
+ <radialGradient id="shadowGrad" gradientUnits="userSpaceOnUse"
+ cx="0" cy="0" r="100" fx="-50" fy="50">
+ <stop offset="0%" stop-color="black" stop-opacity="1.0" />
+ <stop offset="100%" stop-color="white" stop-opacity="0.0" />
+ </radialGradient>
+
+ <!-- Define a shadow for each sphere. -->
+ <circle id="shadow" fill="url(#shadowGrad)" cx="0" cy="0" r="100" />
+ </defs>
+ <g fill="#ffee99" stroke="none" >
+ <rect x="0" y="0" width="400" height="400" />
+ </g>
+ <g fill="white" stroke="none" >
+ <rect x="0" y="175" width="400" height="225" />
+ </g>
+ <g transform="translate(200,175)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#blueSphere)" cx="0" cy="0" r="100" />
+ </g>
+ <g transform="translate(315,240)">
+ <g transform="scale(0.5,0.5)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#redSphere)" cx="0" cy="0" r="100" />
+ </g>
+ </g>
+ <g transform="translate(80,275)">
+ <g transform="scale(0.65,0.65)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#greenSphere)" cx="0" cy="0" r="100" />
+ </g>
+ </g>
+ <g transform="translate(255,325)">
+ <g transform="scale(0.3,0.3)">
+ <use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
+ <circle fill="url(#yellowSphere)" cx="0" cy="0" r="100" />
+ </g>
+ </g>
+</svg>
diff --git a/libs/svgviewer/main.cpp b/libs/svgviewer/main.cpp
new file mode 100644
index 000000000..34866f854
--- /dev/null
+++ b/libs/svgviewer/main.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QString>
+#ifndef QT_NO_OPENGL
+#include <QGLFormat>
+#endif
+
+#include "mainwindow.h"
+
+int main(int argc, char **argv)
+{
+ Q_INIT_RESOURCE(svgviewer);
+
+ QApplication app(argc, argv);
+
+ MainWindow window;
+ if (argc == 2)
+ window.openFile(argv[1]);
+ else
+ window.openFile(":/files/bubbles.svg");
+#if defined(Q_OS_SYMBIAN)
+ window.showMaximized();
+#else
+ window.show();
+#endif
+ return app.exec();
+}
diff --git a/libs/svgviewer/mainwindow.cpp b/libs/svgviewer/mainwindow.cpp
new file mode 100644
index 000000000..b352ff9f7
--- /dev/null
+++ b/libs/svgviewer/mainwindow.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+
+#include <QtGui>
+#include <QFileSystemWatcher>
+
+#include "svgview.h"
+
+MainWindow::MainWindow()
+ : QMainWindow()
+ , m_view(new SvgView)
+ , m_watcher(NULL)
+ , m_filehandle(NULL)
+{
+ QMenu *fileMenu = new QMenu(tr("&File"), this);
+ QAction *openAction = fileMenu->addAction(tr("&Open..."));
+ openAction->setShortcut(QKeySequence(tr("Ctrl+O")));
+ QAction *quitAction = fileMenu->addAction(tr("E&xit"));
+ quitAction->setShortcuts(QKeySequence::Quit);
+
+ menuBar()->addMenu(fileMenu);
+
+ QMenu *viewMenu = new QMenu(tr("&View"), this);
+ m_backgroundAction = viewMenu->addAction(tr("&Background"));
+ m_backgroundAction->setEnabled(false);
+ m_backgroundAction->setCheckable(true);
+ m_backgroundAction->setChecked(false);
+ connect(m_backgroundAction, SIGNAL(toggled(bool)), m_view, SLOT(setViewBackground(bool)));
+
+ m_outlineAction = viewMenu->addAction(tr("&Outline"));
+ m_outlineAction->setEnabled(false);
+ m_outlineAction->setCheckable(true);
+ m_outlineAction->setChecked(true);
+ connect(m_outlineAction, SIGNAL(toggled(bool)), m_view, SLOT(setViewOutline(bool)));
+
+ menuBar()->addMenu(viewMenu);
+
+ QMenu *rendererMenu = new QMenu(tr("&Renderer"), this);
+ m_nativeAction = rendererMenu->addAction(tr("&Native"));
+ m_nativeAction->setCheckable(true);
+ m_nativeAction->setChecked(true);
+#ifndef QT_NO_OPENGL
+ m_glAction = rendererMenu->addAction(tr("&OpenGL"));
+ m_glAction->setCheckable(true);
+#endif
+ m_imageAction = rendererMenu->addAction(tr("&Image"));
+ m_imageAction->setCheckable(true);
+
+#ifndef QT_NO_OPENGL
+ rendererMenu->addSeparator();
+ m_highQualityAntialiasingAction = rendererMenu->addAction(tr("&High Quality Antialiasing"));
+ m_highQualityAntialiasingAction->setEnabled(false);
+ m_highQualityAntialiasingAction->setCheckable(true);
+ m_highQualityAntialiasingAction->setChecked(false);
+ connect(m_highQualityAntialiasingAction, SIGNAL(toggled(bool)), m_view, SLOT(setHighQualityAntialiasing(bool)));
+#endif
+
+ QActionGroup *rendererGroup = new QActionGroup(this);
+ rendererGroup->addAction(m_nativeAction);
+#ifndef QT_NO_OPENGL
+ rendererGroup->addAction(m_glAction);
+#endif
+ rendererGroup->addAction(m_imageAction);
+
+ menuBar()->addMenu(rendererMenu);
+
+ connect(openAction, SIGNAL(triggered()), this, SLOT(openFile()));
+ connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
+ connect(rendererGroup, SIGNAL(triggered(QAction*)),
+ this, SLOT(setRenderer(QAction*)));
+
+ setCentralWidget(m_view);
+ setWindowTitle(tr("SVG Viewer"));
+}
+
+void MainWindow::openFile(const QString &path, bool reload)
+{
+ QString fileName;
+ if (path.isNull())
+ fileName = QFileDialog::getOpenFileName(this, tr("Open SVG File"),
+ m_currentPath, "SVG files (*.svg *.svgz *.svg.gz)");
+ else
+ fileName = path;
+
+ if (m_watcher) {
+ delete m_watcher;
+ m_watcher = NULL;
+ }
+ if (m_filehandle) {
+ fclose(m_filehandle);
+ m_filehandle = NULL;
+ }
+
+ if (!fileName.isEmpty()) {
+ QFile file(fileName);
+ if (!file.exists()) {
+ QMessageBox::critical(this, tr("Open SVG File"),
+ QString("Could not open file '%1'.").arg(fileName));
+
+ m_outlineAction->setEnabled(false);
+ m_backgroundAction->setEnabled(false);
+ return;
+ }
+
+ QTransform oldTransform = m_view->transform();
+ m_view->openFile(file);
+
+ if (!fileName.startsWith(":/"))
+ {
+ m_currentPath = fileName;
+ setWindowTitle(tr("%1 - SVGViewer").arg(m_currentPath));
+
+ // just keep the file open so this process is found using 'fuser'
+ m_filehandle = fopen(fileName.toAscii(), "r");
+
+ m_watcher = new QFileSystemWatcher(this);
+ m_watcher->addPath(fileName);
+ connect(m_watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(reloadFile()));
+ }
+
+ m_outlineAction->setEnabled(true);
+ m_backgroundAction->setEnabled(true);
+
+ if (reload)
+ m_view->setTransform(oldTransform);
+ else
+ resize(m_view->sizeHint() + QSize(80, 80 + menuBar()->height()));
+ }
+}
+
+void MainWindow::reloadFile()
+{
+ openFile(m_currentPath, true);
+}
+
+void MainWindow::setRenderer(QAction *action)
+{
+#ifndef QT_NO_OPENGL
+ m_highQualityAntialiasingAction->setEnabled(false);
+#endif
+
+ if (action == m_nativeAction)
+ m_view->setRenderer(SvgView::Native);
+#ifndef QT_NO_OPENGL
+ else if (action == m_glAction) {
+ m_highQualityAntialiasingAction->setEnabled(true);
+ m_view->setRenderer(SvgView::OpenGL);
+ }
+#endif
+ else if (action == m_imageAction) {
+ m_view->setRenderer(SvgView::Image);
+ }
+}
diff --git a/libs/svgviewer/mainwindow.h b/libs/svgviewer/mainwindow.h
new file mode 100644
index 000000000..5b549e92a
--- /dev/null
+++ b/libs/svgviewer/mainwindow.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QString>
+#include <stdio.h>
+
+class SvgView;
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QGraphicsView;
+class QGraphicsScene;
+class QGraphicsRectItem;
+class QFileSystemWatcher;
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+public slots:
+ void openFile(const QString &path = QString(), bool reload = false);
+ void setRenderer(QAction *action);
+ void reloadFile();
+
+private:
+ QAction *m_nativeAction;
+ QAction *m_glAction;
+ QAction *m_imageAction;
+ QAction *m_highQualityAntialiasingAction;
+ QAction *m_backgroundAction;
+ QAction *m_outlineAction;
+
+ SvgView *m_view;
+
+ QString m_currentPath;
+ QFileSystemWatcher *m_watcher;
+ FILE *m_filehandle;
+};
+
+#endif
diff --git a/libs/svgviewer/svgview.cpp b/libs/svgviewer/svgview.cpp
new file mode 100644
index 000000000..da9a4aee3
--- /dev/null
+++ b/libs/svgviewer/svgview.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "svgview.h"
+
+#include <QFile>
+#include <QWheelEvent>
+#include <QMouseEvent>
+#include <QGraphicsRectItem>
+#include <QGraphicsSvgItem>
+#include <QPaintEvent>
+#include <qmath.h>
+
+#ifndef QT_NO_OPENGL
+#include <QGLWidget>
+#endif
+
+SvgView::SvgView(QWidget *parent)
+ : QGraphicsView(parent)
+ , m_renderer(Native)
+ , m_svgItem(0)
+ , m_backgroundItem(0)
+ , m_outlineItem(0)
+{
+ setScene(new QGraphicsScene(this));
+ setTransformationAnchor(AnchorUnderMouse);
+ setDragMode(ScrollHandDrag);
+ setViewportUpdateMode(FullViewportUpdate);
+
+ // Prepare background check-board pattern
+ QPixmap tilePixmap(64, 64);
+ tilePixmap.fill(Qt::white);
+ QPainter tilePainter(&tilePixmap);
+ QColor color(220, 220, 220);
+ tilePainter.fillRect(0, 0, 32, 32, color);
+ tilePainter.fillRect(32, 32, 32, 32, color);
+ tilePainter.end();
+
+ setBackgroundBrush(tilePixmap);
+}
+
+void SvgView::drawBackground(QPainter *p, const QRectF &)
+{
+ p->save();
+ p->resetTransform();
+ p->drawTiledPixmap(viewport()->rect(), backgroundBrush().texture());
+ p->restore();
+}
+
+void SvgView::openFile(const QFile &file)
+{
+ if (!file.exists())
+ return;
+
+ QGraphicsScene *s = scene();
+
+ bool drawBackground = (m_backgroundItem ? m_backgroundItem->isVisible() : false);
+ bool drawOutline = (m_outlineItem ? m_outlineItem->isVisible() : true);
+
+ s->clear();
+ resetTransform();
+
+ m_svgItem = new QGraphicsSvgItem(file.fileName());
+ m_svgItem->setFlags(QGraphicsItem::ItemClipsToShape);
+ m_svgItem->setCacheMode(QGraphicsItem::NoCache);
+ m_svgItem->setZValue(0);
+
+ m_backgroundItem = new QGraphicsRectItem(m_svgItem->boundingRect());
+ m_backgroundItem->setBrush(Qt::white);
+ m_backgroundItem->setPen(Qt::NoPen);
+ m_backgroundItem->setVisible(drawBackground);
+ m_backgroundItem->setZValue(-1);
+
+ m_outlineItem = new QGraphicsRectItem(m_svgItem->boundingRect());
+ QPen outline(Qt::black, 2, Qt::DashLine);
+ outline.setCosmetic(true);
+ m_outlineItem->setPen(outline);
+ m_outlineItem->setBrush(Qt::NoBrush);
+ m_outlineItem->setVisible(drawOutline);
+ m_outlineItem->setZValue(1);
+
+ s->addItem(m_backgroundItem);
+ s->addItem(m_svgItem);
+ s->addItem(m_outlineItem);
+
+ s->setSceneRect(m_outlineItem->boundingRect().adjusted(-10, -10, 10, 10));
+}
+
+void SvgView::setRenderer(RendererType type)
+{
+ m_renderer = type;
+
+ if (m_renderer == OpenGL) {
+#ifndef QT_NO_OPENGL
+ setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
+#endif
+ } else {
+ setViewport(new QWidget);
+ }
+}
+
+void SvgView::setHighQualityAntialiasing(bool highQualityAntialiasing)
+{
+#ifndef QT_NO_OPENGL
+ setRenderHint(QPainter::HighQualityAntialiasing, highQualityAntialiasing);
+#else
+ Q_UNUSED(highQualityAntialiasing);
+#endif
+}
+
+void SvgView::setViewBackground(bool enable)
+{
+ if (!m_backgroundItem)
+ return;
+
+ m_backgroundItem->setVisible(enable);
+}
+
+void SvgView::setViewOutline(bool enable)
+{
+ if (!m_outlineItem)
+ return;
+
+ m_outlineItem->setVisible(enable);
+}
+
+void SvgView::paintEvent(QPaintEvent *event)
+{
+ if (m_renderer == Image) {
+ if (m_image.size() != viewport()->size()) {
+ m_image = QImage(viewport()->size(), QImage::Format_ARGB32_Premultiplied);
+ }
+
+ QPainter imagePainter(&m_image);
+ QGraphicsView::render(&imagePainter);
+ imagePainter.end();
+
+ QPainter p(viewport());
+ p.drawImage(0, 0, m_image);
+
+ } else {
+ QGraphicsView::paintEvent(event);
+ }
+}
+
+void SvgView::wheelEvent(QWheelEvent *event)
+{
+ qreal factor = qPow(1.2, event->delta() / 240.0);
+ scale(factor, factor);
+ event->accept();
+}
+
diff --git a/libs/svgviewer/svgview.h b/libs/svgviewer/svgview.h
new file mode 100644
index 000000000..944401ac9
--- /dev/null
+++ b/libs/svgviewer/svgview.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SVGVIEW_H
+#define SVGVIEW_H
+
+#include <QGraphicsView>
+
+QT_BEGIN_NAMESPACE
+class QWheelEvent;
+class QPaintEvent;
+class QFile;
+QT_END_NAMESPACE
+
+class SvgView : public QGraphicsView
+{
+ Q_OBJECT
+
+public:
+ enum RendererType { Native, OpenGL, Image };
+
+ SvgView(QWidget *parent = 0);
+
+ void openFile(const QFile &file);
+ void setRenderer(RendererType type = Native);
+ void drawBackground(QPainter *p, const QRectF &rect);
+
+public slots:
+ void setHighQualityAntialiasing(bool highQualityAntialiasing);
+ void setViewBackground(bool enable);
+ void setViewOutline(bool enable);
+
+protected:
+ void wheelEvent(QWheelEvent *event);
+ void paintEvent(QPaintEvent *event);
+
+private:
+ RendererType m_renderer;
+
+ QGraphicsItem *m_svgItem;
+ QGraphicsRectItem *m_backgroundItem;
+ QGraphicsRectItem *m_outlineItem;
+
+ QImage m_image;
+};
+#endif // SVGVIEW_H
diff --git a/libs/svgviewer/svgviewer.desktop b/libs/svgviewer/svgviewer.desktop
new file mode 100644
index 000000000..477ef789d
--- /dev/null
+++ b/libs/svgviewer/svgviewer.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0
+Type=Application
+Terminal=false
+Name=SVG Viewer
+Exec=/opt/usr/bin/svgviewer
+Icon=svgviewer
+X-Window-Icon=
+X-HildonDesk-ShowInToolbar=true
+X-Osso-Type=application/x-executable
diff --git a/libs/svgviewer/svgviewer.pro b/libs/svgviewer/svgviewer.pro
new file mode 100644
index 000000000..0d938f444
--- /dev/null
+++ b/libs/svgviewer/svgviewer.pro
@@ -0,0 +1,33 @@
+HEADERS = mainwindow.h \
+ svgview.h
+RESOURCES = svgviewer.qrc
+SOURCES = main.cpp \
+ mainwindow.cpp \
+ svgview.cpp
+QT += svg xml
+
+contains(QT_CONFIG, opengl): QT += opengl
+
+CONFIG += console
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/painting/svgviewer
+sources.files = $$SOURCES $$HEADERS $$RESOURCES svgviewer.pro files
+sources.path = $$[QT_INSTALL_EXAMPLES]/painting/svgviewer
+INSTALLS += target sources
+
+wince*: {
+ addFiles.files = files\\*.svg
+ addFiles.path = "\\My Documents"
+ DEPLOYMENT += addFiles
+}
+
+symbian: {
+ TARGET.UID3 = 0xA000A64E
+ include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
+ addFiles.files = files\\*.svg
+ addFiles.path = .
+ DEPLOYMENT += addFiles
+}
+maemo5: include($$QT_SOURCE_TREE/examples/maemo5pkgrules.pri)
+
diff --git a/libs/svgviewer/svgviewer.qrc b/libs/svgviewer/svgviewer.qrc
new file mode 100644
index 000000000..db611f51f
--- /dev/null
+++ b/libs/svgviewer/svgviewer.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>files/bubbles.svg</file>
+</qresource>
+</RCC>
+
diff --git a/passes/dfflibmap/Makefile.inc b/passes/dfflibmap/Makefile.inc
index ed92b299c..b4d73fa12 100644
--- a/passes/dfflibmap/Makefile.inc
+++ b/passes/dfflibmap/Makefile.inc
@@ -2,9 +2,9 @@
OBJS += passes/dfflibmap/dfflibmap.o
OBJS += passes/dfflibmap/libparse.o
-TARGETS += filterlib
+TARGETS += yosys-filterlib
GENFILES += passes/dfflibmap/filterlib.o
-filterlib: passes/dfflibmap/filterlib.o
- $(CXX) -o filterlib $(LDFLAGS) $^ $(LDLIBS)
+yosys-filterlib: passes/dfflibmap/filterlib.o
+ $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS)
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
index 26d120a16..dc9ec2b06 100644
--- a/passes/fsm/fsm_export.cc
+++ b/passes/fsm/fsm_export.cc
@@ -49,7 +49,7 @@ std::string kiss_convert_signal(const RTLIL::SigSpec &sig) {
* @param module pointer to module which contains the FSM cell.
* @param cell pointer to the FSM cell which should be exported.
*/
-void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell) {
+void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell, std::string filename, bool origenc) {
std::map<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
FsmData fsm_data;
FsmData::transition_t tr;
@@ -58,7 +58,9 @@ void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell) {
size_t i;
attr_it = cell->attributes.find("\\fsm_export");
- if (attr_it != cell->attributes.end() && attr_it->second.str != "") {
+ if (!filename.empty()) {
+ kiss_name.assign(filename);
+ } else if (attr_it != cell->attributes.end() && attr_it->second.str != "") {
kiss_name.assign(attr_it->second.str);
}
else {
@@ -84,15 +86,24 @@ void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell) {
kiss_file << ".o " << std::dec << fsm_data.num_outputs << std::endl;
kiss_file << ".p " << std::dec << fsm_data.transition_table.size() << std::endl;
kiss_file << ".s " << std::dec << fsm_data.state_table.size() << std::endl;
- kiss_file << ".r s" << std::dec << fsm_data.reset_state << std::endl;
+ if (origenc) {
+ kiss_file << ".r " << kiss_convert_signal(fsm_data.state_table[fsm_data.reset_state]) << std::endl;
+ } else {
+ kiss_file << ".r s" << std::dec << fsm_data.reset_state << std::endl;
+ }
for (i = 0; i < fsm_data.transition_table.size(); i++) {
tr = fsm_data.transition_table[i];
try {
kiss_file << kiss_convert_signal(tr.ctrl_in) << ' ';
- kiss_file << 's' << tr.state_in << ' ';
- kiss_file << 's' << tr.state_out << ' ';
+ if (origenc) {
+ kiss_file << kiss_convert_signal(fsm_data.state_table[tr.state_in]) << ' ';
+ kiss_file << kiss_convert_signal(fsm_data.state_table[tr.state_out]) << ' ';
+ } else {
+ kiss_file << 's' << tr.state_in << ' ';
+ kiss_file << 's' << tr.state_out << ' ';
+ }
kiss_file << kiss_convert_signal(tr.ctrl_out) << std::endl;
}
catch (int) {
@@ -114,21 +125,32 @@ struct FsmExportPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" fsm_export [-noauto] [selection]\n");
+ log(" fsm_export [-noauto] [-o filename] [-origenc] [selection]\n");
log("\n");
log("This pass creates a KISS2 file for every selected FSM. For FSMs with the\n");
log("'fsm_export' attribute set, the attribute value is used as filename, otherwise\n");
- log("the module and cell name is used as filename.\n");
+ log("the module and cell name is used as filename. If the parameter '-o' is given,\n");
+ log("the first exported FSM is written to the specified filename. This overwrites\n");
+ log("the setting as specified with the 'fsm_export' attribute. All other FSMs are\n");
+ log("exported to the default name as mentioned above.\n");
log("\n");
log(" -noauto\n");
log(" only export FSMs that have the 'fsm_export' attribute set\n");
log("\n");
+ log(" -o filename\n");
+ log(" filename of the first exported FSM\n");
+ log("\n");
+ log(" -origenc\n");
+ log(" use binary state encoding as state names instead of s0, s1, ...\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::map<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
std::string arg;
bool flag_noauto = false;
+ std::string filename;
+ bool flag_origenc = false;
size_t argidx;
log_header("Executing FSM_EXPORT pass (exporting FSMs in KISS2 file format).\n");
@@ -139,6 +161,15 @@ struct FsmExportPass : public Pass {
flag_noauto = true;
continue;
}
+ if (arg == "-o") {
+ argidx++;
+ filename = args[argidx];
+ continue;
+ }
+ if (arg == "-origenc") {
+ flag_origenc = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -149,7 +180,8 @@ struct FsmExportPass : public Pass {
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second)) {
attr_it = cell_it.second->attributes.find("\\fsm_export");
if (!flag_noauto || (attr_it != cell_it.second->attributes.end())) {
- write_kiss2(mod_it.second, cell_it.second);
+ write_kiss2(mod_it.second, cell_it.second, filename, flag_origenc);
+ filename.clear();
}
}
}
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 04274990d..287f93097 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -50,17 +50,21 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
for (auto &celltype : found_celltypes)
{
std::set<std::string> portnames;
+ std::set<std::string> parameters;
std::map<std::string, int> portwidths;
log("Generate module for cell type %s:\n", celltype.c_str());
for (auto i1 : design->modules)
for (auto i2 : i1.second->cells)
- if (i2.second->type == celltype)
+ if (i2.second->type == celltype) {
for (auto &conn : i2.second->connections) {
if (conn.first[0] != '$')
portnames.insert(conn.first);
portwidths[conn.first] = std::max(portwidths[conn.first], conn.second.width);
}
+ for (auto &para : i2.second->parameters)
+ parameters.insert(para.first);
+ }
for (auto &decl : portdecls)
if (decl.index > 0)
@@ -109,6 +113,7 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
RTLIL::Module *mod = new RTLIL::Module;
mod->name = celltype;
+ mod->attributes["\\placeholder"] = RTLIL::Const(0, 0);
design->modules[mod->name] = mod;
for (auto &decl : ports) {
@@ -121,6 +126,9 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
mod->add(wire);
}
+ for (auto &para : parameters)
+ log(" ignoring parameter %s.\n", RTLIL::id2cstr(para));
+
log(" module %s created.\n", RTLIL::id2cstr(mod->name));
}
}
@@ -139,9 +147,12 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
}
if (cell->parameters.size() == 0)
continue;
+ if (design->modules.at(cell->type)->attributes.count("\\placeholder") > 0)
+ continue;
RTLIL::Module *mod = design->modules[cell->type];
cell->type = mod->derive(design, cell->parameters);
cell->parameters.clear();
+ did_something = true;
}
if (did_something)
@@ -200,7 +211,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
if (auto_sizes.size() > 0) {
module->update_auto_wires(auto_sizes);
- log_header("Continuing EXPAND pass.\n");
+ log_header("Continuing HIERARCHY pass.\n");
did_something = true;
}
@@ -262,7 +273,7 @@ struct HierarchyPass : public Pass {
log(" use the specified top module to built a design hierarchy. modules\n");
log(" outside this tree (unused modules) are removed.\n");
log("\n");
- log("In -generate mode this pass generates skeletton modules for the given cell\n");
+ log("In -generate mode this pass generates placeholder modules for the given cell\n");
log("types (wildcards supported). For this the design is searched for cells that\n");
log("match the given types and then the given port declarations are used to\n");
log("determine the direction of the ports. The syntax for a port declaration is:\n");
diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc
index 0effd964b..7c82f0fcb 100644
--- a/passes/opt/opt_const.cc
+++ b/passes/opt/opt_const.cc
@@ -181,8 +181,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module)
RTLIL::SigSpec b = assign_map(cell->connections["\\B"]);
if (a.is_fully_const()) {
- RTLIL::SigSpec tmp = a;
- a = b, b = tmp;
+ RTLIL::SigSpec tmp;
+ tmp = a, a = b, b = tmp;
+ cell->connections["\\A"] = a;
+ cell->connections["\\B"] = b;
}
if (b.is_fully_const()) {
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index 9f79d0603..43d1a57e1 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -65,7 +65,32 @@ struct OptShareWorker
for (auto &it : cell->parameters)
hash_string += "P " + it.first + "=" + it.second.as_string() + "\n";
- for (auto &it : cell->connections) {
+ const std::map<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections;
+ std::map<RTLIL::IdString, RTLIL::SigSpec> alt_conn;
+
+ if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" || cell->type == "$add" || cell->type == "$mul" ||
+ cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") {
+ alt_conn = *conn;
+ if (assign_map(alt_conn.at("\\A")) < assign_map(alt_conn.at("\\B"))) {
+ alt_conn["\\A"] = conn->at("\\B");
+ alt_conn["\\B"] = conn->at("\\A");
+ }
+ conn = &alt_conn;
+ } else
+ if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor") {
+ alt_conn = *conn;
+ assign_map.apply(alt_conn.at("\\A"));
+ alt_conn.at("\\A").sort();
+ conn = &alt_conn;
+ } else
+ if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_bool") {
+ alt_conn = *conn;
+ assign_map.apply(alt_conn.at("\\A"));
+ alt_conn.at("\\A").sort_and_unify();
+ conn = &alt_conn;
+ }
+
+ for (auto &it : *conn) {
if (ct.cell_output(cell->type, it.first))
continue;
RTLIL::SigSpec sig = it.second;
@@ -126,6 +151,28 @@ struct OptShareWorker
assign_map.apply(it.second);
}
+ if (cell1->type == "$and" || cell1->type == "$or" || cell1->type == "$xor" || cell1->type == "$xnor" || cell1->type == "$add" || cell1->type == "$mul" ||
+ cell1->type == "$logic_and" || cell1->type == "$logic_or" || cell1->type == "$_AND_" || cell1->type == "$_OR_" || cell1->type == "$_XOR_") {
+ if (conn1.at("\\A") < conn1.at("\\B")) {
+ RTLIL::SigSpec tmp = conn1["\\A"];
+ conn1["\\A"] = conn1["\\B"];
+ conn1["\\B"] = tmp;
+ }
+ if (conn2.at("\\A") < conn2.at("\\B")) {
+ RTLIL::SigSpec tmp = conn2["\\A"];
+ conn2["\\A"] = conn2["\\B"];
+ conn2["\\B"] = tmp;
+ }
+ } else
+ if (cell1->type == "$reduce_xor" || cell1->type == "$reduce_xnor") {
+ conn1["\\A"].sort();
+ conn2["\\A"].sort();
+ } else
+ if (cell1->type == "$reduce_and" || cell1->type == "$reduce_or" || cell1->type == "$reduce_bool") {
+ conn1["\\A"].sort_and_unify();
+ conn2["\\A"].sort_and_unify();
+ }
+
if (conn1 != conn2) {
lt = conn1 < conn2;
return true;
diff --git a/passes/submod/submod.cc b/passes/submod/submod.cc
index f91d1ec3a..98854da23 100644
--- a/passes/submod/submod.cc
+++ b/passes/submod/submod.cc
@@ -29,6 +29,7 @@ struct SubmodWorker
CellTypes ct;
RTLIL::Design *design;
RTLIL::Module *module;
+ std::string opt_name;
struct SubModule
{
@@ -188,9 +189,9 @@ struct SubmodWorker
module->cells[new_cell->name] = new_cell;
}
- SubmodWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module)
+ SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, std::string opt_name = std::string()) : design(design), module(module), opt_name(opt_name)
{
- if (!design->selected_whole_module(module->name))
+ if (!design->selected_whole_module(module->name) && opt_name.empty())
return;
if (module->processes.size() > 0) {
@@ -208,29 +209,47 @@ struct SubmodWorker
ct.setup_stdcells();
ct.setup_stdcells_mem();
- for (auto &it : module->wires)
- it.second->attributes.erase("\\submod");
-
- for (auto &it : module->cells)
+ if (opt_name.empty())
{
- RTLIL::Cell *cell = it.second;
- if (cell->attributes.count("\\submod") == 0 || cell->attributes["\\submod"].str.size() == 0) {
+ for (auto &it : module->wires)
+ it.second->attributes.erase("\\submod");
+
+ for (auto &it : module->cells)
+ {
+ RTLIL::Cell *cell = it.second;
+ if (cell->attributes.count("\\submod") == 0 || cell->attributes["\\submod"].str.size() == 0) {
+ cell->attributes.erase("\\submod");
+ continue;
+ }
+
+ std::string submod_str = cell->attributes["\\submod"].str;
cell->attributes.erase("\\submod");
- continue;
- }
- std::string submod_str = cell->attributes["\\submod"].str;
- cell->attributes.erase("\\submod");
+ if (submodules.count(submod_str) == 0) {
+ submodules[submod_str].name = submod_str;
+ submodules[submod_str].full_name = module->name + "_" + submod_str;
+ while (design->modules.count(submodules[submod_str].full_name) != 0 ||
+ module->count_id(submodules[submod_str].full_name) != 0)
+ submodules[submod_str].full_name += "_";
+ }
- if (submodules.count(submod_str) == 0) {
- submodules[submod_str].name = submod_str;
- submodules[submod_str].full_name = module->name + "_" + submod_str;
- while (design->modules.count(submodules[submod_str].full_name) != 0 ||
- module->count_id(submodules[submod_str].full_name) != 0)
- submodules[submod_str].full_name += "_";
+ submodules[submod_str].cells.insert(cell);
+ }
+ }
+ else
+ {
+ for (auto &it : module->cells)
+ {
+ RTLIL::Cell *cell = it.second;
+ if (!design->selected(module, cell))
+ continue;
+ submodules[opt_name].name = opt_name;
+ submodules[opt_name].full_name = RTLIL::escape_id(opt_name);
+ submodules[opt_name].cells.insert(cell);
}
- submodules[submod_str].cells.insert(cell);
+ if (submodules.size() == 0)
+ log("Nothing selected -> do nothing.\n");
}
for (auto &it : submodules)
@@ -256,35 +275,72 @@ struct SubmodPass : public Pass {
log("This pass only operates on completely selected modules with no processes\n");
log("or memories.\n");
log("\n");
+ log("\n");
+ log(" submod -name <name> [selection]\n");
+ log("\n");
+ log("As above, but don't use the 'submod' attribute but instead use the selection.\n");
+ log("Only objects from one module might be selected. The value of the -name option\n");
+ log("is used as the value of the 'submod' attribute above.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing SUBMOD pass (moving cells to submodules as requested).\n");
log_push();
- Pass::call(design, "opt_rmunused");
- log_header("Continuing SUBMOD pass.\n");
-
- extra_args(args, 1, design);
-
- std::set<std::string> handled_modules;
-
- bool did_something = true;
- while (did_something) {
- did_something = false;
- std::vector<std::string> queued_modules;
- for (auto &mod_it : design->modules)
- if (handled_modules.count(mod_it.first) == 0)
- queued_modules.push_back(mod_it.first);
- for (auto &modname : queued_modules)
- if (design->modules.count(modname) != 0) {
- SubmodWorker worker(design, design->modules[modname]);
- handled_modules.insert(modname);
- did_something = true;
- }
+ std::string opt_name;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-name" && argidx+1 < args.size()) {
+ opt_name = args[++argidx];
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (opt_name.empty())
+ {
+ Pass::call(design, "opt_rmunused");
+ log_header("Continuing SUBMOD pass.\n");
+
+ std::set<std::string> handled_modules;
+
+ bool did_something = true;
+ while (did_something) {
+ did_something = false;
+ std::vector<std::string> queued_modules;
+ for (auto &mod_it : design->modules)
+ if (handled_modules.count(mod_it.first) == 0 && design->selected_whole_module(mod_it.first))
+ queued_modules.push_back(mod_it.first);
+ for (auto &modname : queued_modules)
+ if (design->modules.count(modname) != 0) {
+ SubmodWorker worker(design, design->modules[modname]);
+ handled_modules.insert(modname);
+ did_something = true;
+ }
+ }
+
+ Pass::call(design, "opt_rmunused");
+ }
+ else
+ {
+ RTLIL::Module *module = NULL;
+ for (auto &mod_it : design->modules) {
+ if (!design->selected_module(mod_it.first))
+ continue;
+ if (module != NULL)
+ log_cmd_error("More than one module selected: %s %s\n", module->name.c_str(), mod_it.first.c_str());
+ module = mod_it.second;
+ }
+ if (module == NULL)
+ log("Nothing selected -> do nothing.\n");
+ else
+ SubmodWorker worker(design, module, opt_name);
}
- Pass::call(design, "opt_rmunused");
+ log_pop();
}
} SubmodPass;
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 5fd5858aa..732bd5cb9 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -31,7 +31,7 @@ static void apply_prefix(std::string prefix, std::string &id)
if (id[0] == '\\')
id = prefix + "." + id.substr(1);
else
- id = prefix + "." + id;
+ id = "$techmap" + prefix + "." + id;
}
static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
@@ -47,8 +47,93 @@ static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module
}
std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
+std::map<RTLIL::Module*, bool> techmap_fail_cache;
-static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map)
+static bool techmap_fail_check(RTLIL::Module *module)
+{
+ if (module == NULL)
+ return false;
+
+ if (techmap_fail_cache.count(module) > 0)
+ return techmap_fail_cache.at(module);
+
+ for (auto &it : module->wires) {
+ std::string name = it.first;
+ if (name == "\\TECHMAP_FAIL")
+ return techmap_fail_cache[module] = true;
+ if (name.size() > 13 && name[0] == '\\' && name.substr(name.size()-13) == ".TECHMAP_FAIL")
+ return techmap_fail_cache[module] = true;
+ }
+
+ return techmap_fail_cache[module] = false;
+}
+
+static void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl)
+{
+ log("Mapping `%s.%s' using `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(tpl->name));
+
+ if (tpl->memories.size() != 0)
+ log_error("Technology map yielded memories -> this is not supported.");
+
+ if (tpl->processes.size() != 0)
+ log_error("Technology map yielded processes -> this is not supported.");
+
+ for (auto &it : tpl->wires) {
+ RTLIL::Wire *w = new RTLIL::Wire(*it.second);
+ apply_prefix(cell->name, w->name);
+ w->port_input = false;
+ w->port_output = false;
+ w->port_id = 0;
+ module->wires[w->name] = w;
+ design->select(module, w);
+ }
+
+ for (auto &it : tpl->cells) {
+ RTLIL::Cell *c = new RTLIL::Cell(*it.second);
+ if (c->type.substr(0, 2) == "\\$")
+ c->type = c->type.substr(1);
+ apply_prefix(cell->name, c->name);
+ for (auto &it2 : c->connections)
+ apply_prefix(cell->name, it2.second, module);
+ module->cells[c->name] = c;
+ design->select(module, c);
+ }
+
+ for (auto &it : tpl->connections) {
+ RTLIL::SigSig c = it;
+ apply_prefix(cell->name, c.first, module);
+ apply_prefix(cell->name, c.second, module);
+ module->connections.push_back(c);
+ }
+
+ for (auto &it : cell->connections) {
+ if (tpl->wires.count(it.first) == 0 || tpl->wires.at(it.first)->port_id == 0)
+ continue;
+ RTLIL::Wire *w = tpl->wires[it.first];
+ RTLIL::SigSig c;
+ if (w->port_output) {
+ c.first = it.second;
+ c.second = RTLIL::SigSpec(w);
+ apply_prefix(cell->name, c.second, module);
+ } else {
+ c.first = RTLIL::SigSpec(w);
+ c.second = it.second;
+ apply_prefix(cell->name, c.first, module);
+ }
+ if (c.second.width > c.first.width)
+ c.second.remove(c.first.width, c.second.width - c.first.width);
+ if (c.second.width < c.first.width)
+ c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.width - c.second.width));
+ assert(c.first.width == c.second.width);
+ module->connections.push_back(c);
+ }
+
+ module->cells.erase(cell->name);
+ delete cell;
+}
+
+static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells,
+ const std::map<RTLIL::IdString, std::set<RTLIL::IdString>> &celltypeMap)
{
if (!design->selected(module))
return false;
@@ -67,98 +152,55 @@ static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::
RTLIL::Cell *cell = module->cells[cell_name];
- if (!design->selected(module, cell))
+ if (!design->selected(module, cell) || handled_cells.count(cell) > 0)
continue;
- if (map->modules.count(cell->type) == 0)
+ if (celltypeMap.count(cell->type) == 0)
continue;
- RTLIL::Module *tpl = map->modules[cell->type];
- std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(cell->type, cell->parameters);
-
- if (techmap_cache.count(key) > 0) {
- tpl = techmap_cache[key];
- } else {
- std::string derived_name = cell->type;
- if (cell->parameters.size() != 0) {
- derived_name = tpl->derive(map, cell->parameters);
- tpl = map->modules[derived_name];
- log_header("Continuing TECHMAP pass.\n");
+ for (auto &tpl_name : celltypeMap.at(cell->type))
+ {
+ std::string derived_name = tpl_name;
+ RTLIL::Module *tpl = map->modules[tpl_name];
+ std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters;
+
+ for (auto conn : cell->connections) {
+ if (tpl->wires.count(conn.first) > 0 && tpl->wires.at(conn.first)->port_id > 0)
+ continue;
+ if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0)
+ goto next_tpl;
+ parameters[conn.first] = conn.second.as_const();
}
- for (auto &cit : tpl->cells)
- if (cit.second->type == "\\TECHMAP_FAILED") {
- log("Not using module `%s' from techmap as it contains a TECHMAP_FAILED marker cell.\n", derived_name.c_str());
- tpl = NULL;
- break;
- }
- techmap_cache[key] = tpl;
- }
-
- if (tpl == NULL)
- goto next_cell;
-
- log("Mapping `%s.%s' using `%s'.\n", module->name.c_str(), cell_name.c_str(), tpl->name.c_str());
-
- if (tpl->memories.size() != 0)
- log_error("Technology map yielded memories -> this is not supported.");
- if (tpl->processes.size() != 0)
- log_error("Technology map yielded processes -> this is not supported.");
-
- for (auto &it : tpl->wires) {
- RTLIL::Wire *w = new RTLIL::Wire(*it.second);
- apply_prefix(cell_name, w->name);
- w->port_input = false;
- w->port_output = false;
- w->port_id = 0;
- module->wires[w->name] = w;
- design->select(module, w);
- }
-
- for (auto &it : tpl->cells) {
- RTLIL::Cell *c = new RTLIL::Cell(*it.second);
- if (c->type.substr(0, 2) == "\\$")
- c->type = c->type.substr(1);
- apply_prefix(cell_name, c->name);
- for (auto &it2 : c->connections)
- apply_prefix(cell_name, it2.second, module);
- module->cells[c->name] = c;
- design->select(module, c);
- }
-
- for (auto &it : tpl->connections) {
- RTLIL::SigSig c = it;
- apply_prefix(cell_name, c.first, module);
- apply_prefix(cell_name, c.second, module);
- module->connections.push_back(c);
- }
+ if (0) {
+ next_tpl:
+ continue;
+ }
- for (auto &it : cell->connections) {
- assert(tpl->wires.count(it.first));
- assert(tpl->wires[it.first]->port_id > 0);
- RTLIL::Wire *w = tpl->wires[it.first];
- RTLIL::SigSig c;
- if (w->port_output) {
- c.first = it.second;
- c.second = RTLIL::SigSpec(w);
- apply_prefix(cell_name, c.second, module);
+ std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters);
+ if (techmap_cache.count(key) > 0) {
+ tpl = techmap_cache[key];
} else {
- c.first = RTLIL::SigSpec(w);
- c.second = it.second;
- apply_prefix(cell_name, c.first, module);
+ if (cell->parameters.size() != 0) {
+ derived_name = tpl->derive(map, parameters);
+ tpl = map->modules[derived_name];
+ log_header("Continuing TECHMAP pass.\n");
+ }
+ techmap_cache[key] = tpl;
}
- if (c.second.width > c.first.width)
- c.second.remove(c.first.width, c.second.width - c.first.width);
- if (c.second.width < c.first.width)
- c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.width - c.second.width));
- assert(c.first.width == c.second.width);
- module->connections.push_back(c);
+
+ if (techmap_fail_check(tpl)) {
+ log("Not using module `%s' from techmap as it contains a TECHMAP_FAIL marker wire.\n", derived_name.c_str());
+ continue;
+ }
+
+ techmap_module_worker(design, module, cell, tpl);
+ did_something = true;
+ cell = NULL;
+ break;
}
- delete cell;
- module->cells.erase(cell_name);
- did_something = true;
- next_cell:;
+ handled_cells.insert(cell);
}
return did_something;
@@ -182,8 +224,23 @@ struct TechmapPass : public Pass {
log(" transforms the internal RTL cells to the internal gate\n");
log(" library.\n");
log("\n");
+ log("When a module in the map file has the 'celltype' attribute set, it will match\n");
+ log("cells with a type that match the text value of this attribute.\n");
+ log("\n");
+ log("When a module in the map file contains a wire with the name 'TECHMAP_FAIL' (or\n");
+ log("one matching '*.TECHMAP_FAIL') then no substitution will be performed. The\n");
+ log("modules in the map file are tried in alphabetical order.\n");
+ log("\n");
+ log("When a module in the map file has a parameter where the according cell in the\n");
+ log("design has a port, the module from the map file is only used if the port in\n");
+ log("the design is connected to a constant value. The parameter is then set to the\n");
+ log("constant value.\n");
+ log("\n");
log("See 'help extract' for a pass that does the opposite thing.\n");
log("\n");
+ log("See 'help flatten' for a pass that does flatten the design (which is\n");
+ log("esentially techmap but using the design itself as map library).\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -220,18 +277,68 @@ struct TechmapPass : public Pass {
}
map->modules.swap(modules_new);
+ std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap;
+ for (auto &it : map->modules) {
+ if (it.second->attributes.count("\\celltype") && !it.second->attributes.at("\\celltype").str.empty()) {
+ celltypeMap[RTLIL::escape_id(it.second->attributes.at("\\celltype").str)].insert(it.first);
+ } else
+ celltypeMap[it.first].insert(it.first);
+ }
+
bool did_something = true;
+ std::set<RTLIL::Cell*> handled_cells;
while (did_something) {
did_something = false;
for (auto &mod_it : design->modules)
- if (techmap_module(design, mod_it.second, map))
+ if (techmap_module(design, mod_it.second, map, handled_cells, celltypeMap))
did_something = true;
}
log("No more expansions possible.\n");
techmap_cache.clear();
+ techmap_fail_cache.clear();
delete map;
log_pop();
}
} TechmapPass;
+struct FlattenPass : public Pass {
+ FlattenPass() : Pass("flatten", "flatten design") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" flatten [selection]\n");
+ log("\n");
+ log("This pass flattens the design by replacing cells by their implementation. This\n");
+ log("pass is very simmilar to the 'techmap' pass. The only difference is that this\n");
+ log("pass is using the current design as mapping library.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing FLATTEN pass (flatten design).\n");
+ log_push();
+
+ extra_args(args, 1, design);
+
+ std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap;
+ for (auto &it : design->modules)
+ celltypeMap[it.first].insert(it.first);
+
+ bool did_something = true;
+ std::set<RTLIL::Cell*> handled_cells;
+ while (did_something) {
+ did_something = false;
+ for (auto &mod_it : design->modules)
+ if (techmap_module(design, mod_it.second, design, handled_cells, celltypeMap))
+ did_something = true;
+ }
+
+ log("No more expansions possible.\n");
+ techmap_cache.clear();
+ techmap_fail_cache.clear();
+ log_pop();
+ }
+} FlattenPass;
+
diff --git a/techlibs/Makefile.inc b/techlibs/Makefile.inc
index 031a4ad30..6c2a5f66a 100644
--- a/techlibs/Makefile.inc
+++ b/techlibs/Makefile.inc
@@ -1,5 +1,5 @@
-TARGETS += techlibs/blackbox.v
+EXTRA_TARGETS += techlibs/blackbox.v
techlibs/blackbox.v: techlibs/blackbox.sed techlibs/simlib.v techlibs/stdcells_sim.v
cat techlibs/simlib.v techlibs/stdcells_sim.v | sed -rf techlibs/blackbox.sed > techlibs/blackbox.v.new
diff --git a/techlibs/simlib.v b/techlibs/simlib.v
index 29c13503b..ff988cbe5 100644
--- a/techlibs/simlib.v
+++ b/techlibs/simlib.v
@@ -646,7 +646,6 @@ module \$sr (S, R, Q);
parameter WIDTH = 0;
-input CLK;
input [WIDTH-1:0] S, R;
output reg [WIDTH-1:0] Q;
@@ -800,8 +799,8 @@ parameter MEMID = "";
parameter ABITS = 8;
parameter WIDTH = 8;
-parameter RD_CLK_ENABLE = 0;
-parameter RD_CLK_POLARITY = 0;
+parameter CLK_ENABLE = 0;
+parameter CLK_POLARITY = 0;
input CLK;
input [ABITS-1:0] ADDR;
@@ -822,8 +821,8 @@ parameter MEMID = "";
parameter ABITS = 8;
parameter WIDTH = 8;
-parameter RD_CLK_ENABLE = 0;
-parameter RD_CLK_POLARITY = 0;
+parameter CLK_ENABLE = 0;
+parameter CLK_POLARITY = 0;
input CLK, EN;
input [ABITS-1:0] ADDR;
diff --git a/tests/k68_vltor/changes.diff b/tests/k68_vltor/changes.diff
new file mode 100644
index 000000000..7b9034032
--- /dev/null
+++ b/tests/k68_vltor/changes.diff
@@ -0,0 +1,12 @@
+diff --git a/bench/bench.cpp b/bench/bench.cpp
+index 47a50c4..de27fbb 100755
+--- a/bench/bench.cpp
++++ b/bench/bench.cpp
+@@ -71,6 +71,7 @@ int main(int argc, char **argv, char **env) {
+ main_time++;
+ top->arbclk_i = !top->arbclk_i;
+ if (main_time%5 == 0) top->clk = !top->clk;
++ if (main_time%100000 == 0) cout<<"Partial sum = "<<hex<<top->sum<<"\n";
+ }
+
+ cout<<"Final sum = "<<hex<<top->sum<<"\n";
diff --git a/tests/k68_vltor/clone.sh b/tests/k68_vltor/clone.sh
new file mode 100644
index 000000000..54bba5219
--- /dev/null
+++ b/tests/k68_vltor/clone.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+set -ex
+rm -rf verilog-sim-benchmarks
+git clone http://git.veripool.org/git/verilog-sim-benchmarks
+cd verilog-sim-benchmarks
+patch -p1 < ../changes.diff
diff --git a/tests/k68_vltor/run.sh b/tests/k68_vltor/run.sh
new file mode 100644
index 000000000..97ccf2389
--- /dev/null
+++ b/tests/k68_vltor/run.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+if (
+ set -ex
+ cd verilog-sim-benchmarks
+ rm -rf obj_dir_* synth
+
+ cd rtl
+ mkdir -p ../synth
+ ../../../../yosys -o ../synth/k68_soc.v -p 'hierarchy -check -top k68_soc; proc; opt; memory; opt' \
+ k68_soc.v k68_arb.v k68_cpu.v k68_load.v k68_clkgen.v k68_decode.v k68_execute.v \
+ k68_fetch.v k68_regbank.v k68_buni.v k68_b2d.v k68_ccc.v k68_d2b.v k68_rox.v \
+ k68_calc.v k68_dpmem.v k68_sasc.v sasc_brg.v sasc_top.v sasc_fifo4.v
+
+ cd ..
+ VERILATOR_OPT="-Wno-fatal -Ibench --cc bench/k68_soc_test.v --exe bench/bench.cpp -prefix m68 -x-assign 0"
+ verilator -Mdir obj_dir_rtl -Irtl $VERILATOR_OPT; make -C obj_dir_rtl -f m68.mk
+ verilator -Mdir obj_dir_synth -Isynth $VERILATOR_OPT; make -C obj_dir_synth -f m68.mk
+
+ ./obj_dir_rtl/m68 100000 | tee output_rtl.txt
+ ./obj_dir_synth/m68 100000 | tee output_synth.txt
+ diff -u <( grep ' sum ' output_rtl.txt; ) <( grep ' sum ' output_synth.txt; )
+); then
+ echo OK
+ exit 0
+else
+ echo ERROR
+ exit 1
+fi
+
diff --git a/tests/simple/always01.v b/tests/simple/always01.v
new file mode 100644
index 000000000..21379cb01
--- /dev/null
+++ b/tests/simple/always01.v
@@ -0,0 +1,10 @@
+module uut_always01(clock, reset, count);
+
+input clock, reset;
+output [3:0] count;
+reg [3:0] count;
+
+always @(posedge clock)
+ count <= reset ? 0 : count + 1;
+
+endmodule
diff --git a/tests/simple/always02.v b/tests/simple/always02.v
new file mode 100644
index 000000000..8c7ef0fb5
--- /dev/null
+++ b/tests/simple/always02.v
@@ -0,0 +1,13 @@
+module uut_always02(clock, reset, count);
+
+input clock, reset;
+output [3:0] count;
+reg [3:0] count;
+
+always @(posedge clock) begin
+ count <= count + 1;
+ if (reset)
+ count <= 0;
+end
+
+endmodule
diff --git a/tests/simple/always03.v b/tests/simple/always03.v
new file mode 100644
index 000000000..5542175e5
--- /dev/null
+++ b/tests/simple/always03.v
@@ -0,0 +1,22 @@
+module uut_always03(clock, in1, in2, in3, in4, in5, in6, in7, out1, out2, out3);
+
+input clock, in1, in2, in3, in4, in5, in6, in7;
+output out1, out2, out3;
+reg out1, out2, out3;
+
+always @(posedge clock) begin
+ out1 = in1;
+ if (in2)
+ out1 = !out1;
+ out2 <= out1;
+ if (in3)
+ out2 <= out2;
+ if (in4)
+ if (in5)
+ out3 <= in6;
+ else
+ out3 <= in7;
+ out1 = out1 ^ out2;
+end
+
+endmodule
diff --git a/tests/simple/arrays01.v b/tests/simple/arrays01.v
new file mode 100644
index 000000000..bd0eda294
--- /dev/null
+++ b/tests/simple/arrays01.v
@@ -0,0 +1,16 @@
+module uut_arrays01(clock, we, addr, wr_data, rd_data);
+
+input clock, we;
+input [3:0] addr, wr_data;
+output [3:0] rd_data;
+reg [3:0] rd_data;
+
+reg [3:0] memory [15:0];
+
+always @(posedge clock) begin
+ if (we)
+ memory[addr] <= wr_data;
+ rd_data <= memory[addr];
+end
+
+endmodule
diff --git a/tests/simple/forgen01.v b/tests/simple/forgen01.v
new file mode 100644
index 000000000..70ee7e667
--- /dev/null
+++ b/tests/simple/forgen01.v
@@ -0,0 +1,20 @@
+module uut_forgen01(a, y);
+
+input [4:0] a;
+output y;
+
+integer i, j;
+reg [31:0] lut;
+
+initial begin
+ for (i = 0; i < 32; i = i+1) begin
+ lut[i] = i > 1;
+ for (j = 2; j*j <= i; j = j+1)
+ if (i % j == 0)
+ lut[i] = 0;
+ end
+end
+
+assign y = lut[a];
+
+endmodule
diff --git a/tests/simple/forgen02.v b/tests/simple/forgen02.v
new file mode 100644
index 000000000..14af070c3
--- /dev/null
+++ b/tests/simple/forgen02.v
@@ -0,0 +1,30 @@
+module uut_forgen02(a, b, cin, y, cout);
+
+parameter WIDTH = 8;
+
+input [WIDTH-1:0] a, b;
+input cin;
+
+output [WIDTH-1:0] y;
+output cout;
+
+genvar i;
+wire [WIDTH-1:0] carry;
+
+generate
+ for (i = 0; i < WIDTH; i=i+1) begin:adder
+ wire [2:0] D;
+ assign D[1:0] = { a[i], b[i] };
+ if (i == 0) begin:chain
+ assign D[2] = cin;
+ end else begin:chain
+ assign D[2] = carry[i-1];
+ end
+ assign y[i] = ^D;
+ assign carry[i] = &D[1:0] | (^D[1:0] & D[2]);
+ end
+endgenerate
+
+assign cout = carry[WIDTH-1];
+
+endmodule
diff --git a/tests/simple/process.v b/tests/simple/process.v
index 532586649..8cb4c870e 100644
--- a/tests/simple/process.v
+++ b/tests/simple/process.v
@@ -1,4 +1,23 @@
+module blocking_cond (in, out);
+
+input in;
+output reg out;
+reg tmp;
+
+always @* begin
+ tmp = 1;
+ out = 1'b0;
+ case (1'b1)
+ tmp: out = in;
+ endcase
+ tmp = 0;
+end
+
+endmodule
+
+// -------------------------------------------------------------
+
module uut(clk, arst, a, b, c, d, e, f, out1);
input clk, arst, a, b, c, d, e, f;
diff --git a/tests/tools/vcdcd.pl b/tests/tools/vcdcd.pl
index 4875eeeb0..93041534b 100755
--- a/tests/tools/vcdcd.pl
+++ b/tests/tools/vcdcd.pl
@@ -8,14 +8,21 @@ use Verilog::VCD qw(parse_vcd list_sigs);
$| = 1;
+my $opt_width = 0;
+if ($ARGV[0] eq '-w') {
+ $opt_width = +$ARGV[1];
+ shift @ARGV;
+ shift @ARGV;
+}
+
if ($#ARGV != 1) {
print STDERR "\n";
print STDERR "VCDCD - Value Change Dump Change Dumper\n";
print STDERR "\n";
- print STDERR "Usage: $0 gold.vcd gate.vcd\n";
+ print STDERR "Usage: $0 [-w N] gold.vcd gate.vcd\n";
print STDERR "\n";
print STDERR "Compare a known-good (gold) vcd file with a second (gate) vcd file.\n";
- print STDERR "This is not very efficient -- so use with care with large vcd files.\n";
+ print STDERR "This is not very efficient -- so use with care on large vcd files.\n";
print STDERR "\n";
exit 1;
}
@@ -112,6 +119,8 @@ for my $key (keys %$vcd_gate) {
}
}
+$signal_maxlen = $opt_width if $opt_width > 0;
+
my $diffcount = 0;
my %state_gold;
my %state_gate;
@@ -161,8 +170,11 @@ sub cmp_signal($$)
my @a = split //, $a;
my @b = split //, $b;
- unshift @a, "-" while $#a < $#b;
- unshift @b, "-" while $#b < $#a;
+ my $trail_a = $#a < 0 ? '-' : $a[0] eq '1' ? '0' : $a[0];
+ my $trail_b = $#b < 0 ? '-' : $b[0] eq '1' ? '0' : $b[0];
+
+ unshift @a, $trail_a while $#a < $#b;
+ unshift @b, $trail_b while $#b < $#a;
for (my $i = 0; $i <= $#a; $i++) {
return 0 if $a[$i] ne "x" && $a[$i] ne $b[$i];