Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jim Lawson 2019-04-01 11:09:12 -07:00
commit b8dfda8767
120 changed files with 5512 additions and 610 deletions

View File

@ -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.

2
.gitignore vendored
View File

@ -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

View File

@ -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 ""

View File

@ -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.

View File

@ -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)));
} }

View File

@ -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)

View File

@ -204,7 +204,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
f << stringf("%s case ", indent.c_str()); f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) { for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0) if (i > 0)
f << stringf(", "); f << stringf(" , ");
dump_sigspec(f, (*it)->compare[i]); dump_sigspec(f, (*it)->compare[i]);
} }
f << stringf("\n"); f << stringf("\n");

View File

@ -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

View File

@ -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",

View File

@ -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;

7
examples/anlogic/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
demo.bit
demo_phy.area
full.v
*.log
*.h
*.tde
*.svf

12
examples/anlogic/README Normal file
View File

@ -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.

4
examples/anlogic/build.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
set -ex
yosys demo.ys
$TD_HOME/bin/td build.tcl

View File

@ -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

View File

@ -0,0 +1,2 @@
set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ
set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED

18
examples/anlogic/demo.v Normal file
View File

@ -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

3
examples/anlogic/demo.ys Normal file
View File

@ -0,0 +1,3 @@
read_verilog demo.v
synth_anlogic -top demo
write_verilog full.v

View File

@ -1,3 +1,4 @@
/netlist.edn /netlist.edn
/netlist.vm /netlist.vm
/example.stp
/proj /proj

View File

@ -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

View File

@ -1 +1,2 @@
# Add timing constraints here # Add timing constraints here
create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]

View File

@ -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

View File

@ -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}

View File

@ -0,0 +1,3 @@
OBJS += frontends/aiger/aigerparse.o

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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");

View File

@ -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)

View File

@ -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, &parameters);
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, &parameters);
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";

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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); }

View File

@ -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);
} | } |

View File

@ -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()

View File

@ -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(); }
}; };

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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 {

View File

@ -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;

358
misc/launcher.c Normal file
View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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),

View File

@ -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);

View File

@ -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);
}
}
}
} }
}; };

View File

@ -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

View File

@ -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

View File

@ -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())

168
passes/sat/cutpoint.cc Normal file
View File

@ -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

341
passes/sat/fmcombine.cc Normal file
View File

@ -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

956
passes/sat/mutate.cc Normal file
View File

@ -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

View File

@ -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) \

View File

@ -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);
}; };
} }

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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

View File

@ -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"))

View File

@ -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

View File

@ -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

View File

@ -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 {
@ -124,6 +97,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;

View File

@ -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");
} }

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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;

42
techlibs/xilinx/ff_map.v Normal file
View File

@ -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

View File

@ -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

94
techlibs/xilinx/lut_map.v Normal file
View File

@ -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

View File

@ -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"))
{ {

5
tests/aiger/and.aag Normal file
View File

@ -0,0 +1,5 @@
aag 3 2 0 1 1
2
4
6
6 2 4

3
tests/aiger/and.aig Normal file
View File

@ -0,0 +1,3 @@
aig 3 2 0 1 1
6


3
tests/aiger/buffer.aag Normal file
View File

@ -0,0 +1,3 @@
aag 1 1 0 1 0
2
2

2
tests/aiger/buffer.aig Normal file
View File

@ -0,0 +1,2 @@
aig 1 1 0 1 0
2

3
tests/aiger/cnt1.aag Normal file
View File

@ -0,0 +1,3 @@
aag 1 0 1 0 0 1
2 3
2

3
tests/aiger/cnt1.aig Normal file
View File

@ -0,0 +1,3 @@
aig 1 0 1 0 0 1
3
2

8
tests/aiger/cnt1e.aag Normal file
View File

@ -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

4
tests/aiger/cnt1e.aig Normal file
View File

@ -0,0 +1,4 @@
aig 5 1 1 0 3 1
10
4
b0 AIGER_NEVER

1
tests/aiger/empty.aag Normal file
View File

@ -0,0 +1 @@
aag 0 0 0 0 0

1
tests/aiger/empty.aig Normal file
View File

@ -0,0 +1 @@
aig 0 0 0 0 0

2
tests/aiger/false.aag Normal file
View File

@ -0,0 +1,2 @@
aag 0 0 0 1 0
0

2
tests/aiger/false.aig Normal file
View File

@ -0,0 +1,2 @@
aig 0 0 0 1 0
0

14
tests/aiger/halfadder.aag Normal file
View File

@ -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

View File

@ -0,0 +1,9 @@
aig 5 2 0 2 3
10
6
i0 x
i1 y
o0 s
o1 c
c
half adder

3
tests/aiger/inverter.aag Normal file
View File

@ -0,0 +1,3 @@
aag 1 1 0 1 0
2
3

2
tests/aiger/inverter.aig Normal file
View File

@ -0,0 +1,2 @@
aig 1 1 0 1 0
3

4
tests/aiger/notcnt1.aag Normal file
View File

@ -0,0 +1,4 @@
aag 1 0 1 0 0 1
2 3
3
b0 AIGER_NEVER

4
tests/aiger/notcnt1.aig Normal file
View File

@ -0,0 +1,4 @@
aig 1 0 1 0 0 1
3
3
b0 AIGER_NEVER

8
tests/aiger/notcnt1e.aag Normal file
View File

@ -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

4
tests/aiger/notcnt1e.aig Normal file
View File

@ -0,0 +1,4 @@
aig 5 1 1 0 3 1
10
5
b0 AIGER_NEVER

5
tests/aiger/or.aag Normal file
View File

@ -0,0 +1,5 @@
aag 3 2 0 1 1
2
4
7
6 3 5

3
tests/aiger/or.aig Normal file
View File

@ -0,0 +1,3 @@
aig 3 2 0 1 1
7


24
tests/aiger/run-test.sh Executable file
View File

@ -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"

Some files were not shown because too many files have changed in this diff Show More