mirror of https://github.com/YosysHQ/yosys.git
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
b8dfda8767
|
@ -4,6 +4,17 @@
|
||||||
all necessary source files. (You can simply drag&drop a .zip file into
|
all necessary source files. (You can simply drag&drop a .zip file into
|
||||||
the issue editor.)*
|
the issue editor.)*
|
||||||
|
|
||||||
|
Also, make sure that the issue is actually reproducable in current git
|
||||||
|
master of Yosys.
|
||||||
|
|
||||||
|
See https://stackoverflow.com/help/mcve for some information on how to
|
||||||
|
create a Minimal, Complete, and Verifiable example (MCVE).
|
||||||
|
|
||||||
|
Please do not waste our time with issues that lack sufficient information
|
||||||
|
to reproduce the issue easily. We will simply close those issues.
|
||||||
|
|
||||||
|
Contact https://www.symbioticeda.com/ if you need commercial support for Yosys.
|
||||||
|
|
||||||
## Expected behavior
|
## Expected behavior
|
||||||
|
|
||||||
*Please describe the behavior you would have expected from the tool.*
|
*Please describe the behavior you would have expected from the tool.*
|
||||||
|
@ -11,6 +22,3 @@ the issue editor.)*
|
||||||
## Actual behavior
|
## Actual behavior
|
||||||
|
|
||||||
*Please describe how the behavior you see differs from the expected behavior.*
|
*Please describe how the behavior you see differs from the expected behavior.*
|
||||||
|
|
||||||
**Important Note:** Nobody will be able to help you and/or fix the issue if you
|
|
||||||
do not provide sufficient information for reproducing the problem.
|
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
/yosys-abc.exe
|
/yosys-abc.exe
|
||||||
/yosys-config
|
/yosys-config
|
||||||
/yosys-smtbmc
|
/yosys-smtbmc
|
||||||
|
/yosys-smtbmc.exe
|
||||||
|
/yosys-smtbmc-script.py
|
||||||
/yosys-filterlib
|
/yosys-filterlib
|
||||||
/yosys-filterlib.exe
|
/yosys-filterlib.exe
|
||||||
/kernel/version_*.cc
|
/kernel/version_*.cc
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -10,6 +10,7 @@ CONFIG := clang
|
||||||
# features (the more the better)
|
# features (the more the better)
|
||||||
ENABLE_TCL := 1
|
ENABLE_TCL := 1
|
||||||
ENABLE_ABC := 1
|
ENABLE_ABC := 1
|
||||||
|
ENABLE_GLOB := 1
|
||||||
ENABLE_PLUGINS := 1
|
ENABLE_PLUGINS := 1
|
||||||
ENABLE_READLINE := 1
|
ENABLE_READLINE := 1
|
||||||
ENABLE_EDITLINE := 0
|
ENABLE_EDITLINE := 0
|
||||||
|
@ -298,6 +299,10 @@ LDLIBS += -ldl
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_GLOB),1)
|
||||||
|
CXXFLAGS += -DYOSYS_ENABLE_GLOB
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_TCL),1)
|
ifeq ($(ENABLE_TCL),1)
|
||||||
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
|
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
|
||||||
ifeq ($(OS), FreeBSD)
|
ifeq ($(OS), FreeBSD)
|
||||||
|
@ -570,7 +575,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
|
||||||
+cd tests/simple && bash run-test.sh $(SEEDOPT)
|
+cd tests/simple && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/hana && bash run-test.sh $(SEEDOPT)
|
+cd tests/hana && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
|
+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/realmath && bash run-test.sh $(SEEDOPT)
|
# +cd tests/realmath && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/share && bash run-test.sh $(SEEDOPT)
|
+cd tests/share && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
|
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/techmap && bash run-test.sh
|
+cd tests/techmap && bash run-test.sh
|
||||||
|
@ -580,6 +585,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
|
||||||
+cd tests/sat && bash run-test.sh
|
+cd tests/sat && bash run-test.sh
|
||||||
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
|
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
|
||||||
+cd tests/opt && bash run-test.sh
|
+cd tests/opt && bash run-test.sh
|
||||||
|
+cd tests/aiger && bash run-test.sh
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " Passed \"make test\"."
|
@echo " Passed \"make test\"."
|
||||||
@echo ""
|
@echo ""
|
||||||
|
|
|
@ -105,12 +105,15 @@ Makefile.
|
||||||
To build Yosys simply type 'make' in this directory.
|
To build Yosys simply type 'make' in this directory.
|
||||||
|
|
||||||
$ make
|
$ make
|
||||||
$ make test
|
|
||||||
$ sudo make install
|
$ sudo make install
|
||||||
|
|
||||||
Note that this also downloads, builds and installs ABC (using yosys-abc
|
Note that this also downloads, builds and installs ABC (using yosys-abc
|
||||||
as executable name).
|
as executable name).
|
||||||
|
|
||||||
|
Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via:
|
||||||
|
|
||||||
|
$ make test
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
@ -312,6 +315,9 @@ Verilog Attributes and non-standard features
|
||||||
- The ``dynports'' attribute is used by the Verilog front-end to mark modules
|
- The ``dynports'' attribute is used by the Verilog front-end to mark modules
|
||||||
that have ports with a width that depends on a parameter.
|
that have ports with a width that depends on a parameter.
|
||||||
|
|
||||||
|
- The ``hdlname'' attribute is used by some passes to document the original
|
||||||
|
(HDL) name of a module when renaming a module.
|
||||||
|
|
||||||
- The ``keep`` attribute on cells and wires is used to mark objects that should
|
- The ``keep`` attribute on cells and wires is used to mark objects that should
|
||||||
never be removed by the optimizer. This is used for example for cells that
|
never be removed by the optimizer. This is used for example for cells that
|
||||||
have hidden connections that are not part of the netlist, such as IO pads.
|
have hidden connections that are not part of the netlist, such as IO pads.
|
||||||
|
|
|
@ -615,6 +615,7 @@ struct BtorWorker
|
||||||
{
|
{
|
||||||
int abits = cell->getParam("\\ABITS").as_int();
|
int abits = cell->getParam("\\ABITS").as_int();
|
||||||
int width = cell->getParam("\\WIDTH").as_int();
|
int width = cell->getParam("\\WIDTH").as_int();
|
||||||
|
int nwords = cell->getParam("\\SIZE").as_int();
|
||||||
int rdports = cell->getParam("\\RD_PORTS").as_int();
|
int rdports = cell->getParam("\\RD_PORTS").as_int();
|
||||||
int wrports = cell->getParam("\\WR_PORTS").as_int();
|
int wrports = cell->getParam("\\WR_PORTS").as_int();
|
||||||
|
|
||||||
|
@ -641,6 +642,52 @@ struct BtorWorker
|
||||||
int data_sid = get_bv_sid(width);
|
int data_sid = get_bv_sid(width);
|
||||||
int bool_sid = get_bv_sid(1);
|
int bool_sid = get_bv_sid(1);
|
||||||
int sid = get_mem_sid(abits, width);
|
int sid = get_mem_sid(abits, width);
|
||||||
|
|
||||||
|
Const initdata = cell->getParam("\\INIT");
|
||||||
|
initdata.exts(nwords*width);
|
||||||
|
int nid_init_val = -1;
|
||||||
|
|
||||||
|
if (!initdata.is_fully_undef())
|
||||||
|
{
|
||||||
|
bool constword = true;
|
||||||
|
Const firstword = initdata.extract(0, width);
|
||||||
|
|
||||||
|
for (int i = 1; i < nwords; i++) {
|
||||||
|
Const thisword = initdata.extract(i*width, width);
|
||||||
|
if (thisword != firstword) {
|
||||||
|
constword = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constword)
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
btorf("; initval = %s\n", log_signal(firstword));
|
||||||
|
nid_init_val = get_sig_nid(firstword);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int nid_init_val = next_nid++;
|
||||||
|
btorf("%d state %d\n", nid_init_val, sid);
|
||||||
|
|
||||||
|
for (int i = 0; i < nwords; i++) {
|
||||||
|
Const thisword = initdata.extract(i*width, width);
|
||||||
|
if (thisword.is_fully_undef())
|
||||||
|
continue;
|
||||||
|
Const thisaddr(i, abits);
|
||||||
|
int nid_thisword = get_sig_nid(thisword);
|
||||||
|
int nid_thisaddr = get_sig_nid(thisaddr);
|
||||||
|
int last_nid_init_val = nid_init_val;
|
||||||
|
nid_init_val = next_nid++;
|
||||||
|
if (verbose)
|
||||||
|
btorf("; initval[%d] = %s\n", i, log_signal(thisword));
|
||||||
|
btorf("%d write %d %d %d %d\n", nid_init_val, sid, last_nid_init_val, nid_thisaddr, nid_thisword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int nid = next_nid++;
|
int nid = next_nid++;
|
||||||
int nid_head = nid;
|
int nid_head = nid;
|
||||||
|
|
||||||
|
@ -649,6 +696,12 @@ struct BtorWorker
|
||||||
else
|
else
|
||||||
btorf("%d state %d %s\n", nid, sid, log_id(cell));
|
btorf("%d state %d %s\n", nid, sid, log_id(cell));
|
||||||
|
|
||||||
|
if (nid_init_val >= 0)
|
||||||
|
{
|
||||||
|
int nid_init = next_nid++;
|
||||||
|
btorf("%d init %d %d %d\n", nid_init, sid, nid, nid_init_val);
|
||||||
|
}
|
||||||
|
|
||||||
if (asyncwr)
|
if (asyncwr)
|
||||||
{
|
{
|
||||||
for (int port = 0; port < wrports; port++)
|
for (int port = 0; port < wrports; port++)
|
||||||
|
@ -932,9 +985,8 @@ struct BtorWorker
|
||||||
|
|
||||||
btorf_push(stringf("output %s", log_id(wire)));
|
btorf_push(stringf("output %s", log_id(wire)));
|
||||||
|
|
||||||
int sid = get_bv_sid(GetSize(wire));
|
|
||||||
int nid = get_sig_nid(wire);
|
int nid = get_sig_nid(wire);
|
||||||
btorf("%d output %d %d %s\n", next_nid++, sid, nid, log_id(wire));
|
btorf("%d output %d %s\n", next_nid++, nid, log_id(wire));
|
||||||
|
|
||||||
btorf_pop(stringf("output %s", log_id(wire)));
|
btorf_pop(stringf("output %s", log_id(wire)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,8 +165,7 @@ struct FirrtlWorker
|
||||||
|
|
||||||
std::string fid(RTLIL::IdString internal_id)
|
std::string fid(RTLIL::IdString internal_id)
|
||||||
{
|
{
|
||||||
const char *str = internal_id.c_str();
|
return make_id(internal_id);
|
||||||
return *str == '\\' ? str + 1 : str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string cellname(RTLIL::Cell *cell)
|
std::string cellname(RTLIL::Cell *cell)
|
||||||
|
|
|
@ -3,14 +3,30 @@ OBJS += backends/smt2/smt2.o
|
||||||
|
|
||||||
ifneq ($(CONFIG),mxe)
|
ifneq ($(CONFIG),mxe)
|
||||||
ifneq ($(CONFIG),emcc)
|
ifneq ($(CONFIG),emcc)
|
||||||
|
|
||||||
|
# MSYS targets support yosys-smtbmc, but require a launcher script
|
||||||
|
ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64))
|
||||||
|
TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py
|
||||||
|
# Needed to find the Python interpreter for yosys-smtbmc scripts.
|
||||||
|
# Override if necessary, it is only used for msys2 targets.
|
||||||
|
PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3)
|
||||||
|
|
||||||
|
yosys-smtbmc-script.py: backends/smt2/smtbmc.py
|
||||||
|
$(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \
|
||||||
|
-e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
|
||||||
|
|
||||||
|
yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py
|
||||||
|
$(P) gcc -DGUI=0 -O -s -o $@ $<
|
||||||
|
# Other targets
|
||||||
|
else
|
||||||
TARGETS += yosys-smtbmc
|
TARGETS += yosys-smtbmc
|
||||||
|
|
||||||
yosys-smtbmc: backends/smt2/smtbmc.py
|
yosys-smtbmc: backends/smt2/smtbmc.py
|
||||||
$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
|
$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
|
||||||
$(Q) chmod +x $@.new
|
$(Q) chmod +x $@.new
|
||||||
$(Q) mv $@.new $@
|
$(Q) mv $@.new $@
|
||||||
|
endif
|
||||||
|
|
||||||
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
|
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -416,6 +416,7 @@ struct Smt2Worker
|
||||||
for (char ch : expr) {
|
for (char ch : expr) {
|
||||||
if (ch == 'A') processed_expr += get_bv(sig_a);
|
if (ch == 'A') processed_expr += get_bv(sig_a);
|
||||||
else if (ch == 'B') processed_expr += get_bv(sig_b);
|
else if (ch == 'B') processed_expr += get_bv(sig_b);
|
||||||
|
else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B"));
|
||||||
else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
|
else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
|
||||||
else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
|
else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
|
||||||
else processed_expr += ch;
|
else processed_expr += ch;
|
||||||
|
@ -554,7 +555,7 @@ struct Smt2Worker
|
||||||
|
|
||||||
if (cell->type.in("$shift", "$shiftx")) {
|
if (cell->type.in("$shift", "$shiftx")) {
|
||||||
if (cell->getParam("\\B_SIGNED").as_bool()) {
|
if (cell->getParam("\\B_SIGNED").as_bool()) {
|
||||||
return export_bvop(cell, stringf("(ite (bvsge B #b%0*d) "
|
return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) "
|
||||||
"(bvlshr A B) (bvlshr A (bvneg B)))",
|
"(bvlshr A B) (bvlshr A (bvneg B)))",
|
||||||
GetSize(cell->getPort("\\B")), 0), 's');
|
GetSize(cell->getPort("\\B")), 0), 's');
|
||||||
} else {
|
} else {
|
||||||
|
@ -887,8 +888,8 @@ struct Smt2Worker
|
||||||
|
|
||||||
string name_a = get_bool(cell->getPort("\\A"));
|
string name_a = get_bool(cell->getPort("\\A"));
|
||||||
string name_en = get_bool(cell->getPort("\\EN"));
|
string name_en = get_bool(cell->getPort("\\EN"));
|
||||||
decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id,
|
string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : get_id(cell);
|
||||||
cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
|
decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, infostr.c_str()));
|
||||||
|
|
||||||
if (cell->type == "$cover")
|
if (cell->type == "$cover")
|
||||||
decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
|
decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
|
||||||
|
|
|
@ -1673,6 +1673,8 @@ struct VerilogBackend : public Backend {
|
||||||
bool blackboxes = false;
|
bool blackboxes = false;
|
||||||
bool selected = false;
|
bool selected = false;
|
||||||
|
|
||||||
|
auto_name_map.clear();
|
||||||
|
reg_wires.clear();
|
||||||
reg_ct.clear();
|
reg_ct.clear();
|
||||||
|
|
||||||
reg_ct.insert("$dff");
|
reg_ct.insert("$dff");
|
||||||
|
@ -1779,6 +1781,8 @@ struct VerilogBackend : public Backend {
|
||||||
dump_module(*f, "", it->second);
|
dump_module(*f, "", it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto_name_map.clear();
|
||||||
|
reg_wires.clear();
|
||||||
reg_ct.clear();
|
reg_ct.clear();
|
||||||
}
|
}
|
||||||
} VerilogBackend;
|
} VerilogBackend;
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
demo.bit
|
||||||
|
demo_phy.area
|
||||||
|
full.v
|
||||||
|
*.log
|
||||||
|
*.h
|
||||||
|
*.tde
|
||||||
|
*.svf
|
|
@ -0,0 +1,12 @@
|
||||||
|
LED Blink project for Anlogic Lichee Tang board.
|
||||||
|
|
||||||
|
Follow the install instructions for the Tang Dynasty IDE from given link below.
|
||||||
|
|
||||||
|
https://tang.sipeed.com/en/getting-started/installing-td-ide/linux/
|
||||||
|
|
||||||
|
|
||||||
|
set TD_HOME env variable to the full path to the TD <TD Install Directory> as follow.
|
||||||
|
|
||||||
|
export TD_HOME=<TD Install Directory>
|
||||||
|
|
||||||
|
then run "bash build.sh" in this directory.
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -ex
|
||||||
|
yosys demo.ys
|
||||||
|
$TD_HOME/bin/td build.tcl
|
|
@ -0,0 +1,11 @@
|
||||||
|
import_device eagle_s20.db -package BG256
|
||||||
|
read_verilog full.v -top demo
|
||||||
|
read_adc demo.adc
|
||||||
|
optimize_rtl
|
||||||
|
map_macro
|
||||||
|
map
|
||||||
|
pack
|
||||||
|
place
|
||||||
|
route
|
||||||
|
report_area -io_info -file demo_phy.area
|
||||||
|
bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000
|
|
@ -0,0 +1,2 @@
|
||||||
|
set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ
|
||||||
|
set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED
|
|
@ -0,0 +1,18 @@
|
||||||
|
module demo (
|
||||||
|
input wire CLK_IN,
|
||||||
|
output wire R_LED
|
||||||
|
);
|
||||||
|
parameter time1 = 30'd12_000_000;
|
||||||
|
reg led_state;
|
||||||
|
reg [29:0] count;
|
||||||
|
|
||||||
|
always @(posedge CLK_IN)begin
|
||||||
|
if(count == time1)begin
|
||||||
|
count<= 30'd0;
|
||||||
|
led_state <= ~led_state;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
count <= count + 1'b1;
|
||||||
|
end
|
||||||
|
assign R_LED = led_state;
|
||||||
|
endmodule
|
|
@ -0,0 +1,3 @@
|
||||||
|
read_verilog demo.v
|
||||||
|
synth_anlogic -top demo
|
||||||
|
write_verilog full.v
|
|
@ -1,3 +1,4 @@
|
||||||
/netlist.edn
|
/netlist.edn
|
||||||
/netlist.vm
|
/netlist.vm
|
||||||
|
/example.stp
|
||||||
/proj
|
/proj
|
||||||
|
|
|
@ -1 +1,20 @@
|
||||||
# Add placement constraints here
|
# Add placement constraints here
|
||||||
|
|
||||||
|
set_io clk -pinname H16 -fixed yes -DIRECTION INPUT
|
||||||
|
|
||||||
|
set_io SW1 -pinname H12 -fixed yes -DIRECTION INPUT
|
||||||
|
set_io SW2 -pinname H13 -fixed yes -DIRECTION INPUT
|
||||||
|
|
||||||
|
set_io LED1 -pinname J16 -fixed yes -DIRECTION OUTPUT
|
||||||
|
set_io LED2 -pinname M16 -fixed yes -DIRECTION OUTPUT
|
||||||
|
set_io LED3 -pinname K16 -fixed yes -DIRECTION OUTPUT
|
||||||
|
set_io LED4 -pinname N16 -fixed yes -DIRECTION OUTPUT
|
||||||
|
|
||||||
|
set_io AA -pinname L12 -fixed yes -DIRECTION OUTPUT
|
||||||
|
set_io AB -pinname L13 -fixed yes -DIRECTION OUTPUT
|
||||||
|
set_io AC -pinname M13 -fixed yes -DIRECTION OUTPUT
|
||||||
|
set_io AD -pinname N15 -fixed yes -DIRECTION OUTPUT
|
||||||
|
set_io AE -pinname L11 -fixed yes -DIRECTION OUTPUT
|
||||||
|
set_io AF -pinname L14 -fixed yes -DIRECTION OUTPUT
|
||||||
|
set_io AG -pinname N14 -fixed yes -DIRECTION OUTPUT
|
||||||
|
set_io CA -pinname M15 -fixed yes -DIRECTION OUTPUT
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
# Add timing constraints here
|
# Add timing constraints here
|
||||||
|
create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]
|
||||||
|
|
|
@ -1,23 +1,64 @@
|
||||||
module example (
|
module example (
|
||||||
input clk,
|
input clk,
|
||||||
input EN,
|
input SW1,
|
||||||
|
input SW2,
|
||||||
output LED1,
|
output LED1,
|
||||||
output LED2,
|
output LED2,
|
||||||
output LED3,
|
output LED3,
|
||||||
output LED4,
|
output LED4,
|
||||||
output LED5
|
|
||||||
|
output AA, AB, AC, AD,
|
||||||
|
output AE, AF, AG, CA
|
||||||
);
|
);
|
||||||
|
|
||||||
localparam BITS = 5;
|
localparam BITS = 8;
|
||||||
localparam LOG2DELAY = 22;
|
localparam LOG2DELAY = 22;
|
||||||
|
|
||||||
reg [BITS+LOG2DELAY-1:0] counter = 0;
|
reg [BITS+LOG2DELAY-1:0] counter = 0;
|
||||||
reg [BITS-1:0] outcnt;
|
reg [BITS-1:0] outcnt;
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
counter <= counter + EN;
|
counter <= counter + SW1 + SW2 + 1;
|
||||||
outcnt <= counter >> LOG2DELAY;
|
outcnt <= counter >> LOG2DELAY;
|
||||||
end
|
end
|
||||||
|
|
||||||
assign {LED1, LED2, LED3, LED4, LED5} = outcnt ^ (outcnt >> 1);
|
assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1);
|
||||||
|
|
||||||
|
// assign CA = counter[10];
|
||||||
|
// seg7enc seg7encinst (
|
||||||
|
// .seg({AA, AB, AC, AD, AE, AF, AG}),
|
||||||
|
// .dat(CA ? outcnt[3:0] : outcnt[7:4])
|
||||||
|
// );
|
||||||
|
|
||||||
|
assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]);
|
||||||
|
assign CA = outcnt[7];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module seg7enc (
|
||||||
|
input [3:0] dat,
|
||||||
|
output [6:0] seg
|
||||||
|
);
|
||||||
|
reg [6:0] seg_inv;
|
||||||
|
always @* begin
|
||||||
|
seg_inv = 0;
|
||||||
|
case (dat)
|
||||||
|
4'h0: seg_inv = 7'b 0111111;
|
||||||
|
4'h1: seg_inv = 7'b 0000110;
|
||||||
|
4'h2: seg_inv = 7'b 1011011;
|
||||||
|
4'h3: seg_inv = 7'b 1001111;
|
||||||
|
4'h4: seg_inv = 7'b 1100110;
|
||||||
|
4'h5: seg_inv = 7'b 1101101;
|
||||||
|
4'h6: seg_inv = 7'b 1111101;
|
||||||
|
4'h7: seg_inv = 7'b 0000111;
|
||||||
|
4'h8: seg_inv = 7'b 1111111;
|
||||||
|
4'h9: seg_inv = 7'b 1101111;
|
||||||
|
4'hA: seg_inv = 7'b 1110111;
|
||||||
|
4'hB: seg_inv = 7'b 1111100;
|
||||||
|
4'hC: seg_inv = 7'b 0111001;
|
||||||
|
4'hD: seg_inv = 7'b 1011110;
|
||||||
|
4'hE: seg_inv = 7'b 1111001;
|
||||||
|
4'hF: seg_inv = 7'b 1110001;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
assign seg = ~seg_inv;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -8,8 +8,8 @@ new_project \
|
||||||
-block_mode 0 \
|
-block_mode 0 \
|
||||||
-hdl "VERILOG" \
|
-hdl "VERILOG" \
|
||||||
-family IGLOO2 \
|
-family IGLOO2 \
|
||||||
-die PA4MGL500 \
|
-die PA4MGL2500 \
|
||||||
-package tq144 \
|
-package vf256 \
|
||||||
-speed -1
|
-speed -1
|
||||||
|
|
||||||
import_files -hdl_source {netlist.vm}
|
import_files -hdl_source {netlist.vm}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
OBJS += frontends/aiger/aigerparse.o
|
||||||
|
|
|
@ -0,0 +1,414 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Eddie Hung <eddie@fpgeh.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// [[CITE]] The AIGER And-Inverter Graph (AIG) Format Version 20071012
|
||||||
|
// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
|
||||||
|
// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <libgen.h>
|
||||||
|
#endif
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
#include "aigerparse.h"
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
#define log_debug log
|
||||||
|
|
||||||
|
AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
|
||||||
|
: design(design), f(f), clk_name(clk_name)
|
||||||
|
{
|
||||||
|
module = new RTLIL::Module;
|
||||||
|
module->name = module_name;
|
||||||
|
if (design->module(module->name))
|
||||||
|
log_error("Duplicate definition of module %s!\n", log_id(module->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AigerReader::parse_aiger()
|
||||||
|
{
|
||||||
|
std::string header;
|
||||||
|
f >> header;
|
||||||
|
if (header != "aag" && header != "aig")
|
||||||
|
log_error("Unsupported AIGER file!\n");
|
||||||
|
|
||||||
|
// Parse rest of header
|
||||||
|
if (!(f >> M >> I >> L >> O >> A))
|
||||||
|
log_error("Invalid AIGER header\n");
|
||||||
|
|
||||||
|
// Optional values
|
||||||
|
B = C = J = F = 0;
|
||||||
|
for (auto &i : std::array<std::reference_wrapper<unsigned>,4>{B, C, J, F}) {
|
||||||
|
if (f.peek() != ' ') break;
|
||||||
|
if (!(f >> i))
|
||||||
|
log_error("Invalid AIGER header\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::getline(f, line); // Ignore up to start of next line, as standard
|
||||||
|
// says anything that follows could be used for
|
||||||
|
// optional sections
|
||||||
|
|
||||||
|
log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
|
||||||
|
|
||||||
|
line_count = 1;
|
||||||
|
|
||||||
|
if (header == "aag")
|
||||||
|
parse_aiger_ascii();
|
||||||
|
else if (header == "aig")
|
||||||
|
parse_aiger_binary();
|
||||||
|
else
|
||||||
|
log_abort();
|
||||||
|
|
||||||
|
// Parse footer (symbol table, comments, etc.)
|
||||||
|
unsigned l1;
|
||||||
|
std::string s;
|
||||||
|
for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
|
||||||
|
if (c == 'i' || c == 'l' || c == 'o') {
|
||||||
|
f.ignore(1);
|
||||||
|
if (!(f >> l1 >> s))
|
||||||
|
log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
|
||||||
|
|
||||||
|
if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
|
||||||
|
log_error("Line %u has invalid symbol position!\n", line_count);
|
||||||
|
|
||||||
|
RTLIL::Wire* wire;
|
||||||
|
if (c == 'i') wire = inputs[l1];
|
||||||
|
else if (c == 'l') wire = latches[l1];
|
||||||
|
else if (c == 'o') wire = outputs[l1];
|
||||||
|
else log_abort();
|
||||||
|
|
||||||
|
module->rename(wire, stringf("\\%s", s.c_str()));
|
||||||
|
}
|
||||||
|
else if (c == 'b' || c == 'j' || c == 'f') {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
else if (c == 'c') {
|
||||||
|
f.ignore(1);
|
||||||
|
if (f.peek() == '\n')
|
||||||
|
break;
|
||||||
|
// Else constraint (TODO)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
}
|
||||||
|
|
||||||
|
module->fixup_ports();
|
||||||
|
design->add(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal)
|
||||||
|
{
|
||||||
|
const unsigned variable = literal >> 1;
|
||||||
|
const bool invert = literal & 1;
|
||||||
|
RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix?
|
||||||
|
RTLIL::Wire *wire = module->wire(wire_name);
|
||||||
|
if (wire) return wire;
|
||||||
|
log_debug("Creating %s\n", wire_name.c_str());
|
||||||
|
wire = module->addWire(wire_name);
|
||||||
|
if (!invert) return wire;
|
||||||
|
RTLIL::IdString wire_inv_name(stringf("\\n%d", variable));
|
||||||
|
RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
|
||||||
|
if (wire_inv) {
|
||||||
|
if (module->cell(wire_inv_name)) return wire;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_debug("Creating %s\n", wire_inv_name.c_str());
|
||||||
|
wire_inv = module->addWire(wire_inv_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
|
||||||
|
module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix?
|
||||||
|
|
||||||
|
return wire;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AigerReader::parse_aiger_ascii()
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
unsigned l1, l2, l3;
|
||||||
|
|
||||||
|
// Parse inputs
|
||||||
|
for (unsigned i = 0; i < I; ++i, ++line_count) {
|
||||||
|
if (!(f >> l1))
|
||||||
|
log_error("Line %u cannot be interpreted as an input!\n", line_count);
|
||||||
|
log_debug("%d is an input\n", l1);
|
||||||
|
log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted?
|
||||||
|
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||||
|
wire->port_input = true;
|
||||||
|
inputs.push_back(wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse latches
|
||||||
|
RTLIL::Wire *clk_wire = nullptr;
|
||||||
|
if (L > 0) {
|
||||||
|
clk_wire = module->wire(clk_name);
|
||||||
|
log_assert(!clk_wire);
|
||||||
|
log_debug("Creating %s\n", clk_name.c_str());
|
||||||
|
clk_wire = module->addWire(clk_name);
|
||||||
|
clk_wire->port_input = true;
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < L; ++i, ++line_count) {
|
||||||
|
if (!(f >> l1 >> l2))
|
||||||
|
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||||
|
log_debug("%d %d is a latch\n", l1, l2);
|
||||||
|
log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted?
|
||||||
|
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
||||||
|
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
||||||
|
|
||||||
|
module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
|
||||||
|
|
||||||
|
// Reset logic is optional in AIGER 1.9
|
||||||
|
if (f.peek() == ' ') {
|
||||||
|
if (!(f >> l3))
|
||||||
|
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||||
|
|
||||||
|
if (l3 == 0 || l3 == 1)
|
||||||
|
q_wire->attributes["\\init"] = RTLIL::Const(l3);
|
||||||
|
else if (l3 == l1) {
|
||||||
|
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_error("Line %u has invalid reset literal for latch!\n", line_count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// AIGER latches are assumed to be initialized to zero
|
||||||
|
q_wire->attributes["\\init"] = RTLIL::Const(0);
|
||||||
|
}
|
||||||
|
latches.push_back(q_wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse outputs
|
||||||
|
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||||
|
if (!(f >> l1))
|
||||||
|
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||||
|
|
||||||
|
log_debug("%d is an output\n", l1);
|
||||||
|
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||||
|
wire->port_output = true;
|
||||||
|
outputs.push_back(wire);
|
||||||
|
}
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
|
||||||
|
// TODO: Parse bad state properties
|
||||||
|
for (unsigned i = 0; i < B; ++i, ++line_count)
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
|
||||||
|
// TODO: Parse invariant constraints
|
||||||
|
for (unsigned i = 0; i < C; ++i, ++line_count)
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
|
||||||
|
// TODO: Parse justice properties
|
||||||
|
for (unsigned i = 0; i < J; ++i, ++line_count)
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
|
||||||
|
// TODO: Parse fairness constraints
|
||||||
|
for (unsigned i = 0; i < F; ++i, ++line_count)
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
|
||||||
|
// Parse AND
|
||||||
|
for (unsigned i = 0; i < A; ++i) {
|
||||||
|
if (!(f >> l1 >> l2 >> l3))
|
||||||
|
log_error("Line %u cannot be interpreted as an AND!\n", line_count);
|
||||||
|
|
||||||
|
log_debug("%d %d %d is an AND\n", l1, l2, l3);
|
||||||
|
log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
|
||||||
|
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||||
|
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||||
|
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
|
||||||
|
module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire);
|
||||||
|
}
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned parse_next_delta_literal(std::istream &f, unsigned ref)
|
||||||
|
{
|
||||||
|
unsigned x = 0, i = 0;
|
||||||
|
unsigned char ch;
|
||||||
|
while ((ch = f.get()) & 0x80)
|
||||||
|
x |= (ch & 0x7f) << (7 * i++);
|
||||||
|
return ref - (x | (ch << (7 * i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AigerReader::parse_aiger_binary()
|
||||||
|
{
|
||||||
|
unsigned l1, l2, l3;
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
// Parse inputs
|
||||||
|
for (unsigned i = 1; i <= I; ++i) {
|
||||||
|
RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
|
||||||
|
wire->port_input = true;
|
||||||
|
inputs.push_back(wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse latches
|
||||||
|
RTLIL::Wire *clk_wire = nullptr;
|
||||||
|
if (L > 0) {
|
||||||
|
clk_wire = module->wire(clk_name);
|
||||||
|
log_assert(!clk_wire);
|
||||||
|
log_debug("Creating %s\n", clk_name.c_str());
|
||||||
|
clk_wire = module->addWire(clk_name);
|
||||||
|
clk_wire->port_input = true;
|
||||||
|
}
|
||||||
|
l1 = (I+1) * 2;
|
||||||
|
for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
|
||||||
|
if (!(f >> l2))
|
||||||
|
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||||
|
log_debug("%d %d is a latch\n", l1, l2);
|
||||||
|
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
|
||||||
|
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
|
||||||
|
|
||||||
|
module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
|
||||||
|
|
||||||
|
// Reset logic is optional in AIGER 1.9
|
||||||
|
if (f.peek() == ' ') {
|
||||||
|
if (!(f >> l3))
|
||||||
|
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
|
||||||
|
|
||||||
|
if (l3 == 0 || l3 == 1)
|
||||||
|
q_wire->attributes["\\init"] = RTLIL::Const(l3);
|
||||||
|
else if (l3 == l1) {
|
||||||
|
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_error("Line %u has invalid reset literal for latch!\n", line_count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// AIGER latches are assumed to be initialized to zero
|
||||||
|
q_wire->attributes["\\init"] = RTLIL::Const(0);
|
||||||
|
}
|
||||||
|
latches.push_back(q_wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse outputs
|
||||||
|
for (unsigned i = 0; i < O; ++i, ++line_count) {
|
||||||
|
if (!(f >> l1))
|
||||||
|
log_error("Line %u cannot be interpreted as an output!\n", line_count);
|
||||||
|
|
||||||
|
log_debug("%d is an output\n", l1);
|
||||||
|
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
|
||||||
|
wire->port_output = true;
|
||||||
|
outputs.push_back(wire);
|
||||||
|
}
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
|
||||||
|
// TODO: Parse bad state properties
|
||||||
|
for (unsigned i = 0; i < B; ++i, ++line_count)
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
|
||||||
|
// TODO: Parse invariant constraints
|
||||||
|
for (unsigned i = 0; i < C; ++i, ++line_count)
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
|
||||||
|
// TODO: Parse justice properties
|
||||||
|
for (unsigned i = 0; i < J; ++i, ++line_count)
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
|
||||||
|
// TODO: Parse fairness constraints
|
||||||
|
for (unsigned i = 0; i < F; ++i, ++line_count)
|
||||||
|
std::getline(f, line); // Ignore up to start of next line
|
||||||
|
|
||||||
|
// Parse AND
|
||||||
|
l1 = (I+L+1) << 1;
|
||||||
|
for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) {
|
||||||
|
l2 = parse_next_delta_literal(f, l1);
|
||||||
|
l3 = parse_next_delta_literal(f, l2);
|
||||||
|
|
||||||
|
log_debug("%d %d %d is an AND\n", l1, l2, l3);
|
||||||
|
log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
|
||||||
|
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
|
||||||
|
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
|
||||||
|
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
|
||||||
|
|
||||||
|
RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_");
|
||||||
|
and_cell->setPort("\\A", i1_wire);
|
||||||
|
and_cell->setPort("\\B", i2_wire);
|
||||||
|
and_cell->setPort("\\Y", o_wire);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AigerFrontend : public Frontend {
|
||||||
|
AigerFrontend() : Frontend("aiger", "read AIGER file") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" read_aiger [options] [filename]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Load module from an AIGER file into the current design.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -module_name <module_name>\n");
|
||||||
|
log(" Name of module to be created (default: <filename>)"
|
||||||
|
#ifdef _WIN32
|
||||||
|
"top" // FIXME
|
||||||
|
#else
|
||||||
|
"<filename>"
|
||||||
|
#endif
|
||||||
|
")\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -clk_name <wire_name>\n");
|
||||||
|
log(" AIGER latches to be transformed into posedge DFFs clocked by wire of");
|
||||||
|
log(" this name (default: clk)\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
log_header(design, "Executing AIGER frontend.\n");
|
||||||
|
|
||||||
|
RTLIL::IdString clk_name = "\\clk";
|
||||||
|
RTLIL::IdString module_name;
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
|
std::string arg = args[argidx];
|
||||||
|
if (arg == "-module_name" && argidx+1 < args.size()) {
|
||||||
|
module_name = RTLIL::escape_id(args[++argidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-clk_name" && argidx+1 < args.size()) {
|
||||||
|
clk_name = RTLIL::escape_id(args[++argidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(f, filename, args, argidx);
|
||||||
|
|
||||||
|
if (module_name.empty()) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
module_name = "top"; // FIXME: basename equivalent on Win32?
|
||||||
|
#else
|
||||||
|
char* bn = strdup(filename.c_str());
|
||||||
|
module_name = RTLIL::escape_id(bn);
|
||||||
|
free(bn);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
AigerReader reader(design, *f, module_name, clk_name);
|
||||||
|
reader.parse_aiger();
|
||||||
|
}
|
||||||
|
} AigerFrontend;
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_END
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
* Eddie Hung <eddie@fpgeh.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ABC_AIGERPARSE
|
||||||
|
#define ABC_AIGERPARSE
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct AigerReader
|
||||||
|
{
|
||||||
|
RTLIL::Design *design;
|
||||||
|
std::istream &f;
|
||||||
|
RTLIL::IdString clk_name;
|
||||||
|
RTLIL::Module *module;
|
||||||
|
|
||||||
|
unsigned M, I, L, O, A;
|
||||||
|
unsigned B, C, J, F; // Optional in AIGER 1.9
|
||||||
|
unsigned line_count;
|
||||||
|
|
||||||
|
std::vector<RTLIL::Wire*> inputs;
|
||||||
|
std::vector<RTLIL::Wire*> latches;
|
||||||
|
std::vector<RTLIL::Wire*> outputs;
|
||||||
|
|
||||||
|
AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name);
|
||||||
|
void parse_aiger();
|
||||||
|
void parse_aiger_ascii();
|
||||||
|
void parse_aiger_binary();
|
||||||
|
};
|
||||||
|
|
||||||
|
YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
|
@ -45,7 +45,7 @@ namespace AST {
|
||||||
|
|
||||||
// instantiate global variables (private API)
|
// instantiate global variables (private API)
|
||||||
namespace AST_INTERNAL {
|
namespace AST_INTERNAL {
|
||||||
bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
|
bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
|
||||||
bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
|
bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
|
||||||
AstNode *current_ast, *current_ast_mod;
|
AstNode *current_ast, *current_ast_mod;
|
||||||
std::map<std::string, AstNode*> current_scope;
|
std::map<std::string, AstNode*> current_scope;
|
||||||
|
@ -431,9 +431,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_RANGE:
|
case AST_RANGE:
|
||||||
if (range_valid)
|
if (range_valid) {
|
||||||
|
if (range_swapped)
|
||||||
|
fprintf(f, "[%d:%d]", range_right, range_left);
|
||||||
|
else
|
||||||
fprintf(f, "[%d:%d]", range_left, range_right);
|
fprintf(f, "[%d:%d]", range_left, range_right);
|
||||||
else {
|
} else {
|
||||||
for (auto child : children) {
|
for (auto child : children) {
|
||||||
fprintf(f, "%c", first ? '[' : ':');
|
fprintf(f, "%c", first ? '[' : ':');
|
||||||
child->dumpVlog(f, "");
|
child->dumpVlog(f, "");
|
||||||
|
@ -562,7 +565,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
|
||||||
|
|
||||||
case AST_CONCAT:
|
case AST_CONCAT:
|
||||||
fprintf(f, "{");
|
fprintf(f, "{");
|
||||||
for (auto child : children) {
|
for (int i = GetSize(children)-1; i >= 0; i--) {
|
||||||
|
auto child = children[i];
|
||||||
if (!first)
|
if (!first)
|
||||||
fprintf(f, ", ");
|
fprintf(f, ", ");
|
||||||
child->dumpVlog(f, "");
|
child->dumpVlog(f, "");
|
||||||
|
@ -926,23 +930,28 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
|
||||||
ast_before_simplify = ast->clone();
|
ast_before_simplify = ast->clone();
|
||||||
|
|
||||||
if (flag_dump_ast1) {
|
if (flag_dump_ast1) {
|
||||||
log("Dumping Verilog AST before simplification:\n");
|
log("Dumping AST before simplification:\n");
|
||||||
ast->dumpAst(NULL, " ");
|
ast->dumpAst(NULL, " ");
|
||||||
log("--- END OF AST DUMP ---\n");
|
log("--- END OF AST DUMP ---\n");
|
||||||
}
|
}
|
||||||
|
if (flag_dump_vlog1) {
|
||||||
|
log("Dumping Verilog AST before simplification:\n");
|
||||||
|
ast->dumpVlog(NULL, " ");
|
||||||
|
log("--- END OF AST DUMP ---\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (!defer)
|
if (!defer)
|
||||||
{
|
{
|
||||||
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
|
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
|
||||||
|
|
||||||
if (flag_dump_ast2) {
|
if (flag_dump_ast2) {
|
||||||
log("Dumping Verilog AST after simplification:\n");
|
log("Dumping AST after simplification:\n");
|
||||||
ast->dumpAst(NULL, " ");
|
ast->dumpAst(NULL, " ");
|
||||||
log("--- END OF AST DUMP ---\n");
|
log("--- END OF AST DUMP ---\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag_dump_vlog) {
|
if (flag_dump_vlog2) {
|
||||||
log("Dumping Verilog AST (as requested by dump_vlog option):\n");
|
log("Dumping Verilog AST after simplification:\n");
|
||||||
ast->dumpVlog(NULL, " ");
|
ast->dumpVlog(NULL, " ");
|
||||||
log("--- END OF AST DUMP ---\n");
|
log("--- END OF AST DUMP ---\n");
|
||||||
}
|
}
|
||||||
|
@ -1016,14 +1025,15 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
|
||||||
}
|
}
|
||||||
|
|
||||||
// create AstModule instances for all modules in the AST tree and add them to 'design'
|
// 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_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog, bool dump_rtlil,
|
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
|
||||||
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
|
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
|
||||||
{
|
{
|
||||||
current_ast = ast;
|
current_ast = ast;
|
||||||
flag_dump_ast1 = dump_ast1;
|
flag_dump_ast1 = dump_ast1;
|
||||||
flag_dump_ast2 = dump_ast2;
|
flag_dump_ast2 = dump_ast2;
|
||||||
flag_no_dump_ptr = no_dump_ptr;
|
flag_no_dump_ptr = no_dump_ptr;
|
||||||
flag_dump_vlog = dump_vlog;
|
flag_dump_vlog1 = dump_vlog1;
|
||||||
|
flag_dump_vlog2 = dump_vlog2;
|
||||||
flag_dump_rtlil = dump_rtlil;
|
flag_dump_rtlil = dump_rtlil;
|
||||||
flag_nolatches = nolatches;
|
flag_nolatches = nolatches;
|
||||||
flag_nomeminit = nomeminit;
|
flag_nomeminit = nomeminit;
|
||||||
|
@ -1357,7 +1367,8 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
|
||||||
current_ast = NULL;
|
current_ast = NULL;
|
||||||
flag_dump_ast1 = false;
|
flag_dump_ast1 = false;
|
||||||
flag_dump_ast2 = false;
|
flag_dump_ast2 = false;
|
||||||
flag_dump_vlog = false;
|
flag_dump_vlog1 = false;
|
||||||
|
flag_dump_vlog2 = false;
|
||||||
flag_nolatches = nolatches;
|
flag_nolatches = nolatches;
|
||||||
flag_nomeminit = nomeminit;
|
flag_nomeminit = nomeminit;
|
||||||
flag_nomem2reg = nomem2reg;
|
flag_nomem2reg = nomem2reg;
|
||||||
|
|
|
@ -282,7 +282,7 @@ namespace AST
|
||||||
};
|
};
|
||||||
|
|
||||||
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
|
// 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_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit,
|
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
|
||||||
bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
|
bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
|
||||||
|
|
||||||
// parametric modules are supported directly by the AST library
|
// parametric modules are supported directly by the AST library
|
||||||
|
|
|
@ -525,7 +525,16 @@ struct AST_INTERNAL::ProcessGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
|
if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
|
||||||
|
#if 0
|
||||||
|
// this is a valid transformation, but as optimization it is premature.
|
||||||
|
// better: add a default case that assigns 'x' to everything, and let later
|
||||||
|
// optimizations take care of the rest
|
||||||
last_generated_case->compare.clear();
|
last_generated_case->compare.clear();
|
||||||
|
#else
|
||||||
|
default_case = new RTLIL::CaseRule;
|
||||||
|
addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue)));
|
||||||
|
sw->cases.push_back(default_case);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
if (default_case == NULL) {
|
if (default_case == NULL) {
|
||||||
default_case = new RTLIL::CaseRule;
|
default_case = new RTLIL::CaseRule;
|
||||||
|
@ -1413,10 +1422,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||||
if (GetSize(en) != 1)
|
if (GetSize(en) != 1)
|
||||||
en = current_module->ReduceBool(NEW_ID, en);
|
en = current_module->ReduceBool(NEW_ID, en);
|
||||||
|
|
||||||
|
IdString cellname;
|
||||||
|
if (str.empty()) {
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||||
|
cellname = sstr.str();
|
||||||
|
} else {
|
||||||
|
cellname = str;
|
||||||
|
}
|
||||||
|
|
||||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype);
|
RTLIL::Cell *cell = current_module->addCell(cellname, celltype);
|
||||||
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
|
||||||
|
|
||||||
for (auto &attr : attributes) {
|
for (auto &attr : attributes) {
|
||||||
|
|
|
@ -50,7 +50,6 @@ using namespace AST_INTERNAL;
|
||||||
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
|
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
|
||||||
{
|
{
|
||||||
static int recursion_counter = 0;
|
static int recursion_counter = 0;
|
||||||
static pair<string, int> last_blocking_assignment_warn;
|
|
||||||
static bool deep_recursion_warning = false;
|
static bool deep_recursion_warning = false;
|
||||||
|
|
||||||
if (recursion_counter++ == 1000 && deep_recursion_warning) {
|
if (recursion_counter++ == 1000 && deep_recursion_warning) {
|
||||||
|
@ -72,7 +71,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
if (stage == 0)
|
if (stage == 0)
|
||||||
{
|
{
|
||||||
log_assert(type == AST_MODULE || type == AST_INTERFACE);
|
log_assert(type == AST_MODULE || type == AST_INTERFACE);
|
||||||
last_blocking_assignment_warn = pair<string, int>();
|
|
||||||
|
|
||||||
deep_recursion_warning = true;
|
deep_recursion_warning = true;
|
||||||
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
|
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
|
||||||
|
@ -140,9 +138,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
int mem_width, mem_size, addr_bits;
|
int mem_width, mem_size, addr_bits;
|
||||||
node->meminfo(mem_width, mem_size, addr_bits);
|
node->meminfo(mem_width, mem_size, addr_bits);
|
||||||
|
|
||||||
|
int data_range_left = node->children[0]->range_left;
|
||||||
|
int data_range_right = node->children[0]->range_right;
|
||||||
|
|
||||||
|
if (node->children[0]->range_swapped)
|
||||||
|
std::swap(data_range_left, data_range_right);
|
||||||
|
|
||||||
for (int i = 0; i < mem_size; i++) {
|
for (int i = 0; i < mem_size; i++) {
|
||||||
AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
|
AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
|
||||||
mkconst_int(mem_width-1, true), mkconst_int(0, true)));
|
mkconst_int(data_range_left, true), mkconst_int(data_range_right, true)));
|
||||||
reg->str = stringf("%s[%d]", node->str.c_str(), i);
|
reg->str = stringf("%s[%d]", node->str.c_str(), i);
|
||||||
reg->is_reg = true;
|
reg->is_reg = true;
|
||||||
reg->is_signed = node->is_signed;
|
reg->is_signed = node->is_signed;
|
||||||
|
@ -978,6 +982,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
int data_range_left = id2ast->children[0]->range_left;
|
int data_range_left = id2ast->children[0]->range_left;
|
||||||
int data_range_right = id2ast->children[0]->range_right;
|
int data_range_right = id2ast->children[0]->range_right;
|
||||||
|
|
||||||
|
if (id2ast->children[0]->range_swapped)
|
||||||
|
std::swap(data_range_left, data_range_right);
|
||||||
|
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||||
std::string wire_id = sstr.str();
|
std::string wire_id = sstr.str();
|
||||||
|
@ -1511,6 +1518,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
newNode->children.push_back(assign_en);
|
newNode->children.push_back(assign_en);
|
||||||
|
|
||||||
AstNode *assertnode = new AstNode(type);
|
AstNode *assertnode = new AstNode(type);
|
||||||
|
assertnode->str = str;
|
||||||
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
|
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||||
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
|
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||||
assertnode->children[0]->str = id_check;
|
assertnode->children[0]->str = id_check;
|
||||||
|
@ -1591,14 +1599,6 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||||
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
|
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
|
||||||
|
|
||||||
if (type == AST_ASSIGN_EQ) {
|
|
||||||
pair<string, int> this_blocking_assignment_warn(filename, linenum);
|
|
||||||
if (this_blocking_assignment_warn != last_blocking_assignment_warn)
|
|
||||||
log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
|
|
||||||
filename.c_str(), linenum);
|
|
||||||
last_blocking_assignment_warn = this_blocking_assignment_warn;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mem_width, mem_size, addr_bits;
|
int mem_width, mem_size, addr_bits;
|
||||||
bool mem_signed = children[0]->id2ast->is_signed;
|
bool mem_signed = children[0]->id2ast->is_signed;
|
||||||
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
|
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
|
||||||
|
@ -2224,6 +2224,8 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
std::map<std::string, std::string> replace_rules;
|
std::map<std::string, std::string> replace_rules;
|
||||||
vector<AstNode*> added_mod_children;
|
vector<AstNode*> added_mod_children;
|
||||||
dict<std::string, AstNode*> wire_cache;
|
dict<std::string, AstNode*> wire_cache;
|
||||||
|
vector<AstNode*> new_stmts;
|
||||||
|
vector<AstNode*> output_assignments;
|
||||||
|
|
||||||
if (current_block == NULL)
|
if (current_block == NULL)
|
||||||
{
|
{
|
||||||
|
@ -2348,7 +2350,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
wire->port_id = 0;
|
wire->port_id = 0;
|
||||||
wire->is_input = false;
|
wire->is_input = false;
|
||||||
wire->is_output = false;
|
wire->is_output = false;
|
||||||
if (!child->is_output)
|
wire->is_reg = true;
|
||||||
wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||||
wire_cache[child->str] = wire;
|
wire_cache[child->str] = wire;
|
||||||
|
|
||||||
|
@ -2371,13 +2373,10 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
|
new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
|
||||||
new AstNode(AST_ASSIGN_EQ, arg, wire_id);
|
new AstNode(AST_ASSIGN_EQ, arg, wire_id);
|
||||||
assign->children[0]->was_checked = true;
|
assign->children[0]->was_checked = true;
|
||||||
|
if (child->is_input)
|
||||||
for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
|
new_stmts.push_back(assign);
|
||||||
if (*it != current_block_child)
|
else
|
||||||
continue;
|
output_assignments.push_back(assign);
|
||||||
current_block->children.insert(it, assign);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2391,11 +2390,15 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
{
|
{
|
||||||
AstNode *stmt = child->clone();
|
AstNode *stmt = child->clone();
|
||||||
stmt->replace_ids(prefix, replace_rules);
|
stmt->replace_ids(prefix, replace_rules);
|
||||||
|
new_stmts.push_back(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
|
new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end());
|
||||||
if (*it != current_block_child)
|
|
||||||
continue;
|
for (auto it = current_block->children.begin(); ; it++) {
|
||||||
current_block->children.insert(it, stmt);
|
log_assert(it != current_block->children.end());
|
||||||
|
if (*it == current_block_child) {
|
||||||
|
current_block->children.insert(it, new_stmts.begin(), new_stmts.end());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2869,7 +2872,11 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
|
||||||
|
|
||||||
for (size_t i = 0; i < children.size(); i++) {
|
for (size_t i = 0; i < children.size(); i++) {
|
||||||
AstNode *child = children[i];
|
AstNode *child = children[i];
|
||||||
if (child->type != AST_FUNCTION && child->type != AST_TASK && child->type != AST_PREFIX)
|
// AST_PREFIX member names should not be prefixed; a nested AST_PREFIX
|
||||||
|
// still needs to recursed-into
|
||||||
|
if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER)
|
||||||
|
continue;
|
||||||
|
if (child->type != AST_FUNCTION && child->type != AST_TASK)
|
||||||
child->expand_genblock(index_var, prefix, name_map);
|
child->expand_genblock(index_var, prefix, name_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2924,7 +2931,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
|
||||||
dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
|
dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
|
||||||
{
|
{
|
||||||
uint32_t children_flags = 0;
|
uint32_t children_flags = 0;
|
||||||
int ignore_children_counter = 0;
|
int lhs_children_counter = 0;
|
||||||
|
|
||||||
if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
|
if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
|
||||||
{
|
{
|
||||||
|
@ -2950,13 +2957,15 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
|
||||||
proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
|
proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember if this is a constant index or not
|
// for proper (non-init) writes: remember if this is a constant index or not
|
||||||
|
if ((flags & MEM2REG_FL_INIT) == 0) {
|
||||||
if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) {
|
if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) {
|
||||||
if (children[0]->children[0]->children[0]->type == AST_CONSTANT)
|
if (children[0]->children[0]->children[0]->type == AST_CONSTANT)
|
||||||
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS;
|
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS;
|
||||||
else
|
else
|
||||||
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS;
|
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// remember where this is
|
// remember where this is
|
||||||
if (flags & MEM2REG_FL_INIT) {
|
if (flags & MEM2REG_FL_INIT) {
|
||||||
|
@ -2970,7 +2979,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ignore_children_counter = 1;
|
lhs_children_counter = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY)
|
if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY)
|
||||||
|
@ -3013,12 +3022,23 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
|
||||||
log_assert((flags & ~0x000000ff) == 0);
|
log_assert((flags & ~0x000000ff) == 0);
|
||||||
|
|
||||||
for (auto child : children)
|
for (auto child : children)
|
||||||
if (ignore_children_counter > 0)
|
{
|
||||||
ignore_children_counter--;
|
if (lhs_children_counter > 0) {
|
||||||
else if (proc_flags_p)
|
lhs_children_counter--;
|
||||||
|
if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) {
|
||||||
|
for (auto c : child->children[0]->children) {
|
||||||
|
if (proc_flags_p)
|
||||||
|
c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
|
||||||
|
else
|
||||||
|
c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
if (proc_flags_p)
|
||||||
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
|
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
|
||||||
else
|
else
|
||||||
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
|
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
|
||||||
|
}
|
||||||
|
|
||||||
flags &= ~children_flags | backup_flags;
|
flags &= ~children_flags | backup_flags;
|
||||||
|
|
||||||
|
|
|
@ -584,7 +584,7 @@ struct BlifFrontend : public Frontend {
|
||||||
{
|
{
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" read_blif [filename]\n");
|
log(" read_blif [options] [filename]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Load modules from a BLIF file into the current design.\n");
|
log("Load modules from a BLIF file into the current design.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
|
|
@ -21,7 +21,7 @@ Then run in the following command in this directory:
|
||||||
|
|
||||||
sby -f example.sby
|
sby -f example.sby
|
||||||
|
|
||||||
This will generate approximately one page of text outpout. The last lines
|
This will generate approximately one page of text output. The last lines
|
||||||
should be something like this:
|
should be something like this:
|
||||||
|
|
||||||
SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0)
|
SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0)
|
||||||
|
|
|
@ -1619,30 +1619,35 @@ struct VerificExtNets
|
||||||
int portname_cnt = 0;
|
int portname_cnt = 0;
|
||||||
|
|
||||||
// a map from Net to the same Net one level up in the design hierarchy
|
// a map from Net to the same Net one level up in the design hierarchy
|
||||||
std::map<Net*, Net*> net_level_up;
|
std::map<Net*, Net*> net_level_up_drive_up;
|
||||||
|
std::map<Net*, Net*> net_level_up_drive_down;
|
||||||
|
|
||||||
Net *get_net_level_up(Net *net)
|
Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr)
|
||||||
{
|
{
|
||||||
|
auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down;
|
||||||
|
|
||||||
if (net_level_up.count(net) == 0)
|
if (net_level_up.count(net) == 0)
|
||||||
{
|
{
|
||||||
Netlist *nl = net->Owner();
|
Netlist *nl = net->Owner();
|
||||||
|
|
||||||
// Simply return if Netlist is not unique
|
// Simply return if Netlist is not unique
|
||||||
if (nl->NumOfRefs() != 1)
|
log_assert(nl->NumOfRefs() == 1);
|
||||||
return net;
|
|
||||||
|
|
||||||
Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
|
Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
|
||||||
Netlist *up_nl = up_inst->Owner();
|
Netlist *up_nl = up_inst->Owner();
|
||||||
|
|
||||||
// create new Port
|
// create new Port
|
||||||
string name = stringf("___extnets_%d", portname_cnt++);
|
string name = stringf("___extnets_%d", portname_cnt++);
|
||||||
Port *new_port = new Port(name.c_str(), DIR_OUT);
|
Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN);
|
||||||
nl->Add(new_port);
|
nl->Add(new_port);
|
||||||
net->Connect(new_port);
|
net->Connect(new_port);
|
||||||
|
|
||||||
// create new Net in up Netlist
|
// create new Net in up Netlist
|
||||||
Net *new_net = new Net(name.c_str());
|
Net *new_net = final_net;
|
||||||
|
if (new_net == nullptr || new_net->Owner() != up_nl) {
|
||||||
|
new_net = new Net(name.c_str());
|
||||||
up_nl->Add(new_net);
|
up_nl->Add(new_net);
|
||||||
|
}
|
||||||
up_inst->Connect(new_port, new_net);
|
up_inst->Connect(new_port, new_net);
|
||||||
|
|
||||||
net_level_up[net] = new_net;
|
net_level_up[net] = new_net;
|
||||||
|
@ -1651,6 +1656,39 @@ struct VerificExtNets
|
||||||
return net_level_up.at(net);
|
return net_level_up.at(net);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr)
|
||||||
|
{
|
||||||
|
while (net->Owner() != dest)
|
||||||
|
net = route_up(net, drive_up, final_net);
|
||||||
|
if (final_net != nullptr)
|
||||||
|
log_assert(net == final_net);
|
||||||
|
return net;
|
||||||
|
}
|
||||||
|
|
||||||
|
Netlist *find_common_ancestor(Netlist *A, Netlist *B)
|
||||||
|
{
|
||||||
|
std::set<Netlist*> ancestors_of_A;
|
||||||
|
|
||||||
|
Netlist *cursor = A;
|
||||||
|
while (1) {
|
||||||
|
ancestors_of_A.insert(cursor);
|
||||||
|
if (cursor->NumOfRefs() != 1)
|
||||||
|
break;
|
||||||
|
cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = B;
|
||||||
|
while (1) {
|
||||||
|
if (ancestors_of_A.count(cursor))
|
||||||
|
return cursor;
|
||||||
|
if (cursor->NumOfRefs() != 1)
|
||||||
|
break;
|
||||||
|
cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void run(Netlist *nl)
|
void run(Netlist *nl)
|
||||||
{
|
{
|
||||||
MapIter mi, mi2;
|
MapIter mi, mi2;
|
||||||
|
@ -1674,19 +1712,37 @@ struct VerificExtNets
|
||||||
if (verific_verbose)
|
if (verific_verbose)
|
||||||
log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
|
log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
|
||||||
|
|
||||||
while (net->IsExternalTo(nl))
|
Netlist *ext_nl = net->Owner();
|
||||||
{
|
|
||||||
Net *newnet = get_net_level_up(net);
|
|
||||||
if (newnet == net) break;
|
|
||||||
|
|
||||||
if (verific_verbose)
|
if (verific_verbose)
|
||||||
log(" external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name());
|
log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str());
|
||||||
net = newnet;
|
|
||||||
|
Netlist *ca_nl = find_common_ancestor(nl, ext_nl);
|
||||||
|
|
||||||
|
if (verific_verbose)
|
||||||
|
log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str());
|
||||||
|
|
||||||
|
Net *ca_net = route_up(net, !port->IsOutput(), ca_nl);
|
||||||
|
Net *new_net = ca_net;
|
||||||
|
|
||||||
|
if (ca_nl != nl)
|
||||||
|
{
|
||||||
|
if (verific_verbose)
|
||||||
|
log(" net in common ancestor: %s\n", ca_net->Name());
|
||||||
|
|
||||||
|
string name = stringf("___extnets_%d", portname_cnt++);
|
||||||
|
new_net = new Net(name.c_str());
|
||||||
|
nl->Add(new_net);
|
||||||
|
|
||||||
|
Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
|
||||||
|
log_assert(n == ca_net);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verific_verbose)
|
if (verific_verbose)
|
||||||
log(" final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : "");
|
log(" new local net: %s\n", new_net->Name());
|
||||||
todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net));
|
|
||||||
|
log_assert(!new_net->IsExternalTo(nl));
|
||||||
|
todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, new_net));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it : todo_connect) {
|
for (auto it : todo_connect) {
|
||||||
|
@ -1855,6 +1911,13 @@ struct VerificPass : public Pass {
|
||||||
log(" -autocover\n");
|
log(" -autocover\n");
|
||||||
log(" Generate automatic cover statements for all asserts\n");
|
log(" Generate automatic cover statements for all asserts\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -chparam name value \n");
|
||||||
|
log(" Elaborate the specified top modules (all modules when -all given) using\n");
|
||||||
|
log(" this parameter value. Modules on which this parameter does not exist will\n");
|
||||||
|
log(" cause Verific to produce a VERI-1928 or VHDL-1676 message. This option\n");
|
||||||
|
log(" can be specified multiple times to override multiple parameters.\n");
|
||||||
|
log(" String values must be passed in double quotes (\").\n");
|
||||||
|
log("\n");
|
||||||
log(" -v, -vv\n");
|
log(" -v, -vv\n");
|
||||||
log(" Verbose log messages. (-vv is even more verbose than -v.)\n");
|
log(" Verbose log messages. (-vv is even more verbose than -v.)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -2109,6 +2172,7 @@ struct VerificPass : public Pass {
|
||||||
bool mode_autocover = false;
|
bool mode_autocover = false;
|
||||||
bool flatten = false, extnets = false;
|
bool flatten = false, extnets = false;
|
||||||
string dumpfile;
|
string dumpfile;
|
||||||
|
Map parameters(STRING_HASH);
|
||||||
|
|
||||||
for (argidx++; argidx < GetSize(args); argidx++) {
|
for (argidx++; argidx < GetSize(args); argidx++) {
|
||||||
if (args[argidx] == "-all") {
|
if (args[argidx] == "-all") {
|
||||||
|
@ -2147,6 +2211,15 @@ struct VerificPass : public Pass {
|
||||||
mode_autocover = true;
|
mode_autocover = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
|
||||||
|
const std::string &key = args[++argidx];
|
||||||
|
const std::string &value = args[++argidx];
|
||||||
|
unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
|
||||||
|
1 /* force_overwrite */);
|
||||||
|
if (!new_insertion)
|
||||||
|
log_warning_noprefix("-chparam %s already specified: overwriting.\n", key.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-V") {
|
if (args[argidx] == "-V") {
|
||||||
mode_verific = true;
|
mode_verific = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -2180,7 +2253,7 @@ struct VerificPass : public Pass {
|
||||||
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
|
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
|
||||||
if (veri_lib) veri_libs.InsertLast(veri_lib);
|
if (veri_lib) veri_libs.InsertLast(veri_lib);
|
||||||
|
|
||||||
Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
|
Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, ¶meters);
|
||||||
Netlist *nl;
|
Netlist *nl;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -2217,7 +2290,7 @@ struct VerificPass : public Pass {
|
||||||
}
|
}
|
||||||
|
|
||||||
log("Running hier_tree::Elaborate().\n");
|
log("Running hier_tree::Elaborate().\n");
|
||||||
Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units);
|
Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters);
|
||||||
Netlist *nl;
|
Netlist *nl;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -2313,21 +2386,43 @@ struct ReadPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Add directory to global Verilog/SystemVerilog include directories.\n");
|
log("Add directory to global Verilog/SystemVerilog include directories.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("\n");
|
||||||
|
log(" read -verific\n");
|
||||||
|
log(" read -noverific\n");
|
||||||
|
log("\n");
|
||||||
|
log("Subsequent calls to 'read' will either use or not use Verific. Calling 'read'\n");
|
||||||
|
log("with -verific will result in an error on Yosys binaries that are built without\n");
|
||||||
|
log("Verific support. The default is to use Verific if it is available.\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
#ifdef YOSYS_ENABLE_VERIFIC
|
||||||
|
static bool verific_available = !check_noverific_env();
|
||||||
|
#else
|
||||||
|
static bool verific_available = false;
|
||||||
|
#endif
|
||||||
|
static bool use_verific = verific_available;
|
||||||
|
|
||||||
if (args.size() < 2 || args[1][0] != '-')
|
if (args.size() < 2 || args[1][0] != '-')
|
||||||
log_cmd_error("Missing mode parameter.\n");
|
log_cmd_error("Missing mode parameter.\n");
|
||||||
|
|
||||||
|
if (args[1] == "-verific" || args[1] == "-noverific") {
|
||||||
|
if (args.size() != 2)
|
||||||
|
log_cmd_error("Additional arguments to -verific/-noverific.\n");
|
||||||
|
if (args[1] == "-verific") {
|
||||||
|
if (!verific_available)
|
||||||
|
log_cmd_error("This version of Yosys is built without Verific support.\n");
|
||||||
|
use_verific = true;
|
||||||
|
} else {
|
||||||
|
use_verific = false;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (args.size() < 3)
|
if (args.size() < 3)
|
||||||
log_cmd_error("Missing file name parameter.\n");
|
log_cmd_error("Missing file name parameter.\n");
|
||||||
|
|
||||||
#ifdef YOSYS_ENABLE_VERIFIC
|
|
||||||
bool use_verific = !check_noverific_env();
|
|
||||||
#else
|
|
||||||
bool use_verific = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (args[1] == "-vlog95" || args[1] == "-vlog2k") {
|
if (args[1] == "-vlog95" || args[1] == "-vlog2k") {
|
||||||
if (use_verific) {
|
if (use_verific) {
|
||||||
args[0] = "verific";
|
args[0] = "verific";
|
||||||
|
|
|
@ -1666,7 +1666,20 @@ struct VerificSvaImporter
|
||||||
log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(),
|
log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(),
|
||||||
LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile()));
|
LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile()));
|
||||||
|
|
||||||
RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID);
|
bool is_user_declared = root->IsUserDeclared();
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
if (!is_user_declared) {
|
||||||
|
const char *name = root->Name();
|
||||||
|
for (int i = 0; name[i]; i++) {
|
||||||
|
if (i ? (name[i] < '0' || name[i] > '9') : (name[i] != 'i')) {
|
||||||
|
is_user_declared = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RTLIL::IdString root_name = module->uniquify(importer->mode_names || is_user_declared ? RTLIL::escape_id(root->Name()) : NEW_ID);
|
||||||
|
|
||||||
// parse SVA sequence into trigger signal
|
// parse SVA sequence into trigger signal
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
|
||||||
$(Q) mkdir -p $(dir $@)
|
$(Q) mkdir -p $(dir $@)
|
||||||
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
|
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
|
||||||
|
|
||||||
|
frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=100000
|
||||||
|
|
||||||
OBJS += frontends/verilog/verilog_parser.tab.o
|
OBJS += frontends/verilog/verilog_parser.tab.o
|
||||||
OBJS += frontends/verilog/verilog_lexer.o
|
OBJS += frontends/verilog/verilog_lexer.o
|
||||||
OBJS += frontends/verilog/preproc.o
|
OBJS += frontends/verilog/preproc.o
|
||||||
|
|
|
@ -81,6 +81,9 @@ struct VerilogFrontend : public Frontend {
|
||||||
log(" -assert-assumes\n");
|
log(" -assert-assumes\n");
|
||||||
log(" treat all assume() statements like assert() statements\n");
|
log(" treat all assume() statements like assert() statements\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -debug\n");
|
||||||
|
log(" alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug\n");
|
||||||
|
log("\n");
|
||||||
log(" -dump_ast1\n");
|
log(" -dump_ast1\n");
|
||||||
log(" dump abstract syntax tree (before simplification)\n");
|
log(" dump abstract syntax tree (before simplification)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -90,7 +93,10 @@ struct VerilogFrontend : public Frontend {
|
||||||
log(" -no_dump_ptr\n");
|
log(" -no_dump_ptr\n");
|
||||||
log(" do not include hex memory addresses in dump (easier to diff dumps)\n");
|
log(" do not include hex memory addresses in dump (easier to diff dumps)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -dump_vlog\n");
|
log(" -dump_vlog1\n");
|
||||||
|
log(" dump ast as Verilog code (before simplification)\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -dump_vlog2\n");
|
||||||
log(" dump ast as Verilog code (after simplification)\n");
|
log(" dump ast as Verilog code (after simplification)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" -dump_rtlil\n");
|
log(" -dump_rtlil\n");
|
||||||
|
@ -197,7 +203,8 @@ struct VerilogFrontend : public Frontend {
|
||||||
bool flag_dump_ast1 = false;
|
bool flag_dump_ast1 = false;
|
||||||
bool flag_dump_ast2 = false;
|
bool flag_dump_ast2 = false;
|
||||||
bool flag_no_dump_ptr = false;
|
bool flag_no_dump_ptr = false;
|
||||||
bool flag_dump_vlog = false;
|
bool flag_dump_vlog1 = false;
|
||||||
|
bool flag_dump_vlog2 = false;
|
||||||
bool flag_dump_rtlil = false;
|
bool flag_dump_rtlil = false;
|
||||||
bool flag_nolatches = false;
|
bool flag_nolatches = false;
|
||||||
bool flag_nomeminit = false;
|
bool flag_nomeminit = false;
|
||||||
|
@ -258,6 +265,14 @@ struct VerilogFrontend : public Frontend {
|
||||||
assert_assumes_mode = true;
|
assert_assumes_mode = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-debug") {
|
||||||
|
flag_dump_ast1 = true;
|
||||||
|
flag_dump_ast2 = true;
|
||||||
|
flag_dump_vlog1 = true;
|
||||||
|
flag_dump_vlog2 = true;
|
||||||
|
frontend_verilog_yydebug = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg == "-dump_ast1") {
|
if (arg == "-dump_ast1") {
|
||||||
flag_dump_ast1 = true;
|
flag_dump_ast1 = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -270,8 +285,12 @@ struct VerilogFrontend : public Frontend {
|
||||||
flag_no_dump_ptr = true;
|
flag_no_dump_ptr = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (arg == "-dump_vlog") {
|
if (arg == "-dump_vlog1") {
|
||||||
flag_dump_vlog = true;
|
flag_dump_vlog1 = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arg == "-dump_vlog2") {
|
||||||
|
flag_dump_vlog2 = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (arg == "-dump_rtlil") {
|
if (arg == "-dump_rtlil") {
|
||||||
|
@ -410,7 +429,7 @@ struct VerilogFrontend : public Frontend {
|
||||||
if (flag_nodpi)
|
if (flag_nodpi)
|
||||||
error_on_dpi_function(current_ast);
|
error_on_dpi_function(current_ast);
|
||||||
|
|
||||||
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
|
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
|
||||||
|
|
||||||
if (!flag_nopp)
|
if (!flag_nopp)
|
||||||
delete lexin;
|
delete lexin;
|
||||||
|
|
|
@ -189,6 +189,14 @@ YOSYS_NAMESPACE_END
|
||||||
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
|
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
|
||||||
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
|
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
|
||||||
|
|
||||||
|
/* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
|
||||||
|
to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
|
||||||
|
global state.. its a mess) */
|
||||||
|
[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] {
|
||||||
|
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
|
||||||
|
return TOK_SVA_LABEL;
|
||||||
|
}
|
||||||
|
|
||||||
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
|
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
|
||||||
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
|
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
|
||||||
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
|
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
|
||||||
|
|
|
@ -105,7 +105,8 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
||||||
bool boolean;
|
bool boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
|
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
|
||||||
|
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
|
||||||
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
||||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||||
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
|
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
|
||||||
|
@ -119,14 +120,13 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
||||||
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
|
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
|
||||||
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
||||||
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
|
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
|
||||||
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
|
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
|
||||||
%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
|
|
||||||
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
|
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
|
||||||
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
|
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
|
||||||
|
|
||||||
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
|
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
|
||||||
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
|
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
|
||||||
%type <string> opt_label tok_prim_wrapper hierarchical_id
|
%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id
|
||||||
%type <boolean> opt_signed opt_property unique_case_attr
|
%type <boolean> opt_signed opt_property unique_case_attr
|
||||||
%type <al> attr case_attr
|
%type <al> attr case_attr
|
||||||
|
|
||||||
|
@ -1329,6 +1329,14 @@ opt_label:
|
||||||
$$ = NULL;
|
$$ = NULL;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
opt_sva_label:
|
||||||
|
TOK_SVA_LABEL ':' {
|
||||||
|
$$ = $1;
|
||||||
|
} |
|
||||||
|
/* empty */ {
|
||||||
|
$$ = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
opt_property:
|
opt_property:
|
||||||
TOK_PROPERTY {
|
TOK_PROPERTY {
|
||||||
$$ = true;
|
$$ = true;
|
||||||
|
@ -1337,9 +1345,6 @@ opt_property:
|
||||||
$$ = false;
|
$$ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
opt_stmt_label:
|
|
||||||
TOK_ID ':' | /* empty */;
|
|
||||||
|
|
||||||
modport_stmt:
|
modport_stmt:
|
||||||
TOK_MODPORT TOK_ID {
|
TOK_MODPORT TOK_ID {
|
||||||
AstNode *modport = new AstNode(AST_MODPORT);
|
AstNode *modport = new AstNode(AST_MODPORT);
|
||||||
|
@ -1376,83 +1381,164 @@ modport_type_token:
|
||||||
TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
|
TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
|
||||||
|
|
||||||
assert:
|
assert:
|
||||||
opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
|
opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' {
|
||||||
if (noassert_mode)
|
if (noassert_mode) {
|
||||||
delete $5;
|
delete $5;
|
||||||
else
|
} else {
|
||||||
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
|
AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
|
||||||
|
if ($1 != nullptr)
|
||||||
|
node->str = *$1;
|
||||||
|
ast_stack.back()->children.push_back(node);
|
||||||
|
}
|
||||||
|
if ($1 != nullptr)
|
||||||
|
delete $1;
|
||||||
} |
|
} |
|
||||||
opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' {
|
opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' {
|
||||||
if (noassume_mode)
|
if (noassume_mode) {
|
||||||
delete $5;
|
delete $5;
|
||||||
else
|
} else {
|
||||||
ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5));
|
AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);
|
||||||
|
if ($1 != nullptr)
|
||||||
|
node->str = *$1;
|
||||||
|
ast_stack.back()->children.push_back(node);
|
||||||
|
}
|
||||||
|
if ($1 != nullptr)
|
||||||
|
delete $1;
|
||||||
} |
|
} |
|
||||||
opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
||||||
if (noassert_mode)
|
if (noassert_mode) {
|
||||||
delete $6;
|
delete $6;
|
||||||
else
|
} else {
|
||||||
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
|
AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
|
||||||
|
if ($1 != nullptr)
|
||||||
|
node->str = *$1;
|
||||||
|
ast_stack.back()->children.push_back(node);
|
||||||
|
}
|
||||||
|
if ($1 != nullptr)
|
||||||
|
delete $1;
|
||||||
} |
|
} |
|
||||||
opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
||||||
if (noassume_mode)
|
if (noassume_mode) {
|
||||||
delete $6;
|
delete $6;
|
||||||
else
|
} else {
|
||||||
ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6));
|
AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6);
|
||||||
|
if ($1 != nullptr)
|
||||||
|
node->str = *$1;
|
||||||
|
ast_stack.back()->children.push_back(node);
|
||||||
|
}
|
||||||
|
if ($1 != nullptr)
|
||||||
|
delete $1;
|
||||||
} |
|
} |
|
||||||
opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' {
|
opt_sva_label TOK_COVER opt_property '(' expr ')' ';' {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
|
AstNode *node = new AstNode(AST_COVER, $5);
|
||||||
|
if ($1 != nullptr) {
|
||||||
|
node->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
}
|
||||||
|
ast_stack.back()->children.push_back(node);
|
||||||
} |
|
} |
|
||||||
opt_stmt_label TOK_COVER opt_property '(' ')' ';' {
|
opt_sva_label TOK_COVER opt_property '(' ')' ';' {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
|
AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
|
||||||
|
if ($1 != nullptr) {
|
||||||
|
node->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
}
|
||||||
|
ast_stack.back()->children.push_back(node);
|
||||||
} |
|
} |
|
||||||
opt_stmt_label TOK_COVER ';' {
|
opt_sva_label TOK_COVER ';' {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
|
AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
|
||||||
|
if ($1 != nullptr) {
|
||||||
|
node->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
}
|
||||||
|
ast_stack.back()->children.push_back(node);
|
||||||
} |
|
} |
|
||||||
opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' {
|
opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' {
|
||||||
if (norestrict_mode)
|
if (norestrict_mode) {
|
||||||
delete $5;
|
delete $5;
|
||||||
else
|
} else {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
|
AstNode *node = new AstNode(AST_ASSUME, $5);
|
||||||
|
if ($1 != nullptr)
|
||||||
|
node->str = *$1;
|
||||||
|
ast_stack.back()->children.push_back(node);
|
||||||
|
}
|
||||||
if (!$3)
|
if (!$3)
|
||||||
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
|
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
|
||||||
|
if ($1 != nullptr)
|
||||||
|
delete $1;
|
||||||
} |
|
} |
|
||||||
opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
|
||||||
if (norestrict_mode)
|
if (norestrict_mode) {
|
||||||
delete $6;
|
delete $6;
|
||||||
else
|
} else {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
|
AstNode *node = new AstNode(AST_FAIR, $6);
|
||||||
|
if ($1 != nullptr)
|
||||||
|
node->str = *$1;
|
||||||
|
ast_stack.back()->children.push_back(node);
|
||||||
|
}
|
||||||
if (!$3)
|
if (!$3)
|
||||||
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
|
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
|
||||||
|
if ($1 != nullptr)
|
||||||
|
delete $1;
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_property:
|
assert_property:
|
||||||
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
|
opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
|
||||||
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4));
|
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
|
||||||
|
if ($1 != nullptr) {
|
||||||
|
ast_stack.back()->children.back()->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
}
|
||||||
} |
|
} |
|
||||||
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
|
opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
|
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
|
||||||
|
if ($1 != nullptr) {
|
||||||
|
ast_stack.back()->children.back()->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
}
|
||||||
} |
|
} |
|
||||||
TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
||||||
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5));
|
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
|
||||||
|
if ($1 != nullptr) {
|
||||||
|
ast_stack.back()->children.back()->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
}
|
||||||
} |
|
} |
|
||||||
TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
|
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
|
||||||
|
if ($1 != nullptr) {
|
||||||
|
ast_stack.back()->children.back()->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
}
|
||||||
} |
|
} |
|
||||||
TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
|
opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4));
|
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
|
||||||
|
if ($1 != nullptr) {
|
||||||
|
ast_stack.back()->children.back()->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
}
|
||||||
} |
|
} |
|
||||||
TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
|
opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
|
||||||
if (norestrict_mode)
|
if (norestrict_mode) {
|
||||||
delete $4;
|
|
||||||
else
|
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
|
|
||||||
} |
|
|
||||||
TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
|
||||||
if (norestrict_mode)
|
|
||||||
delete $5;
|
delete $5;
|
||||||
else
|
} else {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
|
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
|
||||||
|
if ($1 != nullptr) {
|
||||||
|
ast_stack.back()->children.back()->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} |
|
||||||
|
opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
|
||||||
|
if (norestrict_mode) {
|
||||||
|
delete $6;
|
||||||
|
} else {
|
||||||
|
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
|
||||||
|
if ($1 != nullptr) {
|
||||||
|
ast_stack.back()->children.back()->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
simple_behavioral_stmt:
|
simple_behavioral_stmt:
|
||||||
|
@ -1670,6 +1756,11 @@ case_expr_list:
|
||||||
TOK_DEFAULT {
|
TOK_DEFAULT {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));
|
ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));
|
||||||
} |
|
} |
|
||||||
|
TOK_SVA_LABEL {
|
||||||
|
ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER));
|
||||||
|
ast_stack.back()->children.back()->str = *$1;
|
||||||
|
delete $1;
|
||||||
|
} |
|
||||||
expr {
|
expr {
|
||||||
ast_stack.back()->children.push_back($1);
|
ast_stack.back()->children.push_back($1);
|
||||||
} |
|
} |
|
||||||
|
|
|
@ -81,6 +81,27 @@ struct CellTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_internals()
|
void setup_internals()
|
||||||
|
{
|
||||||
|
setup_internals_eval();
|
||||||
|
|
||||||
|
IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
|
||||||
|
|
||||||
|
setup_type("$tribuf", {A, EN}, {Y}, true);
|
||||||
|
|
||||||
|
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||||
|
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||||
|
setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||||
|
setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||||
|
setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||||
|
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
|
||||||
|
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
|
||||||
|
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
|
||||||
|
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
|
||||||
|
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
|
||||||
|
setup_type("$equiv", {A, B}, {Y}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_internals_eval()
|
||||||
{
|
{
|
||||||
std::vector<RTLIL::IdString> unary_ops = {
|
std::vector<RTLIL::IdString> unary_ops = {
|
||||||
"$not", "$pos", "$neg",
|
"$not", "$pos", "$neg",
|
||||||
|
@ -111,20 +132,6 @@ struct CellTypes
|
||||||
setup_type("$lcu", {P, G, CI}, {CO}, true);
|
setup_type("$lcu", {P, G, CI}, {CO}, true);
|
||||||
setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
|
setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
|
||||||
setup_type("$fa", {A, B, C}, {X, Y}, true);
|
setup_type("$fa", {A, B, C}, {X, Y}, true);
|
||||||
|
|
||||||
setup_type("$tribuf", {A, EN}, {Y}, true);
|
|
||||||
|
|
||||||
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
|
|
||||||
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
|
|
||||||
setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
|
|
||||||
setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
|
|
||||||
setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
|
|
||||||
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
|
|
||||||
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
|
|
||||||
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
|
|
||||||
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
|
|
||||||
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
|
|
||||||
setup_type("$equiv", {A, B}, {Y}, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_internals_mem()
|
void setup_internals_mem()
|
||||||
|
@ -153,6 +160,15 @@ struct CellTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_stdcells()
|
void setup_stdcells()
|
||||||
|
{
|
||||||
|
setup_stdcells_eval();
|
||||||
|
|
||||||
|
IdString A = "\\A", E = "\\E", Y = "\\Y";
|
||||||
|
|
||||||
|
setup_type("$_TBUF_", {A, E}, {Y}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_stdcells_eval()
|
||||||
{
|
{
|
||||||
IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D";
|
IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D";
|
||||||
IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H";
|
IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H";
|
||||||
|
@ -179,7 +195,6 @@ struct CellTypes
|
||||||
setup_type("$_OAI3_", {A, B, C}, {Y}, true);
|
setup_type("$_OAI3_", {A, B, C}, {Y}, true);
|
||||||
setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
|
setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
|
||||||
setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
|
setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
|
||||||
setup_type("$_TBUF_", {A, E}, {Y}, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_stdcells_mem()
|
void setup_stdcells_mem()
|
||||||
|
|
|
@ -557,9 +557,11 @@ public:
|
||||||
void clear() { hashtable.clear(); entries.clear(); }
|
void clear() { hashtable.clear(); entries.clear(); }
|
||||||
|
|
||||||
iterator begin() { return iterator(this, int(entries.size())-1); }
|
iterator begin() { return iterator(this, int(entries.size())-1); }
|
||||||
|
iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
|
||||||
iterator end() { return iterator(nullptr, -1); }
|
iterator end() { return iterator(nullptr, -1); }
|
||||||
|
|
||||||
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
|
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
|
||||||
|
const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
|
||||||
const_iterator end() const { return const_iterator(nullptr, -1); }
|
const_iterator end() const { return const_iterator(nullptr, -1); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -881,9 +883,11 @@ public:
|
||||||
void clear() { hashtable.clear(); entries.clear(); }
|
void clear() { hashtable.clear(); entries.clear(); }
|
||||||
|
|
||||||
iterator begin() { return iterator(this, int(entries.size())-1); }
|
iterator begin() { return iterator(this, int(entries.size())-1); }
|
||||||
|
iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
|
||||||
iterator end() { return iterator(nullptr, -1); }
|
iterator end() { return iterator(nullptr, -1); }
|
||||||
|
|
||||||
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
|
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
|
||||||
|
const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
|
||||||
const_iterator end() const { return const_iterator(nullptr, -1); }
|
const_iterator end() const { return const_iterator(nullptr, -1); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -952,6 +956,7 @@ public:
|
||||||
void clear() { database.clear(); }
|
void clear() { database.clear(); }
|
||||||
|
|
||||||
const_iterator begin() const { return database.begin(); }
|
const_iterator begin() const { return database.begin(); }
|
||||||
|
const_iterator element(int n) const { return database.element(n); }
|
||||||
const_iterator end() const { return database.end(); }
|
const_iterator end() const { return database.end(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1051,6 +1056,7 @@ public:
|
||||||
void clear() { database.clear(); parents.clear(); }
|
void clear() { database.clear(); parents.clear(); }
|
||||||
|
|
||||||
const_iterator begin() const { return database.begin(); }
|
const_iterator begin() const { return database.begin(); }
|
||||||
|
const_iterator element(int n) const { return database.element(n); }
|
||||||
const_iterator end() const { return database.end(); }
|
const_iterator end() const { return database.end(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,11 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap)
|
||||||
if (log_hdump.count(header_id) && design != nullptr)
|
if (log_hdump.count(header_id) && design != nullptr)
|
||||||
for (auto &filename : log_hdump.at(header_id)) {
|
for (auto &filename : log_hdump.at(header_id)) {
|
||||||
log("Dumping current design to '%s'.\n", filename.c_str());
|
log("Dumping current design to '%s'.\n", filename.c_str());
|
||||||
|
if (yosys_xtrace)
|
||||||
|
IdString::xtrace_db_dump();
|
||||||
Pass::call(design, {"dump", "-o", filename});
|
Pass::call(design, {"dump", "-o", filename});
|
||||||
|
if (yosys_xtrace)
|
||||||
|
log("#X# -- end of dump --\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pop_errfile)
|
if (pop_errfile)
|
||||||
|
|
|
@ -86,6 +86,8 @@ Pass::pre_post_exec_state_t Pass::pre_execute()
|
||||||
|
|
||||||
void Pass::post_execute(Pass::pre_post_exec_state_t state)
|
void Pass::post_execute(Pass::pre_post_exec_state_t state)
|
||||||
{
|
{
|
||||||
|
IdString::checkpoint();
|
||||||
|
|
||||||
int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
|
int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
|
||||||
runtime_ns += time_ns;
|
runtime_ns += time_ns;
|
||||||
current_pass = state.parent_pass;
|
current_pass = state.parent_pass;
|
||||||
|
|
|
@ -33,6 +33,8 @@ std::vector<int> RTLIL::IdString::global_refcount_storage_;
|
||||||
std::vector<char*> RTLIL::IdString::global_id_storage_;
|
std::vector<char*> RTLIL::IdString::global_id_storage_;
|
||||||
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
|
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
|
||||||
std::vector<int> RTLIL::IdString::global_free_idx_list_;
|
std::vector<int> RTLIL::IdString::global_free_idx_list_;
|
||||||
|
int RTLIL::IdString::last_created_idx_[8];
|
||||||
|
int RTLIL::IdString::last_created_idx_ptr_;
|
||||||
|
|
||||||
RTLIL::Const::Const()
|
RTLIL::Const::Const()
|
||||||
{
|
{
|
||||||
|
@ -758,7 +760,7 @@ namespace {
|
||||||
|
|
||||||
void check()
|
void check()
|
||||||
{
|
{
|
||||||
if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" ||
|
if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || cell->type.substr(0,10) == "$fmcombine" ||
|
||||||
cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
|
cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -2358,7 +2360,7 @@ void RTLIL::Cell::check()
|
||||||
|
|
||||||
void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
|
void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
|
||||||
{
|
{
|
||||||
if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" ||
|
if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || type.substr(0,10) == "$fmcombine" ||
|
||||||
type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
|
type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -3235,7 +3237,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed)
|
||||||
remove(width, width_ - width);
|
remove(width, width_ - width);
|
||||||
|
|
||||||
if (width_ < width) {
|
if (width_ < width) {
|
||||||
RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::S0;
|
RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx;
|
||||||
if (!is_signed)
|
if (!is_signed)
|
||||||
padding = RTLIL::State::S0;
|
padding = RTLIL::State::S0;
|
||||||
while (width_ < width)
|
while (width_ < width)
|
||||||
|
|
|
@ -76,6 +76,9 @@ namespace RTLIL
|
||||||
|
|
||||||
struct IdString
|
struct IdString
|
||||||
{
|
{
|
||||||
|
#undef YOSYS_XTRACE_GET_PUT
|
||||||
|
#undef YOSYS_SORT_ID_FREE_LIST
|
||||||
|
|
||||||
// the global id string cache
|
// the global id string cache
|
||||||
|
|
||||||
static struct destruct_guard_t {
|
static struct destruct_guard_t {
|
||||||
|
@ -89,9 +92,43 @@ namespace RTLIL
|
||||||
static dict<char*, int, hash_cstr_ops> global_id_index_;
|
static dict<char*, int, hash_cstr_ops> global_id_index_;
|
||||||
static std::vector<int> global_free_idx_list_;
|
static std::vector<int> global_free_idx_list_;
|
||||||
|
|
||||||
|
static int last_created_idx_ptr_;
|
||||||
|
static int last_created_idx_[8];
|
||||||
|
|
||||||
|
static inline void xtrace_db_dump()
|
||||||
|
{
|
||||||
|
#ifdef YOSYS_XTRACE_GET_PUT
|
||||||
|
for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
|
||||||
|
{
|
||||||
|
if (global_id_storage_.at(idx) == nullptr)
|
||||||
|
log("#X# DB-DUMP index %d: FREE\n", idx);
|
||||||
|
else
|
||||||
|
log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void checkpoint()
|
||||||
|
{
|
||||||
|
last_created_idx_ptr_ = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (last_created_idx_[i])
|
||||||
|
put_reference(last_created_idx_[i]);
|
||||||
|
last_created_idx_[i] = 0;
|
||||||
|
}
|
||||||
|
#ifdef YOSYS_SORT_ID_FREE_LIST
|
||||||
|
std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline int get_reference(int idx)
|
static inline int get_reference(int idx)
|
||||||
{
|
{
|
||||||
global_refcount_storage_.at(idx)++;
|
global_refcount_storage_.at(idx)++;
|
||||||
|
#ifdef YOSYS_XTRACE_GET_PUT
|
||||||
|
if (yosys_xtrace) {
|
||||||
|
log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +144,11 @@ namespace RTLIL
|
||||||
auto it = global_id_index_.find((char*)p);
|
auto it = global_id_index_.find((char*)p);
|
||||||
if (it != global_id_index_.end()) {
|
if (it != global_id_index_.end()) {
|
||||||
global_refcount_storage_.at(it->second)++;
|
global_refcount_storage_.at(it->second)++;
|
||||||
|
#ifdef YOSYS_XTRACE_GET_PUT
|
||||||
|
if (yosys_xtrace) {
|
||||||
|
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,16 +166,22 @@ namespace RTLIL
|
||||||
global_refcount_storage_.at(idx)++;
|
global_refcount_storage_.at(idx)++;
|
||||||
|
|
||||||
// Avoid Create->Delete->Create pattern
|
// Avoid Create->Delete->Create pattern
|
||||||
static IdString last_created_id;
|
if (last_created_idx_[last_created_idx_ptr_])
|
||||||
put_reference(last_created_id.index_);
|
put_reference(last_created_idx_[last_created_idx_ptr_]);
|
||||||
last_created_id.index_ = idx;
|
last_created_idx_[last_created_idx_ptr_] = idx;
|
||||||
get_reference(last_created_id.index_);
|
get_reference(last_created_idx_[last_created_idx_ptr_]);
|
||||||
|
last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
|
||||||
|
|
||||||
if (yosys_xtrace) {
|
if (yosys_xtrace) {
|
||||||
log("#X# New IdString '%s' with index %d.\n", p, idx);
|
log("#X# New IdString '%s' with index %d.\n", p, idx);
|
||||||
log_backtrace("-X- ", yosys_xtrace-1);
|
log_backtrace("-X- ", yosys_xtrace-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef YOSYS_XTRACE_GET_PUT
|
||||||
|
if (yosys_xtrace) {
|
||||||
|
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +192,12 @@ namespace RTLIL
|
||||||
if (!destruct_guard.ok)
|
if (!destruct_guard.ok)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef YOSYS_XTRACE_GET_PUT
|
||||||
|
if (yosys_xtrace) {
|
||||||
|
log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
log_assert(global_refcount_storage_.at(idx) > 0);
|
log_assert(global_refcount_storage_.at(idx) > 0);
|
||||||
|
|
||||||
if (--global_refcount_storage_.at(idx) != 0)
|
if (--global_refcount_storage_.at(idx) != 0)
|
||||||
|
@ -492,6 +546,14 @@ struct RTLIL::Const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void extu(int width) {
|
||||||
|
bits.resize(width, RTLIL::State::S0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exts(int width) {
|
||||||
|
bits.resize(width, bits.empty() ? RTLIL::State::Sx : bits.back());
|
||||||
|
}
|
||||||
|
|
||||||
inline unsigned int hash() const {
|
inline unsigned int hash() const {
|
||||||
unsigned int h = mkhash_init;
|
unsigned int h = mkhash_init;
|
||||||
for (auto b : bits)
|
for (auto b : bits)
|
||||||
|
@ -1282,7 +1344,7 @@ inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
|
||||||
return wire ? (offset < other.offset) : (data < other.data);
|
return wire ? (offset < other.offset) : (data < other.data);
|
||||||
if (wire != nullptr && other.wire != nullptr)
|
if (wire != nullptr && other.wire != nullptr)
|
||||||
return wire->name < other.wire->name;
|
return wire->name < other.wire->name;
|
||||||
return wire < other.wire;
|
return (wire != nullptr) < (other.wire != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
|
inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
# include <dlfcn.h>
|
# include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
|
@ -41,13 +41,15 @@
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# include <dirent.h>
|
# include <dirent.h>
|
||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
# include <glob.h>
|
|
||||||
#else
|
#else
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# include <dirent.h>
|
# include <dirent.h>
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <sys/wait.h>
|
# include <sys/wait.h>
|
||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB)
|
||||||
# include <glob.h>
|
# include <glob.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -216,12 +218,18 @@ std::string next_token(std::string &text, const char *sep, bool long_strings)
|
||||||
|
|
||||||
if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') {
|
if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') {
|
||||||
string sep_string = sep;
|
string sep_string = sep;
|
||||||
for (size_t i = pos_begin+1; i < text.size(); i++)
|
for (size_t i = pos_begin+1; i < text.size(); i++) {
|
||||||
if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) {
|
if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) {
|
||||||
std::string token = text.substr(pos_begin, i-pos_begin+1);
|
std::string token = text.substr(pos_begin, i-pos_begin+1);
|
||||||
text = text.substr(i+1);
|
text = text.substr(i+1);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) {
|
||||||
|
std::string token = text.substr(pos_begin, i-pos_begin+1);
|
||||||
|
text = text.substr(i+2);
|
||||||
|
return token + ";";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t pos_end = text.find_first_of(sep, pos_begin);
|
size_t pos_end = text.find_first_of(sep, pos_begin);
|
||||||
|
@ -564,7 +572,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern)
|
||||||
{
|
{
|
||||||
std::vector<std::string> results;
|
std::vector<std::string> results;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB)
|
||||||
results.push_back(filename_pattern);
|
results.push_back(filename_pattern);
|
||||||
#else
|
#else
|
||||||
glob_t globbuf;
|
glob_t globbuf;
|
||||||
|
|
|
@ -0,0 +1,358 @@
|
||||||
|
/* This file comes from the PyPA Setuptools repository, commit 16e452a:
|
||||||
|
https://github.com/pypa/setuptools
|
||||||
|
Modifications include this comment and inline inclusion of the LICENSE text. */
|
||||||
|
|
||||||
|
/* Copyright (C) 2016 Jason R Coombs <jaraco@jaraco.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE. */
|
||||||
|
|
||||||
|
/* Setuptools Script Launcher for Windows
|
||||||
|
|
||||||
|
This is a stub executable for Windows that functions somewhat like
|
||||||
|
Effbot's "exemaker", in that it runs a script with the same name but
|
||||||
|
a .py extension, using information from a #! line. It differs in that
|
||||||
|
it spawns the actual Python executable, rather than attempting to
|
||||||
|
hook into the Python DLL. This means that the script will run with
|
||||||
|
sys.executable set to the Python executable, where exemaker ends up with
|
||||||
|
sys.executable pointing to itself. (Which means it won't work if you try
|
||||||
|
to run another Python process using sys.executable.)
|
||||||
|
|
||||||
|
To build/rebuild with mingw32, do this in the setuptools project directory:
|
||||||
|
|
||||||
|
gcc -DGUI=0 -mno-cygwin -O -s -o setuptools/cli.exe launcher.c
|
||||||
|
gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c
|
||||||
|
|
||||||
|
To build for Windows RT, install both Visual Studio Express for Windows 8
|
||||||
|
and for Windows Desktop (both freeware), create "win32" application using
|
||||||
|
"Windows Desktop" version, create new "ARM" target via
|
||||||
|
"Configuration Manager" menu and modify ".vcxproj" file by adding
|
||||||
|
"<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>" tag
|
||||||
|
as child of "PropertyGroup" tags that has "Debug|ARM" and "Release|ARM"
|
||||||
|
properties.
|
||||||
|
|
||||||
|
It links to msvcrt.dll, but this shouldn't be a problem since it doesn't
|
||||||
|
actually run Python in the same process. Note that using 'exec' instead
|
||||||
|
of 'spawn' doesn't work, because on Windows this leads to the Python
|
||||||
|
executable running in the *background*, attached to the same console
|
||||||
|
window, meaning you get a command prompt back *before* Python even finishes
|
||||||
|
starting. So, we have to use spawnv() and wait for Python to exit before
|
||||||
|
continuing. :(
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
int child_pid=0;
|
||||||
|
|
||||||
|
int fail(char *format, char *data) {
|
||||||
|
/* Print error message to stderr and return 2 */
|
||||||
|
fprintf(stderr, format, data);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *quoted(char *data) {
|
||||||
|
int i, ln = strlen(data), nb;
|
||||||
|
|
||||||
|
/* We allocate twice as much space as needed to deal with worse-case
|
||||||
|
of having to escape everything. */
|
||||||
|
char *result = calloc(ln*2+3, sizeof(char));
|
||||||
|
char *presult = result;
|
||||||
|
|
||||||
|
*presult++ = '"';
|
||||||
|
for (nb=0, i=0; i < ln; i++)
|
||||||
|
{
|
||||||
|
if (data[i] == '\\')
|
||||||
|
nb += 1;
|
||||||
|
else if (data[i] == '"')
|
||||||
|
{
|
||||||
|
for (; nb > 0; nb--)
|
||||||
|
*presult++ = '\\';
|
||||||
|
*presult++ = '\\';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
nb = 0;
|
||||||
|
*presult++ = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; nb > 0; nb--) /* Deal w trailing slashes */
|
||||||
|
*presult++ = '\\';
|
||||||
|
|
||||||
|
*presult++ = '"';
|
||||||
|
*presult++ = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char *loadable_exe(char *exename) {
|
||||||
|
/* HINSTANCE hPython; DLL handle for python executable */
|
||||||
|
char *result;
|
||||||
|
|
||||||
|
/* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||||
|
if (!hPython) return NULL; */
|
||||||
|
|
||||||
|
/* Return the absolute filename for spawnv */
|
||||||
|
result = calloc(MAX_PATH, sizeof(char));
|
||||||
|
strncpy(result, exename, MAX_PATH);
|
||||||
|
/*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
|
||||||
|
|
||||||
|
FreeLibrary(hPython); */
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *find_exe(char *exename, char *script) {
|
||||||
|
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
|
||||||
|
char path[_MAX_PATH], c, *result;
|
||||||
|
|
||||||
|
/* convert slashes to backslashes for uniform search below */
|
||||||
|
result = exename;
|
||||||
|
while (c = *result++) if (c=='/') result[-1] = '\\';
|
||||||
|
|
||||||
|
_splitpath(exename, drive, dir, fname, ext);
|
||||||
|
if (drive[0] || dir[0]=='\\') {
|
||||||
|
return loadable_exe(exename); /* absolute path, use directly */
|
||||||
|
}
|
||||||
|
/* Use the script's parent directory, which should be the Python home
|
||||||
|
(This should only be used for bdist_wininst-installed scripts, because
|
||||||
|
easy_install-ed scripts use the absolute path to python[w].exe
|
||||||
|
*/
|
||||||
|
_splitpath(script, drive, dir, fname, ext);
|
||||||
|
result = dir + strlen(dir) -1;
|
||||||
|
if (*result == '\\') result--;
|
||||||
|
while (*result != '\\' && result>=dir) *result-- = 0;
|
||||||
|
_makepath(path, drive, dir, exename, NULL);
|
||||||
|
return loadable_exe(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char **parse_argv(char *cmdline, int *argc)
|
||||||
|
{
|
||||||
|
/* Parse a command line in-place using MS C rules */
|
||||||
|
|
||||||
|
char **result = calloc(strlen(cmdline), sizeof(char *));
|
||||||
|
char *output = cmdline;
|
||||||
|
char c;
|
||||||
|
int nb = 0;
|
||||||
|
int iq = 0;
|
||||||
|
*argc = 0;
|
||||||
|
|
||||||
|
result[0] = output;
|
||||||
|
while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
|
||||||
|
|
||||||
|
do {
|
||||||
|
c = *cmdline++;
|
||||||
|
if (!c || (isspace(c) && !iq)) {
|
||||||
|
while (nb) {*output++ = '\\'; nb--; }
|
||||||
|
*output++ = 0;
|
||||||
|
result[++*argc] = output;
|
||||||
|
if (!c) return result;
|
||||||
|
while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
|
||||||
|
if (!*cmdline) return result; /* avoid empty arg if trailing ws */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '\\')
|
||||||
|
++nb; /* count \'s */
|
||||||
|
else {
|
||||||
|
if (c == '"') {
|
||||||
|
if (!(nb & 1)) { iq = !iq; c = 0; } /* skip " unless odd # of \ */
|
||||||
|
nb = nb >> 1; /* cut \'s in half */
|
||||||
|
}
|
||||||
|
while (nb) {*output++ = '\\'; nb--; }
|
||||||
|
if (c) *output++ = c;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pass_control_to_child(DWORD control_type) {
|
||||||
|
/*
|
||||||
|
* distribute-issue207
|
||||||
|
* passes the control event to child process (Python)
|
||||||
|
*/
|
||||||
|
if (!child_pid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GenerateConsoleCtrlEvent(child_pid,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL control_handler(DWORD control_type) {
|
||||||
|
/*
|
||||||
|
* distribute-issue207
|
||||||
|
* control event handler callback function
|
||||||
|
*/
|
||||||
|
switch (control_type) {
|
||||||
|
case CTRL_C_EVENT:
|
||||||
|
pass_control_to_child(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_and_wait_for_subprocess(char* command) {
|
||||||
|
/*
|
||||||
|
* distribute-issue207
|
||||||
|
* launches child process (Python)
|
||||||
|
*/
|
||||||
|
DWORD return_value = 0;
|
||||||
|
LPSTR commandline = command;
|
||||||
|
STARTUPINFOA s_info;
|
||||||
|
PROCESS_INFORMATION p_info;
|
||||||
|
ZeroMemory(&p_info, sizeof(p_info));
|
||||||
|
ZeroMemory(&s_info, sizeof(s_info));
|
||||||
|
s_info.cb = sizeof(STARTUPINFO);
|
||||||
|
// set-up control handler callback funciotn
|
||||||
|
SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
|
||||||
|
if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
|
||||||
|
fprintf(stderr, "failed to create process.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
child_pid = p_info.dwProcessId;
|
||||||
|
// wait for Python to exit
|
||||||
|
WaitForSingleObject(p_info.hProcess, INFINITE);
|
||||||
|
if (!GetExitCodeProcess(p_info.hProcess, &return_value)) {
|
||||||
|
fprintf(stderr, "failed to get exit code from process.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* join_executable_and_args(char *executable, char **args, int argc)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* distribute-issue207
|
||||||
|
* CreateProcess needs a long string of the executable and command-line arguments,
|
||||||
|
* so we need to convert it from the args that was built
|
||||||
|
*/
|
||||||
|
int len,counter;
|
||||||
|
char* cmdline;
|
||||||
|
|
||||||
|
len=strlen(executable)+2;
|
||||||
|
for (counter=1; counter<argc; counter++) {
|
||||||
|
len+=strlen(args[counter])+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdline = (char*)calloc(len, sizeof(char));
|
||||||
|
sprintf(cmdline, "%s", executable);
|
||||||
|
len=strlen(executable);
|
||||||
|
for (counter=1; counter<argc; counter++) {
|
||||||
|
sprintf(cmdline+len, " %s", args[counter]);
|
||||||
|
len+=strlen(args[counter])+1;
|
||||||
|
}
|
||||||
|
return cmdline;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run(int argc, char **argv, int is_gui) {
|
||||||
|
|
||||||
|
char python[256]; /* python executable's filename*/
|
||||||
|
char *pyopt; /* Python option */
|
||||||
|
char script[256]; /* the script's filename */
|
||||||
|
|
||||||
|
int scriptf; /* file descriptor for script file */
|
||||||
|
|
||||||
|
char **newargs, **newargsp, **parsedargs; /* argument array for exec */
|
||||||
|
char *ptr, *end; /* working pointers for string manipulation */
|
||||||
|
char *cmdline;
|
||||||
|
int i, parsedargc; /* loop counter */
|
||||||
|
|
||||||
|
/* compute script name from our .exe name*/
|
||||||
|
GetModuleFileNameA(NULL, script, sizeof(script));
|
||||||
|
end = script + strlen(script);
|
||||||
|
while( end>script && *end != '.')
|
||||||
|
*end-- = '\0';
|
||||||
|
*end-- = '\0';
|
||||||
|
strcat(script, (GUI ? "-script.pyw" : "-script.py"));
|
||||||
|
|
||||||
|
/* figure out the target python executable */
|
||||||
|
|
||||||
|
scriptf = open(script, O_RDONLY);
|
||||||
|
if (scriptf == -1) {
|
||||||
|
return fail("Cannot open %s\n", script);
|
||||||
|
}
|
||||||
|
end = python + read(scriptf, python, sizeof(python));
|
||||||
|
close(scriptf);
|
||||||
|
|
||||||
|
ptr = python-1;
|
||||||
|
while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;}
|
||||||
|
|
||||||
|
*ptr-- = '\0';
|
||||||
|
|
||||||
|
if (strncmp(python, "#!", 2)) {
|
||||||
|
/* default to python.exe if no #! header */
|
||||||
|
strcpy(python, "#!python.exe");
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedargs = parse_argv(python+2, &parsedargc);
|
||||||
|
|
||||||
|
/* Using spawnv() can fail strangely if you e.g. find the Cygwin
|
||||||
|
Python, so we'll make sure Windows can find and load it */
|
||||||
|
|
||||||
|
ptr = find_exe(parsedargs[0], script);
|
||||||
|
if (!ptr) {
|
||||||
|
return fail("Cannot find Python executable %s\n", parsedargs[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* printf("Python executable: %s\n", ptr); */
|
||||||
|
|
||||||
|
/* Argument array needs to be
|
||||||
|
parsedargc + argc, plus 1 for null sentinel */
|
||||||
|
|
||||||
|
newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *));
|
||||||
|
newargsp = newargs;
|
||||||
|
|
||||||
|
*newargsp++ = quoted(ptr);
|
||||||
|
for (i = 1; i<parsedargc; i++) *newargsp++ = quoted(parsedargs[i]);
|
||||||
|
|
||||||
|
*newargsp++ = quoted(script);
|
||||||
|
for (i = 1; i < argc; i++) *newargsp++ = quoted(argv[i]);
|
||||||
|
|
||||||
|
*newargsp++ = NULL;
|
||||||
|
|
||||||
|
/* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */
|
||||||
|
|
||||||
|
if (is_gui) {
|
||||||
|
/* Use exec, we don't need to wait for the GUI to finish */
|
||||||
|
execv(ptr, (const char * const *)(newargs));
|
||||||
|
return fail("Could not exec %s", ptr); /* shouldn't get here! */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* distribute-issue207: using CreateProcessA instead of spawnv
|
||||||
|
*/
|
||||||
|
cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc);
|
||||||
|
return create_and_wait_for_subprocess(cmdline);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
|
||||||
|
return run(__argc, __argv, GUI);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
return run(argc, argv, GUI);
|
||||||
|
}
|
|
@ -24,7 +24,7 @@
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name)
|
static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name, bool flag_output)
|
||||||
{
|
{
|
||||||
from_name = RTLIL::escape_id(from_name);
|
from_name = RTLIL::escape_id(from_name);
|
||||||
to_name = RTLIL::escape_id(to_name);
|
to_name = RTLIL::escape_id(to_name);
|
||||||
|
@ -37,13 +37,18 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
|
||||||
Wire *w = it.second;
|
Wire *w = it.second;
|
||||||
log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module));
|
log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module));
|
||||||
module->rename(w, to_name);
|
module->rename(w, to_name);
|
||||||
if (w->port_id)
|
if (w->port_id || flag_output) {
|
||||||
|
if (flag_output)
|
||||||
|
w->port_output = true;
|
||||||
module->fixup_ports();
|
module->fixup_ports();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &it : module->cells_)
|
for (auto &it : module->cells_)
|
||||||
if (it.first == from_name) {
|
if (it.first == from_name) {
|
||||||
|
if (flag_output)
|
||||||
|
log_cmd_error("Called with -output but the specified object is a cell.\n");
|
||||||
log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
|
log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
|
||||||
module->rename(it.second, to_name);
|
module->rename(it.second, to_name);
|
||||||
return;
|
return;
|
||||||
|
@ -108,15 +113,26 @@ struct RenamePass : public Pass {
|
||||||
log("Rename the specified object. Note that selection patterns are not supported\n");
|
log("Rename the specified object. Note that selection patterns are not supported\n");
|
||||||
log("by this command.\n");
|
log("by this command.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("\n");
|
||||||
|
log("\n");
|
||||||
|
log(" rename -output old_name new_name\n");
|
||||||
|
log("\n");
|
||||||
|
log("Like above, but also make the wire an output. This will fail if the object is\n");
|
||||||
|
log("not a wire.\n");
|
||||||
|
log("\n");
|
||||||
|
log("\n");
|
||||||
log(" rename -src [selection]\n");
|
log(" rename -src [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Assign names auto-generated from the src attribute to all selected wires and\n");
|
log("Assign names auto-generated from the src attribute to all selected wires and\n");
|
||||||
log("cells with private names.\n");
|
log("cells with private names.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("\n");
|
||||||
log(" rename -wire [selection]\n");
|
log(" rename -wire [selection]\n");
|
||||||
|
log("\n");
|
||||||
log("Assign auto-generated names based on the wires they drive to all selected\n");
|
log("Assign auto-generated names based on the wires they drive to all selected\n");
|
||||||
log("cells with private names. Ignores cells driving privatly named wires.\n");
|
log("cells with private names. Ignores cells driving privatly named wires.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("\n");
|
||||||
log(" rename -enumerate [-pattern <pattern>] [selection]\n");
|
log(" rename -enumerate [-pattern <pattern>] [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Assign short auto-generated names to all selected wires and cells with private\n");
|
log("Assign short auto-generated names to all selected wires and cells with private\n");
|
||||||
|
@ -124,11 +140,13 @@ struct RenamePass : public Pass {
|
||||||
log("The character %% in the pattern is replaced with a integer number. The default\n");
|
log("The character %% in the pattern is replaced with a integer number. The default\n");
|
||||||
log("pattern is '_%%_'.\n");
|
log("pattern is '_%%_'.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("\n");
|
||||||
log(" rename -hide [selection]\n");
|
log(" rename -hide [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Assign private names (the ones with $-prefix) to all selected wires and cells\n");
|
log("Assign private names (the ones with $-prefix) to all selected wires and cells\n");
|
||||||
log("with public names. This ignores all selected ports.\n");
|
log("with public names. This ignores all selected ports.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("\n");
|
||||||
log(" rename -top new_name\n");
|
log(" rename -top new_name\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Rename top module.\n");
|
log("Rename top module.\n");
|
||||||
|
@ -142,6 +160,7 @@ struct RenamePass : public Pass {
|
||||||
bool flag_enumerate = false;
|
bool flag_enumerate = false;
|
||||||
bool flag_hide = false;
|
bool flag_hide = false;
|
||||||
bool flag_top = false;
|
bool flag_top = false;
|
||||||
|
bool flag_output = false;
|
||||||
bool got_mode = false;
|
bool got_mode = false;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
|
@ -153,6 +172,11 @@ struct RenamePass : public Pass {
|
||||||
got_mode = true;
|
got_mode = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-output" && !got_mode) {
|
||||||
|
flag_output = true;
|
||||||
|
got_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg == "-wire" && !got_mode) {
|
if (arg == "-wire" && !got_mode) {
|
||||||
flag_wire = true;
|
flag_wire = true;
|
||||||
got_mode = true;
|
got_mode = true;
|
||||||
|
@ -322,10 +346,12 @@ struct RenamePass : public Pass {
|
||||||
if (!design->selected_active_module.empty())
|
if (!design->selected_active_module.empty())
|
||||||
{
|
{
|
||||||
if (design->modules_.count(design->selected_active_module) > 0)
|
if (design->modules_.count(design->selected_active_module) > 0)
|
||||||
rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name);
|
rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name, flag_output);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (flag_output)
|
||||||
|
log_cmd_error("Mode -output requires that there is an active module selected.\n");
|
||||||
for (auto &mod : design->modules_) {
|
for (auto &mod : design->modules_) {
|
||||||
if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
|
if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
|
||||||
to_name = RTLIL::escape_id(to_name);
|
to_name = RTLIL::escape_id(to_name);
|
||||||
|
|
|
@ -87,6 +87,8 @@ struct UniquifyPass : public Pass {
|
||||||
smod->name = newname;
|
smod->name = newname;
|
||||||
cell->type = newname;
|
cell->type = newname;
|
||||||
smod->set_bool_attribute("\\unique");
|
smod->set_bool_attribute("\\unique");
|
||||||
|
if (smod->attributes.count("\\hdlname") == 0)
|
||||||
|
smod->attributes["\\hdlname"] = string(log_id(tmod->name));
|
||||||
design->add(smod);
|
design->add(smod);
|
||||||
|
|
||||||
did_something = true;
|
did_something = true;
|
||||||
|
|
|
@ -542,7 +542,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign write ports
|
// assign write ports
|
||||||
|
pair<SigBit, bool> wr_clkdom;
|
||||||
for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++)
|
for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++)
|
||||||
{
|
{
|
||||||
bool clken = wr_clken[cell_port_i] == State::S1;
|
bool clken = wr_clken[cell_port_i] == State::S1;
|
||||||
|
@ -552,7 +552,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
|
||||||
pair<SigBit, bool> clkdom(clksig, clkpol);
|
pair<SigBit, bool> clkdom(clksig, clkpol);
|
||||||
if (!clken)
|
if (!clken)
|
||||||
clkdom = pair<SigBit, bool>(State::S1, false);
|
clkdom = pair<SigBit, bool>(State::S1, false);
|
||||||
|
wr_clkdom = clkdom;
|
||||||
log(" Write port #%d is in clock domain %s%s.\n",
|
log(" Write port #%d is in clock domain %s%s.\n",
|
||||||
cell_port_i, clkdom.second ? "" : "!",
|
cell_port_i, clkdom.second ? "" : "!",
|
||||||
clken ? log_signal(clkdom.first) : "~async~");
|
clken ? log_signal(clkdom.first) : "~async~");
|
||||||
|
@ -641,6 +641,7 @@ grow_read_ports:;
|
||||||
pi.sig_data = SigSpec();
|
pi.sig_data = SigSpec();
|
||||||
pi.sig_en = SigSpec();
|
pi.sig_en = SigSpec();
|
||||||
pi.make_outreg = false;
|
pi.make_outreg = false;
|
||||||
|
pi.make_transp = false;
|
||||||
}
|
}
|
||||||
new_portinfos.push_back(pi);
|
new_portinfos.push_back(pi);
|
||||||
if (pi.dupidx == dup_count-1) {
|
if (pi.dupidx == dup_count-1) {
|
||||||
|
@ -718,7 +719,13 @@ grow_read_ports:;
|
||||||
if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
|
if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
|
||||||
if (match.make_transp && wr_ports <= 1) {
|
if (match.make_transp && wr_ports <= 1) {
|
||||||
pi.make_transp = true;
|
pi.make_transp = true;
|
||||||
|
if (pi.clocks != 0) {
|
||||||
|
if (wr_ports == 1 && wr_clkdom != clkdom) {
|
||||||
|
log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
|
||||||
|
goto skip_bram_rport;
|
||||||
|
}
|
||||||
enable_make_transp = true;
|
enable_make_transp = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
|
log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
|
||||||
goto skip_bram_rport;
|
goto skip_bram_rport;
|
||||||
|
@ -913,17 +920,18 @@ grow_read_ports:;
|
||||||
} else {
|
} else {
|
||||||
SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits);
|
SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits);
|
||||||
c->setPort(stringf("\\%sDATA", pf), bram_dout);
|
c->setPort(stringf("\\%sDATA", pf), bram_dout);
|
||||||
|
if (pi.make_outreg && pi.make_transp) {
|
||||||
if (pi.make_outreg) {
|
log(" Moving output register to address for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
|
||||||
|
SigSpec sig_addr_q = module->addWire(NEW_ID, bram.abits);
|
||||||
|
module->addDff(NEW_ID, pi.sig_clock, sig_addr, sig_addr_q, pi.effective_clkpol);
|
||||||
|
c->setPort(stringf("\\%sADDR", pf), sig_addr_q);
|
||||||
|
} else if (pi.make_outreg) {
|
||||||
SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits);
|
SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits);
|
||||||
if (!pi.sig_en.empty())
|
if (!pi.sig_en.empty())
|
||||||
bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en);
|
bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en);
|
||||||
module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol);
|
module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol);
|
||||||
bram_dout = bram_dout_q;
|
bram_dout = bram_dout_q;
|
||||||
}
|
} else if (pi.make_transp) {
|
||||||
|
|
||||||
if (pi.make_transp)
|
|
||||||
{
|
|
||||||
log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
|
log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
|
||||||
|
|
||||||
SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits),
|
SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits),
|
||||||
|
|
|
@ -155,6 +155,13 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
|
||||||
new_b.append_bit(it.first.second);
|
new_b.append_bit(it.first.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cell->type.in("$and", "$or") && i == GRP_CONST_A) {
|
||||||
|
log(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a));
|
||||||
|
module->connect(new_y, new_b);
|
||||||
|
module->connect(new_conn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
|
RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
|
||||||
|
|
||||||
c->setPort("\\A", new_a);
|
c->setPort("\\A", new_a);
|
||||||
|
|
|
@ -54,6 +54,7 @@ struct WreduceWorker
|
||||||
std::set<SigBit> work_queue_bits;
|
std::set<SigBit> work_queue_bits;
|
||||||
pool<SigBit> keep_bits;
|
pool<SigBit> keep_bits;
|
||||||
dict<SigBit, State> init_bits;
|
dict<SigBit, State> init_bits;
|
||||||
|
pool<SigBit> remove_init_bits;
|
||||||
|
|
||||||
WreduceWorker(WreduceConfig *config, Module *module) :
|
WreduceWorker(WreduceConfig *config, Module *module) :
|
||||||
config(config), module(module), mi(module) { }
|
config(config), module(module), mi(module) { }
|
||||||
|
@ -164,6 +165,7 @@ struct WreduceWorker
|
||||||
{
|
{
|
||||||
if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) {
|
if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) {
|
||||||
module->connect(sig_q[i], State::S0);
|
module->connect(sig_q[i], State::S0);
|
||||||
|
remove_init_bits.insert(sig_q[i]);
|
||||||
sig_d.remove(i);
|
sig_d.remove(i);
|
||||||
sig_q.remove(i);
|
sig_q.remove(i);
|
||||||
continue;
|
continue;
|
||||||
|
@ -171,6 +173,7 @@ struct WreduceWorker
|
||||||
|
|
||||||
if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) {
|
if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) {
|
||||||
module->connect(sig_q[i], sig_q[i-1]);
|
module->connect(sig_q[i], sig_q[i-1]);
|
||||||
|
remove_init_bits.insert(sig_q[i]);
|
||||||
sig_d.remove(i);
|
sig_d.remove(i);
|
||||||
sig_q.remove(i);
|
sig_q.remove(i);
|
||||||
continue;
|
continue;
|
||||||
|
@ -178,6 +181,7 @@ struct WreduceWorker
|
||||||
|
|
||||||
auto info = mi.query(sig_q[i]);
|
auto info = mi.query(sig_q[i]);
|
||||||
if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
|
if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
|
||||||
|
remove_init_bits.insert(sig_q[i]);
|
||||||
sig_d.remove(i);
|
sig_d.remove(i);
|
||||||
sig_q.remove(i);
|
sig_q.remove(i);
|
||||||
zero_ext = false;
|
zero_ext = false;
|
||||||
|
@ -387,13 +391,16 @@ struct WreduceWorker
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
|
// create a copy as mi.sigmap will be updated as we process the module
|
||||||
|
SigMap init_attr_sigmap = mi.sigmap;
|
||||||
|
|
||||||
for (auto w : module->wires()) {
|
for (auto w : module->wires()) {
|
||||||
if (w->get_bool_attribute("\\keep"))
|
if (w->get_bool_attribute("\\keep"))
|
||||||
for (auto bit : mi.sigmap(w))
|
for (auto bit : mi.sigmap(w))
|
||||||
keep_bits.insert(bit);
|
keep_bits.insert(bit);
|
||||||
if (w->attributes.count("\\init")) {
|
if (w->attributes.count("\\init")) {
|
||||||
Const initval = w->attributes.at("\\init");
|
Const initval = w->attributes.at("\\init");
|
||||||
SigSpec initsig = mi.sigmap(w);
|
SigSpec initsig = init_attr_sigmap(w);
|
||||||
int width = std::min(GetSize(initval), GetSize(initsig));
|
int width = std::min(GetSize(initval), GetSize(initsig));
|
||||||
for (int i = 0; i < width; i++)
|
for (int i = 0; i < width; i++)
|
||||||
init_bits[initsig[i]] = initval[i];
|
init_bits[initsig[i]] = initval[i];
|
||||||
|
@ -446,6 +453,24 @@ struct WreduceWorker
|
||||||
module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
|
module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
|
||||||
module->swap_names(w, nw);
|
module->swap_names(w, nw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!remove_init_bits.empty()) {
|
||||||
|
for (auto w : module->wires()) {
|
||||||
|
if (w->attributes.count("\\init")) {
|
||||||
|
Const initval = w->attributes.at("\\init");
|
||||||
|
Const new_initval(State::Sx, GetSize(w));
|
||||||
|
SigSpec initsig = init_attr_sigmap(w);
|
||||||
|
int width = std::min(GetSize(initval), GetSize(initsig));
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
log_dump(initsig[i], remove_init_bits.count(initsig[i]));
|
||||||
|
if (!remove_init_bits.count(initsig[i]))
|
||||||
|
new_initval[i] = initval[i];
|
||||||
|
}
|
||||||
|
w->attributes.at("\\init") = new_initval;
|
||||||
|
log_dump(w->name, initval, new_initval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ API of Generated Matcher
|
||||||
========================
|
========================
|
||||||
|
|
||||||
When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing
|
When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing
|
||||||
a class `foobar_pm`. That class is instanciated with an RTLIL module and a
|
a class `foobar_pm`. That class is instantiated with an RTLIL module and a
|
||||||
list of cells from that module:
|
list of cells from that module:
|
||||||
|
|
||||||
foobar_pm pm(module, module->selected_cells());
|
foobar_pm pm(module, module->selected_cells());
|
||||||
|
@ -142,7 +142,7 @@ The `select` lines are evaluated once for each cell when the matcher is
|
||||||
initialized. A `match` block will only consider cells for which all `select`
|
initialized. A `match` block will only consider cells for which all `select`
|
||||||
expressions evaluated to `true`. Note that the state variable corresponding to
|
expressions evaluated to `true`. Note that the state variable corresponding to
|
||||||
the match (in the example `mul`) is the only state variable that may be used
|
the match (in the example `mul`) is the only state variable that may be used
|
||||||
`select` lines.
|
in `select` lines.
|
||||||
|
|
||||||
Index lines are using the `index <type> expr1 === expr2` syntax. `expr1` is
|
Index lines are using the `index <type> expr1 === expr2` syntax. `expr1` is
|
||||||
evaluated during matcher initialization and the same restrictions apply as for
|
evaluated during matcher initialization and the same restrictions apply as for
|
||||||
|
|
|
@ -9,4 +9,7 @@ OBJS += passes/sat/assertpmux.o
|
||||||
OBJS += passes/sat/clk2fflogic.o
|
OBJS += passes/sat/clk2fflogic.o
|
||||||
OBJS += passes/sat/async2sync.o
|
OBJS += passes/sat/async2sync.o
|
||||||
OBJS += passes/sat/supercover.o
|
OBJS += passes/sat/supercover.o
|
||||||
|
OBJS += passes/sat/fmcombine.o
|
||||||
|
OBJS += passes/sat/mutate.o
|
||||||
|
OBJS += passes/sat/cutpoint.o
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ struct Async2syncPass : public Pass {
|
||||||
log("reset value in the next cycle regardless of the data-in value at the time of\n");
|
log("reset value in the next cycle regardless of the data-in value at the time of\n");
|
||||||
log("the clock edge.\n");
|
log("the clock edge.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Currently only $adff cells are supported by this pass.\n");
|
log("Currently only $adff and $dffsr cells are supported by this pass.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
@ -84,7 +84,7 @@ struct Async2syncPass : public Pass {
|
||||||
bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool();
|
bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool();
|
||||||
Const arst_val = cell->parameters["\\ARST_VALUE"];
|
Const arst_val = cell->parameters["\\ARST_VALUE"];
|
||||||
|
|
||||||
SigSpec sig_clk = cell->getPort("\\CLK");
|
// SigSpec sig_clk = cell->getPort("\\CLK");
|
||||||
SigSpec sig_arst = cell->getPort("\\ARST");
|
SigSpec sig_arst = cell->getPort("\\ARST");
|
||||||
SigSpec sig_d = cell->getPort("\\D");
|
SigSpec sig_d = cell->getPort("\\D");
|
||||||
SigSpec sig_q = cell->getPort("\\Q");
|
SigSpec sig_q = cell->getPort("\\Q");
|
||||||
|
@ -120,6 +120,55 @@ struct Async2syncPass : public Pass {
|
||||||
cell->type = "$dff";
|
cell->type = "$dff";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cell->type.in("$dffsr"))
|
||||||
|
{
|
||||||
|
// bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool();
|
||||||
|
bool set_pol = cell->parameters["\\SET_POLARITY"].as_bool();
|
||||||
|
bool clr_pol = cell->parameters["\\CLR_POLARITY"].as_bool();
|
||||||
|
|
||||||
|
// SigSpec sig_clk = cell->getPort("\\CLK");
|
||||||
|
SigSpec sig_set = cell->getPort("\\SET");
|
||||||
|
SigSpec sig_clr = cell->getPort("\\CLR");
|
||||||
|
SigSpec sig_d = cell->getPort("\\D");
|
||||||
|
SigSpec sig_q = cell->getPort("\\Q");
|
||||||
|
|
||||||
|
log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
|
||||||
|
log_id(module), log_id(cell), log_id(cell->type),
|
||||||
|
log_signal(sig_set), log_signal(sig_clr), log_signal(sig_d), log_signal(sig_q));
|
||||||
|
|
||||||
|
Const init_val;
|
||||||
|
for (int i = 0; i < GetSize(sig_q); i++) {
|
||||||
|
SigBit bit = sigmap(sig_q[i]);
|
||||||
|
init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
|
||||||
|
del_initbits.insert(bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
|
||||||
|
Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
|
||||||
|
new_q->attributes["\\init"] = init_val;
|
||||||
|
|
||||||
|
if (!set_pol)
|
||||||
|
sig_set = module->Not(NEW_ID, sig_set);
|
||||||
|
|
||||||
|
if (clr_pol)
|
||||||
|
sig_clr = module->Not(NEW_ID, sig_clr);
|
||||||
|
|
||||||
|
SigSpec tmp = module->Or(NEW_ID, sig_d, sig_set);
|
||||||
|
module->addAnd(NEW_ID, tmp, sig_clr, new_d);
|
||||||
|
|
||||||
|
tmp = module->Or(NEW_ID, new_q, sig_set);
|
||||||
|
module->addAnd(NEW_ID, tmp, sig_clr, sig_q);
|
||||||
|
|
||||||
|
cell->setPort("\\D", new_d);
|
||||||
|
cell->setPort("\\Q", new_q);
|
||||||
|
cell->unsetPort("\\SET");
|
||||||
|
cell->unsetPort("\\CLR");
|
||||||
|
cell->unsetParam("\\SET_POLARITY");
|
||||||
|
cell->unsetParam("\\CLR_POLARITY");
|
||||||
|
cell->type = "$dff";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto wire : module->wires())
|
for (auto wire : module->wires())
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct CutpointPass : public Pass {
|
||||||
|
CutpointPass() : Pass("cutpoint", "add hi/lo cover cells for each wire bit") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" cutpoint [options] [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("This command adds formal cut points to the design.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -undef\n");
|
||||||
|
log(" set cupoint nets to undef (x). the default behavior is to create a\n");
|
||||||
|
log(" $anyseq cell and drive the cutpoint net from that\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
bool flag_undef = false;
|
||||||
|
|
||||||
|
log_header(design, "Executing CUTPOINT pass.\n");
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
if (args[argidx] == "-undef") {
|
||||||
|
flag_undef = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules())
|
||||||
|
{
|
||||||
|
if (design->selected_whole_module(module->name)) {
|
||||||
|
log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module));
|
||||||
|
module->new_connections(std::vector<RTLIL::SigSig>());
|
||||||
|
for (auto cell : vector<Cell*>(module->cells()))
|
||||||
|
module->remove(cell);
|
||||||
|
vector<Wire*> output_wires;
|
||||||
|
for (auto wire : module->wires())
|
||||||
|
if (wire->port_output)
|
||||||
|
output_wires.push_back(wire);
|
||||||
|
for (auto wire : output_wires)
|
||||||
|
module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SigMap sigmap(module);
|
||||||
|
pool<SigBit> cutpoint_bits;
|
||||||
|
|
||||||
|
for (auto cell : module->selected_cells()) {
|
||||||
|
if (cell->type == "$anyseq")
|
||||||
|
continue;
|
||||||
|
log("Removing cell %s.%s, making all cell outputs cutpoints.\n", log_id(module), log_id(cell));
|
||||||
|
for (auto &conn : cell->connections()) {
|
||||||
|
if (cell->output(conn.first))
|
||||||
|
module->connect(conn.second, flag_undef ? Const(State::Sx, GetSize(conn.second)) : module->Anyseq(NEW_ID, GetSize(conn.second)));
|
||||||
|
}
|
||||||
|
module->remove(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto wire : module->selected_wires()) {
|
||||||
|
if (wire->port_output) {
|
||||||
|
log("Making output wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
|
||||||
|
Wire *new_wire = module->addWire(NEW_ID, wire);
|
||||||
|
module->swap_names(wire, new_wire);
|
||||||
|
module->connect(new_wire, flag_undef ? Const(State::Sx, GetSize(new_wire)) : module->Anyseq(NEW_ID, GetSize(new_wire)));
|
||||||
|
wire->port_id = 0;
|
||||||
|
wire->port_input = false;
|
||||||
|
wire->port_output = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log("Making wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
|
||||||
|
for (auto bit : sigmap(wire))
|
||||||
|
cutpoint_bits.insert(bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cutpoint_bits.empty())
|
||||||
|
{
|
||||||
|
for (auto cell : module->cells()) {
|
||||||
|
for (auto &conn : cell->connections()) {
|
||||||
|
if (!cell->output(conn.first))
|
||||||
|
continue;
|
||||||
|
SigSpec sig = sigmap(conn.second);
|
||||||
|
int bit_count = 0;
|
||||||
|
for (auto &bit : sig) {
|
||||||
|
if (cutpoint_bits.count(bit))
|
||||||
|
bit_count++;
|
||||||
|
}
|
||||||
|
if (bit_count == 0)
|
||||||
|
continue;
|
||||||
|
SigSpec dummy = module->addWire(NEW_ID, bit_count);
|
||||||
|
bit_count = 0;
|
||||||
|
for (auto &bit : sig) {
|
||||||
|
if (cutpoint_bits.count(bit))
|
||||||
|
bit = dummy[bit_count++];
|
||||||
|
}
|
||||||
|
cell->setPort(conn.first, sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<Wire*> rewrite_wires;
|
||||||
|
for (auto wire : module->wires()) {
|
||||||
|
if (!wire->port_input)
|
||||||
|
continue;
|
||||||
|
int bit_count = 0;
|
||||||
|
for (auto &bit : sigmap(wire))
|
||||||
|
if (cutpoint_bits.count(bit))
|
||||||
|
bit_count++;
|
||||||
|
if (bit_count)
|
||||||
|
rewrite_wires.push_back(wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto wire : rewrite_wires) {
|
||||||
|
Wire *new_wire = module->addWire(NEW_ID, wire);
|
||||||
|
SigSpec lhs, rhs, sig = sigmap(wire);
|
||||||
|
for (int i = 0; i < GetSize(sig); i++)
|
||||||
|
if (!cutpoint_bits.count(sig[i])) {
|
||||||
|
lhs.append(SigBit(wire, i));
|
||||||
|
rhs.append(SigBit(new_wire, i));
|
||||||
|
}
|
||||||
|
if (GetSize(lhs))
|
||||||
|
module->connect(lhs, rhs);
|
||||||
|
module->swap_names(wire, new_wire);
|
||||||
|
wire->port_id = 0;
|
||||||
|
wire->port_input = false;
|
||||||
|
wire->port_output = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec sig(cutpoint_bits);
|
||||||
|
sig.sort_and_unify();
|
||||||
|
|
||||||
|
for (auto chunk : sig.chunks()) {
|
||||||
|
SigSpec s(chunk);
|
||||||
|
module->connect(s, flag_undef ? Const(State::Sx, GetSize(s)) : module->Anyseq(NEW_ID, GetSize(s)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} CutpointPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,341 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
#include "kernel/celltypes.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct opts_t
|
||||||
|
{
|
||||||
|
bool fwd = false;
|
||||||
|
bool bwd = false;
|
||||||
|
bool nop = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FmcombineWorker
|
||||||
|
{
|
||||||
|
const opts_t &opts;
|
||||||
|
Design *design;
|
||||||
|
Module *original = nullptr;
|
||||||
|
Module *module = nullptr;
|
||||||
|
IdString orig_type, combined_type;
|
||||||
|
|
||||||
|
FmcombineWorker(Design *design, IdString orig_type, const opts_t &opts) :
|
||||||
|
opts(opts), design(design), original(design->module(orig_type)),
|
||||||
|
orig_type(orig_type), combined_type("$fmcombine" + orig_type.str())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec import_sig(SigSpec sig, const string &suffix)
|
||||||
|
{
|
||||||
|
SigSpec newsig;
|
||||||
|
for (auto chunk : sig.chunks()) {
|
||||||
|
if (chunk.wire != nullptr)
|
||||||
|
chunk.wire = module->wire(chunk.wire->name.str() + suffix);
|
||||||
|
newsig.append(chunk);
|
||||||
|
}
|
||||||
|
return newsig;
|
||||||
|
}
|
||||||
|
|
||||||
|
void import_prim_cell(Cell *cell, const string &suffix)
|
||||||
|
{
|
||||||
|
Cell *c = module->addCell(cell->name.str() + suffix, cell->type);
|
||||||
|
c->parameters = cell->parameters;
|
||||||
|
c->attributes = cell->attributes;
|
||||||
|
|
||||||
|
for (auto &conn : cell->connections())
|
||||||
|
c->setPort(conn.first, import_sig(conn.second, suffix));
|
||||||
|
}
|
||||||
|
|
||||||
|
void import_hier_cell(Cell *cell)
|
||||||
|
{
|
||||||
|
if (!cell->parameters.empty())
|
||||||
|
log_cmd_error("Cell %s.%s has unresolved instance parameters.\n", log_id(original), log_id(cell));
|
||||||
|
|
||||||
|
FmcombineWorker sub_worker(design, cell->type, opts);
|
||||||
|
sub_worker.generate();
|
||||||
|
|
||||||
|
Cell *c = module->addCell(cell->name.str() + "_combined", sub_worker.combined_type);
|
||||||
|
// c->parameters = cell->parameters;
|
||||||
|
c->attributes = cell->attributes;
|
||||||
|
|
||||||
|
for (auto &conn : cell->connections()) {
|
||||||
|
c->setPort(conn.first.str() + "_gold", import_sig(conn.second, "_gold"));
|
||||||
|
c->setPort(conn.first.str() + "_gate", import_sig(conn.second, "_gate"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate()
|
||||||
|
{
|
||||||
|
if (design->module(combined_type)) {
|
||||||
|
// log("Combined module %s already exists.\n", log_id(combined_type));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log("Generating combined module %s from module %s.\n", log_id(combined_type), log_id(orig_type));
|
||||||
|
module = design->addModule(combined_type);
|
||||||
|
|
||||||
|
for (auto wire : original->wires()) {
|
||||||
|
module->addWire(wire->name.str() + "_gold", wire);
|
||||||
|
module->addWire(wire->name.str() + "_gate", wire);
|
||||||
|
}
|
||||||
|
module->fixup_ports();
|
||||||
|
|
||||||
|
for (auto cell : original->cells()) {
|
||||||
|
if (design->module(cell->type) == nullptr) {
|
||||||
|
import_prim_cell(cell, "_gold");
|
||||||
|
import_prim_cell(cell, "_gate");
|
||||||
|
} else {
|
||||||
|
import_hier_cell(cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &conn : original->connections()) {
|
||||||
|
module->connect(import_sig(conn.first, "_gold"), import_sig(conn.second, "_gold"));
|
||||||
|
module->connect(import_sig(conn.first, "_gate"), import_sig(conn.second, "_gate"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.nop)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CellTypes ct;
|
||||||
|
ct.setup_internals_eval();
|
||||||
|
ct.setup_stdcells_eval();
|
||||||
|
|
||||||
|
SigMap sigmap(module);
|
||||||
|
|
||||||
|
dict<SigBit, SigBit> data_bit_to_eq_net;
|
||||||
|
dict<Cell*, SigSpec> cell_to_eq_nets;
|
||||||
|
dict<SigSpec, SigSpec> reduce_db;
|
||||||
|
dict<SigSpec, SigSpec> invert_db;
|
||||||
|
|
||||||
|
for (auto cell : original->cells())
|
||||||
|
{
|
||||||
|
if (!ct.cell_known(cell->type))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (auto &conn : cell->connections())
|
||||||
|
{
|
||||||
|
if (!cell->output(conn.first))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigSpec A = import_sig(conn.second, "_gold");
|
||||||
|
SigSpec B = import_sig(conn.second, "_gate");
|
||||||
|
SigBit EQ = module->Eq(NEW_ID, A, B);
|
||||||
|
|
||||||
|
for (auto bit : sigmap({A, B}))
|
||||||
|
data_bit_to_eq_net[bit] = EQ;
|
||||||
|
|
||||||
|
cell_to_eq_nets[cell].append(EQ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto cell : original->cells())
|
||||||
|
{
|
||||||
|
if (!ct.cell_known(cell->type))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool skip_cell = !cell_to_eq_nets.count(cell);
|
||||||
|
pool<SigBit> src_eq_bits;
|
||||||
|
|
||||||
|
for (auto &conn : cell->connections())
|
||||||
|
{
|
||||||
|
if (skip_cell)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (cell->output(conn.first))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigSpec A = import_sig(conn.second, "_gold");
|
||||||
|
SigSpec B = import_sig(conn.second, "_gate");
|
||||||
|
|
||||||
|
for (auto bit : sigmap({A, B})) {
|
||||||
|
if (data_bit_to_eq_net.count(bit))
|
||||||
|
src_eq_bits.insert(data_bit_to_eq_net.at(bit));
|
||||||
|
else
|
||||||
|
skip_cell = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skip_cell) {
|
||||||
|
SigSpec antecedent = SigSpec(src_eq_bits);
|
||||||
|
antecedent.sort_and_unify();
|
||||||
|
|
||||||
|
if (GetSize(antecedent) > 1) {
|
||||||
|
if (reduce_db.count(antecedent) == 0)
|
||||||
|
reduce_db[antecedent] = module->ReduceAnd(NEW_ID, antecedent);
|
||||||
|
antecedent = reduce_db.at(antecedent);
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec consequent = cell_to_eq_nets.at(cell);
|
||||||
|
consequent.sort_and_unify();
|
||||||
|
|
||||||
|
if (GetSize(consequent) > 1) {
|
||||||
|
if (reduce_db.count(consequent) == 0)
|
||||||
|
reduce_db[consequent] = module->ReduceAnd(NEW_ID, consequent);
|
||||||
|
consequent = reduce_db.at(consequent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.fwd)
|
||||||
|
module->addAssume(NEW_ID, consequent, antecedent);
|
||||||
|
|
||||||
|
if (opts.bwd)
|
||||||
|
{
|
||||||
|
if (invert_db.count(antecedent) == 0)
|
||||||
|
invert_db[antecedent] = module->Not(NEW_ID, antecedent);
|
||||||
|
|
||||||
|
if (invert_db.count(consequent) == 0)
|
||||||
|
invert_db[consequent] = module->Not(NEW_ID, consequent);
|
||||||
|
|
||||||
|
module->addAssume(NEW_ID, invert_db.at(antecedent), invert_db.at(consequent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FmcombinePass : public Pass {
|
||||||
|
FmcombinePass() : Pass("fmcombine", "combine two instances of a cell into one") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" fmcombine [options] module_name gold_cell gate_cell\n");
|
||||||
|
// log(" fmcombine [options] @gold_cell @gate_cell\n");
|
||||||
|
log("\n");
|
||||||
|
log("This pass takes two cells, which are instances of the same module, and replaces\n");
|
||||||
|
log("them with one instance of a special 'combined' module, that effectively\n");
|
||||||
|
log("contains two copies of the original module, plus some formal properties.\n");
|
||||||
|
log("\n");
|
||||||
|
log("This is useful for formal test benches that check what differences in behavior\n");
|
||||||
|
log("a slight difference in input causes in a module.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -fwd\n");
|
||||||
|
log(" Insert forward hint assumptions into the combined module.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -bwd\n");
|
||||||
|
log(" Insert backward hint assumptions into the combined module.\n");
|
||||||
|
log(" (Backward hints are logically equivalend to fordward hits, but\n");
|
||||||
|
log(" some solvers are faster with bwd hints, or even both -bwd and -fwd.)\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -nop\n");
|
||||||
|
log(" Don't insert hint assumptions into the combined module.\n");
|
||||||
|
log(" (This should not provide any speedup over the original design, but\n");
|
||||||
|
log(" strangely sometimes it does.)\n");
|
||||||
|
log("\n");
|
||||||
|
log("If none of -fwd, -bwd, and -nop is given, then -fwd is used as default.\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
opts_t opts;
|
||||||
|
Module *module = nullptr;
|
||||||
|
Cell *gold_cell = nullptr;
|
||||||
|
Cell *gate_cell = nullptr;
|
||||||
|
|
||||||
|
log_header(design, "Executing FMCOMBINE pass.\n");
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
// if (args[argidx] == "-o" && argidx+1 < args.size()) {
|
||||||
|
// filename = args[++argidx];
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
if (args[argidx] == "-fwd") {
|
||||||
|
opts.fwd = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-bwd") {
|
||||||
|
opts.bwd = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-nop") {
|
||||||
|
opts.nop = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (argidx+2 == args.size())
|
||||||
|
{
|
||||||
|
string gold_name = args[argidx++];
|
||||||
|
string gate_name = args[argidx++];
|
||||||
|
log_cmd_error("fmcombine @gold_cell @gate_cell call style is not implemented yet.");
|
||||||
|
}
|
||||||
|
else if (argidx+3 == args.size())
|
||||||
|
{
|
||||||
|
IdString module_name = RTLIL::escape_id(args[argidx++]);
|
||||||
|
IdString gold_name = RTLIL::escape_id(args[argidx++]);
|
||||||
|
IdString gate_name = RTLIL::escape_id(args[argidx++]);
|
||||||
|
|
||||||
|
module = design->module(module_name);
|
||||||
|
if (module == nullptr)
|
||||||
|
log_cmd_error("Module %s not found.\n", log_id(module_name));
|
||||||
|
|
||||||
|
gold_cell = module->cell(gold_name);
|
||||||
|
if (gold_cell == nullptr)
|
||||||
|
log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gold_name), log_id(module));
|
||||||
|
|
||||||
|
gate_cell = module->cell(gate_name);
|
||||||
|
if (gate_cell == nullptr)
|
||||||
|
log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gate_name), log_id(module));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_cmd_error("Invalid number of arguments.\n");
|
||||||
|
}
|
||||||
|
// extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
if (opts.nop && (opts.fwd || opts.bwd))
|
||||||
|
log_cmd_error("Option -nop can not be combined with -fwd and/or -bwd.\n");
|
||||||
|
|
||||||
|
if (!opts.nop && !opts.fwd && !opts.bwd)
|
||||||
|
opts.fwd = true;
|
||||||
|
|
||||||
|
if (gold_cell->type != gate_cell->type)
|
||||||
|
log_cmd_error("Types of gold and gate cells do not match.\n");
|
||||||
|
if (!gold_cell->parameters.empty())
|
||||||
|
log_cmd_error("Gold cell has unresolved instance parameters.\n");
|
||||||
|
if (!gate_cell->parameters.empty())
|
||||||
|
log_cmd_error("Gold cell has unresolved instance parameters.\n");
|
||||||
|
|
||||||
|
FmcombineWorker worker(design, gold_cell->type, opts);
|
||||||
|
worker.generate();
|
||||||
|
IdString combined_cell_name = module->uniquify(stringf("\\%s_%s", log_id(gold_cell), log_id(gate_cell)));
|
||||||
|
|
||||||
|
Cell *cell = module->addCell(combined_cell_name, worker.combined_type);
|
||||||
|
cell->attributes = gold_cell->attributes;
|
||||||
|
cell->add_strpool_attribute("\\src", gate_cell->get_strpool_attribute("\\src"));
|
||||||
|
|
||||||
|
log("Combining cells %s and %s in module %s into new cell %s.\n", log_id(gold_cell), log_id(gate_cell), log_id(module), log_id(cell));
|
||||||
|
|
||||||
|
for (auto &conn : gold_cell->connections())
|
||||||
|
cell->setPort(conn.first.str() + "_gold", conn.second);
|
||||||
|
module->remove(gold_cell);
|
||||||
|
|
||||||
|
for (auto &conn : gate_cell->connections())
|
||||||
|
cell->setPort(conn.first.str() + "_gate", conn.second);
|
||||||
|
module->remove(gate_cell);
|
||||||
|
}
|
||||||
|
} FmcombinePass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -0,0 +1,956 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct mutate_t {
|
||||||
|
string mode;
|
||||||
|
pool<string> src;
|
||||||
|
IdString module, cell;
|
||||||
|
IdString port, wire;
|
||||||
|
int portbit = -1;
|
||||||
|
int ctrlbit = -1;
|
||||||
|
int wirebit = -1;
|
||||||
|
bool used = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mutate_opts_t {
|
||||||
|
int seed = 0;
|
||||||
|
std::string mode;
|
||||||
|
pool<string> src;
|
||||||
|
IdString module, cell, port, wire;
|
||||||
|
int portbit = -1;
|
||||||
|
int ctrlbit = -1;
|
||||||
|
int wirebit = -1;
|
||||||
|
|
||||||
|
IdString ctrl_name;
|
||||||
|
int ctrl_width = -1, ctrl_value = -1;
|
||||||
|
|
||||||
|
bool none = false;
|
||||||
|
|
||||||
|
int pick_cover_prcnt = 80;
|
||||||
|
|
||||||
|
int weight_cover = 500;
|
||||||
|
|
||||||
|
int weight_pq_w = 100;
|
||||||
|
int weight_pq_b = 100;
|
||||||
|
int weight_pq_c = 100;
|
||||||
|
int weight_pq_s = 100;
|
||||||
|
|
||||||
|
int weight_pq_mw = 100;
|
||||||
|
int weight_pq_mb = 100;
|
||||||
|
int weight_pq_mc = 100;
|
||||||
|
int weight_pq_ms = 100;
|
||||||
|
};
|
||||||
|
|
||||||
|
void database_add(std::vector<mutate_t> &database, const mutate_opts_t &opts, const mutate_t &entry)
|
||||||
|
{
|
||||||
|
if (!opts.mode.empty() && opts.mode != entry.mode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!opts.src.empty()) {
|
||||||
|
bool found_match = false;
|
||||||
|
for (auto &s : opts.src) {
|
||||||
|
if (entry.src.count(s))
|
||||||
|
found_match = true;
|
||||||
|
}
|
||||||
|
if (!found_match)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opts.module.empty() && opts.module != entry.module)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!opts.cell.empty() && opts.cell != entry.cell)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!opts.port.empty() && opts.port != entry.port)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (opts.portbit >= 0 && opts.portbit != entry.portbit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (opts.ctrlbit >= 0 && opts.ctrlbit != entry.ctrlbit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!opts.wire.empty() && opts.wire != entry.wire)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (opts.wirebit >= 0 && opts.wirebit != entry.wirebit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
database.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct xs128_t
|
||||||
|
{
|
||||||
|
uint32_t x = 123456789;
|
||||||
|
uint32_t y = 0, z = 0, w = 0;
|
||||||
|
|
||||||
|
xs128_t(int seed = 0) : w(seed) {
|
||||||
|
next();
|
||||||
|
next();
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
void next() {
|
||||||
|
uint32_t t = x ^ (x << 11);
|
||||||
|
x = y, y = z, z = w;
|
||||||
|
w ^= (w >> 19) ^ t ^ (t >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int operator()() {
|
||||||
|
next();
|
||||||
|
return w & 0x3fffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
int operator()(int n) {
|
||||||
|
if (n < 2)
|
||||||
|
return 0;
|
||||||
|
while (1) {
|
||||||
|
int k = (*this)(), p = k % n;
|
||||||
|
if ((k - p + n) <= 0x40000000)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct coverdb_t
|
||||||
|
{
|
||||||
|
dict<string, int> src_db;
|
||||||
|
dict<tuple<IdString, IdString>, int> wire_db;
|
||||||
|
dict<tuple<IdString, IdString, int>, int> wirebit_db;
|
||||||
|
|
||||||
|
void insert(const mutate_t &m) {
|
||||||
|
if (!m.wire.empty()) {
|
||||||
|
wire_db[tuple<IdString, IdString>(m.module, m.wire)] = 0;
|
||||||
|
wirebit_db[tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)] = 0;
|
||||||
|
}
|
||||||
|
for (auto &s : m.src) {
|
||||||
|
src_db[s] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(const mutate_t &m) {
|
||||||
|
if (!m.wire.empty()) {
|
||||||
|
wire_db.at(tuple<IdString, IdString>(m.module, m.wire))++;
|
||||||
|
wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit))++;
|
||||||
|
}
|
||||||
|
for (auto &s : m.src) {
|
||||||
|
src_db.at(s)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int score(const mutate_t &m) {
|
||||||
|
int this_score = m.src.empty() ? 0 : 1;
|
||||||
|
if (!m.wire.empty()) {
|
||||||
|
this_score += wire_db.at(tuple<IdString, IdString>(m.module, m.wire)) ? 0 : 5;
|
||||||
|
this_score += wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)) ? 0 : 1;
|
||||||
|
}
|
||||||
|
for (auto &s : m.src) {
|
||||||
|
this_score += src_db.at(s) ? 0 : 5;
|
||||||
|
}
|
||||||
|
return this_score;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mutate_queue_t
|
||||||
|
{
|
||||||
|
pool<mutate_t*, hash_ptr_ops> db;
|
||||||
|
|
||||||
|
mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
|
||||||
|
mutate_t *m = nullptr;
|
||||||
|
if (rng(100) < opts.pick_cover_prcnt) {
|
||||||
|
vector<mutate_t*> candidates, rmqueue;
|
||||||
|
int best_score = -1;
|
||||||
|
for (auto p : db) {
|
||||||
|
if (p->used) {
|
||||||
|
rmqueue.push_back(p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int this_score = coverdb.score(*p);
|
||||||
|
if (this_score > best_score) {
|
||||||
|
best_score = this_score;
|
||||||
|
candidates.clear();
|
||||||
|
}
|
||||||
|
if (best_score == this_score)
|
||||||
|
candidates.push_back(p);
|
||||||
|
}
|
||||||
|
for (auto p : rmqueue)
|
||||||
|
db.erase(p);
|
||||||
|
if (!candidates.empty())
|
||||||
|
m = candidates[rng(GetSize(candidates))];
|
||||||
|
}
|
||||||
|
if (m == nullptr) {
|
||||||
|
while (!db.empty()) {
|
||||||
|
int i = rng(GetSize(db));
|
||||||
|
auto it = db.element(i);
|
||||||
|
mutate_t *p = *it;
|
||||||
|
db.erase(it);
|
||||||
|
if (p->used == false) {
|
||||||
|
m = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(mutate_t *m) {
|
||||||
|
db.insert(m);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename T>
|
||||||
|
struct mutate_chain_queue_t
|
||||||
|
{
|
||||||
|
dict<K, T> db;
|
||||||
|
|
||||||
|
mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
|
||||||
|
while (!db.empty()) {
|
||||||
|
int i = rng(GetSize(db));
|
||||||
|
auto it = db.element(i);
|
||||||
|
mutate_t *m = it->second.pick(rng, coverdb, opts);
|
||||||
|
if (m != nullptr)
|
||||||
|
return m;
|
||||||
|
db.erase(it);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void add(mutate_t *m, K key, Args... args) {
|
||||||
|
db[key].add(m, args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename T>
|
||||||
|
struct mutate_once_queue_t
|
||||||
|
{
|
||||||
|
dict<K, T> db;
|
||||||
|
|
||||||
|
mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
|
||||||
|
while (!db.empty()) {
|
||||||
|
int i = rng(GetSize(db));
|
||||||
|
auto it = db.element(i);
|
||||||
|
mutate_t *m = it->second.pick(rng, coverdb, opts);
|
||||||
|
db.erase(it);
|
||||||
|
if (m != nullptr)
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void add(mutate_t *m, K key, Args... args) {
|
||||||
|
db[key].add(m, args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void database_reduce(std::vector<mutate_t> &database, const mutate_opts_t &opts, int N, xs128_t &rng)
|
||||||
|
{
|
||||||
|
std::vector<mutate_t> new_database;
|
||||||
|
coverdb_t coverdb;
|
||||||
|
|
||||||
|
int total_weight = opts.weight_cover + opts.weight_pq_w + opts.weight_pq_b + opts.weight_pq_c + opts.weight_pq_s;
|
||||||
|
total_weight += opts.weight_pq_mw + opts.weight_pq_mb + opts.weight_pq_mc + opts.weight_pq_ms;
|
||||||
|
|
||||||
|
if (N >= GetSize(database))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_wire;
|
||||||
|
mutate_once_queue_t<tuple<IdString, IdString, int>, mutate_queue_t> primary_queue_bit;
|
||||||
|
mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_cell;
|
||||||
|
mutate_once_queue_t<string, mutate_queue_t> primary_queue_src;
|
||||||
|
|
||||||
|
mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_wire;
|
||||||
|
mutate_chain_queue_t<IdString, mutate_once_queue_t<pair<IdString, int>, mutate_queue_t>> primary_queue_module_bit;
|
||||||
|
mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_cell;
|
||||||
|
mutate_chain_queue_t<IdString, mutate_once_queue_t<string, mutate_queue_t>> primary_queue_module_src;
|
||||||
|
|
||||||
|
for (auto &m : database)
|
||||||
|
{
|
||||||
|
coverdb.insert(m);
|
||||||
|
|
||||||
|
if (!m.wire.empty()) {
|
||||||
|
primary_queue_wire.add(&m, tuple<IdString, IdString>(m.module, m.wire));
|
||||||
|
primary_queue_bit.add(&m, tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit));
|
||||||
|
primary_queue_module_wire.add(&m, m.module, m.wire);
|
||||||
|
primary_queue_module_bit.add(&m, m.module, pair<IdString, int>(m.wire, m.wirebit));
|
||||||
|
}
|
||||||
|
|
||||||
|
primary_queue_cell.add(&m, tuple<IdString, IdString>(m.module, m.cell));
|
||||||
|
primary_queue_module_cell.add(&m, m.module, m.cell);
|
||||||
|
|
||||||
|
for (auto &s : m.src) {
|
||||||
|
primary_queue_src.add(&m, s);
|
||||||
|
primary_queue_module_src.add(&m, m.module, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<mutate_t*> cover_candidates;
|
||||||
|
int best_cover_score = -1;
|
||||||
|
bool skip_cover = false;
|
||||||
|
|
||||||
|
while (GetSize(new_database) < N)
|
||||||
|
{
|
||||||
|
int k = rng(total_weight);
|
||||||
|
|
||||||
|
k -= opts.weight_cover;
|
||||||
|
if (k < 0) {
|
||||||
|
while (!skip_cover) {
|
||||||
|
if (cover_candidates.empty()) {
|
||||||
|
best_cover_score = -1;
|
||||||
|
for (auto &m : database) {
|
||||||
|
if (m.used || m.src.empty())
|
||||||
|
continue;
|
||||||
|
int this_score = -1;
|
||||||
|
for (auto &s : m.src) {
|
||||||
|
if (this_score == -1 || this_score > coverdb.src_db.at(s))
|
||||||
|
this_score = coverdb.src_db.at(s);
|
||||||
|
}
|
||||||
|
log_assert(this_score != -1);
|
||||||
|
if (best_cover_score == -1 || this_score < best_cover_score) {
|
||||||
|
cover_candidates.clear();
|
||||||
|
best_cover_score = this_score;
|
||||||
|
}
|
||||||
|
if (best_cover_score == this_score)
|
||||||
|
cover_candidates.push_back(&m);
|
||||||
|
}
|
||||||
|
if (best_cover_score == -1) {
|
||||||
|
skip_cover = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutate_t *m = nullptr;
|
||||||
|
while (!cover_candidates.empty())
|
||||||
|
{
|
||||||
|
int idx = rng(GetSize(cover_candidates));
|
||||||
|
mutate_t *p = cover_candidates[idx];
|
||||||
|
cover_candidates[idx] = cover_candidates.back();
|
||||||
|
cover_candidates.pop_back();
|
||||||
|
|
||||||
|
if (p->used)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int this_score = -1;
|
||||||
|
for (auto &s : p->src) {
|
||||||
|
if (this_score == -1 || this_score > coverdb.src_db.at(s))
|
||||||
|
this_score = coverdb.src_db.at(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this_score != best_cover_score)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m != nullptr) {
|
||||||
|
m->used = true;
|
||||||
|
coverdb.update(*m);
|
||||||
|
new_database.push_back(*m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X(__wght, __queue) \
|
||||||
|
k -= __wght; \
|
||||||
|
if (k < 0) { \
|
||||||
|
mutate_t *m = __queue.pick(rng, coverdb, opts); \
|
||||||
|
if (m != nullptr) { \
|
||||||
|
m->used = true; \
|
||||||
|
coverdb.update(*m); \
|
||||||
|
new_database.push_back(*m); \
|
||||||
|
}; \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
|
X(opts.weight_pq_w, primary_queue_wire)
|
||||||
|
X(opts.weight_pq_b, primary_queue_bit)
|
||||||
|
X(opts.weight_pq_c, primary_queue_cell)
|
||||||
|
X(opts.weight_pq_s, primary_queue_src)
|
||||||
|
|
||||||
|
X(opts.weight_pq_mw, primary_queue_module_wire)
|
||||||
|
X(opts.weight_pq_mb, primary_queue_module_bit)
|
||||||
|
X(opts.weight_pq_mc, primary_queue_module_cell)
|
||||||
|
X(opts.weight_pq_ms, primary_queue_module_src)
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
std::swap(new_database, database);
|
||||||
|
|
||||||
|
int covered_src_cnt = 0;
|
||||||
|
int covered_wire_cnt = 0;
|
||||||
|
int covered_wirebit_cnt = 0;
|
||||||
|
|
||||||
|
for (auto &it : coverdb.src_db)
|
||||||
|
if (it.second)
|
||||||
|
covered_src_cnt++;
|
||||||
|
|
||||||
|
for (auto &it : coverdb.wire_db)
|
||||||
|
if (it.second)
|
||||||
|
covered_wire_cnt++;
|
||||||
|
|
||||||
|
for (auto &it : coverdb.wirebit_db)
|
||||||
|
if (it.second)
|
||||||
|
covered_wirebit_cnt++;
|
||||||
|
|
||||||
|
log("Covered %d/%d src attributes (%.2f%%).\n", covered_src_cnt, GetSize(coverdb.src_db), 100.0 * covered_src_cnt / GetSize(coverdb.src_db));
|
||||||
|
log("Covered %d/%d wires (%.2f%%).\n", covered_wire_cnt, GetSize(coverdb.wire_db), 100.0 * covered_wire_cnt / GetSize(coverdb.wire_db));
|
||||||
|
log("Covered %d/%d wire bits (%.2f%%).\n", covered_wirebit_cnt, GetSize(coverdb.wirebit_db), 100.0 * covered_wirebit_cnt / GetSize(coverdb.wirebit_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, const string &srcsfile, int N)
|
||||||
|
{
|
||||||
|
pool<string> sources;
|
||||||
|
std::vector<mutate_t> database;
|
||||||
|
xs128_t rng(opts.seed);
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules())
|
||||||
|
{
|
||||||
|
if (!opts.module.empty() && module->name != opts.module)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigMap sigmap(module);
|
||||||
|
dict<SigBit, int> bit_user_cnt;
|
||||||
|
|
||||||
|
for (auto wire : module->wires()) {
|
||||||
|
if (wire->name[0] == '\\' && wire->attributes.count("\\src"))
|
||||||
|
sigmap.add(wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto cell : module->cells()) {
|
||||||
|
for (auto &conn : cell->connections()) {
|
||||||
|
if (cell->output(conn.first))
|
||||||
|
continue;
|
||||||
|
for (auto bit : sigmap(conn.second))
|
||||||
|
bit_user_cnt[bit]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto wire : module->selected_wires())
|
||||||
|
{
|
||||||
|
for (SigBit bit : SigSpec(wire))
|
||||||
|
{
|
||||||
|
SigBit sigbit = sigmap(bit);
|
||||||
|
|
||||||
|
if (bit.wire == nullptr || sigbit.wire == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!bit.wire->port_id != !sigbit.wire->port_id) {
|
||||||
|
if (bit.wire->port_id)
|
||||||
|
sigmap.add(bit);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bit.wire->name[0] != !sigbit.wire->name[0]) {
|
||||||
|
if (bit.wire->name[0] == '\\')
|
||||||
|
sigmap.add(bit);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto cell : module->selected_cells())
|
||||||
|
{
|
||||||
|
if (!opts.cell.empty() && cell->name != opts.cell)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (auto &conn : cell->connections())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < GetSize(conn.second); i++) {
|
||||||
|
mutate_t entry;
|
||||||
|
entry.module = module->name;
|
||||||
|
entry.cell = cell->name;
|
||||||
|
entry.port = conn.first;
|
||||||
|
entry.portbit = i;
|
||||||
|
|
||||||
|
for (auto &s : cell->get_strpool_attribute("\\src"))
|
||||||
|
entry.src.insert(s);
|
||||||
|
|
||||||
|
SigBit bit = sigmap(conn.second[i]);
|
||||||
|
if (bit.wire && bit.wire->name[0] == '\\' && (cell->output(conn.first) || bit_user_cnt[bit] == 1)) {
|
||||||
|
for (auto &s : bit.wire->get_strpool_attribute("\\src"))
|
||||||
|
entry.src.insert(s);
|
||||||
|
entry.wire = bit.wire->name;
|
||||||
|
entry.wirebit = bit.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!srcsfile.empty())
|
||||||
|
sources.insert(entry.src.begin(), entry.src.end());
|
||||||
|
|
||||||
|
entry.mode = "inv";
|
||||||
|
database_add(database, opts, entry);
|
||||||
|
|
||||||
|
entry.mode = "const0";
|
||||||
|
database_add(database, opts, entry);
|
||||||
|
|
||||||
|
entry.mode = "const1";
|
||||||
|
database_add(database, opts, entry);
|
||||||
|
|
||||||
|
entry.mode = "cnot0";
|
||||||
|
entry.ctrlbit = rng(GetSize(conn.second));
|
||||||
|
if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire)
|
||||||
|
database_add(database, opts, entry);
|
||||||
|
|
||||||
|
entry.mode = "cnot1";
|
||||||
|
entry.ctrlbit = rng(GetSize(conn.second));
|
||||||
|
if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire)
|
||||||
|
database_add(database, opts, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log("Raw database size: %d\n", GetSize(database));
|
||||||
|
if (N != 0) {
|
||||||
|
database_reduce(database, opts, opts.none ? N-1 : N, rng);
|
||||||
|
log("Reduced database size: %d\n", GetSize(database));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!srcsfile.empty()) {
|
||||||
|
std::ofstream sout;
|
||||||
|
sout.open(srcsfile, std::ios::out | std::ios::trunc);
|
||||||
|
if (!sout.is_open())
|
||||||
|
log_error("Could not open file \"%s\" with write access.\n", srcsfile.c_str());
|
||||||
|
sources.sort();
|
||||||
|
for (auto &s : sources)
|
||||||
|
sout << s << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream fout;
|
||||||
|
|
||||||
|
if (!filename.empty()) {
|
||||||
|
fout.open(filename, std::ios::out | std::ios::trunc);
|
||||||
|
if (!fout.is_open())
|
||||||
|
log_error("Could not open file \"%s\" with write access.\n", filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctrl_value = opts.ctrl_value;
|
||||||
|
|
||||||
|
if (opts.none) {
|
||||||
|
string str = "mutate";
|
||||||
|
if (!opts.ctrl_name.empty())
|
||||||
|
str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++);
|
||||||
|
str += " -mode none";
|
||||||
|
if (filename.empty())
|
||||||
|
log("%s\n", str.c_str());
|
||||||
|
else
|
||||||
|
fout << str << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &entry : database) {
|
||||||
|
string str = "mutate";
|
||||||
|
if (!opts.ctrl_name.empty())
|
||||||
|
str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++);
|
||||||
|
str += stringf(" -mode %s", entry.mode.c_str());
|
||||||
|
if (!entry.module.empty())
|
||||||
|
str += stringf(" -module %s", log_id(entry.module));
|
||||||
|
if (!entry.cell.empty())
|
||||||
|
str += stringf(" -cell %s", log_id(entry.cell));
|
||||||
|
if (!entry.port.empty())
|
||||||
|
str += stringf(" -port %s", log_id(entry.port));
|
||||||
|
if (entry.portbit >= 0)
|
||||||
|
str += stringf(" -portbit %d", entry.portbit);
|
||||||
|
if (entry.ctrlbit >= 0)
|
||||||
|
str += stringf(" -ctrlbit %d", entry.ctrlbit);
|
||||||
|
if (!entry.wire.empty())
|
||||||
|
str += stringf(" -wire %s", log_id(entry.wire));
|
||||||
|
if (entry.wirebit >= 0)
|
||||||
|
str += stringf(" -wirebit %d", entry.wirebit);
|
||||||
|
for (auto &s : entry.src)
|
||||||
|
str += stringf(" -src %s", s.c_str());
|
||||||
|
if (filename.empty())
|
||||||
|
log("%s\n", str.c_str());
|
||||||
|
else
|
||||||
|
fout << str << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec mutate_ctrl_sig(Module *module, IdString name, int width)
|
||||||
|
{
|
||||||
|
Wire *ctrl_wire = module->wire(name);
|
||||||
|
|
||||||
|
if (ctrl_wire == nullptr)
|
||||||
|
{
|
||||||
|
log("Adding ctrl port %s to module %s.\n", log_id(name), log_id(module));
|
||||||
|
|
||||||
|
ctrl_wire = module->addWire(name, width);
|
||||||
|
ctrl_wire->port_input = true;
|
||||||
|
module->fixup_ports();
|
||||||
|
|
||||||
|
for (auto mod : module->design->modules())
|
||||||
|
for (auto cell : mod->cells())
|
||||||
|
{
|
||||||
|
if (cell->type != module->name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigSpec ctrl = mutate_ctrl_sig(mod, name, width);
|
||||||
|
|
||||||
|
log("Connecting ctrl port to cell %s in module %s.\n", log_id(cell), log_id(mod));
|
||||||
|
cell->setPort(name, ctrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_assert(GetSize(ctrl_wire) == width);
|
||||||
|
return ctrl_wire;
|
||||||
|
}
|
||||||
|
|
||||||
|
SigBit mutate_ctrl(Module *module, const mutate_opts_t &opts)
|
||||||
|
{
|
||||||
|
if (opts.ctrl_name.empty())
|
||||||
|
return State::S1;
|
||||||
|
|
||||||
|
SigSpec sig = mutate_ctrl_sig(module, opts.ctrl_name, opts.ctrl_width);
|
||||||
|
return module->Eq(NEW_ID, sig, Const(opts.ctrl_value, GetSize(sig)));
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec mutate_ctrl_mux(Module *module, const mutate_opts_t &opts, SigSpec unchanged_sig, SigSpec changed_sig)
|
||||||
|
{
|
||||||
|
SigBit ctrl_bit = mutate_ctrl(module, opts);
|
||||||
|
if (ctrl_bit == State::S0)
|
||||||
|
return unchanged_sig;
|
||||||
|
if (ctrl_bit == State::S1)
|
||||||
|
return changed_sig;
|
||||||
|
return module->Mux(NEW_ID, unchanged_sig, changed_sig, ctrl_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutate_inv(Design *design, const mutate_opts_t &opts)
|
||||||
|
{
|
||||||
|
Module *module = design->module(opts.module);
|
||||||
|
Cell *cell = module->cell(opts.cell);
|
||||||
|
|
||||||
|
SigBit bit = cell->getPort(opts.port)[opts.portbit];
|
||||||
|
SigBit inbit, outbit;
|
||||||
|
|
||||||
|
if (cell->input(opts.port))
|
||||||
|
{
|
||||||
|
log("Add input inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
|
||||||
|
SigBit outbit = module->Not(NEW_ID, bit);
|
||||||
|
bit = mutate_ctrl_mux(module, opts, bit, outbit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log("Add output inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
|
||||||
|
SigBit inbit = module->addWire(NEW_ID);
|
||||||
|
SigBit outbit = module->Not(NEW_ID, inbit);
|
||||||
|
module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
|
||||||
|
bit = inbit;
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec s = cell->getPort(opts.port);
|
||||||
|
s[opts.portbit] = bit;
|
||||||
|
cell->setPort(opts.port, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutate_const(Design *design, const mutate_opts_t &opts, bool one)
|
||||||
|
{
|
||||||
|
Module *module = design->module(opts.module);
|
||||||
|
Cell *cell = module->cell(opts.cell);
|
||||||
|
|
||||||
|
SigBit bit = cell->getPort(opts.port)[opts.portbit];
|
||||||
|
SigBit inbit, outbit;
|
||||||
|
|
||||||
|
if (cell->input(opts.port))
|
||||||
|
{
|
||||||
|
log("Add input constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
|
||||||
|
SigBit outbit = one ? State::S1 : State::S0;
|
||||||
|
bit = mutate_ctrl_mux(module, opts, bit, outbit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log("Add output constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit);
|
||||||
|
SigBit inbit = module->addWire(NEW_ID);
|
||||||
|
SigBit outbit = one ? State::S1 : State::S0;
|
||||||
|
module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
|
||||||
|
bit = inbit;
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec s = cell->getPort(opts.port);
|
||||||
|
s[opts.portbit] = bit;
|
||||||
|
cell->setPort(opts.port, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutate_cnot(Design *design, const mutate_opts_t &opts, bool one)
|
||||||
|
{
|
||||||
|
Module *module = design->module(opts.module);
|
||||||
|
Cell *cell = module->cell(opts.cell);
|
||||||
|
|
||||||
|
SigBit bit = cell->getPort(opts.port)[opts.portbit];
|
||||||
|
SigBit ctrl = cell->getPort(opts.port)[opts.ctrlbit];
|
||||||
|
SigBit inbit, outbit;
|
||||||
|
|
||||||
|
if (cell->input(opts.port))
|
||||||
|
{
|
||||||
|
log("Add input cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit);
|
||||||
|
SigBit outbit = one ? module->Xor(NEW_ID, bit, ctrl) : module->Xnor(NEW_ID, bit, ctrl);
|
||||||
|
bit = mutate_ctrl_mux(module, opts, bit, outbit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log("Add output cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit);
|
||||||
|
SigBit inbit = module->addWire(NEW_ID);
|
||||||
|
SigBit outbit = one ? module->Xor(NEW_ID, inbit, ctrl) : module->Xnor(NEW_ID, inbit, ctrl);
|
||||||
|
module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit));
|
||||||
|
bit = inbit;
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec s = cell->getPort(opts.port);
|
||||||
|
s[opts.portbit] = bit;
|
||||||
|
cell->setPort(opts.port, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MutatePass : public Pass {
|
||||||
|
MutatePass() : Pass("mutate", "generate or apply design mutations") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" mutate -list N [options] [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Create a list of N mutations using an even sampling.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -o filename\n");
|
||||||
|
log(" Write list to this file instead of console output\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -s filename\n");
|
||||||
|
log(" Write a list of all src tags found in the design to the specified file\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -seed N\n");
|
||||||
|
log(" RNG seed for selecting mutations\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -none\n");
|
||||||
|
log(" Include a \"none\" mutation in the output\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -ctrl name width value\n");
|
||||||
|
log(" Add -ctrl options to the output. Use 'value' for first mutation, then\n");
|
||||||
|
log(" simply count up from there.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -mode name\n");
|
||||||
|
log(" -module name\n");
|
||||||
|
log(" -cell name\n");
|
||||||
|
log(" -port name\n");
|
||||||
|
log(" -portbit int\n");
|
||||||
|
log(" -ctrlbit int\n");
|
||||||
|
log(" -wire name\n");
|
||||||
|
log(" -wirebit int\n");
|
||||||
|
log(" -src string\n");
|
||||||
|
log(" Filter list of mutation candidates to those matching\n");
|
||||||
|
log(" the given parameters.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -cfg option int\n");
|
||||||
|
log(" Set a configuration option. Options available:\n");
|
||||||
|
log(" weight_pq_w weight_pq_b weight_pq_c weight_pq_s\n");
|
||||||
|
log(" weight_pq_mw weight_pq_mb weight_pq_mc weight_pq_ms\n");
|
||||||
|
log(" weight_cover pick_cover_prcnt\n");
|
||||||
|
log("\n");
|
||||||
|
log("\n");
|
||||||
|
log(" mutate -mode MODE [options]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Apply the given mutation.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -ctrl name width value\n");
|
||||||
|
log(" Add a control signal with the given name and width. The mutation is\n");
|
||||||
|
log(" activated if the control signal equals the given value.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -module name\n");
|
||||||
|
log(" -cell name\n");
|
||||||
|
log(" -port name\n");
|
||||||
|
log(" -portbit int\n");
|
||||||
|
log(" -ctrlbit int\n");
|
||||||
|
log(" Mutation parameters, as generated by 'mutate -list N'.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -wire name\n");
|
||||||
|
log(" -wirebit int\n");
|
||||||
|
log(" -src string\n");
|
||||||
|
log(" Ignored. (They are generated by -list for documentation purposes.)\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
mutate_opts_t opts;
|
||||||
|
string filename;
|
||||||
|
string srcsfile;
|
||||||
|
int N = -1;
|
||||||
|
|
||||||
|
log_header(design, "Executing MUTATE pass.\n");
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
if (args[argidx] == "-list" && argidx+1 < args.size()) {
|
||||||
|
N = atoi(args[++argidx].c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-o" && argidx+1 < args.size()) {
|
||||||
|
filename = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-s" && argidx+1 < args.size()) {
|
||||||
|
srcsfile = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-seed" && argidx+1 < args.size()) {
|
||||||
|
opts.seed = atoi(args[++argidx].c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-none") {
|
||||||
|
opts.none = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-mode" && argidx+1 < args.size()) {
|
||||||
|
opts.mode = args[++argidx];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-ctrl" && argidx+3 < args.size()) {
|
||||||
|
opts.ctrl_name = RTLIL::escape_id(args[++argidx]);
|
||||||
|
opts.ctrl_width = atoi(args[++argidx].c_str());
|
||||||
|
opts.ctrl_value = atoi(args[++argidx].c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-module" && argidx+1 < args.size()) {
|
||||||
|
opts.module = RTLIL::escape_id(args[++argidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-cell" && argidx+1 < args.size()) {
|
||||||
|
opts.cell = RTLIL::escape_id(args[++argidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-port" && argidx+1 < args.size()) {
|
||||||
|
opts.port = RTLIL::escape_id(args[++argidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-portbit" && argidx+1 < args.size()) {
|
||||||
|
opts.portbit = atoi(args[++argidx].c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-ctrlbit" && argidx+1 < args.size()) {
|
||||||
|
opts.ctrlbit = atoi(args[++argidx].c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-wire" && argidx+1 < args.size()) {
|
||||||
|
opts.wire = RTLIL::escape_id(args[++argidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-wirebit" && argidx+1 < args.size()) {
|
||||||
|
opts.wirebit = atoi(args[++argidx].c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-src" && argidx+1 < args.size()) {
|
||||||
|
opts.src.insert(args[++argidx]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-cfg" && argidx+2 < args.size()) {
|
||||||
|
if (args[argidx+1] == "pick_cover_prcnt") {
|
||||||
|
opts.pick_cover_prcnt = atoi(args[argidx+2].c_str());
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx+1] == "weight_cover") {
|
||||||
|
opts.weight_cover = atoi(args[argidx+2].c_str());
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx+1] == "weight_pq_w") {
|
||||||
|
opts.weight_pq_w = atoi(args[argidx+2].c_str());
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx+1] == "weight_pq_b") {
|
||||||
|
opts.weight_pq_b = atoi(args[argidx+2].c_str());
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx+1] == "weight_pq_c") {
|
||||||
|
opts.weight_pq_c = atoi(args[argidx+2].c_str());
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx+1] == "weight_pq_s") {
|
||||||
|
opts.weight_pq_s = atoi(args[argidx+2].c_str());
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx+1] == "weight_pq_mw") {
|
||||||
|
opts.weight_pq_mw = atoi(args[argidx+2].c_str());
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx+1] == "weight_pq_mb") {
|
||||||
|
opts.weight_pq_mb = atoi(args[argidx+2].c_str());
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx+1] == "weight_pq_mc") {
|
||||||
|
opts.weight_pq_mc = atoi(args[argidx+2].c_str());
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx+1] == "weight_pq_ms") {
|
||||||
|
opts.weight_pq_ms = atoi(args[argidx+2].c_str());
|
||||||
|
argidx += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
if (N >= 0) {
|
||||||
|
mutate_list(design, opts, filename, srcsfile, N);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.mode == "none") {
|
||||||
|
if (!opts.ctrl_name.empty()) {
|
||||||
|
Module *topmod = opts.module.empty() ? design->top_module() : design->module(opts.module);
|
||||||
|
if (topmod)
|
||||||
|
mutate_ctrl_sig(topmod, opts.ctrl_name, opts.ctrl_width);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.mode == "inv") {
|
||||||
|
mutate_inv(design, opts);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.mode == "const0" || opts.mode == "const1") {
|
||||||
|
mutate_const(design, opts, opts.mode == "const1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.mode == "cnot0" || opts.mode == "cnot1") {
|
||||||
|
mutate_cnot(design, opts, opts.mode == "cnot1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_cmd_error("Invalid mode: %s\n", opts.mode.c_str());
|
||||||
|
}
|
||||||
|
} MutatePass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -24,6 +24,7 @@
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#ifndef FILTERLIB
|
#ifndef FILTERLIB
|
||||||
#include "kernel/log.h"
|
#include "kernel/log.h"
|
||||||
|
@ -86,15 +87,17 @@ int LibertyParser::lexer(std::string &str)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
// eat whitespace
|
||||||
do {
|
do {
|
||||||
c = f.get();
|
c = f.get();
|
||||||
} while (c == ' ' || c == '\t' || c == '\r');
|
} while (c == ' ' || c == '\t' || c == '\r');
|
||||||
|
|
||||||
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']') {
|
// search for identifiers, numbers, plus or minus.
|
||||||
|
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
|
||||||
str = c;
|
str = c;
|
||||||
while (1) {
|
while (1) {
|
||||||
c = f.get();
|
c = f.get();
|
||||||
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']')
|
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
|
||||||
str += c;
|
str += c;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
@ -111,6 +114,8 @@ int LibertyParser::lexer(std::string &str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if it wasn't an identifer, number of array range,
|
||||||
|
// maybe it's a string?
|
||||||
if (c == '"') {
|
if (c == '"') {
|
||||||
str = "";
|
str = "";
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -125,9 +130,10 @@ int LibertyParser::lexer(std::string &str)
|
||||||
return 'v';
|
return 'v';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if it wasn't a string, perhaps it's a comment or a forward slash?
|
||||||
if (c == '/') {
|
if (c == '/') {
|
||||||
c = f.get();
|
c = f.get();
|
||||||
if (c == '*') {
|
if (c == '*') { // start of '/*' block comment
|
||||||
int last_c = 0;
|
int last_c = 0;
|
||||||
while (c > 0 && (last_c != '*' || c != '/')) {
|
while (c > 0 && (last_c != '*' || c != '/')) {
|
||||||
last_c = c;
|
last_c = c;
|
||||||
|
@ -136,7 +142,7 @@ int LibertyParser::lexer(std::string &str)
|
||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
return lexer(str);
|
return lexer(str);
|
||||||
} else if (c == '/') {
|
} else if (c == '/') { // start of '//' line comment
|
||||||
while (c > 0 && c != '\n')
|
while (c > 0 && c != '\n')
|
||||||
c = f.get();
|
c = f.get();
|
||||||
line++;
|
line++;
|
||||||
|
@ -144,24 +150,31 @@ int LibertyParser::lexer(std::string &str)
|
||||||
}
|
}
|
||||||
f.unget();
|
f.unget();
|
||||||
// fprintf(stderr, "LEX: char >>/<<\n");
|
// fprintf(stderr, "LEX: char >>/<<\n");
|
||||||
return '/';
|
return '/'; // a single '/' charater.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for a backslash
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
c = f.get();
|
c = f.get();
|
||||||
if (c == '\r')
|
if (c == '\r')
|
||||||
c = f.get();
|
c = f.get();
|
||||||
if (c == '\n')
|
if (c == '\n') {
|
||||||
|
line++;
|
||||||
return lexer(str);
|
return lexer(str);
|
||||||
|
}
|
||||||
f.unget();
|
f.unget();
|
||||||
return '\\';
|
return '\\';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for a new line
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
line++;
|
line++;
|
||||||
return 'n';
|
return 'n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// anything else, such as ';' will get passed
|
||||||
|
// through as literal items.
|
||||||
|
|
||||||
// if (c >= 32 && c < 255)
|
// if (c >= 32 && c < 255)
|
||||||
// fprintf(stderr, "LEX: char >>%c<<\n", c);
|
// fprintf(stderr, "LEX: char >>%c<<\n", c);
|
||||||
// else
|
// else
|
||||||
|
@ -175,14 +188,39 @@ LibertyAst *LibertyParser::parse()
|
||||||
|
|
||||||
int tok = lexer(str);
|
int tok = lexer(str);
|
||||||
|
|
||||||
while (tok == 'n')
|
// there are liberty files in the wild that
|
||||||
|
// have superfluous ';' at the end of
|
||||||
|
// a { ... }. We simply ignore a ';' here.
|
||||||
|
// and get to the next statement.
|
||||||
|
|
||||||
|
while ((tok == 'n') || (tok == ';'))
|
||||||
tok = lexer(str);
|
tok = lexer(str);
|
||||||
|
|
||||||
if (tok == '}' || tok < 0)
|
if (tok == '}' || tok < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (tok != 'v')
|
if (tok != 'v') {
|
||||||
|
std::string eReport;
|
||||||
|
switch(tok)
|
||||||
|
{
|
||||||
|
case 'n':
|
||||||
|
error("Unexpected newline.");
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '}':
|
||||||
|
case '{':
|
||||||
|
case '\"':
|
||||||
|
case ':':
|
||||||
|
eReport = "Unexpected '";
|
||||||
|
eReport += static_cast<char>(tok);
|
||||||
|
eReport += "'.";
|
||||||
|
error(eReport);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
error();
|
error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LibertyAst *ast = new LibertyAst;
|
LibertyAst *ast = new LibertyAst;
|
||||||
ast->id = str;
|
ast->id = str;
|
||||||
|
@ -191,12 +229,11 @@ LibertyAst *LibertyParser::parse()
|
||||||
{
|
{
|
||||||
tok = lexer(str);
|
tok = lexer(str);
|
||||||
|
|
||||||
if (tok == ';')
|
// allow both ';' and new lines to
|
||||||
|
// terminate a statement.
|
||||||
|
if ((tok == ';') || (tok == 'n'))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (tok == 'n')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (tok == ':' && ast->value.empty()) {
|
if (tok == ':' && ast->value.empty()) {
|
||||||
tok = lexer(ast->value);
|
tok = lexer(ast->value);
|
||||||
if (tok != 'v')
|
if (tok != 'v')
|
||||||
|
@ -210,7 +247,12 @@ LibertyAst *LibertyParser::parse()
|
||||||
ast->value += str;
|
ast->value += str;
|
||||||
tok = lexer(str);
|
tok = lexer(str);
|
||||||
}
|
}
|
||||||
if (tok == ';')
|
|
||||||
|
// In a liberty file, all key : value pairs should end in ';'
|
||||||
|
// However, there are some liberty files in the wild that
|
||||||
|
// just have a newline. We'll be kind and accept a newline
|
||||||
|
// instead of the ';' too..
|
||||||
|
if ((tok == ';') || (tok == 'n'))
|
||||||
break;
|
break;
|
||||||
else
|
else
|
||||||
error();
|
error();
|
||||||
|
@ -225,8 +267,70 @@ LibertyAst *LibertyParser::parse()
|
||||||
continue;
|
continue;
|
||||||
if (tok == ')')
|
if (tok == ')')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// FIXME: the AST needs to be extended to store
|
||||||
|
// these vector ranges.
|
||||||
|
if (tok == '[')
|
||||||
|
{
|
||||||
|
// parse vector range [A] or [A:B]
|
||||||
|
std::string arg;
|
||||||
|
tok = lexer(arg);
|
||||||
if (tok != 'v')
|
if (tok != 'v')
|
||||||
|
{
|
||||||
|
// expected a vector array index
|
||||||
|
error("Expected a number.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// fixme: check for number A
|
||||||
|
}
|
||||||
|
tok = lexer(arg);
|
||||||
|
// optionally check for : in case of [A:B]
|
||||||
|
// if it isn't we just expect ']'
|
||||||
|
// as we have [A]
|
||||||
|
if (tok == ':')
|
||||||
|
{
|
||||||
|
tok = lexer(arg);
|
||||||
|
if (tok != 'v')
|
||||||
|
{
|
||||||
|
// expected a vector array index
|
||||||
|
error("Expected a number.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// fixme: check for number B
|
||||||
|
tok = lexer(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// expect a closing bracket of array range
|
||||||
|
if (tok != ']')
|
||||||
|
{
|
||||||
|
error("Expected ']' on array range.");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tok != 'v') {
|
||||||
|
std::string eReport;
|
||||||
|
switch(tok)
|
||||||
|
{
|
||||||
|
case 'n':
|
||||||
|
error("Unexpected newline.");
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '}':
|
||||||
|
case '{':
|
||||||
|
case '\"':
|
||||||
|
case ':':
|
||||||
|
eReport = "Unexpected '";
|
||||||
|
eReport += static_cast<char>(tok);
|
||||||
|
eReport += "'.";
|
||||||
|
error(eReport);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
error();
|
error();
|
||||||
|
}
|
||||||
|
}
|
||||||
ast->args.push_back(arg);
|
ast->args.push_back(arg);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -255,6 +359,14 @@ void LibertyParser::error()
|
||||||
log_error("Syntax error in liberty file on line %d.\n", line);
|
log_error("Syntax error in liberty file on line %d.\n", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LibertyParser::error(const std::string &str)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Syntax error in liberty file on line " << line << ".\n";
|
||||||
|
ss << " " << str << "\n";
|
||||||
|
log_error("%s", ss.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void LibertyParser::error()
|
void LibertyParser::error()
|
||||||
|
@ -263,6 +375,15 @@ void LibertyParser::error()
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LibertyParser::error(const std::string &str)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Syntax error in liberty file on line " << line << ".\n";
|
||||||
|
ss << " " << str << "\n";
|
||||||
|
printf("%s", ss.str().c_str());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
|
/**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
|
||||||
|
|
||||||
#define CHECK_NV(result, check) \
|
#define CHECK_NV(result, check) \
|
||||||
|
|
|
@ -46,9 +46,17 @@ namespace Yosys
|
||||||
LibertyAst *ast;
|
LibertyAst *ast;
|
||||||
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
|
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
|
||||||
~LibertyParser() { if (ast) delete ast; }
|
~LibertyParser() { if (ast) delete ast; }
|
||||||
|
|
||||||
|
/* lexer return values:
|
||||||
|
'v': identifier, string, array range [...] -> str holds the token string
|
||||||
|
'n': newline
|
||||||
|
anything else is a single character.
|
||||||
|
*/
|
||||||
int lexer(std::string &str);
|
int lexer(std::string &str);
|
||||||
|
|
||||||
LibertyAst *parse();
|
LibertyAst *parse();
|
||||||
void error();
|
void error();
|
||||||
|
void error(const std::string &str);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,10 +79,12 @@ struct Ecp5FfinitPass : public Pass {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (initbits.count(bit)) {
|
if (initbits.count(bit)) {
|
||||||
if (initbits.at(bit) != val)
|
if (initbits.at(bit) != val) {
|
||||||
log_error("Conflicting init values for signal %s (%s = %s, %s = %s).\n",
|
log_warning("Conflicting init values for signal %s (%s = %s, %s = %s).\n",
|
||||||
log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val),
|
log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val),
|
||||||
log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit)));
|
log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit)));
|
||||||
|
initbits.at(bit) = State::Sx;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +123,9 @@ struct Ecp5FfinitPass : public Pass {
|
||||||
|
|
||||||
State val = initbits.at(bit_q);
|
State val = initbits.at(bit_q);
|
||||||
|
|
||||||
|
if (val == State::Sx)
|
||||||
|
continue;
|
||||||
|
|
||||||
log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type),
|
log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type),
|
||||||
log_signal(bit_q), val != State::S0 ? '1' : '0');
|
log_signal(bit_q), val != State::S0 ? '1' : '0');
|
||||||
// Initval is the same as the reset state. Matches hardware, nowt more to do
|
// Initval is the same as the reset state. Matches hardware, nowt more to do
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
OBJS += techlibs/ice40/synth_ice40.o
|
OBJS += techlibs/ice40/synth_ice40.o
|
||||||
|
OBJS += techlibs/ice40/ice40_braminit.o
|
||||||
OBJS += techlibs/ice40/ice40_ffssr.o
|
OBJS += techlibs/ice40/ice40_ffssr.o
|
||||||
OBJS += techlibs/ice40/ice40_ffinit.o
|
OBJS += techlibs/ice40/ice40_ffinit.o
|
||||||
OBJS += techlibs/ice40/ice40_opt.o
|
OBJS += techlibs/ice40/ice40_opt.o
|
||||||
|
|
|
@ -326,6 +326,8 @@ module SB_RAM40_4K (
|
||||||
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||||
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||||
|
|
||||||
|
parameter INIT_FILE = "";
|
||||||
|
|
||||||
`ifndef BLACKBOX
|
`ifndef BLACKBOX
|
||||||
wire [15:0] WMASK_I;
|
wire [15:0] WMASK_I;
|
||||||
wire [15:0] RMASK_I;
|
wire [15:0] RMASK_I;
|
||||||
|
@ -408,25 +410,10 @@ module SB_RAM40_4K (
|
||||||
reg [15:0] memory [0:255];
|
reg [15:0] memory [0:255];
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
|
if (INIT_FILE != "")
|
||||||
|
$readmemh(INIT_FILE, memory);
|
||||||
|
else
|
||||||
for (i=0; i<16; i=i+1) begin
|
for (i=0; i<16; i=i+1) begin
|
||||||
`ifdef YOSYS
|
|
||||||
memory[ 0*16 + i] <= INIT_0[16*i +: 16];
|
|
||||||
memory[ 1*16 + i] <= INIT_1[16*i +: 16];
|
|
||||||
memory[ 2*16 + i] <= INIT_2[16*i +: 16];
|
|
||||||
memory[ 3*16 + i] <= INIT_3[16*i +: 16];
|
|
||||||
memory[ 4*16 + i] <= INIT_4[16*i +: 16];
|
|
||||||
memory[ 5*16 + i] <= INIT_5[16*i +: 16];
|
|
||||||
memory[ 6*16 + i] <= INIT_6[16*i +: 16];
|
|
||||||
memory[ 7*16 + i] <= INIT_7[16*i +: 16];
|
|
||||||
memory[ 8*16 + i] <= INIT_8[16*i +: 16];
|
|
||||||
memory[ 9*16 + i] <= INIT_9[16*i +: 16];
|
|
||||||
memory[10*16 + i] <= INIT_A[16*i +: 16];
|
|
||||||
memory[11*16 + i] <= INIT_B[16*i +: 16];
|
|
||||||
memory[12*16 + i] <= INIT_C[16*i +: 16];
|
|
||||||
memory[13*16 + i] <= INIT_D[16*i +: 16];
|
|
||||||
memory[14*16 + i] <= INIT_E[16*i +: 16];
|
|
||||||
memory[15*16 + i] <= INIT_F[16*i +: 16];
|
|
||||||
`else
|
|
||||||
memory[ 0*16 + i] = INIT_0[16*i +: 16];
|
memory[ 0*16 + i] = INIT_0[16*i +: 16];
|
||||||
memory[ 1*16 + i] = INIT_1[16*i +: 16];
|
memory[ 1*16 + i] = INIT_1[16*i +: 16];
|
||||||
memory[ 2*16 + i] = INIT_2[16*i +: 16];
|
memory[ 2*16 + i] = INIT_2[16*i +: 16];
|
||||||
|
@ -443,7 +430,6 @@ module SB_RAM40_4K (
|
||||||
memory[13*16 + i] = INIT_D[16*i +: 16];
|
memory[13*16 + i] = INIT_D[16*i +: 16];
|
||||||
memory[14*16 + i] = INIT_E[16*i +: 16];
|
memory[14*16 + i] = INIT_E[16*i +: 16];
|
||||||
memory[15*16 + i] = INIT_F[16*i +: 16];
|
memory[15*16 + i] = INIT_F[16*i +: 16];
|
||||||
`endif
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -504,6 +490,8 @@ module SB_RAM40_4KNR (
|
||||||
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||||
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||||
|
|
||||||
|
parameter INIT_FILE = "";
|
||||||
|
|
||||||
SB_RAM40_4K #(
|
SB_RAM40_4K #(
|
||||||
.WRITE_MODE(WRITE_MODE),
|
.WRITE_MODE(WRITE_MODE),
|
||||||
.READ_MODE (READ_MODE ),
|
.READ_MODE (READ_MODE ),
|
||||||
|
@ -522,7 +510,8 @@ module SB_RAM40_4KNR (
|
||||||
.INIT_C (INIT_C ),
|
.INIT_C (INIT_C ),
|
||||||
.INIT_D (INIT_D ),
|
.INIT_D (INIT_D ),
|
||||||
.INIT_E (INIT_E ),
|
.INIT_E (INIT_E ),
|
||||||
.INIT_F (INIT_F )
|
.INIT_F (INIT_F ),
|
||||||
|
.INIT_FILE (INIT_FILE )
|
||||||
) RAM (
|
) RAM (
|
||||||
.RDATA(RDATA),
|
.RDATA(RDATA),
|
||||||
.RCLK (~RCLKN),
|
.RCLK (~RCLKN),
|
||||||
|
@ -566,6 +555,8 @@ module SB_RAM40_4KNW (
|
||||||
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||||
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||||
|
|
||||||
|
parameter INIT_FILE = "";
|
||||||
|
|
||||||
SB_RAM40_4K #(
|
SB_RAM40_4K #(
|
||||||
.WRITE_MODE(WRITE_MODE),
|
.WRITE_MODE(WRITE_MODE),
|
||||||
.READ_MODE (READ_MODE ),
|
.READ_MODE (READ_MODE ),
|
||||||
|
@ -584,7 +575,8 @@ module SB_RAM40_4KNW (
|
||||||
.INIT_C (INIT_C ),
|
.INIT_C (INIT_C ),
|
||||||
.INIT_D (INIT_D ),
|
.INIT_D (INIT_D ),
|
||||||
.INIT_E (INIT_E ),
|
.INIT_E (INIT_E ),
|
||||||
.INIT_F (INIT_F )
|
.INIT_F (INIT_F ),
|
||||||
|
.INIT_FILE (INIT_FILE )
|
||||||
) RAM (
|
) RAM (
|
||||||
.RDATA(RDATA),
|
.RDATA(RDATA),
|
||||||
.RCLK (RCLK ),
|
.RCLK (RCLK ),
|
||||||
|
@ -628,6 +620,8 @@ module SB_RAM40_4KNRNW (
|
||||||
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||||
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
|
||||||
|
|
||||||
|
parameter INIT_FILE = "";
|
||||||
|
|
||||||
SB_RAM40_4K #(
|
SB_RAM40_4K #(
|
||||||
.WRITE_MODE(WRITE_MODE),
|
.WRITE_MODE(WRITE_MODE),
|
||||||
.READ_MODE (READ_MODE ),
|
.READ_MODE (READ_MODE ),
|
||||||
|
@ -646,7 +640,8 @@ module SB_RAM40_4KNRNW (
|
||||||
.INIT_C (INIT_C ),
|
.INIT_C (INIT_C ),
|
||||||
.INIT_D (INIT_D ),
|
.INIT_D (INIT_D ),
|
||||||
.INIT_E (INIT_E ),
|
.INIT_E (INIT_E ),
|
||||||
.INIT_F (INIT_F )
|
.INIT_F (INIT_F ),
|
||||||
|
.INIT_FILE (INIT_FILE )
|
||||||
) RAM (
|
) RAM (
|
||||||
.RDATA(RDATA),
|
.RDATA(RDATA),
|
||||||
.RCLK (~RCLKN),
|
.RCLK (~RCLKN),
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/yosys.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
static void run_ice40_braminit(Module *module)
|
||||||
|
{
|
||||||
|
for (auto cell : module->selected_cells())
|
||||||
|
{
|
||||||
|
uint16_t mem[256];
|
||||||
|
|
||||||
|
/* Only consider cells we're interested in */
|
||||||
|
if (cell->type != "\\SB_RAM40_4K" &&
|
||||||
|
cell->type != "\\SB_RAM40_4KNR" &&
|
||||||
|
cell->type != "\\SB_RAM40_4KNW" &&
|
||||||
|
cell->type != "\\SB_RAM40_4KNRNW")
|
||||||
|
continue;
|
||||||
|
if (!cell->hasParam("\\INIT_FILE"))
|
||||||
|
continue;
|
||||||
|
std::string init_file = cell->getParam("\\INIT_FILE").decode_string();
|
||||||
|
cell->unsetParam("\\INIT_FILE");
|
||||||
|
if (init_file == "")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Open file */
|
||||||
|
log("Processing %s : %s\n", RTLIL::id2cstr(cell->name), init_file.c_str());
|
||||||
|
|
||||||
|
std::ifstream f;
|
||||||
|
f.open(init_file.c_str());
|
||||||
|
if (f.fail()) {
|
||||||
|
log("Can not open file `%s`.\n", init_file.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Defaults to 0 */
|
||||||
|
memset(mem, 0x00, sizeof(mem));
|
||||||
|
|
||||||
|
/* Process each line */
|
||||||
|
bool in_comment = false;
|
||||||
|
int cursor = 0;
|
||||||
|
|
||||||
|
while (!f.eof())
|
||||||
|
{
|
||||||
|
std::string line, token;
|
||||||
|
std::getline(f, line);
|
||||||
|
|
||||||
|
for (int i = 0; i < GetSize(line); i++)
|
||||||
|
{
|
||||||
|
if (in_comment && line.substr(i, 2) == "*/") {
|
||||||
|
line[i] = ' ';
|
||||||
|
line[i+1] = ' ';
|
||||||
|
in_comment = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!in_comment && line.substr(i, 2) == "/*")
|
||||||
|
in_comment = true;
|
||||||
|
if (in_comment)
|
||||||
|
line[i] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
bool set_cursor = false;
|
||||||
|
long value;
|
||||||
|
|
||||||
|
token = next_token(line, " \t\r\n");
|
||||||
|
if (token.empty() || token.substr(0, 2) == "//")
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (token[0] == '@') {
|
||||||
|
token = token.substr(1);
|
||||||
|
set_cursor = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *nptr = token.c_str();
|
||||||
|
char *endptr;
|
||||||
|
value = strtol(nptr, &endptr, 16);
|
||||||
|
if (!*nptr || *endptr) {
|
||||||
|
log("Can not parse %s `%s` for %s.\n",
|
||||||
|
set_cursor ? "address" : "value",
|
||||||
|
nptr, token.c_str()
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_cursor)
|
||||||
|
cursor = value;
|
||||||
|
else if (cursor >= 0 && cursor < 256)
|
||||||
|
mem[cursor++] = value;
|
||||||
|
else
|
||||||
|
log("Attempt to initialize non existent address %d\n", cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set attributes */
|
||||||
|
const char *hex = "0123456789ABCDEF";
|
||||||
|
for (int i=0; i<16; i++) {
|
||||||
|
std::string val = "";
|
||||||
|
for (int j=15; j>=0; j--)
|
||||||
|
val += std::bitset<16>(mem[i*16+j]).to_string();
|
||||||
|
cell->setParam("\\INIT_" + std::string(1, hex[i]), RTLIL::Const::from_string(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Ice40BRAMInitPass : public Pass {
|
||||||
|
Ice40BRAMInitPass() : Pass("ice40_braminit", "iCE40: perform SB_RAM40_4K initialization from file") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" ice40_braminit\n");
|
||||||
|
log("\n");
|
||||||
|
log("This command processes all SB_RAM40_4K blocks with a non-empty INIT_FILE\n");
|
||||||
|
log("parameter and converts it into the required INIT_x attributes\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
log_header(design, "Executing ICE40_BRAMINIT pass.\n");
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||||
|
// if (args[argidx] == "-???") {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules())
|
||||||
|
run_ice40_braminit(module);
|
||||||
|
}
|
||||||
|
} Ice40BRAMInitPass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
|
@ -257,6 +257,7 @@ struct SynthIce40Pass : public ScriptPass
|
||||||
{
|
{
|
||||||
run("memory_bram -rules +/ice40/brams.txt");
|
run("memory_bram -rules +/ice40/brams.txt");
|
||||||
run("techmap -map +/ice40/brams_map.v");
|
run("techmap -map +/ice40/brams_map.v");
|
||||||
|
run("ice40_braminit");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("map"))
|
if (check_label("map"))
|
||||||
|
|
|
@ -1,17 +1,41 @@
|
||||||
// module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule
|
module \$_DFF_N_ (input D, C, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
module \$_DFF_P_ (input D, C, output Q);
|
module \$_DFF_P_ (input D, C, output Q);
|
||||||
SLE _TECHMAP_REPLACE_ (
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
.D(D),
|
endmodule
|
||||||
.CLK(C),
|
|
||||||
.EN(1'b1),
|
module \$_DFF_NN0_ (input D, C, R, output Q);
|
||||||
.ALn(1'b1),
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
.ADn(1'b1),
|
endmodule
|
||||||
.SLn(1'b1),
|
|
||||||
.SD(1'b0),
|
module \$_DFF_NN1_ (input D, C, R, output Q);
|
||||||
.LAT(1'b0),
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
.Q(Q)
|
endmodule
|
||||||
);
|
|
||||||
|
module \$_DFF_NP0_ (input D, C, R, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$_DFF_NP1_ (input D, C, R, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$_DFF_PN0_ (input D, C, R, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$_DFF_PN1_ (input D, C, R, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$_DFF_PP0_ (input D, C, R, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module \$_DFF_PP1_ (input D, C, R, output Q);
|
||||||
|
SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q));
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
// module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
|
// module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
|
||||||
|
@ -20,16 +44,6 @@ endmodule
|
||||||
// module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
|
// module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
|
||||||
// module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
|
// module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
|
||||||
//
|
//
|
||||||
// module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
|
|
||||||
// module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
|
|
||||||
// module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
|
|
||||||
// module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
|
|
||||||
//
|
|
||||||
// module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
|
|
||||||
// module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
|
|
||||||
// module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
|
|
||||||
// module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
|
|
||||||
//
|
|
||||||
// module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
|
// module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
|
||||||
// module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
|
// module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
|
||||||
// module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
|
// module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
|
||||||
|
|
|
@ -1,39 +1,25 @@
|
||||||
module SLE (
|
// https://coredocs.s3.amazonaws.com/Libero/12_0_0/Tool/sf2_mlg.pdf
|
||||||
output Q,
|
|
||||||
input ADn,
|
module ADD2 (
|
||||||
input ALn,
|
|
||||||
input CLK,
|
input A, B,
|
||||||
input D,
|
output Y
|
||||||
input LAT,
|
|
||||||
input SD,
|
|
||||||
input EN,
|
|
||||||
input SLn
|
|
||||||
);
|
);
|
||||||
reg q_latch, q_ff;
|
assign Y = A & B;
|
||||||
|
endmodule
|
||||||
|
|
||||||
always @(posedge CLK, negedge ALn) begin
|
module ADD3 (
|
||||||
if (!ALn) begin
|
input A, B, C,
|
||||||
q_ff <= !ADn;
|
output Y
|
||||||
end else if (EN) begin
|
);
|
||||||
if (!SLn)
|
assign Y = A & B & C;
|
||||||
q_ff <= SD;
|
endmodule
|
||||||
else
|
|
||||||
q_ff <= D;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @* begin
|
module ADD4 (
|
||||||
if (!ALn) begin
|
input A, B, C, D,
|
||||||
q_latch <= !ADn;
|
output Y
|
||||||
end else if (CLK && EN) begin
|
);
|
||||||
if (!SLn)
|
assign Y = A & B & C & D;
|
||||||
q_ff <= SD;
|
|
||||||
else
|
|
||||||
q_ff <= D;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
assign Q = LAT ? q_latch : q_ff;
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module CFG1 (
|
module CFG1 (
|
||||||
|
@ -74,6 +60,238 @@ module CFG4 (
|
||||||
assign Y = INIT >> {D, C, B, A};
|
assign Y = INIT >> {D, C, B, A};
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module BUFF (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module BUFD (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module CLKINT (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module CLKINT_PRESERVE (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module GCLKINT (
|
||||||
|
input A, EN,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A & EN;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module RCLKINT (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module RGCLKINT (
|
||||||
|
input A, EN,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A & EN;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module SLE (
|
||||||
|
output Q,
|
||||||
|
input ADn,
|
||||||
|
input ALn,
|
||||||
|
input CLK,
|
||||||
|
input D,
|
||||||
|
input LAT,
|
||||||
|
input SD,
|
||||||
|
input EN,
|
||||||
|
input SLn
|
||||||
|
);
|
||||||
|
reg q_latch, q_ff;
|
||||||
|
|
||||||
|
always @(posedge CLK, negedge ALn) begin
|
||||||
|
if (!ALn) begin
|
||||||
|
q_ff <= !ADn;
|
||||||
|
end else if (EN) begin
|
||||||
|
if (!SLn)
|
||||||
|
q_ff <= SD;
|
||||||
|
else
|
||||||
|
q_ff <= D;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
if (!ALn) begin
|
||||||
|
q_latch <= !ADn;
|
||||||
|
end else if (CLK && EN) begin
|
||||||
|
if (!SLn)
|
||||||
|
q_ff <= SD;
|
||||||
|
else
|
||||||
|
q_ff <= D;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign Q = LAT ? q_latch : q_ff;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// module AR1
|
||||||
|
// module FCEND_BUFF
|
||||||
|
// module FCINIT_BUFF
|
||||||
|
// module FLASH_FREEZE
|
||||||
|
// module OSCILLATOR
|
||||||
|
// module SYSRESET
|
||||||
|
// module SYSCTRL_RESET_STATUS
|
||||||
|
// module LIVE_PROBE_FB
|
||||||
|
// module GCLKBUF
|
||||||
|
// module GCLKBUF_DIFF
|
||||||
|
// module GCLKBIBUF
|
||||||
|
// module DFN1
|
||||||
|
// module DFN1C0
|
||||||
|
// module DFN1E1
|
||||||
|
// module DFN1E1C0
|
||||||
|
// module DFN1E1P0
|
||||||
|
// module DFN1P0
|
||||||
|
// module DLN1
|
||||||
|
// module DLN1C0
|
||||||
|
// module DLN1P0
|
||||||
|
|
||||||
|
module INV (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module INVD (
|
||||||
|
input A,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module MX2 (
|
||||||
|
input A, B, S,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = S ? B : A;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module MX4 (
|
||||||
|
input D0, D1, D2, D3, S0, S1,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = S1 ? (S0 ? D3 : D2) : (S0 ? D1 : D0);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NAND2 (
|
||||||
|
input A, B,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A & B);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NAND3 (
|
||||||
|
input A, B, C,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A & B & C);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NAND4 (
|
||||||
|
input A, B, C, D,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A & B & C & D);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NOR2 (
|
||||||
|
input A, B,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A | B);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NOR3 (
|
||||||
|
input A, B, C,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A | B | C);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module NOR4 (
|
||||||
|
input A, B, C, D,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = !(A | B | C | D);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module OR2 (
|
||||||
|
input A, B,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A | B;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module OR3 (
|
||||||
|
input A, B, C,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A | B | C;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module OR4 (
|
||||||
|
input A, B, C, D,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A | B | C | D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module XOR2 (
|
||||||
|
input A, B,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A ^ B;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module XOR3 (
|
||||||
|
input A, B, C,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A ^ B ^ C;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module XOR4 (
|
||||||
|
input A, B, C, D,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A ^ B ^ C ^ D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module XOR8 (
|
||||||
|
input A, B, C, D, E, F, G, H,
|
||||||
|
output Y
|
||||||
|
);
|
||||||
|
assign Y = A ^ B ^ C ^ D ^ E ^ F ^ G ^ H;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// module UJTAG
|
||||||
|
// module BIBUF
|
||||||
|
// module BIBUF_DIFF
|
||||||
|
// module CLKBIBUF
|
||||||
|
|
||||||
module CLKBUF (
|
module CLKBUF (
|
||||||
input PAD,
|
input PAD,
|
||||||
output Y
|
output Y
|
||||||
|
@ -81,6 +299,8 @@ module CLKBUF (
|
||||||
assign Y = PAD;
|
assign Y = PAD;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// module CLKBUF_DIFF
|
||||||
|
|
||||||
module INBUF (
|
module INBUF (
|
||||||
input PAD,
|
input PAD,
|
||||||
output Y
|
output Y
|
||||||
|
@ -88,9 +308,20 @@ module INBUF (
|
||||||
assign Y = PAD;
|
assign Y = PAD;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// module INBUF_DIFF
|
||||||
|
|
||||||
module OUTBUF (
|
module OUTBUF (
|
||||||
input D,
|
input D,
|
||||||
output PAD
|
output PAD
|
||||||
);
|
);
|
||||||
assign PAD = D;
|
assign PAD = D;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// module OUTBUF_DIFF
|
||||||
|
// module TRIBUFF
|
||||||
|
// module TRIBUFF_DIFF
|
||||||
|
// module DDR_IN
|
||||||
|
// module DDR_OUT
|
||||||
|
// module RAM1K18
|
||||||
|
// module RAM64x18
|
||||||
|
// module MACC
|
||||||
|
|
|
@ -23,37 +23,8 @@
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct Sf2IobsPass : public Pass {
|
static void handle_iobufs(Module *module, bool clkbuf_mode)
|
||||||
Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { }
|
|
||||||
void help() YS_OVERRIDE
|
|
||||||
{
|
{
|
||||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
|
||||||
log("\n");
|
|
||||||
log(" sf2_iobs [options] [selection]\n");
|
|
||||||
log("\n");
|
|
||||||
log("Add SF2 I/O buffers to top module IOs as needed.\n");
|
|
||||||
log("\n");
|
|
||||||
}
|
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
|
||||||
{
|
|
||||||
log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n");
|
|
||||||
|
|
||||||
size_t argidx;
|
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
|
||||||
{
|
|
||||||
// if (args[argidx] == "-singleton") {
|
|
||||||
// singleton_mode = true;
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
extra_args(args, argidx, design);
|
|
||||||
|
|
||||||
Module *module = design->top_module();
|
|
||||||
|
|
||||||
if (module == nullptr)
|
|
||||||
log_cmd_error("No top module found.\n");
|
|
||||||
|
|
||||||
SigMap sigmap(module);
|
SigMap sigmap(module);
|
||||||
|
|
||||||
pool<SigBit> clk_bits;
|
pool<SigBit> clk_bits;
|
||||||
|
@ -63,11 +34,13 @@ struct Sf2IobsPass : public Pass {
|
||||||
|
|
||||||
for (auto cell : module->cells())
|
for (auto cell : module->cells())
|
||||||
{
|
{
|
||||||
if (cell->type == "\\SLE") {
|
if (clkbuf_mode && cell->type == "\\SLE") {
|
||||||
for (auto bit : sigmap(cell->getPort("\\CLK")))
|
for (auto bit : sigmap(cell->getPort("\\CLK")))
|
||||||
clk_bits.insert(bit);
|
clk_bits.insert(bit);
|
||||||
}
|
}
|
||||||
if (cell->type.in("\\INBUF", "\\OUTBUF", "\\CLKBUF")) {
|
if (cell->type.in("\\INBUF", "\\OUTBUF", "\\TRIBUFF", "\\BIBUF", "\\CLKBUF", "\\CLKBIBUF",
|
||||||
|
"\\INBUF_DIFF", "\\OUTBUF_DIFF", "\\BIBUFF_DIFF", "\\TRIBUFF_DIFF", "\\CLKBUF_DIFF",
|
||||||
|
"\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF")) {
|
||||||
for (auto bit : sigmap(cell->getPort("\\PAD")))
|
for (auto bit : sigmap(cell->getPort("\\PAD")))
|
||||||
handled_io_bits.insert(bit);
|
handled_io_bits.insert(bit);
|
||||||
}
|
}
|
||||||
|
@ -94,7 +67,7 @@ struct Sf2IobsPass : public Pass {
|
||||||
if (wire->port_output) {
|
if (wire->port_output) {
|
||||||
buf_type = "\\OUTBUF";
|
buf_type = "\\OUTBUF";
|
||||||
buf_port = "\\D";
|
buf_port = "\\D";
|
||||||
} else if (clk_bits.count(canonical_bit)) {
|
} else if (clkbuf_mode && clk_bits.count(canonical_bit)) {
|
||||||
buf_type = "\\CLKBUF";
|
buf_type = "\\CLKBUF";
|
||||||
buf_port = "\\Y";
|
buf_port = "\\Y";
|
||||||
} else {
|
} else {
|
||||||
|
@ -125,6 +98,100 @@ struct Sf2IobsPass : public Pass {
|
||||||
for (auto &it : pad_bits)
|
for (auto &it : pad_bits)
|
||||||
it.first->setPort("\\PAD", it.second);
|
it.first->setPort("\\PAD", it.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_clkint(Module *module)
|
||||||
|
{
|
||||||
|
SigMap sigmap(module);
|
||||||
|
|
||||||
|
pool<SigBit> clk_bits;
|
||||||
|
vector<SigBit> handled_clk_bits;
|
||||||
|
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
if (cell->type == "\\SLE") {
|
||||||
|
for (auto bit : sigmap(cell->getPort("\\CLK")))
|
||||||
|
clk_bits.insert(bit);
|
||||||
|
}
|
||||||
|
if (cell->type.in("\\CLKBUF", "\\CLKBIBUF", "\\CLKBUF_DIFF", "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF",
|
||||||
|
"\\CLKINT", "\\CLKINT_PRESERVE", "\\GCLKINT", "\\RCLKINT", "\\RGCLKINT")) {
|
||||||
|
for (auto bit : sigmap(cell->getPort("\\Y")))
|
||||||
|
handled_clk_bits.push_back(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto bit : handled_clk_bits)
|
||||||
|
clk_bits.erase(bit);
|
||||||
|
|
||||||
|
for (auto cell : vector<Cell*>(module->cells()))
|
||||||
|
for (auto &conn : cell->connections())
|
||||||
|
{
|
||||||
|
if (!cell->output(conn.first))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SigSpec sig = conn.second;
|
||||||
|
bool did_something = false;
|
||||||
|
|
||||||
|
for (auto &bit : sig) {
|
||||||
|
SigBit canonical_bit = sigmap(bit);
|
||||||
|
if (clk_bits.count(canonical_bit)) {
|
||||||
|
Cell *c = module->addCell(NEW_ID, "\\CLKINT");
|
||||||
|
SigBit new_bit = module->addWire(NEW_ID);
|
||||||
|
c->setPort("\\A", new_bit);
|
||||||
|
c->setPort("\\Y", bit);
|
||||||
|
log("Added %s cell %s for clock signal %s.\n", log_id(c->type), log_id(c), log_signal(bit));
|
||||||
|
clk_bits.erase(canonical_bit);
|
||||||
|
did_something = true;
|
||||||
|
bit = new_bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (did_something)
|
||||||
|
cell->setPort(conn.first, sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto bit : clk_bits)
|
||||||
|
log_error("Failed to insert CLKINT for clock signal %s.\n", log_signal(bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Sf2IobsPass : public Pass {
|
||||||
|
Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" sf2_iobs [options] [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Add SF2 I/O buffers and global buffers to top module as needed.\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -clkbuf\n");
|
||||||
|
log(" Insert PAD->global_net clock buffers\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
bool clkbuf_mode = false;
|
||||||
|
|
||||||
|
log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n");
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
if (args[argidx] == "-clkbuf") {
|
||||||
|
clkbuf_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
Module *module = design->top_module();
|
||||||
|
|
||||||
|
if (module == nullptr)
|
||||||
|
log_cmd_error("No top module found.\n");
|
||||||
|
|
||||||
|
handle_iobufs(module, clkbuf_mode);
|
||||||
|
handle_clkint(module);
|
||||||
|
}
|
||||||
} Sf2IobsPass;
|
} Sf2IobsPass;
|
||||||
|
|
||||||
PRIVATE_NAMESPACE_END
|
PRIVATE_NAMESPACE_END
|
||||||
|
|
|
@ -63,6 +63,9 @@ struct SynthSf2Pass : public ScriptPass
|
||||||
log(" -noiobs\n");
|
log(" -noiobs\n");
|
||||||
log(" run synthesis in \"block mode\", i.e. do not insert IO buffers\n");
|
log(" run synthesis in \"block mode\", i.e. do not insert IO buffers\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -clkbuf\n");
|
||||||
|
log(" insert direct PAD->global_net buffers\n");
|
||||||
|
log("\n");
|
||||||
log(" -retime\n");
|
log(" -retime\n");
|
||||||
log(" run 'abc' with -dff option\n");
|
log(" run 'abc' with -dff option\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -73,7 +76,7 @@ struct SynthSf2Pass : public ScriptPass
|
||||||
}
|
}
|
||||||
|
|
||||||
string top_opt, edif_file, vlog_file, json_file;
|
string top_opt, edif_file, vlog_file, json_file;
|
||||||
bool flatten, retime, iobs;
|
bool flatten, retime, iobs, clkbuf;
|
||||||
|
|
||||||
void clear_flags() YS_OVERRIDE
|
void clear_flags() YS_OVERRIDE
|
||||||
{
|
{
|
||||||
|
@ -84,6 +87,7 @@ struct SynthSf2Pass : public ScriptPass
|
||||||
flatten = true;
|
flatten = true;
|
||||||
retime = false;
|
retime = false;
|
||||||
iobs = true;
|
iobs = true;
|
||||||
|
clkbuf = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
@ -130,6 +134,10 @@ struct SynthSf2Pass : public ScriptPass
|
||||||
iobs = false;
|
iobs = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-clkbuf") {
|
||||||
|
clkbuf = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
@ -201,8 +209,10 @@ struct SynthSf2Pass : public ScriptPass
|
||||||
|
|
||||||
if (check_label("map_iobs"))
|
if (check_label("map_iobs"))
|
||||||
{
|
{
|
||||||
if (iobs || help_mode)
|
if (help_mode)
|
||||||
run("sf2_iobs", "(unless -noiobs)");
|
run("sf2_iobs [-clkbuf]", "(unless -noiobs)");
|
||||||
|
else if (iobs)
|
||||||
|
run(clkbuf ? "sf2_iobs -clkbuf" : "sf2_iobs");
|
||||||
run("clean");
|
run("clean");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_bb.v))
|
||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt))
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt))
|
||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
|
||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
|
||||||
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut2lut.v))
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
|
||||||
|
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
|
||||||
|
|
||||||
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
|
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
|
||||||
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
|
$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// LCU
|
||||||
|
|
||||||
(* techmap_celltype = "$lcu" *)
|
(* techmap_celltype = "$lcu" *)
|
||||||
module _80_xilinx_lcu (P, G, CI, CO);
|
module _80_xilinx_lcu (P, G, CI, CO);
|
||||||
parameter WIDTH = 2;
|
parameter WIDTH = 2;
|
||||||
|
@ -28,10 +31,78 @@ module _80_xilinx_lcu (P, G, CI, CO);
|
||||||
|
|
||||||
wire _TECHMAP_FAIL_ = WIDTH <= 2;
|
wire _TECHMAP_FAIL_ = WIDTH <= 2;
|
||||||
|
|
||||||
|
genvar i;
|
||||||
|
|
||||||
|
`ifdef _CLB_CARRY
|
||||||
|
|
||||||
|
localparam CARRY4_COUNT = (WIDTH + 3) / 4;
|
||||||
|
localparam MAX_WIDTH = CARRY4_COUNT * 4;
|
||||||
|
localparam PAD_WIDTH = MAX_WIDTH - WIDTH;
|
||||||
|
|
||||||
|
wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G};
|
||||||
|
wire [MAX_WIDTH-1:0] C = CO;
|
||||||
|
|
||||||
|
generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
|
||||||
|
|
||||||
|
// Partially occupied CARRY4
|
||||||
|
if ((i+1)*4 > WIDTH) begin
|
||||||
|
|
||||||
|
// First one
|
||||||
|
if (i == 0) begin
|
||||||
|
CARRY4 carry4_1st_part
|
||||||
|
(
|
||||||
|
.CYINIT(CI),
|
||||||
|
.CI (1'd0),
|
||||||
|
.DI (G [(Y_WIDTH - 1):i*4]),
|
||||||
|
.S (S [(Y_WIDTH - 1):i*4]),
|
||||||
|
.CO (CO[(Y_WIDTH - 1):i*4]),
|
||||||
|
);
|
||||||
|
// Another one
|
||||||
|
end else begin
|
||||||
|
CARRY4 carry4_part
|
||||||
|
(
|
||||||
|
.CYINIT(1'd0),
|
||||||
|
.CI (C [i*4 - 1]),
|
||||||
|
.DI (G [(Y_WIDTH - 1):i*4]),
|
||||||
|
.S (S [(Y_WIDTH - 1):i*4]),
|
||||||
|
.CO (CO[(Y_WIDTH - 1):i*4]),
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
// Fully occupied CARRY4
|
||||||
|
end else begin
|
||||||
|
|
||||||
|
// First one
|
||||||
|
if (i == 0) begin
|
||||||
|
CARRY4 carry4_1st_full
|
||||||
|
(
|
||||||
|
.CYINIT(CI),
|
||||||
|
.CI (1'd0),
|
||||||
|
.DI (G [((i+1)*4 - 1):i*4]),
|
||||||
|
.S (S [((i+1)*4 - 1):i*4]),
|
||||||
|
.CO (CO[((i+1)*4 - 1):i*4]),
|
||||||
|
);
|
||||||
|
// Another one
|
||||||
|
end else begin
|
||||||
|
CARRY4 carry4_full
|
||||||
|
(
|
||||||
|
.CYINIT(1'd0),
|
||||||
|
.CI (C [i*4 - 1]),
|
||||||
|
.DI (G [((i+1)*4 - 1):i*4]),
|
||||||
|
.S (S [((i+1)*4 - 1):i*4]),
|
||||||
|
.CO (CO[((i+1)*4 - 1):i*4]),
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end endgenerate
|
||||||
|
|
||||||
|
`elsif _EXPLICIT_CARRY
|
||||||
|
|
||||||
wire [WIDTH-1:0] C = {CO, CI};
|
wire [WIDTH-1:0] C = {CO, CI};
|
||||||
wire [WIDTH-1:0] S = P & ~G;
|
wire [WIDTH-1:0] S = P & ~G;
|
||||||
|
|
||||||
genvar i;
|
|
||||||
generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
|
generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
|
||||||
MUXCY muxcy (
|
MUXCY muxcy (
|
||||||
.CI(C[i]),
|
.CI(C[i]),
|
||||||
|
@ -40,8 +111,28 @@ module _80_xilinx_lcu (P, G, CI, CO);
|
||||||
.O(CO[i])
|
.O(CO[i])
|
||||||
);
|
);
|
||||||
end endgenerate
|
end endgenerate
|
||||||
|
|
||||||
|
`else
|
||||||
|
|
||||||
|
wire [WIDTH-1:0] C = {CO, CI};
|
||||||
|
wire [WIDTH-1:0] S = P & ~G;
|
||||||
|
|
||||||
|
generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
|
||||||
|
MUXCY muxcy (
|
||||||
|
.CI(C[i]),
|
||||||
|
.DI(G[i]),
|
||||||
|
.S(S[i]),
|
||||||
|
.O(CO[i])
|
||||||
|
);
|
||||||
|
end endgenerate
|
||||||
|
`endif
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// ALU
|
||||||
|
|
||||||
(* techmap_celltype = "$alu" *)
|
(* techmap_celltype = "$alu" *)
|
||||||
module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
|
module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
|
||||||
parameter A_SIGNED = 0;
|
parameter A_SIGNED = 0;
|
||||||
|
@ -49,6 +140,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
|
||||||
parameter A_WIDTH = 1;
|
parameter A_WIDTH = 1;
|
||||||
parameter B_WIDTH = 1;
|
parameter B_WIDTH = 1;
|
||||||
parameter Y_WIDTH = 1;
|
parameter Y_WIDTH = 1;
|
||||||
|
parameter _TECHMAP_CONSTVAL_CI_ = 0;
|
||||||
|
parameter _TECHMAP_CONSTMSK_CI_ = 0;
|
||||||
|
|
||||||
input [A_WIDTH-1:0] A;
|
input [A_WIDTH-1:0] A;
|
||||||
input [B_WIDTH-1:0] B;
|
input [B_WIDTH-1:0] B;
|
||||||
|
@ -66,16 +159,189 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
|
||||||
wire [Y_WIDTH-1:0] AA = A_buf;
|
wire [Y_WIDTH-1:0] AA = A_buf;
|
||||||
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
|
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
|
||||||
|
|
||||||
wire [Y_WIDTH-1:0] P = AA ^ BB;
|
genvar i;
|
||||||
wire [Y_WIDTH-1:0] G = AA & BB;
|
|
||||||
wire [Y_WIDTH-1:0] C = {CO, CI};
|
`ifdef _CLB_CARRY
|
||||||
wire [Y_WIDTH-1:0] S = P & ~G;
|
|
||||||
|
localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4;
|
||||||
|
localparam MAX_WIDTH = CARRY4_COUNT * 4;
|
||||||
|
localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH;
|
||||||
|
|
||||||
|
wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB};
|
||||||
|
wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB};
|
||||||
|
|
||||||
|
wire [MAX_WIDTH-1:0] C = CO;
|
||||||
|
|
||||||
genvar i;
|
genvar i;
|
||||||
|
generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
|
||||||
|
|
||||||
|
// Partially occupied CARRY4
|
||||||
|
if ((i+1)*4 > Y_WIDTH) begin
|
||||||
|
|
||||||
|
// First one
|
||||||
|
if (i == 0) begin
|
||||||
|
CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_part
|
||||||
|
(
|
||||||
|
.CYINIT(CI),
|
||||||
|
.CI (1'd0),
|
||||||
|
.DI (DI[(Y_WIDTH - 1):i*4]),
|
||||||
|
.S (S [(Y_WIDTH - 1):i*4]),
|
||||||
|
.O (Y [(Y_WIDTH - 1):i*4]),
|
||||||
|
.CO (CO[(Y_WIDTH - 1):i*4])
|
||||||
|
);
|
||||||
|
// Another one
|
||||||
|
end else begin
|
||||||
|
CARRY4 carry4_part
|
||||||
|
(
|
||||||
|
.CYINIT(1'd0),
|
||||||
|
.CI (C [i*4 - 1]),
|
||||||
|
.DI (DI[(Y_WIDTH - 1):i*4]),
|
||||||
|
.S (S [(Y_WIDTH - 1):i*4]),
|
||||||
|
.O (Y [(Y_WIDTH - 1):i*4]),
|
||||||
|
.CO (CO[(Y_WIDTH - 1):i*4])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
// Fully occupied CARRY4
|
||||||
|
end else begin
|
||||||
|
|
||||||
|
// First one
|
||||||
|
if (i == 0) begin
|
||||||
|
CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_full
|
||||||
|
(
|
||||||
|
.CYINIT(CI),
|
||||||
|
.CI (1'd0),
|
||||||
|
.DI (DI[((i+1)*4 - 1):i*4]),
|
||||||
|
.S (S [((i+1)*4 - 1):i*4]),
|
||||||
|
.O (Y [((i+1)*4 - 1):i*4]),
|
||||||
|
.CO (CO[((i+1)*4 - 1):i*4])
|
||||||
|
);
|
||||||
|
// Another one
|
||||||
|
end else begin
|
||||||
|
CARRY4 carry4_full
|
||||||
|
(
|
||||||
|
.CYINIT(1'd0),
|
||||||
|
.CI (C [i*4 - 1]),
|
||||||
|
.DI (DI[((i+1)*4 - 1):i*4]),
|
||||||
|
.S (S [((i+1)*4 - 1):i*4]),
|
||||||
|
.O (Y [((i+1)*4 - 1):i*4]),
|
||||||
|
.CO (CO[((i+1)*4 - 1):i*4])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end endgenerate
|
||||||
|
|
||||||
|
`elsif _EXPLICIT_CARRY
|
||||||
|
|
||||||
|
wire [Y_WIDTH-1:0] S = AA ^ BB;
|
||||||
|
wire [Y_WIDTH-1:0] DI = AA & BB;
|
||||||
|
|
||||||
|
wire CINIT;
|
||||||
|
// Carry chain.
|
||||||
|
//
|
||||||
|
// VPR requires that the carry chain never hit the fabric. The CO input
|
||||||
|
// to this techmap is the carry outputs for synthesis, e.g. might hit the
|
||||||
|
// fabric.
|
||||||
|
//
|
||||||
|
// So we maintain two wire sets, CO_CHAIN is the carry that is for VPR,
|
||||||
|
// e.g. off fabric dedicated chain. CO is the carry outputs that are
|
||||||
|
// available to the fabric.
|
||||||
|
wire [Y_WIDTH-1:0] CO_CHAIN;
|
||||||
|
wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT};
|
||||||
|
|
||||||
|
// If carry chain is being initialized to a constant, techmap the constant
|
||||||
|
// source. Otherwise techmap the fabric source.
|
||||||
|
generate for (i = 0; i < 1; i = i + 1) begin:slice
|
||||||
|
CARRY0 #(.CYINIT_FABRIC(1)) carry(
|
||||||
|
.CI_INIT(CI),
|
||||||
|
.DI(DI[0]),
|
||||||
|
.S(S[0]),
|
||||||
|
.CO_CHAIN(CO_CHAIN[0]),
|
||||||
|
.CO_FABRIC(CO[0]),
|
||||||
|
.O(Y[0])
|
||||||
|
);
|
||||||
|
end endgenerate
|
||||||
|
|
||||||
|
generate for (i = 1; i < Y_WIDTH-1; i = i + 1) begin:slice
|
||||||
|
if(i % 4 == 0) begin
|
||||||
|
CARRY0 carry (
|
||||||
|
.CI(C[i]),
|
||||||
|
.DI(DI[i]),
|
||||||
|
.S(S[i]),
|
||||||
|
.CO_CHAIN(CO_CHAIN[i]),
|
||||||
|
.CO_FABRIC(CO[i]),
|
||||||
|
.O(Y[i])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
CARRY carry (
|
||||||
|
.CI(C[i]),
|
||||||
|
.DI(DI[i]),
|
||||||
|
.S(S[i]),
|
||||||
|
.CO_CHAIN(CO_CHAIN[i]),
|
||||||
|
.CO_FABRIC(CO[i]),
|
||||||
|
.O(Y[i])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
end endgenerate
|
||||||
|
|
||||||
|
generate for (i = Y_WIDTH-1; i < Y_WIDTH; i = i + 1) begin:slice
|
||||||
|
if(i % 4 == 0) begin
|
||||||
|
CARRY0 top_of_carry (
|
||||||
|
.CI(C[i]),
|
||||||
|
.DI(DI[i]),
|
||||||
|
.S(S[i]),
|
||||||
|
.CO_CHAIN(CO_CHAIN[i]),
|
||||||
|
.O(Y[i])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
CARRY top_of_carry (
|
||||||
|
.CI(C[i]),
|
||||||
|
.DI(DI[i]),
|
||||||
|
.S(S[i]),
|
||||||
|
.CO_CHAIN(CO_CHAIN[i]),
|
||||||
|
.O(Y[i])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
// Turns out CO_FABRIC and O both use [ABCD]MUX, so provide
|
||||||
|
// a non-congested path to output the top of the carry chain.
|
||||||
|
// Registering the output of the CARRY block would solve this, but not
|
||||||
|
// all designs do that.
|
||||||
|
if((i+1) % 4 == 0) begin
|
||||||
|
CARRY0 carry_output (
|
||||||
|
.CI(CO_CHAIN[i]),
|
||||||
|
.DI(0),
|
||||||
|
.S(0),
|
||||||
|
.O(CO[i])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
CARRY carry_output (
|
||||||
|
.CI(CO_CHAIN[i]),
|
||||||
|
.DI(0),
|
||||||
|
.S(0),
|
||||||
|
.O(CO[i])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
end endgenerate
|
||||||
|
|
||||||
|
`else
|
||||||
|
|
||||||
|
wire [Y_WIDTH-1:0] S = AA ^ BB;
|
||||||
|
wire [Y_WIDTH-1:0] DI = AA & BB;
|
||||||
|
|
||||||
|
wire [Y_WIDTH-1:0] C = {CO, CI};
|
||||||
|
|
||||||
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
|
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
|
||||||
MUXCY muxcy (
|
MUXCY muxcy (
|
||||||
.CI(C[i]),
|
.CI(C[i]),
|
||||||
.DI(G[i]),
|
.DI(DI[i]),
|
||||||
.S(S[i]),
|
.S(S[i]),
|
||||||
.O(CO[i])
|
.O(CO[i])
|
||||||
);
|
);
|
||||||
|
@ -86,6 +352,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
|
||||||
);
|
);
|
||||||
end endgenerate
|
end endgenerate
|
||||||
|
|
||||||
assign X = P;
|
`endif
|
||||||
|
|
||||||
|
assign X = S;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
|
|
@ -1,86 +1,20 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
module \$_DFF_N_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
|
// Empty for now
|
||||||
module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
|
|
||||||
|
|
||||||
module \$_DFFE_NP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
|
|
||||||
module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
|
|
||||||
|
|
||||||
module \$_DFF_NN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
|
|
||||||
module \$_DFF_NP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
|
|
||||||
module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
|
|
||||||
module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule
|
|
||||||
|
|
||||||
module \$_DFF_NN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
|
|
||||||
module \$_DFF_NP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
|
|
||||||
module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
|
|
||||||
module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
|
|
||||||
|
|
||||||
`ifndef NO_LUT
|
|
||||||
module \$lut (A, Y);
|
|
||||||
parameter WIDTH = 0;
|
|
||||||
parameter LUT = 0;
|
|
||||||
|
|
||||||
input [WIDTH-1:0] A;
|
|
||||||
output Y;
|
|
||||||
|
|
||||||
generate
|
|
||||||
if (WIDTH == 1) begin
|
|
||||||
LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
|
||||||
.I0(A[0]));
|
|
||||||
end else
|
|
||||||
if (WIDTH == 2) begin
|
|
||||||
LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
|
||||||
.I0(A[0]), .I1(A[1]));
|
|
||||||
end else
|
|
||||||
if (WIDTH == 3) begin
|
|
||||||
LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]));
|
|
||||||
end else
|
|
||||||
if (WIDTH == 4) begin
|
|
||||||
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
|
||||||
.I3(A[3]));
|
|
||||||
end else
|
|
||||||
if (WIDTH == 5) begin
|
|
||||||
LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
|
||||||
.I3(A[3]), .I4(A[4]));
|
|
||||||
end else
|
|
||||||
if (WIDTH == 6) begin
|
|
||||||
LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
|
||||||
end else
|
|
||||||
if (WIDTH == 7) begin
|
|
||||||
wire T0, T1;
|
|
||||||
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
|
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
|
||||||
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
|
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
|
||||||
MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6]));
|
|
||||||
end else
|
|
||||||
if (WIDTH == 8) begin
|
|
||||||
wire T0, T1, T2, T3, T4, T5;
|
|
||||||
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
|
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
|
||||||
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
|
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
|
||||||
LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2),
|
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
|
||||||
LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3),
|
|
||||||
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
|
||||||
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
|
||||||
MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6]));
|
|
||||||
MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6]));
|
|
||||||
MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7]));
|
|
||||||
end else begin
|
|
||||||
wire _TECHMAP_FAIL_ = 1;
|
|
||||||
end
|
|
||||||
endgenerate
|
|
||||||
endmodule
|
|
||||||
`endif
|
|
||||||
|
|
|
@ -1,3 +1,21 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
// See Xilinx UG953 and UG474 for a description of the cell types below.
|
// See Xilinx UG953 and UG474 for a description of the cell types below.
|
||||||
// http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf
|
// http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf
|
||||||
|
@ -104,6 +122,29 @@ module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
|
||||||
assign CO[3] = S[3] ? CO[2] : DI[3];
|
assign CO[3] = S[3] ? CO[2] : DI[3];
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
`ifdef _EXPLICIT_CARRY
|
||||||
|
|
||||||
|
module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S);
|
||||||
|
parameter CYINIT_FABRIC = 0;
|
||||||
|
wire CI_COMBINE;
|
||||||
|
if(CYINIT_FABRIC) begin
|
||||||
|
assign CI_COMBINE = CI_INIT;
|
||||||
|
end else begin
|
||||||
|
assign CI_COMBINE = CI;
|
||||||
|
end
|
||||||
|
assign CO_CHAIN = S ? CI_COMBINE : DI;
|
||||||
|
assign CO_FABRIC = S ? CI_COMBINE : DI;
|
||||||
|
assign O = S ^ CI_COMBINE;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S);
|
||||||
|
assign CO_CHAIN = S ? CI : DI;
|
||||||
|
assign CO_FABRIC = S ? CI : DI;
|
||||||
|
assign O = S ^ CI;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
`endif
|
||||||
|
|
||||||
module FDRE (output reg Q, input C, CE, D, R);
|
module FDRE (output reg Q, input C, CE, D, R);
|
||||||
parameter [0:0] INIT = 1'b0;
|
parameter [0:0] INIT = 1'b0;
|
||||||
parameter [0:0] IS_C_INVERTED = 1'b0;
|
parameter [0:0] IS_C_INVERTED = 1'b0;
|
||||||
|
@ -156,6 +197,30 @@ module FDPE (output reg Q, input C, CE, D, PRE);
|
||||||
endcase endgenerate
|
endcase endgenerate
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module FDRE_1 (output reg Q, input C, CE, D, R);
|
||||||
|
parameter [0:0] INIT = 1'b0;
|
||||||
|
initial Q <= INIT;
|
||||||
|
always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module FDSE_1 (output reg Q, input C, CE, D, S);
|
||||||
|
parameter [0:0] INIT = 1'b1;
|
||||||
|
initial Q <= INIT;
|
||||||
|
always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module FDCE_1 (output reg Q, input C, CE, D, CLR);
|
||||||
|
parameter [0:0] INIT = 1'b0;
|
||||||
|
initial Q <= INIT;
|
||||||
|
always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module FDPE_1 (output reg Q, input C, CE, D, PRE);
|
||||||
|
parameter [0:0] INIT = 1'b1;
|
||||||
|
initial Q <= INIT;
|
||||||
|
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
|
||||||
|
endmodule
|
||||||
|
|
||||||
module RAM64X1D (
|
module RAM64X1D (
|
||||||
output DPO, SPO,
|
output DPO, SPO,
|
||||||
input D, WCLK, WE,
|
input D, WCLK, WE,
|
||||||
|
|
|
@ -7,6 +7,7 @@ function xtract_cell_decl()
|
||||||
{
|
{
|
||||||
for dir in $libdir/xeclib $libdir/retarget; do
|
for dir in $libdir/xeclib $libdir/retarget; do
|
||||||
[ -f $dir/$1.v ] || continue
|
[ -f $dir/$1.v ] || continue
|
||||||
|
[ -z "$2" ] || echo $2
|
||||||
egrep '^\s*((end)?module|parameter|input|inout|output|(end)?function|(end)?task)' $dir/$1.v |
|
egrep '^\s*((end)?module|parameter|input|inout|output|(end)?function|(end)?task)' $dir/$1.v |
|
||||||
sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d;
|
sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d;
|
||||||
s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/;
|
s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/;
|
||||||
|
@ -37,10 +38,10 @@ function xtract_cell_decl()
|
||||||
xtract_cell_decl BUFMR
|
xtract_cell_decl BUFMR
|
||||||
xtract_cell_decl BUFMRCE
|
xtract_cell_decl BUFMRCE
|
||||||
xtract_cell_decl BUFR
|
xtract_cell_decl BUFR
|
||||||
xtract_cell_decl CAPTUREE2
|
xtract_cell_decl CAPTUREE2 "(* keep *)"
|
||||||
# xtract_cell_decl CARRY4
|
# xtract_cell_decl CARRY4
|
||||||
xtract_cell_decl CFGLUT5
|
xtract_cell_decl CFGLUT5
|
||||||
xtract_cell_decl DCIRESET
|
xtract_cell_decl DCIRESET "(* keep *)"
|
||||||
xtract_cell_decl DNA_PORT
|
xtract_cell_decl DNA_PORT
|
||||||
xtract_cell_decl DSP48E1
|
xtract_cell_decl DSP48E1
|
||||||
xtract_cell_decl EFUSE_USR
|
xtract_cell_decl EFUSE_USR
|
||||||
|
@ -67,10 +68,10 @@ function xtract_cell_decl()
|
||||||
xtract_cell_decl IBUFDS_GTE2
|
xtract_cell_decl IBUFDS_GTE2
|
||||||
xtract_cell_decl IBUFDS_IBUFDISABLE
|
xtract_cell_decl IBUFDS_IBUFDISABLE
|
||||||
xtract_cell_decl IBUFDS_INTERMDISABLE
|
xtract_cell_decl IBUFDS_INTERMDISABLE
|
||||||
xtract_cell_decl ICAPE2
|
xtract_cell_decl ICAPE2 "(* keep *)"
|
||||||
xtract_cell_decl IDDR
|
xtract_cell_decl IDDR
|
||||||
xtract_cell_decl IDDR_2CLK
|
xtract_cell_decl IDDR_2CLK
|
||||||
xtract_cell_decl IDELAYCTRL
|
xtract_cell_decl IDELAYCTRL "(* keep *)"
|
||||||
xtract_cell_decl IDELAYE2
|
xtract_cell_decl IDELAYE2
|
||||||
xtract_cell_decl IN_FIFO
|
xtract_cell_decl IN_FIFO
|
||||||
xtract_cell_decl IOBUF
|
xtract_cell_decl IOBUF
|
||||||
|
@ -112,10 +113,10 @@ function xtract_cell_decl()
|
||||||
xtract_cell_decl PHY_CONTROL
|
xtract_cell_decl PHY_CONTROL
|
||||||
xtract_cell_decl PLLE2_ADV
|
xtract_cell_decl PLLE2_ADV
|
||||||
xtract_cell_decl PLLE2_BASE
|
xtract_cell_decl PLLE2_BASE
|
||||||
xtract_cell_decl PS7
|
xtract_cell_decl PS7 "(* keep *)"
|
||||||
xtract_cell_decl PULLDOWN
|
xtract_cell_decl PULLDOWN
|
||||||
xtract_cell_decl PULLUP
|
xtract_cell_decl PULLUP
|
||||||
# xtract_cell_decl RAM128X1D
|
xtract_cell_decl RAM128X1D
|
||||||
xtract_cell_decl RAM128X1S
|
xtract_cell_decl RAM128X1S
|
||||||
xtract_cell_decl RAM256X1S
|
xtract_cell_decl RAM256X1S
|
||||||
xtract_cell_decl RAM32M
|
xtract_cell_decl RAM32M
|
||||||
|
@ -124,7 +125,7 @@ function xtract_cell_decl()
|
||||||
xtract_cell_decl RAM32X1S_1
|
xtract_cell_decl RAM32X1S_1
|
||||||
xtract_cell_decl RAM32X2S
|
xtract_cell_decl RAM32X2S
|
||||||
xtract_cell_decl RAM64M
|
xtract_cell_decl RAM64M
|
||||||
# xtract_cell_decl RAM64X1D
|
xtract_cell_decl RAM64X1D
|
||||||
xtract_cell_decl RAM64X1S
|
xtract_cell_decl RAM64X1S
|
||||||
xtract_cell_decl RAM64X1S_1
|
xtract_cell_decl RAM64X1S_1
|
||||||
xtract_cell_decl RAM64X2S
|
xtract_cell_decl RAM64X2S
|
||||||
|
@ -136,7 +137,7 @@ function xtract_cell_decl()
|
||||||
xtract_cell_decl ROM64X1
|
xtract_cell_decl ROM64X1
|
||||||
xtract_cell_decl SRL16E
|
xtract_cell_decl SRL16E
|
||||||
xtract_cell_decl SRLC32E
|
xtract_cell_decl SRLC32E
|
||||||
xtract_cell_decl STARTUPE2
|
xtract_cell_decl STARTUPE2 "(* keep *)"
|
||||||
xtract_cell_decl USR_ACCESSE2
|
xtract_cell_decl USR_ACCESSE2
|
||||||
xtract_cell_decl XADC
|
xtract_cell_decl XADC
|
||||||
} > cells_xtra.new
|
} > cells_xtra.new
|
||||||
|
|
|
@ -114,6 +114,7 @@ module BUFR (...);
|
||||||
parameter SIM_DEVICE = "7SERIES";
|
parameter SIM_DEVICE = "7SERIES";
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
(* keep *)
|
||||||
module CAPTUREE2 (...);
|
module CAPTUREE2 (...);
|
||||||
parameter ONESHOT = "TRUE";
|
parameter ONESHOT = "TRUE";
|
||||||
input CAP;
|
input CAP;
|
||||||
|
@ -130,6 +131,7 @@ module CFGLUT5 (...);
|
||||||
input CDI, CE, CLK;
|
input CDI, CE, CLK;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
(* keep *)
|
||||||
module DCIRESET (...);
|
module DCIRESET (...);
|
||||||
output LOCKED;
|
output LOCKED;
|
||||||
input RST;
|
input RST;
|
||||||
|
@ -2102,6 +2104,7 @@ module IBUFDS_INTERMDISABLE (...);
|
||||||
input INTERMDISABLE;
|
input INTERMDISABLE;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
(* keep *)
|
||||||
module ICAPE2 (...);
|
module ICAPE2 (...);
|
||||||
parameter [31:0] DEVICE_ID = 32'h04244093;
|
parameter [31:0] DEVICE_ID = 32'h04244093;
|
||||||
parameter ICAP_WIDTH = "X32";
|
parameter ICAP_WIDTH = "X32";
|
||||||
|
@ -2149,6 +2152,7 @@ module IDDR_2CLK (...);
|
||||||
input S;
|
input S;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
(* keep *)
|
||||||
module IDELAYCTRL (...);
|
module IDELAYCTRL (...);
|
||||||
parameter SIM_DEVICE = "7SERIES";
|
parameter SIM_DEVICE = "7SERIES";
|
||||||
output RDY;
|
output RDY;
|
||||||
|
@ -3057,6 +3061,7 @@ module PLLE2_BASE (...);
|
||||||
input RST;
|
input RST;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
(* keep *)
|
||||||
module PS7 (...);
|
module PS7 (...);
|
||||||
output DMA0DAVALID;
|
output DMA0DAVALID;
|
||||||
output DMA0DRREADY;
|
output DMA0DRREADY;
|
||||||
|
@ -3688,6 +3693,17 @@ module PULLUP (...);
|
||||||
output O;
|
output O;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module RAM128X1D (...);
|
||||||
|
parameter [127:0] INIT = 128'h00000000000000000000000000000000;
|
||||||
|
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
|
||||||
|
output DPO, SPO;
|
||||||
|
input [6:0] A;
|
||||||
|
input [6:0] DPRA;
|
||||||
|
input D;
|
||||||
|
input WCLK;
|
||||||
|
input WE;
|
||||||
|
endmodule
|
||||||
|
|
||||||
module RAM128X1S (...);
|
module RAM128X1S (...);
|
||||||
parameter [127:0] INIT = 128'h00000000000000000000000000000000;
|
parameter [127:0] INIT = 128'h00000000000000000000000000000000;
|
||||||
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
|
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
|
||||||
|
@ -3778,6 +3794,13 @@ module RAM64M (...);
|
||||||
input WE;
|
input WE;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module RAM64X1D (...);
|
||||||
|
parameter [63:0] INIT = 64'h0000000000000000;
|
||||||
|
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
|
||||||
|
output DPO, SPO;
|
||||||
|
input A0, A1, A2, A3, A4, A5, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5, WCLK, WE;
|
||||||
|
endmodule
|
||||||
|
|
||||||
module RAM64X1S (...);
|
module RAM64X1S (...);
|
||||||
parameter [63:0] INIT = 64'h0000000000000000;
|
parameter [63:0] INIT = 64'h0000000000000000;
|
||||||
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
|
parameter [0:0] IS_WCLK_INVERTED = 1'b0;
|
||||||
|
@ -3840,6 +3863,7 @@ module SRLC32E (...);
|
||||||
input CE, CLK, D;
|
input CE, CLK, D;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
(* keep *)
|
||||||
module STARTUPE2 (...);
|
module STARTUPE2 (...);
|
||||||
parameter PROG_USR = "FALSE";
|
parameter PROG_USR = "FALSE";
|
||||||
parameter real SIM_CCLK_FREQ = 0.0;
|
parameter real SIM_CCLK_FREQ = 0.0;
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// FF mapping
|
||||||
|
|
||||||
|
`ifndef _NO_FFS
|
||||||
|
|
||||||
|
module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
|
||||||
|
module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
|
||||||
|
|
||||||
|
module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
|
||||||
|
module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
|
||||||
|
|
||||||
|
module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
|
||||||
|
module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
|
||||||
|
module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
|
||||||
|
module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
|
||||||
|
|
||||||
|
module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
|
||||||
|
module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
|
||||||
|
module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
|
||||||
|
module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
|
||||||
|
|
||||||
|
`endif
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
module LUT1(output O, input I0);
|
|
||||||
parameter [1:0] INIT = 0;
|
|
||||||
\$lut #(
|
|
||||||
.WIDTH(1),
|
|
||||||
.LUT(INIT)
|
|
||||||
) _TECHMAP_REPLACE_ (
|
|
||||||
.A(I0),
|
|
||||||
.Y(O)
|
|
||||||
);
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module LUT2(output O, input I0, I1);
|
|
||||||
parameter [3:0] INIT = 0;
|
|
||||||
\$lut #(
|
|
||||||
.WIDTH(2),
|
|
||||||
.LUT(INIT)
|
|
||||||
) _TECHMAP_REPLACE_ (
|
|
||||||
.A({I1, I0}),
|
|
||||||
.Y(O)
|
|
||||||
);
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module LUT3(output O, input I0, I1, I2);
|
|
||||||
parameter [7:0] INIT = 0;
|
|
||||||
\$lut #(
|
|
||||||
.WIDTH(3),
|
|
||||||
.LUT(INIT)
|
|
||||||
) _TECHMAP_REPLACE_ (
|
|
||||||
.A({I2, I1, I0}),
|
|
||||||
.Y(O)
|
|
||||||
);
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module LUT4(output O, input I0, I1, I2, I3);
|
|
||||||
parameter [15:0] INIT = 0;
|
|
||||||
\$lut #(
|
|
||||||
.WIDTH(4),
|
|
||||||
.LUT(INIT)
|
|
||||||
) _TECHMAP_REPLACE_ (
|
|
||||||
.A({I3, I2, I1, I0}),
|
|
||||||
.Y(O)
|
|
||||||
);
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module LUT5(output O, input I0, I1, I2, I3, I4);
|
|
||||||
parameter [31:0] INIT = 0;
|
|
||||||
\$lut #(
|
|
||||||
.WIDTH(5),
|
|
||||||
.LUT(INIT)
|
|
||||||
) _TECHMAP_REPLACE_ (
|
|
||||||
.A({I4, I3, I2, I1, I0}),
|
|
||||||
.Y(O)
|
|
||||||
);
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module LUT6(output O, input I0, I1, I2, I3, I4, I5);
|
|
||||||
parameter [63:0] INIT = 0;
|
|
||||||
\$lut #(
|
|
||||||
.WIDTH(6),
|
|
||||||
.LUT(INIT)
|
|
||||||
) _TECHMAP_REPLACE_ (
|
|
||||||
.A({I5, I4, I3, I2, I1, I0}),
|
|
||||||
.Y(O)
|
|
||||||
);
|
|
||||||
endmodule
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// LUT mapping
|
||||||
|
|
||||||
|
`ifndef _NO_LUTS
|
||||||
|
|
||||||
|
module \$lut (A, Y);
|
||||||
|
parameter WIDTH = 0;
|
||||||
|
parameter LUT = 0;
|
||||||
|
|
||||||
|
input [WIDTH-1:0] A;
|
||||||
|
output Y;
|
||||||
|
|
||||||
|
generate
|
||||||
|
if (WIDTH == 1) begin
|
||||||
|
LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
|
.I0(A[0]));
|
||||||
|
end else
|
||||||
|
if (WIDTH == 2) begin
|
||||||
|
LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
|
.I0(A[0]), .I1(A[1]));
|
||||||
|
end else
|
||||||
|
if (WIDTH == 3) begin
|
||||||
|
LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
|
.I0(A[0]), .I1(A[1]), .I2(A[2]));
|
||||||
|
end else
|
||||||
|
if (WIDTH == 4) begin
|
||||||
|
LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
|
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||||
|
.I3(A[3]));
|
||||||
|
end else
|
||||||
|
if (WIDTH == 5) begin
|
||||||
|
LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
|
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||||
|
.I3(A[3]), .I4(A[4]));
|
||||||
|
end else
|
||||||
|
if (WIDTH == 6) begin
|
||||||
|
LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
|
||||||
|
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||||
|
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||||
|
end else
|
||||||
|
if (WIDTH == 7) begin
|
||||||
|
wire T0, T1;
|
||||||
|
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||||
|
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||||
|
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||||
|
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||||
|
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||||
|
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||||
|
MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6]));
|
||||||
|
end else
|
||||||
|
if (WIDTH == 8) begin
|
||||||
|
wire T0, T1, T2, T3, T4, T5;
|
||||||
|
LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0),
|
||||||
|
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||||
|
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||||
|
LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1),
|
||||||
|
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||||
|
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||||
|
LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2),
|
||||||
|
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||||
|
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||||
|
LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3),
|
||||||
|
.I0(A[0]), .I1(A[1]), .I2(A[2]),
|
||||||
|
.I3(A[3]), .I4(A[4]), .I5(A[5]));
|
||||||
|
MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6]));
|
||||||
|
MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6]));
|
||||||
|
MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7]));
|
||||||
|
end else begin
|
||||||
|
wire _TECHMAP_FAIL_ = 1;
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
`endif
|
||||||
|
|
|
@ -63,6 +63,12 @@ struct SynthXilinxPass : public Pass
|
||||||
log(" generate an output netlist (and BLIF file) suitable for VPR\n");
|
log(" generate an output netlist (and BLIF file) suitable for VPR\n");
|
||||||
log(" (this feature is experimental and incomplete)\n");
|
log(" (this feature is experimental and incomplete)\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -nobram\n");
|
||||||
|
log(" disable infering of block rams\n");
|
||||||
|
log("\n");
|
||||||
|
log(" -nodram\n");
|
||||||
|
log(" disable infering of distributed rams\n");
|
||||||
|
log("\n");
|
||||||
log(" -run <from_label>:<to_label>\n");
|
log(" -run <from_label>:<to_label>\n");
|
||||||
log(" only run the commands between the labels (see below). an empty\n");
|
log(" only run the commands between the labels (see below). an empty\n");
|
||||||
log(" from label is synonymous to 'begin', and empty to label is\n");
|
log(" from label is synonymous to 'begin', and empty to label is\n");
|
||||||
|
@ -90,11 +96,11 @@ struct SynthXilinxPass : public Pass
|
||||||
log(" coarse:\n");
|
log(" coarse:\n");
|
||||||
log(" synth -run coarse\n");
|
log(" synth -run coarse\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" bram:\n");
|
log(" bram: (only executed when '-nobram' is not given)\n");
|
||||||
log(" memory_bram -rules +/xilinx/brams.txt\n");
|
log(" memory_bram -rules +/xilinx/brams.txt\n");
|
||||||
log(" techmap -map +/xilinx/brams_map.v\n");
|
log(" techmap -map +/xilinx/brams_map.v\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" dram:\n");
|
log(" dram: (only executed when '-nodram' is not given)\n");
|
||||||
log(" memory_bram -rules +/xilinx/drams.txt\n");
|
log(" memory_bram -rules +/xilinx/drams.txt\n");
|
||||||
log(" techmap -map +/xilinx/drams_map.v\n");
|
log(" techmap -map +/xilinx/drams_map.v\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -104,16 +110,18 @@ struct SynthXilinxPass : public Pass
|
||||||
log(" dffsr2dff\n");
|
log(" dffsr2dff\n");
|
||||||
log(" dff2dffe\n");
|
log(" dff2dffe\n");
|
||||||
log(" opt -full\n");
|
log(" opt -full\n");
|
||||||
log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n");
|
log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n");
|
||||||
log(" opt -fast\n");
|
log(" opt -fast\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" map_luts:\n");
|
log(" map_luts:\n");
|
||||||
log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n");
|
log(" abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!)\n");
|
||||||
|
log(" abc -lut 5 [-dff] (with '-vpr' only!)\n");
|
||||||
log(" clean\n");
|
log(" clean\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" map_cells:\n");
|
log(" map_cells:\n");
|
||||||
log(" techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode)\n");
|
log(" techmap -map +/xilinx/cells_map.v\n");
|
||||||
log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT\n");
|
log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n");
|
||||||
|
log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n");
|
||||||
log(" clean\n");
|
log(" clean\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" check:\n");
|
log(" check:\n");
|
||||||
|
@ -137,6 +145,8 @@ struct SynthXilinxPass : public Pass
|
||||||
bool flatten = false;
|
bool flatten = false;
|
||||||
bool retime = false;
|
bool retime = false;
|
||||||
bool vpr = false;
|
bool vpr = false;
|
||||||
|
bool nobram = false;
|
||||||
|
bool nodram = false;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
@ -173,6 +183,14 @@ struct SynthXilinxPass : public Pass
|
||||||
vpr = true;
|
vpr = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-nobram") {
|
||||||
|
nobram = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-nodram") {
|
||||||
|
nodram = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
@ -187,9 +205,18 @@ struct SynthXilinxPass : public Pass
|
||||||
|
|
||||||
if (check_label(active, run_from, run_to, "begin"))
|
if (check_label(active, run_from, run_to, "begin"))
|
||||||
{
|
{
|
||||||
|
if (vpr) {
|
||||||
|
Pass::call(design, "read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
|
||||||
|
} else {
|
||||||
Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v");
|
Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v");
|
||||||
|
}
|
||||||
|
|
||||||
Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v");
|
Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v");
|
||||||
|
|
||||||
|
if (!nobram) {
|
||||||
Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v");
|
Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v");
|
||||||
|
}
|
||||||
|
|
||||||
Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str()));
|
Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,15 +233,19 @@ struct SynthXilinxPass : public Pass
|
||||||
|
|
||||||
if (check_label(active, run_from, run_to, "bram"))
|
if (check_label(active, run_from, run_to, "bram"))
|
||||||
{
|
{
|
||||||
|
if (!nobram) {
|
||||||
Pass::call(design, "memory_bram -rules +/xilinx/brams.txt");
|
Pass::call(design, "memory_bram -rules +/xilinx/brams.txt");
|
||||||
Pass::call(design, "techmap -map +/xilinx/brams_map.v");
|
Pass::call(design, "techmap -map +/xilinx/brams_map.v");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (check_label(active, run_from, run_to, "dram"))
|
if (check_label(active, run_from, run_to, "dram"))
|
||||||
{
|
{
|
||||||
|
if (!nodram) {
|
||||||
Pass::call(design, "memory_bram -rules +/xilinx/drams.txt");
|
Pass::call(design, "memory_bram -rules +/xilinx/drams.txt");
|
||||||
Pass::call(design, "techmap -map +/xilinx/drams_map.v");
|
Pass::call(design, "techmap -map +/xilinx/drams_map.v");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (check_label(active, run_from, run_to, "fine"))
|
if (check_label(active, run_from, run_to, "fine"))
|
||||||
{
|
{
|
||||||
|
@ -223,7 +254,14 @@ struct SynthXilinxPass : public Pass
|
||||||
Pass::call(design, "dffsr2dff");
|
Pass::call(design, "dffsr2dff");
|
||||||
Pass::call(design, "dff2dffe");
|
Pass::call(design, "dff2dffe");
|
||||||
Pass::call(design, "opt -full");
|
Pass::call(design, "opt -full");
|
||||||
Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v");
|
|
||||||
|
if (vpr) {
|
||||||
|
Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v -D _EXPLICIT_CARRY");
|
||||||
|
} else {
|
||||||
|
Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v");
|
||||||
|
}
|
||||||
|
|
||||||
|
Pass::call(design, "hierarchy -check");
|
||||||
Pass::call(design, "opt -fast");
|
Pass::call(design, "opt -fast");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,14 +269,14 @@ struct SynthXilinxPass : public Pass
|
||||||
{
|
{
|
||||||
Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
|
Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
|
||||||
Pass::call(design, "clean");
|
Pass::call(design, "clean");
|
||||||
|
Pass::call(design, "techmap -map +/xilinx/lut_map.v");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label(active, run_from, run_to, "map_cells"))
|
if (check_label(active, run_from, run_to, "map_cells"))
|
||||||
{
|
{
|
||||||
Pass::call(design, "techmap -map +/xilinx/cells_map.v");
|
Pass::call(design, "techmap -map +/xilinx/cells_map.v");
|
||||||
if (vpr)
|
Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
|
||||||
Pass::call(design, "techmap -map +/xilinx/lut2lut.v");
|
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
|
||||||
Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT");
|
|
||||||
Pass::call(design, "clean");
|
Pass::call(design, "clean");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +290,7 @@ struct SynthXilinxPass : public Pass
|
||||||
if (check_label(active, run_from, run_to, "edif"))
|
if (check_label(active, run_from, run_to, "edif"))
|
||||||
{
|
{
|
||||||
if (!edif_file.empty())
|
if (!edif_file.empty())
|
||||||
Pass::call(design, stringf("write_edif %s", edif_file.c_str()));
|
Pass::call(design, stringf("write_edif -pvector bra %s", edif_file.c_str()));
|
||||||
}
|
}
|
||||||
if (check_label(active, run_from, run_to, "blif"))
|
if (check_label(active, run_from, run_to, "blif"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
aag 3 2 0 1 1
|
||||||
|
2
|
||||||
|
4
|
||||||
|
6
|
||||||
|
6 2 4
|
|
@ -0,0 +1,3 @@
|
||||||
|
aig 3 2 0 1 1
|
||||||
|
6
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
aag 1 1 0 1 0
|
||||||
|
2
|
||||||
|
2
|
|
@ -0,0 +1,2 @@
|
||||||
|
aig 1 1 0 1 0
|
||||||
|
2
|
|
@ -0,0 +1,3 @@
|
||||||
|
aag 1 0 1 0 0 1
|
||||||
|
2 3
|
||||||
|
2
|
|
@ -0,0 +1,3 @@
|
||||||
|
aig 1 0 1 0 0 1
|
||||||
|
3
|
||||||
|
2
|
|
@ -0,0 +1,8 @@
|
||||||
|
aag 5 1 1 0 3 1
|
||||||
|
2
|
||||||
|
4 10
|
||||||
|
4
|
||||||
|
6 5 3
|
||||||
|
8 4 2
|
||||||
|
10 9 7
|
||||||
|
b0 AIGER_NEVER
|
|
@ -0,0 +1,4 @@
|
||||||
|
aig 5 1 1 0 3 1
|
||||||
|
10
|
||||||
|
4
|
||||||
|
b0 AIGER_NEVER
|
|
@ -0,0 +1 @@
|
||||||
|
aag 0 0 0 0 0
|
|
@ -0,0 +1 @@
|
||||||
|
aig 0 0 0 0 0
|
|
@ -0,0 +1,2 @@
|
||||||
|
aag 0 0 0 1 0
|
||||||
|
0
|
|
@ -0,0 +1,2 @@
|
||||||
|
aig 0 0 0 1 0
|
||||||
|
0
|
|
@ -0,0 +1,14 @@
|
||||||
|
aag 7 2 0 2 3
|
||||||
|
2
|
||||||
|
4
|
||||||
|
6
|
||||||
|
12
|
||||||
|
6 13 15
|
||||||
|
12 2 4
|
||||||
|
14 3 5
|
||||||
|
i0 x
|
||||||
|
i1 y
|
||||||
|
o0 s
|
||||||
|
o1 c
|
||||||
|
c
|
||||||
|
half adder
|
|
@ -0,0 +1,9 @@
|
||||||
|
aig 5 2 0 2 3
|
||||||
|
10
|
||||||
|
6
|
||||||
|
i0 x
|
||||||
|
i1 y
|
||||||
|
o0 s
|
||||||
|
o1 c
|
||||||
|
c
|
||||||
|
half adder
|
|
@ -0,0 +1,3 @@
|
||||||
|
aag 1 1 0 1 0
|
||||||
|
2
|
||||||
|
3
|
|
@ -0,0 +1,2 @@
|
||||||
|
aig 1 1 0 1 0
|
||||||
|
3
|
|
@ -0,0 +1,4 @@
|
||||||
|
aag 1 0 1 0 0 1
|
||||||
|
2 3
|
||||||
|
3
|
||||||
|
b0 AIGER_NEVER
|
|
@ -0,0 +1,4 @@
|
||||||
|
aig 1 0 1 0 0 1
|
||||||
|
3
|
||||||
|
3
|
||||||
|
b0 AIGER_NEVER
|
|
@ -0,0 +1,8 @@
|
||||||
|
aag 5 1 1 0 3 1
|
||||||
|
2
|
||||||
|
4 10
|
||||||
|
5
|
||||||
|
6 5 3
|
||||||
|
8 4 2
|
||||||
|
10 9 7
|
||||||
|
b0 AIGER_NEVER
|
|
@ -0,0 +1,4 @@
|
||||||
|
aig 5 1 1 0 3 1
|
||||||
|
10
|
||||||
|
5
|
||||||
|
b0 AIGER_NEVER
|
|
@ -0,0 +1,5 @@
|
||||||
|
aag 3 2 0 1 1
|
||||||
|
2
|
||||||
|
4
|
||||||
|
7
|
||||||
|
6 3 5
|
|
@ -0,0 +1,3 @@
|
||||||
|
aig 3 2 0 1 1
|
||||||
|
7
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
OPTIND=1
|
||||||
|
seed="" # default to no seed specified
|
||||||
|
while getopts "S:" opt
|
||||||
|
do
|
||||||
|
case "$opt" in
|
||||||
|
S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space
|
||||||
|
seed="SEED=$arg" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
|
# check for Icarus Verilog
|
||||||
|
if ! which iverilog > /dev/null ; then
|
||||||
|
echo "$0: Error: Icarus Verilog 'iverilog' not found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "===== AAG ======"
|
||||||
|
${MAKE:-make} -f ../tools/autotest.mk $seed *.aag EXTRA_FLAGS="-f aiger"
|
||||||
|
|
||||||
|
echo "===== AIG ======"
|
||||||
|
exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.aig EXTRA_FLAGS="-f aiger"
|
|
@ -0,0 +1,14 @@
|
||||||
|
aag 7 2 1 2 4
|
||||||
|
2
|
||||||
|
4
|
||||||
|
6 8
|
||||||
|
6
|
||||||
|
7
|
||||||
|
8 4 10
|
||||||
|
10 13 15
|
||||||
|
12 2 6
|
||||||
|
14 3 7
|
||||||
|
i0 enable
|
||||||
|
i1 reset
|
||||||
|
o0 Q
|
||||||
|
o1 !Q
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue