Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: azonenberg/yosys
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 7d2fb6e2fc8e
Choose a base ref
...
head repository: azonenberg/yosys
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3c693b656133
Choose a head ref

Commits on Jun 24, 2017

  1. Copy the full SHA
    6e0fb88 View commit details

Commits on Jun 26, 2017

  1. Copy the full SHA
    a64b566 View commit details
  2. Copy the full SHA
    908ce3f View commit details
  3. Copy the full SHA
    5798105 View commit details
  4. Copy the full SHA
    ffff001 View commit details
  5. Copy the full SHA
    1eb5dee View commit details
  6. coolrunner2: Initial mapping of DFFs

    All DFFs map to either FDCP (matches Xilinx) or a custom FDCP_N
    (negative-edge triggered)
    ArcaneNibble committed Jun 26, 2017
    Copy the full SHA
    4af5baa View commit details
  7. Copy the full SHA
    36b75df View commit details
  8. coolrunner2: Add a few more primitives

    These cannot be inferred yet, but add them to cells_sim.v for now
    ArcaneNibble committed Jun 26, 2017
    Copy the full SHA
    b102c0e View commit details

Commits on Jul 1, 2017

  1. Copy the full SHA
    0a02cdb View commit details
  2. Copy the full SHA
    ea805af View commit details

Commits on Jul 3, 2017

  1. Copy the full SHA
    287831d View commit details
  2. Copy the full SHA
    3e0948e View commit details
  3. Copy the full SHA
    ca23554 View commit details
  4. Copy the full SHA
    fb30511 View commit details
  5. Merge pull request YosysHQ#355 from set-soft/exclude_TBUF_merge

    Excluded $_TBUF_ from opt_merge pass
    cliffordwolf authored Jul 3, 2017
    Copy the full SHA
    d223292 View commit details
  6. Merge pull request YosysHQ#356 from set-soft/clean-test

    Added the test outputs to the clean target
    cliffordwolf authored Jul 3, 2017
    Copy the full SHA
    3f863c6 View commit details
  7. Merge pull request YosysHQ#352 from rqou/master

    Initial Coolrunner-II support
    cliffordwolf authored Jul 3, 2017
    Copy the full SHA
    6afee02 View commit details
  8. Copy the full SHA
    5c1c126 View commit details
  9. Copy the full SHA
    621787a View commit details

Commits on Jul 4, 2017

  1. Copy the full SHA
    28039c3 View commit details

Commits on Jul 5, 2017

  1. Add write_table command

    cliffordwolf committed Jul 5, 2017
    Copy the full SHA
    37af629 View commit details
  2. Copy the full SHA
    5442554 View commit details

Commits on Jul 7, 2017

  1. Copy the full SHA
    8f7404f View commit details
  2. Copy the full SHA
    3c693b6 View commit details
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -504,6 +504,14 @@ clean:
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]*
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
rm -rf tests/asicworld/*.out tests/asicworld/*.log
rm -rf tests/hana/*.out tests/hana/*.log
rm -rf tests/simple/*.out tests/simple/*.log
rm -rf tests/memories/*.out tests/memories/*.log tests/memories/*.dmp
rm -rf tests/sat/*.log tests/techmap/*.log tests/various/*.log
rm -rf tests/bram/temp tests/fsm/temp tests/realmath/temp tests/share/temp tests/smv/temp
rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_*
rm -f tests/tools/cmp_tbdata

clean-abc:
$(MAKE) -C abc DEP= clean
49 changes: 41 additions & 8 deletions backends/aiger/aiger.cc
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@ struct AigerWriter

dict<SigBit, bool> init_map;
pool<SigBit> input_bits, output_bits;
dict<SigBit, SigBit> not_map, ff_map;
dict<SigBit, SigBit> not_map, ff_map, alias_map;
dict<SigBit, pair<SigBit, SigBit>> and_map;
vector<pair<SigBit, SigBit>> asserts, assumes;
vector<pair<SigBit, SigBit>> liveness, fairness;
@@ -87,6 +87,9 @@ struct AigerWriter
int a0 = bit2aig(args.first);
int a1 = bit2aig(args.second);
aig_map[bit] = mkgate(a0, a1);
} else
if (alias_map.count(bit)) {
aig_map[bit] = bit2aig(alias_map.at(bit));
}

if (bit == State::Sx || bit == State::Sz)
@@ -102,6 +105,21 @@ struct AigerWriter
pool<SigBit> undriven_bits;
pool<SigBit> unused_bits;

// promote public wires
for (auto wire : module->wires())
if (wire->name[0] == '\\')
sigmap.add(wire);

// promote input wires
for (auto wire : module->wires())
if (wire->port_input)
sigmap.add(wire);

// promote output wires
for (auto wire : module->wires())
if (wire->port_output)
sigmap.add(wire);

for (auto wire : module->wires())
{
if (wire->attributes.count("\\init")) {
@@ -112,19 +130,30 @@ struct AigerWriter
init_map[initsig[i]] = initval[i] == State::S1;
}

for (auto bit : sigmap(wire))
for (int i = 0; i < GetSize(wire); i++)
{
if (bit.wire == nullptr)
SigBit wirebit(wire, i);
SigBit bit = sigmap(wirebit);

if (bit.wire == nullptr) {
if (wire->port_output) {
aig_map[wirebit] = (bit == State::S1) ? 1 : 0;
output_bits.insert(wirebit);
}
continue;
}

undriven_bits.insert(bit);
unused_bits.insert(bit);

if (wire->port_input)
input_bits.insert(bit);

if (wire->port_output)
output_bits.insert(bit);
if (wire->port_output) {
if (bit != wirebit)
alias_map[wirebit] = bit;
output_bits.insert(wirebit);
}
}
}

@@ -495,8 +524,12 @@ struct AigerWriter

for (int i = 0; i < GetSize(wire); i++)
{
if (sig[i].wire == nullptr)
continue;
if (sig[i].wire == nullptr) {
if (wire->port_output)
sig[i] = SigBit(wire, i);
else
continue;
}

if (wire->port_input) {
int a = aig_map.at(sig[i]);
@@ -508,7 +541,7 @@ struct AigerWriter
}

if (wire->port_output) {
int o = ordered_outputs.at(sig[i]);
int o = ordered_outputs.at(SigSpec(wire, i));
if (GetSize(wire) != 1)
symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s[%d]", log_id(wire), i));
else
79 changes: 58 additions & 21 deletions backends/smt2/smtbmc.py
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
aiwfile = None
aigheader = True
vlogtbfile = None
vlogtbtop = None
inconstr = list()
outconstr = None
gentrace = False
@@ -43,6 +44,7 @@
final_only = False
topmod = None
noinfo = False
presat = False
so = SmtOpts()


@@ -91,6 +93,13 @@ def usage():
only run the core proof, do not collect and print any
additional information (e.g. which assert failed)
--presat
check if the design with assumptions but without assertions
is SAT before checking if assertions are UNSAT. This will
detect if there are contradicting assumtions. In some cases
this will also help to "warmup" the solver, potentially
yielding a speedup.
--final-only
only check final constraints, assume base case
@@ -107,6 +116,11 @@ def usage():
--dump-vlogtb <verilog_filename>
write trace as Verilog test bench
--vlogtb-top <hierarchical_name>
use the given entity as top module for the generated
Verilog test bench. The <hierarchical_name> is relative
to the design top module without the top module name.
--dump-smtc <constr_filename>
write trace as constraints file
@@ -125,8 +139,8 @@ def usage():

try:
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts +
["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader",
"dump-vcd=", "dump-vlogtb=", "dump-smtc=", "dump-all", "noinfo", "append="])
["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "presat",
"dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append="])
except:
usage()

@@ -165,10 +179,14 @@ def usage():
vcdfile = a
elif o == "--dump-vlogtb":
vlogtbfile = a
elif o == "--vlogtb-top":
vlogtbtop = a
elif o == "--dump-smtc":
outconstr = a
elif o == "--dump-all":
dumpall = True
elif o == "--presat":
presat = True
elif o == "--noinfo":
noinfo = True
elif o == "--append":
@@ -661,6 +679,15 @@ def write_vlogtb_trace(steps_start, steps_stop, index):
filename = vlogtbfile.replace("%", index)
print_msg("Writing trace to Verilog testbench: %s" % (filename))

vlogtb_topmod = topmod
vlogtb_state = "s@@step_idx@@"

if vlogtbtop is not None:
for item in vlogtbtop.split("."):
assert item in smt.modinfo[vlogtb_topmod].cells
vlogtb_state = "(|%s_h %s| %s)" % (vlogtb_topmod, item, vlogtb_state)
vlogtb_topmod = smt.modinfo[vlogtb_topmod].cells[item]

with open(filename, "w") as f:
print("module testbench;", file=f)
print(" reg [4095:0] vcdfile;", file=f)
@@ -669,10 +696,10 @@ def write_vlogtb_trace(steps_start, steps_stop, index):
primary_inputs = list()
clock_inputs = set()

for name in smt.modinfo[topmod].inputs:
for name in smt.modinfo[vlogtb_topmod].inputs:
if name in ["clk", "clock", "CLK", "CLOCK"]:
clock_inputs.add(name)
width = smt.modinfo[topmod].wsize[name]
width = smt.modinfo[vlogtb_topmod].wsize[name]
primary_inputs.append((name, width))

for name, width in primary_inputs:
@@ -681,7 +708,7 @@ def write_vlogtb_trace(steps_start, steps_stop, index):
else:
print(" reg [%d:0] PI_%s;" % (width-1, name), file=f)

print(" %s UUT (" % topmod, file=f)
print(" %s UUT (" % vlogtb_topmod, file=f)
print(",\n".join(" .{name}(PI_{name})".format(name=name) for name, _ in primary_inputs), file=f)
print(" );", file=f)

@@ -698,8 +725,8 @@ def write_vlogtb_trace(steps_start, steps_stop, index):

print(" initial begin", file=f)

regs = sorted(smt.hiernets(topmod, regs_only=True))
regvals = smt.get_net_bin_list(topmod, regs, "s%d" % steps_start)
regs = sorted(smt.hiernets(vlogtb_topmod, regs_only=True))
regvals = smt.get_net_bin_list(vlogtb_topmod, regs, vlogtb_state.replace("@@step_idx@@", str(steps_start)))

print(" #1;", file=f)
for reg, val in zip(regs, regvals):
@@ -709,23 +736,23 @@ def write_vlogtb_trace(steps_start, steps_stop, index):
hidden_net = True
print(" %sUUT.%s = %d'b%s;" % ("// " if hidden_net else "", ".".join(reg), len(val), val), file=f)

anyconsts = sorted(smt.hieranyconsts(topmod))
anyconsts = sorted(smt.hieranyconsts(vlogtb_topmod))
for info in anyconsts:
if info[3] is not None:
modstate = smt.net_expr(topmod, "s%d" % steps_start, info[0])
modstate = smt.net_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(steps_start)), info[0])
value = smt.bv2bin(smt.get("(|%s| %s)" % (info[1], modstate)))
print(" UUT.%s = %d'b%s;" % (".".join(info[0] + [info[3]]), len(value), value), file=f);

mems = sorted(smt.hiermems(topmod))
mems = sorted(smt.hiermems(vlogtb_topmod))
for mempath in mems:
abits, width, rports, wports = smt.mem_info(topmod, mempath)
abits, width, rports, wports = smt.mem_info(vlogtb_topmod, mempath)

addr_expr_list = list()
data_expr_list = list()
for i in range(steps_start, steps_stop):
for j in range(rports):
addr_expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dA" % j))
data_expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, "R%dD" % j))
addr_expr_list.append(smt.mem_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(i)), mempath, "R%dA" % j))
data_expr_list.append(smt.mem_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(i)), mempath, "R%dD" % j))

addr_list = smt.get_list(addr_expr_list)
data_list = smt.get_list(data_expr_list)
@@ -740,13 +767,13 @@ def write_vlogtb_trace(steps_start, steps_stop, index):
for addr, data in addr_data.items():
print(" UUT.%s[%d'b%s] = %d'b%s;" % (".".join(mempath), len(addr), addr, len(data), data), file=f)

anyseqs = sorted(smt.hieranyseqs(topmod))
anyseqs = sorted(smt.hieranyseqs(vlogtb_topmod))

for i in range(steps_start, steps_stop):
pi_names = [[name] for name, _ in primary_inputs if name not in clock_inputs]
pi_values = smt.get_net_bin_list(topmod, pi_names, "s%d" % i)
pi_values = smt.get_net_bin_list(vlogtb_topmod, pi_names, vlogtb_state.replace("@@step_idx@@", str(i)))

print(" #1;", file=f)
print("", file=f)
print(" // state %d" % i, file=f)
if i > 0:
print(" @(posedge clock);", file=f)
@@ -755,7 +782,7 @@ def write_vlogtb_trace(steps_start, steps_stop, index):

for info in anyseqs:
if info[3] is not None:
modstate = smt.net_expr(topmod, "s%d" % i, info[0])
modstate = smt.net_expr(vlogtb_topmod, vlogtb_state.replace("@@step_idx@@", str(i)), info[0])
value = smt.bv2bin(smt.get("(|%s| %s)" % (info[1], modstate)))
print(" UUT.%s <= %d'b%s;" % (".".join(info[0] + [info[3]]), len(value), value), file=f);

@@ -1086,11 +1113,22 @@ def get_cover_list(mod, base):
last_check_step = step+i

if not gentrace:
if presat:
if last_check_step == step:
print_msg("Checking assumptions in step %d.." % (step))
else:
print_msg("Checking assumptions in steps %d to %d.." % (step, last_check_step))

if smt.check_sat() == "unsat":
print("%s Warmup failed!" % smt.timestamp())
retstatus = False
break

if not final_only:
if last_check_step == step:
print_msg("Checking asserts in step %d.." % (step))
print_msg("Checking assertions in step %d.." % (step))
else:
print_msg("Checking asserts in steps %d to %d.." % (step, last_check_step))
print_msg("Checking assertions in steps %d to %d.." % (step, last_check_step))
smt.write("(push 1)")

smt.write("(assert (not (and %s)))" % " ".join(["(|%s_a| s%d)" % (topmod, i) for i in range(step, last_check_step+1)] +
@@ -1107,8 +1145,7 @@ def get_cover_list(mod, base):
smt.write("(assert (|%s_h| s%d))" % (topmod, i))
smt.write("(assert (|%s_t| s%d s%d))" % (topmod, i-1, i))
smt.write("(assert %s)" % get_constr_expr(constr_assumes, i))
print_msg("Re-solving with appended steps..")
assert smt.check_sat() == "sat"
assert smt.check_sat() == "sat"
print_anyconsts(step)
for i in range(step, last_check_step+1):
print_failed_asserts(i)
3 changes: 3 additions & 0 deletions backends/table/Makefile.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

OBJS += backends/table/table.o

120 changes: 120 additions & 0 deletions backends/table/table.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* 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/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct TableBackend : public Backend {
TableBackend() : Backend("table", "write design as connectivity table") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_table [options] [filename]\n");
log("\n");
log("Write the current design as connectivity table. The output is a tab-separated\n");
log("ASCII table with the following columns:\n");
log("\n");
log(" module name\n");
log(" cell name\n");
log(" cell type\n");
log(" cell port\n");
log(" direction\n");
log(" signal\n");
log("\n");
log("module inputs and outputs are output using cell type and port '-' and with\n");
log("'pi' (primary input) or 'po' (primary output) or 'pio' as direction.\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header(design, "Executing TABLE backend.\n");

size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-top" && argidx+1 < args.size()) {
// top_module_name = args[++argidx];
// continue;
// }
break;
}
extra_args(f, filename, args, argidx);

design->sort();

for (auto module : design->modules())
{
if (module->get_bool_attribute("\\blackbox"))
continue;

SigMap sigmap(module);

for (auto wire : module->wires())
{
if (wire->port_id == 0)
continue;

*f << log_id(module) << "\t";
*f << log_id(wire) << "\t";
*f << "-" << "\t";
*f << "-" << "\t";

if (wire->port_input && wire->port_output)
*f << "pio" << "\t";
else if (wire->port_input)
*f << "pi" << "\t";
else if (wire->port_output)
*f << "po" << "\t";
else
log_abort();

*f << log_signal(sigmap(wire)) << "\n";
}

for (auto cell : module->cells())
for (auto conn : cell->connections())
{
*f << log_id(module) << "\t";
*f << log_id(cell) << "\t";
*f << log_id(cell->type) << "\t";
*f << log_id(conn.first) << "\t";

if (cell->input(conn.first) && cell->output(conn.first))
*f << "inout" << "\t";
else if (cell->input(conn.first))
*f << "in" << "\t";
else if (cell->output(conn.first))
*f << "out" << "\t";
else
*f << "unkown" << "\t";

*f << log_signal(sigmap(conn.second)) << "\n";
}
}
}
} TableBackend;

PRIVATE_NAMESPACE_END
12 changes: 12 additions & 0 deletions frontends/verific/verific.cc
Original file line number Diff line number Diff line change
@@ -1044,6 +1044,18 @@ struct VerificPass : public Pass {
Message::SetConsoleOutput(0);
Message::RegisterCallBackMsg(msg_func);

const char *release_str = Message::ReleaseString();
time_t release_time = Message::ReleaseDate();
char *release_tmstr = ctime(&release_time);

if (release_str == nullptr)
release_str = "(no release string)";

for (char *p = release_tmstr; *p; p++)
if (*p == '\n') *p = 0;

log("Built with Verific %s, released at %s.\n", release_str, release_tmstr);

if (args.size() > 1 && args[1] == "-vlog95") {
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_95))
4 changes: 2 additions & 2 deletions passes/opt/opt_expr.cc
Original file line number Diff line number Diff line change
@@ -371,13 +371,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type.in("$reduce_and", "$_AND_"))
detect_const_and = true;

if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1)
if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool())
detect_const_and = true;

if (cell->type.in("$reduce_or", "$reduce_bool", "$_OR_"))
detect_const_or = true;

if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1)
if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool())
detect_const_or = true;

if (detect_const_and || detect_const_or)
1 change: 1 addition & 0 deletions passes/opt/opt_merge.cc
Original file line number Diff line number Diff line change
@@ -276,6 +276,7 @@ struct OptMergeWorker
}

ct.cell_types.erase("$tribuf");
ct.cell_types.erase("$_TBUF_");
ct.cell_types.erase("$anyseq");
ct.cell_types.erase("$anyconst");

7 changes: 7 additions & 0 deletions techlibs/coolrunner2/Makefile.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

OBJS += techlibs/coolrunner2/synth_coolrunner2.o
OBJS += techlibs/coolrunner2/coolrunner2_sop.o

$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_latch.v))
$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_sim.v))
$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/xc2_dff.lib))
19 changes: 19 additions & 0 deletions techlibs/coolrunner2/cells_latch.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module $_DLATCH_P_(input E, input D, output Q);
LDCP _TECHMAP_REPLACE_ (
.D(D),
.G(E),
.Q(Q),
.PRE(1'b0),
.CLR(1'b0)
);
endmodule

module $_DLATCH_N_(input E, input D, output Q);
LDCP_N _TECHMAP_REPLACE_ (
.D(D),
.G(E),
.Q(Q),
.PRE(1'b0),
.CLR(1'b0)
);
endmodule
246 changes: 246 additions & 0 deletions techlibs/coolrunner2/cells_sim.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
module IBUF(input I, output O);
assign O = I;
endmodule

module IOBUFE(input I, input E, output O, inout IO);
assign O = IO;
assign IO = E ? I : 1'bz;
endmodule

module ANDTERM(IN, IN_B, OUT);
parameter TRUE_INP = 0;
parameter COMP_INP = 0;

input [TRUE_INP-1:0] IN;
input [COMP_INP-1:0] IN_B;
output reg OUT;

integer i;

always @(*) begin
OUT = 1;
for (i = 0; i < TRUE_INP; i=i+1)
OUT = OUT & IN[i];
for (i = 0; i < COMP_INP; i=i+1)
OUT = OUT & ~IN_B[i];
end
endmodule

module ORTERM(IN, OUT);
parameter WIDTH = 0;

input [WIDTH-1:0] IN;
output reg OUT;

integer i;

always @(*) begin
OUT = 0;
for (i = 0; i < WIDTH; i=i+1) begin
OUT = OUT | IN[i];
end
end
endmodule

module MACROCELL_XOR(IN_PTC, IN_ORTERM, OUT);
parameter INVERT_OUT = 0;

input IN_PTC;
input IN_ORTERM;
output wire OUT;

wire xor_intermed;

assign OUT = INVERT_OUT ? ~xor_intermed : xor_intermed;
assign xor_intermed = IN_ORTERM ^ IN_PTC;
endmodule

module FDCP (C, PRE, CLR, D, Q);
parameter INIT = 0;

input C, PRE, CLR, D;
output reg Q;

initial begin
Q <= INIT;
end

always @(posedge C, posedge PRE, posedge CLR) begin
if (CLR == 1)
Q <= 0;
else if (PRE == 1)
Q <= 1;
else
Q <= D;
end
endmodule

module FDCP_N (C, PRE, CLR, D, Q);
parameter INIT = 0;

input C, PRE, CLR, D;
output reg Q;

initial begin
Q <= INIT;
end

always @(negedge C, posedge PRE, posedge CLR) begin
if (CLR == 1)
Q <= 0;
else if (PRE == 1)
Q <= 1;
else
Q <= D;
end
endmodule

module LDCP (G, PRE, CLR, D, Q);
parameter INIT = 0;

input G, PRE, CLR, D;
output reg Q;

initial begin
Q <= INIT;
end

always @* begin
if (CLR == 1)
Q <= 0;
else if (G == 1)
Q <= D;
else if (PRE == 1)
Q <= 1;
end
endmodule

module LDCP_N (G, PRE, CLR, D, Q);
parameter INIT = 0;

input G, PRE, CLR, D;
output reg Q;

initial begin
Q <= INIT;
end

always @* begin
if (CLR == 1)
Q <= 0;
else if (G == 0)
Q <= D;
else if (PRE == 1)
Q <= 1;
end
endmodule

module BUFG(I, O);
input I;
output O;

assign O = I;
endmodule

module BUFGSR(I, O);
input I;
output O;

assign O = I;
endmodule

module BUFGTS(I, O);
input I;
output O;

assign O = I;
endmodule

module FDDCP (C, PRE, CLR, D, Q);
parameter INIT = 0;

input C, PRE, CLR, D;
output reg Q;

initial begin
Q <= INIT;
end

always @(posedge C, negedge C, posedge PRE, posedge CLR) begin
if (CLR == 1)
Q <= 0;
else if (PRE == 1)
Q <= 1;
else
Q <= D;
end
endmodule

module FTCP (C, PRE, CLR, T, Q);
parameter INIT = 0;

input C, PRE, CLR, T;
output wire Q;
reg Q_;

initial begin
Q_ <= INIT;
end

always @(posedge C, posedge PRE, posedge CLR) begin
if (CLR == 1)
Q_ <= 0;
else if (PRE == 1)
Q_ <= 1;
else if (T == 1)
Q_ <= ~Q_;
end

assign Q = Q_;
endmodule

module FTCP_N (C, PRE, CLR, T, Q);
parameter INIT = 0;

input C, PRE, CLR, T;
output wire Q;
reg Q_;

initial begin
Q_ <= INIT;
end

always @(negedge C, posedge PRE, posedge CLR) begin
if (CLR == 1)
Q_ <= 0;
else if (PRE == 1)
Q_ <= 1;
else if (T == 1)
Q_ <= ~Q_;
end

assign Q = Q_;
endmodule

module FTDCP (C, PRE, CLR, T, Q);
parameter INIT = 0;

input C, PRE, CLR, T;
output wire Q;
reg Q_;

initial begin
Q_ <= INIT;
end

always @(posedge C, negedge C, posedge PRE, posedge CLR) begin
if (CLR == 1)
Q_ <= 0;
else if (PRE == 1)
Q_ <= 1;
else if (T == 1)
Q_ <= ~Q_;
end

assign Q = Q_;
endmodule
156 changes: 156 additions & 0 deletions techlibs/coolrunner2/coolrunner2_sop.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2017 Robert Ou <rqou@robertou.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/

#include "kernel/yosys.h"
#include "kernel/sigtools.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct Coolrunner2SopPass : public Pass {
Coolrunner2SopPass() : Pass("coolrunner2_sop", "break $sop cells into ANDTERM/ORTERM cells") { }
virtual void help()
{
log("\n");
log(" coolrunner2_sop [options] [selection]\n");
log("\n");
log("Break $sop cells into ANDTERM/ORTERM cells.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
log_header(design, "Executing COOLRUNNER2_SOP pass (break $sop cells into ANDTERM/ORTERM cells).\n");
extra_args(args, 1, design);

// Find all the $_NOT_ cells
dict<SigBit, tuple<SigBit, Cell*>> not_cells;
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
for (auto cell : module->selected_cells())
{
if (cell->type == "$_NOT_")
{
auto not_input = cell->getPort("\\A")[0];
auto not_output = cell->getPort("\\Y")[0];
not_cells[not_input] = tuple<SigBit, Cell*>(not_output, cell);
}
}
}

pool<tuple<Module*, Cell*>> cells_to_remove;
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
for (auto cell : module->selected_cells())
{
if (cell->type == "$sop")
{
// Read the inputs/outputs/parameters of the $sop cell
auto sop_inputs = sigmap(cell->getPort("\\A"));
auto sop_output = sigmap(cell->getPort("\\Y"))[0];
auto sop_depth = cell->getParam("\\DEPTH").as_int();
auto sop_width = cell->getParam("\\WIDTH").as_int();
auto sop_table = cell->getParam("\\TABLE");

// Check for a $_NOT_ at the output
bool has_invert = false;
if (not_cells.count(sop_output))
{
auto not_cell = not_cells.at(sop_output);

has_invert = true;
sop_output = std::get<0>(not_cell);

// remove the $_NOT_ cell because it gets folded into the xor
cells_to_remove.insert(tuple<Module*, Cell*>(module, std::get<1>(not_cell)));
}

// Construct AND cells
pool<SigBit> intermed_wires;
for (int i = 0; i < sop_depth; i++) {
// Wire for the output
auto and_out = module->addWire(NEW_ID);
intermed_wires.insert(and_out);

// Signals for the inputs
pool<SigBit> and_in_true;
pool<SigBit> and_in_comp;
for (int j = 0; j < sop_width; j++)
{
if (sop_table[2 * (i * sop_width + j) + 0])
{
and_in_comp.insert(sop_inputs[j]);
}
if (sop_table[2 * (i * sop_width + j) + 1])
{
and_in_true.insert(sop_inputs[j]);
}
}

// Construct the cell
auto and_cell = module->addCell(NEW_ID, "\\ANDTERM");
and_cell->setParam("\\TRUE_INP", GetSize(and_in_true));
and_cell->setParam("\\COMP_INP", GetSize(and_in_comp));
and_cell->setPort("\\OUT", and_out);
and_cell->setPort("\\IN", and_in_true);
and_cell->setPort("\\IN_B", and_in_comp);
}

if (sop_depth == 1)
{
// If there is only one term, don't construct an OR cell. Directly construct the XOR gate
auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR");
xor_cell->setParam("\\INVERT_OUT", has_invert);
xor_cell->setPort("\\IN_PTC", *intermed_wires.begin());
xor_cell->setPort("\\OUT", sop_output);
}
else
{
// Wire from OR to XOR
auto or_to_xor_wire = module->addWire(NEW_ID);

// Construct the OR cell
auto or_cell = module->addCell(NEW_ID, "\\ORTERM");
or_cell->setParam("\\WIDTH", sop_depth);
or_cell->setPort("\\IN", intermed_wires);
or_cell->setPort("\\OUT", or_to_xor_wire);

// Construct the XOR cell
auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR");
xor_cell->setParam("\\INVERT_OUT", has_invert);
xor_cell->setPort("\\IN_ORTERM", or_to_xor_wire);
xor_cell->setPort("\\OUT", sop_output);
}

// Finally, remove the $sop cell
cells_to_remove.insert(tuple<Module*, Cell*>(module, cell));
}
}
}

// Actually do the removal now that we aren't iterating
for (auto mod_and_cell : cells_to_remove)
{
std::get<0>(mod_and_cell)->remove(std::get<1>(mod_and_cell));
}
}
} Coolrunner2SopPass;

PRIVATE_NAMESPACE_END
186 changes: 186 additions & 0 deletions techlibs/coolrunner2/synth_coolrunner2.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2017 Robert Ou <rqou@robertou.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SynthCoolrunner2Pass : public ScriptPass
{
SynthCoolrunner2Pass() : ScriptPass("synth_coolrunner2", "synthesis for Xilinx Coolrunner-II CPLDs") { }

virtual void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" synth_coolrunner2 [options]\n");
log("\n");
log("This command runs synthesis for Coolrunner-II CPLDs. This work is experimental.\n");
log("It is intended to be used with https://github.com/azonenberg/openfpga as the\n");
log("place-and-route.\n");
log("\n");
log(" -top <module>\n");
log(" use the specified module as top module (default='top')\n");
log("\n");
log(" -json <file>\n");
log(" write the design to the specified JSON file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
log("\n");
log(" -run <from_label>:<to_label>\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(" synonymous to the end of the command list.\n");
log("\n");
log(" -noflatten\n");
log(" do not flatten design before synthesis\n");
log("\n");
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}

string top_opt, json_file;
bool flatten, retime;

virtual void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
json_file = "";
flatten = true;
retime = false;
}

virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string run_from, run_to;
clear_flags();

size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-top" && argidx+1 < args.size()) {
top_opt = "-top " + args[++argidx];
continue;
}
if (args[argidx] == "-json" && argidx+1 < args.size()) {
json_file = args[++argidx];
continue;
}
if (args[argidx] == "-run" && argidx+1 < args.size()) {
size_t pos = args[argidx+1].find(':');
if (pos == std::string::npos)
break;
run_from = args[++argidx].substr(0, pos);
run_to = args[argidx].substr(pos+1);
continue;
}
if (args[argidx] == "-noflatten") {
flatten = false;
continue;
}
if (args[argidx] == "-retime") {
retime = true;
continue;
}
break;
}
extra_args(args, argidx, design);

if (!design->full_selection())
log_cmd_error("This comannd only operates on fully selected designs!\n");

log_header(design, "Executing SYNTH_COOLRUNNER2 pass.\n");
log_push();

run_script(design, run_from, run_to);

log_pop();
}

virtual void script() YS_OVERRIDE
{
if (check_label("begin"))
{
run("read_verilog -lib +/coolrunner2/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
}

if (check_label("flatten", "(unless -noflatten)") && flatten)
{
run("proc");
run("flatten");
run("tribuf -logic");
}

if (check_label("coarse"))
{
run("synth -run coarse");
}

if (check_label("fine"))
{
run("opt -fast -full");
run("techmap");
run("techmap -map +/coolrunner2/cells_latch.v");
run("dfflibmap -prepare -liberty +/coolrunner2/xc2_dff.lib");
}

if (check_label("map_pla"))
{
run("abc -sop -I 40 -P 56");
run("coolrunner2_sop");
run("opt -fast");
}

if (check_label("map_cells"))
{
run("dfflibmap -liberty +/coolrunner2/xc2_dff.lib");
run("dffinit -ff FDCP Q INIT");
run("dffinit -ff FDCP_N Q INIT");
run("dffinit -ff LDCP Q INIT");
run("dffinit -ff LDCP_N Q INIT");
run("iopadmap -bits -inpad IBUF O:I -outpad IOBUFE I:IO -inoutpad IOBUFE O:IO -toutpad IOBUFE E:I:IO -tinoutpad IOBUFE E:O:I:IO");
}

if (check_label("check"))
{
run("hierarchy -check");
run("stat");
run("check -noinit");
}

if (check_label("json"))
{
if (!json_file.empty() || help_mode)
run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
}

log_pop();
}
} SynthCoolrunner2Pass;

PRIVATE_NAMESPACE_END
31 changes: 31 additions & 0 deletions techlibs/coolrunner2/xc2_dff.lib
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
library(xc2_dff) {
cell(FDCP) {
area: 1;
ff("IQ", "IQN") { clocked_on: C;
next_state: D;
clear: "CLR";
preset: "PRE"; }
pin(C) { direction: input;
clock: true; }
pin(D) { direction: input; }
pin(Q) { direction: output;
function: "IQ"; }
pin(CLR) { direction: input; }
pin(PRE) { direction: input; }
}

cell(FDCP_N) {
area: 1;
ff("IQ", "IQN") { clocked_on: "!C";
next_state: D;
clear: "CLR";
preset: "PRE"; }
pin(C) { direction: input;
clock: true; }
pin(D) { direction: input; }
pin(Q) { direction: output;
function: "IQ"; }
pin(CLR) { direction: input; }
pin(PRE) { direction: input; }
}
}