From 01ea72f53a9707d741a1178d0ac4c4f69d6b65db Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 21 Jan 2019 12:33:47 +0000 Subject: [PATCH 001/132] ecp5: Increase threshold for ALU mapping Signed-off-by: David Shah --- techlibs/ecp5/arith_map.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v index 1094c5f8a..eb7947601 100644 --- a/techlibs/ecp5/arith_map.v +++ b/techlibs/ecp5/arith_map.v @@ -33,7 +33,7 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); input CI, BI; output [Y_WIDTH-1:0] CO; - wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); From d8003e87d1c5962e660ce84150239444b7fb037d Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 21 Jan 2019 12:34:34 +0000 Subject: [PATCH 002/132] ecp5: More blackboxes Signed-off-by: David Shah --- techlibs/ecp5/cells_bb.v | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index 425d62d24..32fb5c1ef 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -156,6 +156,23 @@ module OSCG( parameter DIV = 128; endmodule +(* blackbox *) (* keep *) +module USRMCLK( + input USRMCLKI, USRMCLKTS, + output USRMCLKO +); +endmodule + +(* blackbox *) (* keep *) +module JTAGG( + input TCK, TMS, TDI, JTDO2, JTDO1, + output TDO, JTDI, JTCK, JRTI2, JRTI1, + output JSHIFT, JUPDATE, JRSTN, JCE2, JCE1 +); +parameter ER1 = "ENABLED"; +parameter ER2 = "ENABLED"; +endmodule + (* blackbox *) module IDDRX1F( input D, SCLK, RST, From ee8c9e854f0b5f6500d030d4c700b29f042fb57f Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 21 Jan 2019 12:35:22 +0000 Subject: [PATCH 003/132] ecp5: Add LSRMODE to flipflops for PRLD support Signed-off-by: David Shah --- techlibs/ecp5/cells_sim.v | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 507ab1beb..ca5d020f3 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -203,13 +203,14 @@ endmodule // --------------------------------------- -module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q); +module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); parameter GSR = "ENABLED"; parameter [127:0] CEMUX = "1"; parameter CLKMUX = "CLK"; parameter LSRMUX = "LSR"; parameter SRMODE = "LSR_OVER_CE"; parameter REGSET = "RESET"; + parameter [127:0] LSRMODE = "LSR"; reg muxce; always @(*) @@ -222,8 +223,12 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q); wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; - - localparam srval = (REGSET == "SET") ? 1'b1 : 1'b0; + generate + if (LSRMODE == "PRLD") + wire srval = M; + else + localparam srval = (REGSET == "SET") ? 1'b1 : 1'b0; + endgenerate initial Q = srval; @@ -339,6 +344,8 @@ module TRELLIS_SLICE( parameter REG1_SD = "0"; parameter REG0_REGSET = "RESET"; parameter REG1_REGSET = "RESET"; + parameter REG0_LSRMODE = "LSR"; + parameter REG1_LSRMODE = "LSR"; parameter [127:0] CCU2_INJECT1_0 = "NO"; parameter [127:0] CCU2_INJECT1_1 = "NO"; parameter WREMUX = "WRE"; @@ -428,10 +435,11 @@ module TRELLIS_SLICE( .CLKMUX(CLKMUX), .LSRMUX(LSRMUX), .SRMODE(SRMODE), - .REGSET(REG0_REGSET) + .REGSET(REG0_REGSET), + .LSRMODE(REG0_LSRMODE) ) ff_0 ( .CLK(CLK), .LSR(LSR), .CE(CE), - .DI(muxdi0), + .DI(muxdi0), .M(M0), .Q(Q0) ); TRELLIS_FF #( @@ -440,10 +448,11 @@ module TRELLIS_SLICE( .CLKMUX(CLKMUX), .LSRMUX(LSRMUX), .SRMODE(SRMODE), - .REGSET(REG1_REGSET) + .REGSET(REG1_REGSET), + .LSRMODE(REG1_LSRMODE) ) ff_1 ( .CLK(CLK), .LSR(LSR), .CE(CE), - .DI(muxdi1), + .DI(muxdi1), .M(M1), .Q(Q1) ); endmodule From 549b8e74b2cef41a23e609bdb65c5b04b3141a61 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 30 Nov 2018 19:29:03 +0000 Subject: [PATCH 004/132] ecp5: Support for flipflop initialisation Signed-off-by: David Shah --- techlibs/ecp5/Makefile.inc | 2 +- techlibs/ecp5/ecp5_ffinit.cc | 198 +++++++++++++++++++++++++++++++++++ techlibs/ecp5/synth_ecp5.cc | 3 - 3 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 techlibs/ecp5/ecp5_ffinit.cc diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 8df02be5f..4db087e87 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -1,5 +1,5 @@ -OBJS += techlibs/ecp5/synth_ecp5.o +OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v)) diff --git a/techlibs/ecp5/ecp5_ffinit.cc b/techlibs/ecp5/ecp5_ffinit.cc new file mode 100644 index 000000000..02945fff4 --- /dev/null +++ b/techlibs/ecp5/ecp5_ffinit.cc @@ -0,0 +1,198 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2018-19 David Shah + * + * 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 Ecp5FfinitPass : public Pass { + Ecp5FfinitPass() : Pass("ecp5_ffinit", "ECP5: handle FF init values") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ecp5_ffinit [options] [selection]\n"); + log("\n"); + log("Remove init values for FF output signals when equal to reset value.\n"); + log("If reset is not used, set the reset value to the init value, otherwise\n"); + log("unmap out the reset (if not an async reset).\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ECP5_FFINIT pass (implement FF init values).\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); + + for (auto module : design->selected_modules()) + { + log("Handling FF init values in %s.\n", log_id(module)); + + SigMap sigmap(module); + pool init_wires; + dict initbits; + dict initbit_to_wire; + pool handled_initbits; + + for (auto wire : module->selected_wires()) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec wirebits = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + init_wires.insert(wire); + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) + { + SigBit bit = wirebits[i]; + State val = initval[i]; + + if (val != State::S0 && val != State::S1) + continue; + + if (initbits.count(bit)) { + if (initbits.at(bit) != val) + log_error("Conflicting init values for signal %s (%s = %s, %s = %s).\n", + log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val), + log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit))); + continue; + } + + initbits[bit] = val; + initbit_to_wire[bit] = SigBit(wire, i); + } + } + for (auto cell : module->selected_cells()) + { + if (cell->type != "\\TRELLIS_FF") + continue; + SigSpec sig_d = cell->getPort("\\DI"); + SigSpec sig_q = cell->getPort("\\Q"); + SigSpec sig_lsr = cell->getPort("\\LSR"); + + if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) + continue; + + SigBit bit_d = sigmap(sig_d[0]); + SigBit bit_q = sigmap(sig_q[0]); + + std::string regset = "RESET"; + if (cell->hasParam("\\REGSET")) + regset = cell->getParam("\\REGSET").decode_string(); + State resetState; + if (regset == "SET") + resetState = State::S1; + else if (regset == "RESET") + resetState = State::S0; + else + log_error("FF cell %s has illegal REGSET value %s.\n", + log_id(cell), regset.c_str()); + + if (!initbits.count(bit_q)) + continue; + + State val = initbits.at(bit_q); + + 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'); + // Initval is the same as the reset state. Matches hardware, nowt more to do + if (val == resetState) { + handled_initbits.insert(bit_q); + continue; + } + + if (GetSize(sig_lsr) >= 1 && sig_lsr[0] != State::S0) { + std::string srmode = "LSR_OVER_CE"; + if (cell->hasParam("\\SRMODE")) + srmode = cell->getParam("\\SRMODE").decode_string(); + if (srmode == "ASYNC") { + log("Async reset value %c for FF cell %s inconsistent with init value %c.\n", + resetState != State::S0 ? '1' : '0', log_id(cell), val != State::S0 ? '1' : '0'); + } else { + SigBit bit_lsr = sigmap(sig_lsr[0]); + Wire *new_bit_d = module->addWire(NEW_ID); + if (resetState == State::S0) { + module->addAndnotGate(NEW_ID, bit_d, bit_lsr, new_bit_d); + } else { + module->addOrGate(NEW_ID, bit_d, bit_lsr, new_bit_d); + } + + cell->setPort("\\DI", new_bit_d); + cell->setPort("\\LSR", State::S0); + + if(cell->hasPort("\\CE")) { + std::string cemux = "CE"; + if (cell->hasParam("\\CEMUX")) + cemux = cell->getParam("\\CEMUX").decode_string(); + SigSpec sig_ce = cell->getPort("\\CE"); + if (GetSize(sig_ce) >= 1) { + SigBit bit_ce = sigmap(sig_ce[0]); + Wire *new_bit_ce = module->addWire(NEW_ID); + if (cemux == "INV") + module->addAndnotGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce); + else + module->addOrGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce); + cell->setPort("\\CE", new_bit_ce); + } + } + cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET")); + handled_initbits.insert(bit_q); + } + } else { + cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET")); + handled_initbits.insert(bit_q); + } + } + + for (auto wire : init_wires) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec wirebits = sigmap(wire); + Const &initval = wire->attributes.at("\\init"); + bool remove_attribute = true; + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) { + if (handled_initbits.count(wirebits[i])) + initval[i] = State::Sx; + else if (initval[i] != State::Sx) + remove_attribute = false; + } + + if (remove_attribute) + wire->attributes.erase("\\init"); + } + } + } +} Ecp5FfinitPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 2e9176a84..835f10d8c 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -255,10 +255,7 @@ struct SynthEcp5Pass : public ScriptPass run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); run("opt_expr -mux_undef"); run("simplemap"); - // TODO -#if 0 run("ecp5_ffinit"); -#endif } if (check_label("map_luts")) From 7913baedd8c776243cbcf5ce73549943d1fe83a2 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 12 Feb 2019 12:04:41 +0000 Subject: [PATCH 005/132] ecp5: Full set of IO-related blackboxes Signed-off-by: David Shah --- techlibs/ecp5/cells_bb.v | 102 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index 32fb5c1ef..5b8d6bb4a 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -181,6 +181,31 @@ module IDDRX1F( parameter GSR = "ENABLED"; endmodule +(* blackbox *) +module IDDRX2F( + input D, SCLK, ECLK, RST, + output Q0, Q1, Q2, Q3 +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module IDDR71B( + input D, SCLK, ECLK, RST, ALIGNWD, + output Q0, Q1, Q2, Q3, Q4, Q5, Q6 +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module IDDRX2DQA( + input D, DQSR90, ECLK, SCLK, RST, + input RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0, + output Q0, Q1, Q2, Q3, QWL +); + parameter GSR = "ENABLED"; +endmodule + (* blackbox *) module ODDRX1F( input SCLK, RST, D0, D1, @@ -189,6 +214,83 @@ module ODDRX1F( parameter GSR = "ENABLED"; endmodule +(* blackbox *) +module ODDRX2F( + input SCLK, ECLK, RST, D0, D1, D2, D3, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDR71B( + input SCLK, ECLK, RST, D0, D1, D2, D3, D4, D5, D6, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module OSHX2A( + input D0, D1, RST, ECLK, SCLK, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDRX2DQA( + input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW270, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDRX2DQSB( + input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module TSHX2DQA( + input T0, T1, SCLK, ECLK, DQSW270, RST, + output Q +); + parameter GSR = "ENABLED"; + parameter REGSET = "SET"; +endmodule + +(* blackbox *) +module TSHX2DQSA( + input T0, T1, SCLK, ECLK, DQSW, RST, + output Q +); + parameter GSR = "ENABLED"; + parameter REGSET = "SET"; +endmodule + + +(* blackbox *) +module DQSBUFM( + input DQSI, READ1, READ0, READCLKSEL2, READCLKSEL1, READCLKSEL0, DDRDEL, + input ECLK, SCLK, + input DYNDELAY7, DYNDELAY6, DYNDELAY5, DYNDELAY4, + input DYNDELAY3, DYNDELAY2, DYNDELAY1, DYNDELAY0, + input RST, RDLOADN, RDMOVE, RDDIRECTION, WRLOADN, WRMOVE, WRDIRECTION, PAUSE, + output DQSR90, DQSW, DQSW270, + output RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0, + output DATAVALID, BURSTDET, RDCFLAG, WRCFLAG +); + parameter DQS_LI_DEL_ADJ = "FACTORYONLY"; + parameter DQS_LI_DEL_VAL = 0; + parameter DQS_LO_DEL_ADJ = "FACTORYONLY"; + parameter DQS_LO_DEL_VAL = 0; + parameter GSR = "ENABLED"; +endmodule + (* blackbox *) module CLKDIVF( input CLKI, RST, ALIGNWD, From e0bc190879d1c722c267ae9370a16ce202345b76 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 13 Feb 2019 11:23:25 +0000 Subject: [PATCH 006/132] ecp5: Add ECLKSYNCB blackbox Signed-off-by: David Shah --- techlibs/ecp5/cells_bb.v | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index 5b8d6bb4a..1de623fcd 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -272,7 +272,6 @@ module TSHX2DQSA( parameter REGSET = "SET"; endmodule - (* blackbox *) module DQSBUFM( input DQSI, READ1, READ0, READCLKSEL2, READCLKSEL1, READCLKSEL0, DDRDEL, @@ -300,6 +299,13 @@ module CLKDIVF( parameter DIV = "2.0"; endmodule +(* blackbox *) +module ECLKSYNCB( + input ECLKI, STOP, + output ECLKO +); +endmodule + (* blackbox *) module DCCA( input CLKI, CE, From c36f15b489c1d47e94901e9286c4f1c2afb815c4 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 19 Feb 2019 14:10:43 +0000 Subject: [PATCH 007/132] ecp5: Add DELAYF/DELAYG blackboxes Signed-off-by: David Shah --- techlibs/ecp5/cells_bb.v | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index 1de623fcd..bac17260f 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -173,6 +173,24 @@ parameter ER1 = "ENABLED"; parameter ER2 = "ENABLED"; endmodule +(* blackbox *) +module DELAYF( + input A, LOADN, MOVE, DIRECTION, + output Z, CFLAG +); + parameter DEL_MODE = "USER_DEFINED"; + parameter DEL_VALUE = 0; +endmodule + +(* blackbox *) +module DELAYG( + input A, + output Z +); + parameter DEL_MODE = "USER_DEFINED"; + parameter DEL_VALUE = 0; +endmodule + (* blackbox *) module IDDRX1F( input D, SCLK, RST, From bb56cb738d6586059855cc3deefad12119673157 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 19 Feb 2019 19:34:37 +0000 Subject: [PATCH 008/132] ecp5: Add DDRDLLA Signed-off-by: David Shah --- techlibs/ecp5/cells_bb.v | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index bac17260f..223e19b9e 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -308,6 +308,15 @@ module DQSBUFM( parameter GSR = "ENABLED"; endmodule +(* blackbox *) +module DDRDLLA( + input CLK, RST, UDDCNTLN, FREEZE, + output LOCK, DDRDEL, DCNTL7, DCNTL6, DCNTL5, DCNTL4, DCNTL3, DCNTL2, DCNTL1, DCNTL0 +); + parameter FORCE_MAX_DELAY = "NO"; + parameter GSR = "ENABLED"; +endmodule + (* blackbox *) module CLKDIVF( input CLKI, RST, ALIGNWD, From fa2f595cfa240b86edb26e859449c1c54eaf49ef Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 19 Feb 2019 19:35:10 +0000 Subject: [PATCH 009/132] ecp5: Compatibility with Migen AsyncResetSynchronizer Signed-off-by: David Shah --- techlibs/ecp5/cells_map.v | 3 +++ techlibs/ecp5/cells_sim.v | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index 23182bdeb..6ab4b69f2 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -47,6 +47,9 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED" module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +// For Diamond compatibility, FIXME: add all Diamond flipflop mappings +module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule + `ifndef NO_LUT module \$lut (A, Y); parameter WIDTH = 0; diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index ca5d020f3..d2d8b5793 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -556,3 +556,20 @@ module DP16KD( parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; endmodule + +// For Diamond compatibility, FIXME: add all Diamond flipflop mappings +module FD1S3BX(input PD, D, CK, output Q); + TRELLIS_FF #( + .GSR("DISABLED"), + .CEMUX("1"), + .CLKMUX("CLK"), + .LSRMUX("LSR"), + .REGSET("SET"), + .SRMODE("ASYNC") + ) tff_i ( + .CLK(CK), + .LSR(PD), + .DI(D), + .Q(Q) + ); +endmodule From 171c425cf9addb61ef3f03596fd26355ed8af76d Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 25 Feb 2019 16:18:13 -0800 Subject: [PATCH 010/132] Fix FIRRTL to Verilog process instance subfield assignment. Don't emit subfield assignments: bits(x, y, z) <= ... - but instead, add them to the reverse-wire-map where they'll be treated at the end of the module. Enable tests which were disabled due to incorrect treatment of subfields. Assume the `$firrtl2verilog` variable contains any additional switches to control verilog generation (i.e. `--no-dedup -X mverilog`) --- backends/firrtl/firrtl.cc | 28 ++++++++++++++++++++-------- tests/asicworld/xfirrtl | 1 - tests/simple/xfirrtl | 1 - tests/tools/autotest.sh | 2 +- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 0917ecba6..88c1038b7 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -169,7 +169,6 @@ struct FirrtlWorker return *str == '\\' ? str + 1 : str; } - std::string cellname(RTLIL::Cell *cell) { return fid(cell->name).c_str(); @@ -219,29 +218,42 @@ struct FirrtlWorker if (it->second.size() > 0) { const SigSpec &secondSig = it->second; const std::string firstName = cell_name + "." + make_id(it->first); - const std::string secondName = make_expr(secondSig); + const std::string secondExpr = make_expr(secondSig); // Find the direction for this port. FDirection dir = getPortFDirection(it->first, instModule); - std::string source, sink; + std::string sourceExpr, sinkExpr; + const SigSpec *sinkSig = nullptr; switch (dir) { case FD_INOUT: log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); case FD_OUT: - source = firstName; - sink = secondName; + sourceExpr = firstName; + sinkExpr = secondExpr; + sinkSig = &secondSig; break; case FD_NODIRECTION: log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); /* FALL_THROUGH */ case FD_IN: - source = secondName; - sink = firstName; + sourceExpr = secondExpr; + sinkExpr = firstName; break; default: log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir); break; } - wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str())); + // Check for subfield assignment. + std::string bitsString = "bits("; + if (sinkExpr.substr(0, bitsString.length()) == bitsString ) { + if (sinkSig == nullptr) + log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str()); + // Don't generate the assignment here. + // Add the source and sink to the "reverse_wire_map" and we'll output the assignment + // as part of the coalesced subfield assignments for this wire. + register_reverse_wire_map(sourceExpr, *sinkSig); + } else { + wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str())); + } } } wire_exprs.push_back(stringf("\n")); diff --git a/tests/asicworld/xfirrtl b/tests/asicworld/xfirrtl index c782a2bd6..08bf4ccd8 100644 --- a/tests/asicworld/xfirrtl +++ b/tests/asicworld/xfirrtl @@ -6,7 +6,6 @@ code_hdl_models_d_latch_gates.v combinational loop code_hdl_models_dff_async_reset.v $adff code_hdl_models_tff_async_reset.v $adff code_hdl_models_uart.v $adff -code_specman_switch_fabric.v subfield assignment (bits() <= ...) code_tidbits_asyn_reset.v $adff code_tidbits_reg_seq_example.v $adff code_verilog_tutorial_always_example.v empty module diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl index 00e89b389..5bc75347b 100644 --- a/tests/simple/xfirrtl +++ b/tests/simple/xfirrtl @@ -12,7 +12,6 @@ multiplier.v inst id[0] of muxtree.v drops modules omsp_dbg_uart.v $adff operators.v $pow -paramods.v subfield assignment (bits() <= ...) partsel.v drops modules process.v drops modules realexpr.v drops modules diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 218edf931..99ec3e7cd 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -175,7 +175,7 @@ do if [ -n "$firrtl2verilog" ]; then if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then "$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.v - $firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v -X verilog + $firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v fi fi From a58dbcf2bae38835cdc2964718d4562ae4be4cc5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 27 Feb 2019 11:37:08 -0800 Subject: [PATCH 011/132] Add "supercover" skeleton Signed-off-by: Clifford Wolf --- passes/sat/Makefile.inc | 1 + passes/sat/supercover.cc | 76 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 passes/sat/supercover.cc diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index 8ab0280c0..6cb1ea644 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -8,4 +8,5 @@ OBJS += passes/sat/expose.o OBJS += passes/sat/assertpmux.o OBJS += passes/sat/clk2fflogic.o OBJS += passes/sat/async2sync.o +OBJS += passes/sat/supercover.o diff --git a/passes/sat/supercover.cc b/passes/sat/supercover.cc new file mode 100644 index 000000000..9b208b0bf --- /dev/null +++ b/passes/sat/supercover.cc @@ -0,0 +1,76 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 SupercoverPass : public Pass { + SupercoverPass() : Pass("supercover", "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(" supercover [options] [selection]\n"); + log("\n"); + log("This command adds two cover cells for each bit of each selected wire, one\n"); + log("checking for a hi signal level and one checking for lo level.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + // bool flag_noinit = false; + + log_header(design, "Executing SUPERCOVER pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-noinit") { + // flag_noinit = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + int cnt_wire = 0, cnt_bits = 0; + log("Adding cover cells to module %s.\n", log_id(module)); + for (auto wire : module->selected_wires()) + { + std::string src = wire->get_src_attribute(); + cnt_wire++; + for (auto bit : SigSpec(wire)) + { + SigSpec inv = module->Not(NEW_ID, bit); + module->addCover(NEW_ID, bit, State::S1, src); + module->addCover(NEW_ID, inv, State::S1, src); + cnt_bits++; + } + } + log(" added cover cells to %d wires, %d bits.\n", cnt_wire, cnt_bits); + } + } +} SupercoverPass; + +PRIVATE_NAMESPACE_END From 63be3f3bab9293cf5b8f7416fce13cdeaa030727 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 27 Feb 2019 11:45:13 -0800 Subject: [PATCH 012/132] Improvements in "supercover" pass Signed-off-by: Clifford Wolf --- passes/sat/supercover.cc | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/passes/sat/supercover.cc b/passes/sat/supercover.cc index 9b208b0bf..ba44f02d8 100644 --- a/passes/sat/supercover.cc +++ b/passes/sat/supercover.cc @@ -54,17 +54,33 @@ struct SupercoverPass : public Pass { for (auto module : design->selected_modules()) { + SigMap sigmap(module); + pool handled_bits; + int cnt_wire = 0, cnt_bits = 0; log("Adding cover cells to module %s.\n", log_id(module)); for (auto wire : module->selected_wires()) { + bool counted_wire = false; std::string src = wire->get_src_attribute(); - cnt_wire++; - for (auto bit : SigSpec(wire)) + + for (auto bit : sigmap(SigSpec(wire))) { + if (bit.wire == nullptr) + continue; + + if (handled_bits.count(bit)) + continue; + SigSpec inv = module->Not(NEW_ID, bit); module->addCover(NEW_ID, bit, State::S1, src); module->addCover(NEW_ID, inv, State::S1, src); + + handled_bits.insert(bit); + if (!counted_wire) { + counted_wire = false; + cnt_wire++; + } cnt_bits++; } } From f570aa5e1d3ac201089da2198f8e5084185fd92f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 28 Feb 2019 12:15:58 -0800 Subject: [PATCH 013/132] Fix smt2 code generation for partially initialized memowy words, fixes #831 Signed-off-by: Clifford Wolf --- backends/smt2/smt2.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 418f8d766..7f3cc94ca 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -1103,20 +1103,27 @@ struct Smt2Worker break; Const initword = init_data.extract(i*width, width, State::Sx); + Const initmask = initword; bool gen_init_constr = false; - for (auto bit : initword.bits) - if (bit == State::S0 || bit == State::S1) + for (int k = 0; k < GetSize(initword); k++) { + if (initword[k] == State::S0 || initword[k] == State::S1) { gen_init_constr = true; + initmask[k] = State::S1; + } else { + initmask[k] = State::S0; + initword[k] = State::S0; + } + } if (gen_init_constr) { if (statebv) /* FIXME */; else - init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]", + init_list.push_back(stringf("(= (bvand (select (|%s#%d#0| state) #b%s) #b%s) #b%s) ; %s[%d]", get_id(module), arrayid, Const(i, abits).as_string().c_str(), - initword.as_string().c_str(), get_id(cell), i)); + initmask.as_string().c_str(), initword.as_string().c_str(), get_id(cell), i)); } } } From 64d91219b4e81366976a0e0a9b28efa4bd825022 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 28 Feb 2019 14:00:58 -0800 Subject: [PATCH 014/132] Fix pmgen for out-of-tree build Signed-off-by: Clifford Wolf --- passes/pmgen/Makefile.inc | 4 ++-- passes/pmgen/pmgen.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 33baaca30..b9682612b 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -4,5 +4,5 @@ passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h .SECONDARY: passes/pmgen/ice40_dsp_pm.h -passes/pmgen/ice40_dsp_pm.h: passes/pmgen/ice40_dsp.pmg passes/pmgen/pmgen.py - $(P) cd passes/pmgen && python3 pmgen.py ice40_dsp +passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg + $(P) mkdir -p passes/pmgen && cd passes/pmgen && python3 $^ diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index e688a4567..166d3963a 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -6,7 +6,9 @@ import pprint pp = pprint.PrettyPrinter(indent=4) -prefix = sys.argv[1] +pmgfile = sys.argv[1] +prefix = pmgfile.split("/")[-1] +prefix = prefix.split(".")[0] state_types = dict() udata_types = dict() @@ -73,7 +75,7 @@ def rewrite_cpp(s): return "".join(t) -with open("%s.pmg" % prefix, "r") as f: +with open(pmgfile, "r") as f: while True: line = f.readline() if line == "": break From 68a693717347cefc057cbf1a1c8d0f66500dec4f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 28 Feb 2019 14:56:05 -0800 Subject: [PATCH 015/132] Fix pmgen for in-tree builds Signed-off-by: Clifford Wolf --- passes/pmgen/Makefile.inc | 2 +- passes/pmgen/pmgen.py | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index b9682612b..e0dd0fc06 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -5,4 +5,4 @@ EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h .SECONDARY: passes/pmgen/ice40_dsp_pm.h passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg - $(P) mkdir -p passes/pmgen && cd passes/pmgen && python3 $^ + $(P) mkdir -p passes/pmgen && python3 $^ diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 166d3963a..034ac27aa 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -7,8 +7,9 @@ import pprint pp = pprint.PrettyPrinter(indent=4) pmgfile = sys.argv[1] -prefix = pmgfile.split("/")[-1] -prefix = prefix.split(".")[0] +assert pmgfile.endswith(".pmg") +prefix = pmgfile[0:-4] +pmname = prefix.split('/')[-1] state_types = dict() udata_types = dict() @@ -189,10 +190,10 @@ with open("%s_pm.h" % prefix, "w") as f: print("YOSYS_NAMESPACE_BEGIN", file=f) print("", file=f) - print("struct {}_pm {{".format(prefix), file=f) + print("struct {}_pm {{".format(pmname), file=f) print(" Module *module;", file=f) print(" SigMap sigmap;", file=f) - print(" std::function on_accept;".format(prefix), file=f) + print(" std::function on_accept;".format(pmname), file=f) print("", file=f) for index in range(len(blocks)): @@ -290,7 +291,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print(" {}_pm(Module *module, const vector &cells) :".format(prefix), file=f) + print(" {}_pm(Module *module, const vector &cells) :".format(pmname), file=f) print(" module(module), sigmap(module) {", file=f) for s, t in sorted(udata_types.items()): if t.endswith("*"): @@ -320,7 +321,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print(" ~{}_pm() {{".format(prefix), file=f) + print(" ~{}_pm() {{".format(pmname), file=f) print(" for (auto cell : autoremove_cells)", file=f) print(" module->remove(cell);", file=f) print(" }", file=f) @@ -339,7 +340,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print(" void run(std::function on_accept_f) {{".format(prefix), file=f) + print(" void run(std::function on_accept_f) {{".format(pmname), file=f) print(" run([&](){on_accept_f(*this);});", file=f) print(" }", file=f) print("", file=f) From e2fc18f27b5e9f506724a486787c2106b9f7fb4f Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Tue, 26 Feb 2019 10:28:42 -0800 Subject: [PATCH 016/132] Reduce amount of trailing whitespace in code base --- backends/protobuf/protobuf.cc | 6 +++--- misc/yosys.proto | 12 ++++++------ passes/pmgen/pmgen.py | 2 +- techlibs/achronix/speedster22i/cells_sim.v | 6 +++--- techlibs/anlogic/anlogic_eqn.cc | 4 ++-- techlibs/gowin/arith_map.v | 12 ++++++------ techlibs/gowin/synth_gowin.cc | 2 +- techlibs/intel/cycloneive/arith_map.v | 10 +++++----- techlibs/intel/cyclonev/cells_map.v | 4 ++-- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/backends/protobuf/protobuf.cc b/backends/protobuf/protobuf.cc index f56147cef..549fc73ae 100644 --- a/backends/protobuf/protobuf.cc +++ b/backends/protobuf/protobuf.cc @@ -48,7 +48,7 @@ struct ProtobufDesignSerializer ProtobufDesignSerializer(bool use_selection, bool aig_mode) : aig_mode_(aig_mode), use_selection_(use_selection) { } - + string get_name(IdString name) { return RTLIL::unescape_id(name); @@ -60,7 +60,7 @@ struct ProtobufDesignSerializer { for (auto ¶m : parameters) { std::string key = get_name(param.first); - + yosys::pb::Parameter pb_param; @@ -207,7 +207,7 @@ struct ProtobufDesignSerializer (*models)[aig.name] = pb_model; } } - + void serialize_design(yosys::pb::Design *pb, Design *design) { GOOGLE_PROTOBUF_VERIFY_VERSION; diff --git a/misc/yosys.proto b/misc/yosys.proto index 2870176cb..a583e6265 100644 --- a/misc/yosys.proto +++ b/misc/yosys.proto @@ -1,12 +1,12 @@ // // yosys -- Yosys Open SYnthesis Suite -// +// // Copyright (C) 2018 Serge Bazanski -// +// // 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 @@ -73,7 +73,7 @@ message Module { BitVector bits = 2; } map port = 2; - + // Named cells in this module. message Cell { // Set to true when the name of this cell is automatically created and @@ -129,7 +129,7 @@ message Model { TYPE_FALSE = 6; }; Type type = 1; - + message Port { // Name of port. string portname = 1; @@ -148,7 +148,7 @@ message Model { // Set for AND, NAND. Gate gate = 3; } - + // Set when the node drives given output port(s). message OutPort { // Name of port. diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 034ac27aa..762d8621f 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -85,7 +85,7 @@ with open(pmgfile, "r") as f: cmd = line.split() if len(cmd) == 0 or cmd[0].startswith("//"): continue cmd = cmd[0] - + if cmd == "state": m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) assert m diff --git a/techlibs/achronix/speedster22i/cells_sim.v b/techlibs/achronix/speedster22i/cells_sim.v index a94dce9b1..a0c60b4be 100755 --- a/techlibs/achronix/speedster22i/cells_sim.v +++ b/techlibs/achronix/speedster22i/cells_sim.v @@ -30,7 +30,7 @@ endmodule module PADOUT (output padout, input padin, input oe); assign padout = padin; assign oe = oe; -endmodule +endmodule module LUT4 (output dout, input din0, din1, din2, din3); @@ -66,14 +66,14 @@ always @(dataa_w or datab_w or datac_w or datad_w) begin datac_w, datad_w); end assign dout = combout_rt & 1'b1; -endmodule +endmodule module DFF (output q, input d, ck); reg q; always @(posedge ck) q <= d; - + endmodule diff --git a/techlibs/anlogic/anlogic_eqn.cc b/techlibs/anlogic/anlogic_eqn.cc index c025c65c4..741bf04cc 100644 --- a/techlibs/anlogic/anlogic_eqn.cc +++ b/techlibs/anlogic/anlogic_eqn.cc @@ -52,13 +52,13 @@ struct AnlogicEqnPass : public Pass { eqn += names[j]; else eqn += std::string("~") + names[j]; - + if (j!=(inputs-1)) eqn += "*"; } eqn += ")+"; } } - if (eqn.empty()) return Const("0"); + if (eqn.empty()) return Const("0"); eqn = eqn.substr(0, eqn.length()-1); return Const(eqn); } diff --git a/techlibs/gowin/arith_map.v b/techlibs/gowin/arith_map.v index 25e789e4a..e15de6423 100644 --- a/techlibs/gowin/arith_map.v +++ b/techlibs/gowin/arith_map.v @@ -25,24 +25,24 @@ module _80_gw1n_alu(A, B, CI, BI, X, Y, CO); parameter A_WIDTH = 1; parameter B_WIDTH = 1; parameter Y_WIDTH = 1; - + input [A_WIDTH-1:0] A; input [B_WIDTH-1:0] B; output [Y_WIDTH-1:0] X, Y; - + input CI, BI; output [Y_WIDTH-1:0] CO; - + wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; - + wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_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] C = {CO, CI}; - + genvar i; generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice ALU #(.ALU_MODE(32'b0)) diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 96128a680..9a3fcdbb6 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -111,7 +111,7 @@ struct SynthGowinPass : public ScriptPass if (args[argidx] == "-noflatten") { flatten = false; continue; - } + } break; } extra_args(args, argidx, design); diff --git a/techlibs/intel/cycloneive/arith_map.v b/techlibs/intel/cycloneive/arith_map.v index b3a11272b..49e36aa25 100644 --- a/techlibs/intel/cycloneive/arith_map.v +++ b/techlibs/intel/cycloneive/arith_map.v @@ -32,7 +32,7 @@ module fa wire VCC; assign VCC = 1'b1; - + cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x), .dataa(a_c), .datab(b_c), @@ -40,7 +40,7 @@ module fa .datad(VCC)); defparam syn__05_.lut_mask = 16'b1001011010010110; defparam syn__05_.sum_lutc_input = "datac"; - + cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t), .dataa(cin_c), .datab(b_c), @@ -48,11 +48,11 @@ module fa .datad(VCC)); defparam syn__06_.lut_mask = 16'b1110000011100000; defparam syn__06_.sum_lutc_input = "datac"; - + endmodule // fa module f_stage(); - + endmodule // f_stage module f_end(); @@ -88,7 +88,7 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO); .cin_c(C[0]), .cout_t(C0[1]), .sum_x(Y[0])); - + genvar i; generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i])); diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v index bd60d4e17..f8d142bc9 100644 --- a/techlibs/intel/cyclonev/cells_map.v +++ b/techlibs/intel/cyclonev/cells_map.v @@ -76,7 +76,7 @@ module \$lut (A, Y); wire VCC; wire GND; assign {VCC,GND} = {1'b1,1'b0}; - + generate if (WIDTH == 1) begin assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function @@ -151,7 +151,7 @@ module \$lut (A, Y); TODO: There's not a just 7-input function on Cyclone V, see the following note: **Extended LUT Mode** Use extended LUT mode to implement a specific set of 7-input functions. The set must - be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs. + be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs. [source](Device Interfaces and Integration Basics for Cyclone V Devices). end*/ else From 241901461ae02c6a41837e254088f277b8167476 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 28 Feb 2019 14:56:55 -0800 Subject: [PATCH 017/132] Add "write_verilog -siminit" Signed-off-by: Clifford Wolf --- backends/verilog/verilog_backend.cc | 13 +++++++++++-- tests/tools/autotest.sh | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index d351a6266..6818edb7a 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -33,7 +33,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal; +bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit; int auto_name_counter, auto_name_offset, auto_name_digits; std::map auto_name_map; std::set reg_wires, reg_ct; @@ -1310,7 +1310,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) } } - if (reg_ct.count(cell->type) && cell->hasPort("\\Q")) { + if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) { std::stringstream ss; dump_reg_init(ss, cell->getPort("\\Q")); if (!ss.str().empty()) { @@ -1607,6 +1607,10 @@ struct VerilogBackend : public Backend { log(" without this option all internal cells are converted to Verilog\n"); log(" expressions.\n"); log("\n"); + log(" -siminit\n"); + log(" add initial statements with hierarchical refs to initialize FFs when\n"); + log(" in -noexpr mode.\n"); + log("\n"); log(" -nodec\n"); log(" 32-bit constant values are by default dumped as decimal numbers,\n"); log(" not bit pattern. This option deactivates this feature and instead\n"); @@ -1663,6 +1667,7 @@ struct VerilogBackend : public Backend { nostr = false; defparam = false; decimal = false; + siminit = false; auto_prefix = ""; bool blackboxes = false; @@ -1739,6 +1744,10 @@ struct VerilogBackend : public Backend { decimal = true; continue; } + if (arg == "-siminit") { + siminit = true; + continue; + } if (arg == "-blackboxes") { blackboxes = true; continue; diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 99ec3e7cd..0b9aceacc 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -8,7 +8,7 @@ verbose=false keeprunning=false makejmode=false frontend="verilog" -backend_opts="-noattr -noexpr" +backend_opts="-noattr -noexpr -siminit" autotb_opts="" include_opts="" xinclude_opts="" From cd2902ab1fec57503320e32ba5620c6487f9cb85 Mon Sep 17 00:00:00 2001 From: Elms Date: Thu, 28 Feb 2019 16:22:24 -0800 Subject: [PATCH 018/132] ice40: use 2 bits for READ/WRITE MODE for SB_RAM map EBLIF output .param will only use necessary 2 bits Signed-off-by: Elms --- techlibs/ice40/brams_map.v | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/ice40/brams_map.v b/techlibs/ice40/brams_map.v index 19a61d73b..ad3bccd21 100644 --- a/techlibs/ice40/brams_map.v +++ b/techlibs/ice40/brams_map.v @@ -7,8 +7,8 @@ module \$__ICE40_RAM4K ( input [10:0] WADDR, input [15:0] MASK, WDATA ); - parameter integer READ_MODE = 0; - parameter integer WRITE_MODE = 0; + parameter [1:0] READ_MODE = 0; + parameter [1:0] WRITE_MODE = 0; parameter [0:0] NEGCLK_R = 0; parameter [0:0] NEGCLK_W = 0; From e847690bda520511735680bd4cb65b416edcdc3f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 28 Feb 2019 17:24:46 -0800 Subject: [PATCH 019/132] Fix multiple issues in wreduce FF handling, fixes #835 Signed-off-by: Clifford Wolf --- passes/opt/wreduce.cc | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 09983bc67..1f7222e49 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -53,6 +53,7 @@ struct WreduceWorker std::set> work_queue_cells; std::set work_queue_bits; pool keep_bits; + dict init_bits; WreduceWorker(WreduceConfig *config, Module *module) : config(config), module(module), mi(module) { } @@ -141,6 +142,7 @@ struct WreduceWorker SigSpec sig_d = mi.sigmap(cell->getPort("\\D")); SigSpec sig_q = mi.sigmap(cell->getPort("\\Q")); + Const initval; int width_before = GetSize(sig_q); @@ -150,16 +152,24 @@ struct WreduceWorker bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0; bool sign_ext = !zero_ext; + for (int i = 0; i < GetSize(sig_q); i++) { + SigBit bit = sig_q[i]; + if (init_bits.count(bit)) + initval.bits.push_back(init_bits.at(bit)); + else + initval.bits.push_back(State::Sx); + } + for (int i = GetSize(sig_q)-1; i >= 0; i--) { - if (zero_ext && sig_d[i] == State::S0) { + if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) { module->connect(sig_q[i], State::S0); sig_d.remove(i); sig_q.remove(i); continue; } - if (sign_ext && i > 0 && sig_d[i] == sig_d[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]); sig_d.remove(i); sig_q.remove(i); @@ -167,7 +177,7 @@ struct WreduceWorker } 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]))) { sig_d.remove(i); sig_q.remove(i); zero_ext = false; @@ -183,10 +193,11 @@ struct WreduceWorker if (GetSize(sig_q) == 0) { log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type)); + module->remove(cell); return; } - log("Removed top %d bits (of %d) from mux cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before, + log("Removed top %d bits (of %d) from FF cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before, log_id(module), log_id(cell), log_id(cell->type)); for (auto bit : sig_d) @@ -376,10 +387,18 @@ struct WreduceWorker void run() { - for (auto w : module->wires()) + for (auto w : module->wires()) { if (w->get_bool_attribute("\\keep")) for (auto bit : mi.sigmap(w)) keep_bits.insert(bit); + if (w->attributes.count("\\init")) { + Const initval = w->attributes.at("\\init"); + SigSpec initsig = mi.sigmap(w); + int width = std::min(GetSize(initval), GetSize(initsig)); + for (int i = 0; i < width; i++) + init_bits[initsig[i]] = initval[i]; + } + } for (auto c : module->selected_cells()) work_queue_cells.insert(c); From b84febafd75bc66d64cdc573265e086800b3e420 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 28 Feb 2019 20:26:54 -0800 Subject: [PATCH 020/132] Hotfix for "make test" Signed-off-by: Clifford Wolf --- tests/tools/autotest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 0b9aceacc..84e62e011 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -49,7 +49,7 @@ while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do r) backend_opts="$backend_opts -norename" ;; e) - backend_opts="$( echo " $backend_opts " | sed 's, -noexpr ,,; s,^ ,,; s, $,,;'; )" ;; + backend_opts="$( echo " $backend_opts " | sed 's, -noexpr , ,; s,^ ,,; s, $,,;'; )" ;; f) frontend="$OPTARG" ;; s) From 60e3c38054f10251021fa2f504ad2424da33aa1d Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 28 Feb 2019 20:34:42 -0800 Subject: [PATCH 021/132] Improve "read" error msg Signed-off-by: Clifford Wolf --- frontends/verific/verific.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 8ee951d20..9f52ffdc2 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2316,7 +2316,7 @@ struct ReadPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - if (args.size() < 2) + if (args.size() < 2 || args[1][0] != '-') log_cmd_error("Missing mode parameter.\n"); if (args.size() < 3) From ca2b3feed82f923f06d0cf57787818f0f6793157 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 1 Mar 2019 19:25:23 +0100 Subject: [PATCH 022/132] Fix ECP5 cells_sim for iverilog --- techlibs/ecp5/cells_sim.v | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 8320ee70a..1e4002ee0 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -223,11 +223,12 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; + wire srval; generate if (LSRMODE == "PRLD") - wire srval = M; + assign srval = M; else - localparam srval = (REGSET == "SET") ? 1'b1 : 1'b0; + assign srval = (REGSET == "SET") ? 1'b1 : 1'b0; endgenerate initial Q = srval; From 3090951d54859c331d28232481361bb9c26b3d48 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 1 Mar 2019 11:21:07 -0800 Subject: [PATCH 023/132] Changes required for VPR place and route synth_xilinx. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- manual/command-reference-manual.tex | 19 +- techlibs/xilinx/Makefile.inc | 3 +- techlibs/xilinx/arith_map.v | 282 +++++++++++++++++++++++++++- techlibs/xilinx/brams_map.v | 24 +-- techlibs/xilinx/cells_map.v | 104 ++-------- techlibs/xilinx/cells_sim.v | 105 +++++++---- techlibs/xilinx/cells_xtra.sh | 4 +- techlibs/xilinx/cells_xtra.v | 19 ++ techlibs/xilinx/ff_map.v | 42 +++++ techlibs/xilinx/lut2lut.v | 65 ------- techlibs/xilinx/lut_map.v | 94 ++++++++++ techlibs/xilinx/synth_xilinx.cc | 68 +++++-- 12 files changed, 601 insertions(+), 228 deletions(-) create mode 100644 techlibs/xilinx/ff_map.v delete mode 100644 techlibs/xilinx/lut2lut.v create mode 100644 techlibs/xilinx/lut_map.v diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index bed6326e2..257bf7986 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -4244,9 +4244,15 @@ compatible with 7-Series Xilinx devices. is omitted if this parameter is not specified. -vpr - generate an output netlist (and BLIF file) suitable for VPR + generate an output netlist (and BLIF file) suitable for VPR. (this feature is experimental and incomplete) + -no-brams + disable infering of block rams + + -no-drams + disable infering of distributed rams + -run : only run the commands between the labels (see below). an empty from label is synonymous to 'begin', and empty to label is @@ -4274,11 +4280,11 @@ The following commands are executed by this synthesis command: coarse: synth -run coarse - bram: + bram: (only executed when '-no-brams' is not given) memory_bram -rules +/xilinx/brams.txt techmap -map +/xilinx/brams_map.v - dram: + dram: (only executed when '-no-drams' is not given) memory_bram -rules +/xilinx/drams.txt techmap -map +/xilinx/drams_map.v @@ -4288,16 +4294,17 @@ The following commands are executed by this synthesis command: dffsr2dff dff2dffe opt -full - techmap -map +/techmap.v -map +/xilinx/arith_map.v + techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v opt -fast map_luts: - abc -luts 2:2,3,6:5,10,20 [-dff] + abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!) + abc -lut 5 [-dff] (with '-vpr' only!) clean map_cells: techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode) - dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT + dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT clean check: diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index 887ea27d9..d68f03bb4 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -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_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_32.vh)) diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v index 03719659b..09a5f07e8 100644 --- a/techlibs/xilinx/arith_map.v +++ b/techlibs/xilinx/arith_map.v @@ -17,6 +17,9 @@ * */ +// ============================================================================ +// LCU + (* techmap_celltype = "$lcu" *) module _80_xilinx_lcu (P, G, CI, CO); parameter WIDTH = 2; @@ -28,10 +31,78 @@ module _80_xilinx_lcu (P, G, CI, CO); 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] S = P & ~G; - genvar i; generate for (i = 0; i < WIDTH; i = i + 1) begin:slice MUXCY muxcy ( .CI(C[i]), @@ -40,8 +111,28 @@ module _80_xilinx_lcu (P, G, CI, CO); .O(CO[i]) ); 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 + +// ============================================================================ +// ALU + (* techmap_celltype = "$alu" *) module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); parameter A_SIGNED = 0; @@ -49,6 +140,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); parameter A_WIDTH = 1; parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + parameter _TECHMAP_CONSTVAL_CI_ = 0; + parameter _TECHMAP_CONSTMSK_CI_ = 0; input [A_WIDTH-1:0] A; 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] BB = BI ? ~B_buf : B_buf; - wire [Y_WIDTH-1:0] P = AA ^ BB; - wire [Y_WIDTH-1:0] G = AA & BB; - wire [Y_WIDTH-1:0] C = {CO, CI}; - wire [Y_WIDTH-1:0] S = P & ~G; + genvar i; + +`ifdef _CLB_CARRY + + 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; + 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 MUXCY muxcy ( .CI(C[i]), - .DI(G[i]), + .DI(DI[i]), .S(S[i]), .O(CO[i]) ); @@ -86,6 +352,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); ); end endgenerate - assign X = P; +`endif + + assign X = S; endmodule diff --git a/techlibs/xilinx/brams_map.v b/techlibs/xilinx/brams_map.v index 7ea49158d..2a23b2553 100644 --- a/techlibs/xilinx/brams_map.v +++ b/techlibs/xilinx/brams_map.v @@ -30,8 +30,8 @@ module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .RAM_MODE("SDP"), .READ_WIDTH_A(72), .WRITE_WIDTH_B(72), - .WRITE_MODE_A("READ_FIRST"), - .WRITE_MODE_B("READ_FIRST"), + .WRITE_MODE_A("WRITE_FIRST"), + .WRITE_MODE_B("WRITE_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_36.vh" @@ -95,8 +95,8 @@ module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .RAM_MODE("SDP"), .READ_WIDTH_A(36), .WRITE_WIDTH_B(36), - .WRITE_MODE_A("READ_FIRST"), - .WRITE_MODE_B("READ_FIRST"), + .WRITE_MODE_A("WRITE_FIRST"), + .WRITE_MODE_B("WRITE_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_18.vh" @@ -171,8 +171,8 @@ module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .READ_WIDTH_B(CFG_DBITS), .WRITE_WIDTH_A(CFG_DBITS), .WRITE_WIDTH_B(CFG_DBITS), - .WRITE_MODE_A("READ_FIRST"), - .WRITE_MODE_B("READ_FIRST"), + .WRITE_MODE_A("WRITE_FIRST"), + .WRITE_MODE_B("WRITE_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_36.vh" @@ -209,8 +209,8 @@ module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .READ_WIDTH_B(CFG_DBITS), .WRITE_WIDTH_A(CFG_DBITS), .WRITE_WIDTH_B(CFG_DBITS), - .WRITE_MODE_A("READ_FIRST"), - .WRITE_MODE_B("READ_FIRST"), + .WRITE_MODE_A("WRITE_FIRST"), + .WRITE_MODE_B("WRITE_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_32.vh" @@ -285,8 +285,8 @@ module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .READ_WIDTH_B(CFG_DBITS), .WRITE_WIDTH_A(CFG_DBITS), .WRITE_WIDTH_B(CFG_DBITS), - .WRITE_MODE_A("READ_FIRST"), - .WRITE_MODE_B("READ_FIRST"), + .WRITE_MODE_A("WRITE_FIRST"), + .WRITE_MODE_B("WRITE_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_18.vh" @@ -323,8 +323,8 @@ module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .READ_WIDTH_B(CFG_DBITS), .WRITE_WIDTH_A(CFG_DBITS), .WRITE_WIDTH_B(CFG_DBITS), - .WRITE_MODE_A("READ_FIRST"), - .WRITE_MODE_B("READ_FIRST"), + .WRITE_MODE_A("WRITE_FIRST"), + .WRITE_MODE_B("WRITE_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_16.vh" diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 0771be0b9..d5801c0fc 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -1,86 +1,20 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 -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 +// Empty for now diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index eba17ac9c..787b37cc8 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -1,3 +1,21 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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. // http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf @@ -104,56 +122,75 @@ module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S); assign CO[3] = S[3] ? CO[2] : DI[3]; 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); parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_R_INVERTED = 1'b0; initial Q <= INIT; - generate case (|IS_C_INVERTED) - 1'b0: always @(posedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; - 1'b1: always @(negedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; - endcase endgenerate + always @(posedge C) if (R) Q <= 1'b0; else if(CE) Q <= D; endmodule module FDSE (output reg Q, input C, CE, D, S); - parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_S_INVERTED = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q <= INIT; - generate case (|IS_C_INVERTED) - 1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; - 1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; - endcase endgenerate + always @(posedge C) if (S) Q <= 1'b1; else if(CE) Q <= D; endmodule module FDCE (output reg Q, input C, CE, D, CLR); parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_CLR_INVERTED = 1'b0; initial Q <= INIT; - generate case ({|IS_C_INVERTED, |IS_CLR_INVERTED}) - 2'b00: always @(posedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; - 2'b01: always @(posedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; - 2'b10: always @(negedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; - 2'b11: always @(negedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; - endcase endgenerate + always @(posedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; endmodule module FDPE (output reg Q, input C, CE, D, PRE); - parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_PRE_INVERTED = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q <= INIT; - generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED}) - 2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; - 2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; - 2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; - 2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; - endcase endgenerate + always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; +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 ( diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh index 0480410f5..37c3e5480 100644 --- a/techlibs/xilinx/cells_xtra.sh +++ b/techlibs/xilinx/cells_xtra.sh @@ -115,7 +115,7 @@ function xtract_cell_decl() xtract_cell_decl PS7 xtract_cell_decl PULLDOWN xtract_cell_decl PULLUP - # xtract_cell_decl RAM128X1D + xtract_cell_decl RAM128X1D xtract_cell_decl RAM128X1S xtract_cell_decl RAM256X1S xtract_cell_decl RAM32M @@ -124,7 +124,7 @@ function xtract_cell_decl() xtract_cell_decl RAM32X1S_1 xtract_cell_decl RAM32X2S xtract_cell_decl RAM64M - # xtract_cell_decl RAM64X1D + xtract_cell_decl RAM64X1D xtract_cell_decl RAM64X1S xtract_cell_decl RAM64X1S_1 xtract_cell_decl RAM64X2S diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index 8d8b91ddc..995d62e18 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -3695,6 +3695,25 @@ module RAM128X1S (...); input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE; endmodule +module RAM128X1D ( + output DPO, SPO, + input D, WCLK, WE, + input [6:0] A, DPRA +); + parameter [127:0] INIT = 128'bx; + parameter IS_WCLK_INVERTED = 0; +endmodule + +module RAM64X1D ( + output DPO, SPO, + input D, WCLK, WE, + input A0, A1, A2, A3, A4, A5, + input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 +); + parameter [63:0] INIT = 64'bx; + parameter IS_WCLK_INVERTED = 0; +endmodule + module RAM256X1S (...); parameter [255:0] INIT = 256'h0; parameter [0:0] IS_WCLK_INVERTED = 1'b0; diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v new file mode 100644 index 000000000..13beaa6ae --- /dev/null +++ b/techlibs/xilinx/ff_map.v @@ -0,0 +1,42 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 + diff --git a/techlibs/xilinx/lut2lut.v b/techlibs/xilinx/lut2lut.v deleted file mode 100644 index 061ad2041..000000000 --- a/techlibs/xilinx/lut2lut.v +++ /dev/null @@ -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 diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v new file mode 100644 index 000000000..d07c59dee --- /dev/null +++ b/techlibs/xilinx/lut_map.v @@ -0,0 +1,94 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 + diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 6c11d885d..60cfde604 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -63,6 +63,12 @@ struct SynthXilinxPass : public Pass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); + log(" -no-brams\n"); + log(" disable infering of block rams\n"); + log("\n"); + log(" -no-drams\n"); + log(" disable infering of distributed rams\n"); + log("\n"); log(" -run :\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"); @@ -90,11 +96,11 @@ struct SynthXilinxPass : public Pass log(" coarse:\n"); log(" synth -run coarse\n"); log("\n"); - log(" bram:\n"); + log(" bram: (only executed when '-no-brams' is not given)\n"); log(" memory_bram -rules +/xilinx/brams.txt\n"); log(" techmap -map +/xilinx/brams_map.v\n"); log("\n"); - log(" dram:\n"); + log(" dram: (only executed when '-no-drams' is not given)\n"); log(" memory_bram -rules +/xilinx/drams.txt\n"); log(" techmap -map +/xilinx/drams_map.v\n"); log("\n"); @@ -104,16 +110,17 @@ struct SynthXilinxPass : public Pass log(" dffsr2dff\n"); log(" dff2dffe\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("\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("\n"); log(" map_cells:\n"); - log(" techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode)\n"); - log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT\n"); + log(" techmap -map +/xilinx/cells_map.v\n"); + log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT\n"); log(" clean\n"); log("\n"); log(" check:\n"); @@ -137,6 +144,8 @@ struct SynthXilinxPass : public Pass bool flatten = false; bool retime = false; bool vpr = false; + bool noBrams = false; + bool noDrams = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -173,6 +182,14 @@ struct SynthXilinxPass : public Pass vpr = true; continue; } + if (args[argidx] == "-no-brams") { + noBrams = true; + continue; + } + if (args[argidx] == "-no-drams") { + noDrams = true; + continue; + } break; } extra_args(args, argidx, design); @@ -187,9 +204,18 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "begin")) { - Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v"); + 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_xtra.v"); - Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); + + if (!noBrams) { + Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); + } + Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); } @@ -206,14 +232,18 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "bram")) { - Pass::call(design, "memory_bram -rules +/xilinx/brams.txt"); - Pass::call(design, "techmap -map +/xilinx/brams_map.v"); + if (!noBrams) { + Pass::call(design, "memory_bram -rules +/xilinx/brams.txt"); + Pass::call(design, "techmap -map +/xilinx/brams_map.v"); + } } if (check_label(active, run_from, run_to, "dram")) { - Pass::call(design, "memory_bram -rules +/xilinx/drams.txt"); - Pass::call(design, "techmap -map +/xilinx/drams_map.v"); + if (!noDrams) { + Pass::call(design, "memory_bram -rules +/xilinx/drams.txt"); + Pass::call(design, "techmap -map +/xilinx/drams_map.v"); + } } if (check_label(active, run_from, run_to, "fine")) @@ -223,7 +253,14 @@ struct SynthXilinxPass : public Pass Pass::call(design, "dffsr2dff"); Pass::call(design, "dff2dffe"); 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"); } @@ -231,14 +268,13 @@ struct SynthXilinxPass : public Pass { Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); + Pass::call(design, "techmap -map +/xilinx/lut_map.v"); } if (check_label(active, run_from, run_to, "map_cells")) { Pass::call(design, "techmap -map +/xilinx/cells_map.v"); - if (vpr) - Pass::call(design, "techmap -map +/xilinx/lut2lut.v"); - Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT"); + Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT"); Pass::call(design, "clean"); } From eccaf101d8324f518ed89134b4f21d2bdc636a8d Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 1 Mar 2019 12:14:27 -0800 Subject: [PATCH 024/132] Modify arguments to match existing style. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- manual/command-reference-manual.tex | 10 +++++----- techlibs/xilinx/synth_xilinx.cc | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index 257bf7986..bb9d7238c 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -4247,10 +4247,10 @@ compatible with 7-Series Xilinx devices. generate an output netlist (and BLIF file) suitable for VPR. (this feature is experimental and incomplete) - -no-brams - disable infering of block rams + -nobrams + disable infering of block rams - -no-drams + -nodrams disable infering of distributed rams -run : @@ -4280,11 +4280,11 @@ The following commands are executed by this synthesis command: coarse: synth -run coarse - bram: (only executed when '-no-brams' is not given) + bram: (only executed when '-nobrams' is not given) memory_bram -rules +/xilinx/brams.txt techmap -map +/xilinx/brams_map.v - dram: (only executed when '-no-drams' is not given) + dram: (only executed when '-nodrams' is not given) memory_bram -rules +/xilinx/drams.txt techmap -map +/xilinx/drams_map.v diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 60cfde604..12ad9fdaf 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -63,10 +63,10 @@ struct SynthXilinxPass : public Pass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); - log(" -no-brams\n"); + log(" -nobrams\n"); log(" disable infering of block rams\n"); log("\n"); - log(" -no-drams\n"); + log(" -nodrams\n"); log(" disable infering of distributed rams\n"); log("\n"); log(" -run :\n"); @@ -96,11 +96,11 @@ struct SynthXilinxPass : public Pass log(" coarse:\n"); log(" synth -run coarse\n"); log("\n"); - log(" bram: (only executed when '-no-brams' is not given)\n"); + log(" bram: (only executed when '-nobrams' is not given)\n"); log(" memory_bram -rules +/xilinx/brams.txt\n"); log(" techmap -map +/xilinx/brams_map.v\n"); log("\n"); - log(" dram: (only executed when '-no-drams' is not given)\n"); + log(" dram: (only executed when '-nodrams' is not given)\n"); log(" memory_bram -rules +/xilinx/drams.txt\n"); log(" techmap -map +/xilinx/drams_map.v\n"); log("\n"); @@ -182,11 +182,11 @@ struct SynthXilinxPass : public Pass vpr = true; continue; } - if (args[argidx] == "-no-brams") { + if (args[argidx] == "-nobrams") { noBrams = true; continue; } - if (args[argidx] == "-no-drams") { + if (args[argidx] == "-nodrams") { noDrams = true; continue; } From 03237de68605bb6eae73b96379faab0af6f8ce73 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 1 Mar 2019 12:59:07 -0800 Subject: [PATCH 025/132] Fix "write_edif -gndvccy" Signed-off-by: Clifford Wolf --- backends/edif/edif.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc index 2d25f879d..7e30b67af 100644 --- a/backends/edif/edif.cc +++ b/backends/edif/edif.cc @@ -130,7 +130,7 @@ struct EdifBackend : public Backend { bool port_rename = false; bool attr_properties = false; std::map> lib_cell_ports; - bool nogndvcc = false, gndvccy = true; + bool nogndvcc = false, gndvccy = false; CellTypes ct(design); EdifNames edif_names; From 7cfae2c52fb8e210a68032a109646785e4353dcc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 1 Mar 2019 13:35:09 -0800 Subject: [PATCH 026/132] Use mem2reg on memories that only have constant-index write ports Signed-off-by: Clifford Wolf --- frontends/ast/ast.h | 2 ++ frontends/ast/simplify.cc | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 08f91c9c3..89f7e6e4f 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -214,6 +214,8 @@ namespace AST MEM2REG_FL_SET_ASYNC = 0x00000800, MEM2REG_FL_EQ2 = 0x00001000, MEM2REG_FL_CMPLX_LHS = 0x00002000, + MEM2REG_FL_CONST_LHS = 0x00004000, + MEM2REG_FL_VAR_LHS = 0x00008000, /* proc flags */ MEM2REG_FL_EQ1 = 0x01000000, diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 46013544b..589c683f8 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -113,6 +113,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS) goto verbose_activate; + if ((memflags & AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & AstNode::MEM2REG_FL_VAR_LHS)) + goto verbose_activate; + // log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags)); continue; @@ -2936,6 +2939,14 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; } + // remember if this is a constant index or not + 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) + mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS; + else + mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS; + } + // remember where this is if (flags & MEM2REG_FL_INIT) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) From a02d61576ec42931ed3a67c6900bcd5aeddaf8b8 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 1 Mar 2019 14:29:17 -0800 Subject: [PATCH 027/132] Minor improvements in README Signed-off-by: Clifford Wolf --- README.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 883f2b0a5..f17046488 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,24 @@ compatible license that is similar in terms to the MIT license or the 2-clause BSD license). -Web Site -======== +Web Site and Other Resources +============================ More information and documentation can be found on the Yosys web site: -http://www.clifford.at/yosys/ +- http://www.clifford.at/yosys/ + +The "Documentation" page on the web site contains links to more resources, +including a manual that even describes some of the Yosys internals: +- http://www.clifford.at/yosys/documentation.html + +The file `CodingReadme` in this directory contains additional information +for people interested in using the Yosys C++ APIs. + +Users interested in formal verification might want to use the formal verification +front-end for Yosys, SymbiYosys: +- https://symbiyosys.readthedocs.io/en/latest/ +- https://github.com/YosysHQ/SymbiYosys + Setup ====== From 5ebeca12eb0bf9317acec3d619021ab337d445ba Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 1 Mar 2019 14:35:14 -0800 Subject: [PATCH 028/132] Use singular for disabling of DRAM or BRAM inference. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- manual/command-reference-manual.tex | 19 ++++++------------- techlibs/xilinx/synth_xilinx.cc | 26 +++++++++++++------------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index bb9d7238c..bed6326e2 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -4244,15 +4244,9 @@ compatible with 7-Series Xilinx devices. is omitted if this parameter is not specified. -vpr - generate an output netlist (and BLIF file) suitable for VPR. + generate an output netlist (and BLIF file) suitable for VPR (this feature is experimental and incomplete) - -nobrams - disable infering of block rams - - -nodrams - disable infering of distributed rams - -run : only run the commands between the labels (see below). an empty from label is synonymous to 'begin', and empty to label is @@ -4280,11 +4274,11 @@ The following commands are executed by this synthesis command: coarse: synth -run coarse - bram: (only executed when '-nobrams' is not given) + bram: memory_bram -rules +/xilinx/brams.txt techmap -map +/xilinx/brams_map.v - dram: (only executed when '-nodrams' is not given) + dram: memory_bram -rules +/xilinx/drams.txt techmap -map +/xilinx/drams_map.v @@ -4294,17 +4288,16 @@ The following commands are executed by this synthesis command: dffsr2dff dff2dffe opt -full - techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v + techmap -map +/techmap.v -map +/xilinx/arith_map.v opt -fast map_luts: - abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!) - abc -lut 5 [-dff] (with '-vpr' only!) + abc -luts 2:2,3,6:5,10,20 [-dff] clean map_cells: techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode) - dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT + dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT clean check: diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 12ad9fdaf..9e7559944 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -63,10 +63,10 @@ struct SynthXilinxPass : public Pass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); - log(" -nobrams\n"); + log(" -nobram\n"); log(" disable infering of block rams\n"); log("\n"); - log(" -nodrams\n"); + log(" -nodram\n"); log(" disable infering of distributed rams\n"); log("\n"); log(" -run :\n"); @@ -96,11 +96,11 @@ struct SynthXilinxPass : public Pass log(" coarse:\n"); log(" synth -run coarse\n"); log("\n"); - log(" bram: (only executed when '-nobrams' is not given)\n"); + log(" bram: (only executed when '-nobram' is not given)\n"); log(" memory_bram -rules +/xilinx/brams.txt\n"); log(" techmap -map +/xilinx/brams_map.v\n"); log("\n"); - log(" dram: (only executed when '-nodrams' is not given)\n"); + log(" dram: (only executed when '-nodram' is not given)\n"); log(" memory_bram -rules +/xilinx/drams.txt\n"); log(" techmap -map +/xilinx/drams_map.v\n"); log("\n"); @@ -144,8 +144,8 @@ struct SynthXilinxPass : public Pass bool flatten = false; bool retime = false; bool vpr = false; - bool noBrams = false; - bool noDrams = false; + bool nobram = false; + bool nodram = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -182,12 +182,12 @@ struct SynthXilinxPass : public Pass vpr = true; continue; } - if (args[argidx] == "-nobrams") { - noBrams = true; + if (args[argidx] == "-nobram") { + nobram = true; continue; } - if (args[argidx] == "-nodrams") { - noDrams = true; + if (args[argidx] == "-nodram") { + nodram = true; continue; } break; @@ -212,7 +212,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v"); - if (!noBrams) { + if (!nobram) { Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); } @@ -232,7 +232,7 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "bram")) { - if (!noBrams) { + if (!nobram) { Pass::call(design, "memory_bram -rules +/xilinx/brams.txt"); Pass::call(design, "techmap -map +/xilinx/brams_map.v"); } @@ -240,7 +240,7 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "dram")) { - if (!noDrams) { + if (!nodram) { Pass::call(design, "memory_bram -rules +/xilinx/drams.txt"); Pass::call(design, "techmap -map +/xilinx/drams_map.v"); } From 3e16f75bc6f490cada2b9c4e9b4962a66b1e8008 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 1 Mar 2019 14:41:21 -0800 Subject: [PATCH 029/132] Revert FF models to include IS_x_INVERTED parameters. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- techlibs/xilinx/cells_sim.v | 40 +++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 787b37cc8..ff5ff0726 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -147,26 +147,54 @@ endmodule module FDRE (output reg Q, input C, CE, D, R); parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_R_INVERTED = 1'b0; initial Q <= INIT; - always @(posedge C) if (R) Q <= 1'b0; else if(CE) Q <= D; + generate case (|IS_C_INVERTED) + 1'b0: always @(posedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + 1'b1: always @(negedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + endcase endgenerate endmodule module FDSE (output reg Q, input C, CE, D, S); - parameter [0:0] INIT = 1'b1; + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_S_INVERTED = 1'b0; initial Q <= INIT; - always @(posedge C) if (S) Q <= 1'b1; else if(CE) Q <= D; + generate case (|IS_C_INVERTED) + 1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + 1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + endcase endgenerate endmodule module FDCE (output reg Q, input C, CE, D, CLR); parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; initial Q <= INIT; - always @(posedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; + generate case ({|IS_C_INVERTED, |IS_CLR_INVERTED}) + 2'b00: always @(posedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b01: always @(posedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b10: always @(negedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b11: always @(negedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + endcase endgenerate endmodule module FDPE (output reg Q, input C, CE, D, PRE); - parameter [0:0] INIT = 1'b1; + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; initial Q <= INIT; - always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; + generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED}) + 2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + endcase endgenerate endmodule module FDRE_1 (output reg Q, input C, CE, D, R); From 57f8bb471feecafad9d9e0bae77ea937b6b03a83 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Fri, 1 Mar 2019 20:15:20 -0800 Subject: [PATCH 030/132] Try again for passes/pmgen/ice40_dsp_pm.h rule Tested on both in-tree and out-of-tree builds --- passes/pmgen/Makefile.inc | 2 +- passes/pmgen/pmgen.py | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index e0dd0fc06..e0609d9ba 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -5,4 +5,4 @@ EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h .SECONDARY: passes/pmgen/ice40_dsp_pm.h passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg - $(P) mkdir -p passes/pmgen && python3 $^ + $(P) mkdir -p passes/pmgen && python3 $^ $@ diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 762d8621f..d9747b065 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -9,7 +9,8 @@ pp = pprint.PrettyPrinter(indent=4) pmgfile = sys.argv[1] assert pmgfile.endswith(".pmg") prefix = pmgfile[0:-4] -pmname = prefix.split('/')[-1] +prefix = prefix.split('/')[-1] +outfile = sys.argv[2] state_types = dict() udata_types = dict() @@ -179,7 +180,7 @@ with open(pmgfile, "r") as f: blocks.append(block) -with open("%s_pm.h" % prefix, "w") as f: +with open(outfile, "w") as f: print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) print("", file=f) @@ -190,10 +191,10 @@ with open("%s_pm.h" % prefix, "w") as f: print("YOSYS_NAMESPACE_BEGIN", file=f) print("", file=f) - print("struct {}_pm {{".format(pmname), file=f) + print("struct {}_pm {{".format(prefix), file=f) print(" Module *module;", file=f) print(" SigMap sigmap;", file=f) - print(" std::function on_accept;".format(pmname), file=f) + print(" std::function on_accept;".format(prefix), file=f) print("", file=f) for index in range(len(blocks)): @@ -291,7 +292,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print(" {}_pm(Module *module, const vector &cells) :".format(pmname), file=f) + print(" {}_pm(Module *module, const vector &cells) :".format(prefix), file=f) print(" module(module), sigmap(module) {", file=f) for s, t in sorted(udata_types.items()): if t.endswith("*"): @@ -321,7 +322,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print(" ~{}_pm() {{".format(pmname), file=f) + print(" ~{}_pm() {{".format(prefix), file=f) print(" for (auto cell : autoremove_cells)", file=f) print(" module->remove(cell);", file=f) print(" }", file=f) @@ -340,7 +341,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print(" void run(std::function on_accept_f) {{".format(pmname), file=f) + print(" void run(std::function on_accept_f) {{".format(prefix), file=f) print(" run([&](){on_accept_f(*this);});", file=f) print(" }", file=f) print("", file=f) From f75aee87e3038f663dc61f9d3098d5056ccdced7 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 2 Mar 2019 08:29:28 -0800 Subject: [PATCH 031/132] Disable macOS builds in Travis Signed-off-by: Clifford Wolf --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8aacbb8b1..7c6e4e43c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -132,11 +132,11 @@ matrix: env: - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0" - # Latest clang on Mac OS X - - os: osx - osx_image: xcode9.4 - env: - - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++" +# # Latest clang on Mac OS X +# - os: osx +# osx_image: xcode9.4 +# env: +# - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++" before_install: - ./.travis/setup.sh From 5d93dcce862d281f0df495eeee755cd4bfca342d Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 2 Mar 2019 09:58:20 -0800 Subject: [PATCH 032/132] Fix $readmem[hb] for mem2reg memories, fixes #785 Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 589c683f8..1c35516d4 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2172,6 +2172,8 @@ skip_dynamic_range_lvalue_expansion:; } newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init); + delete node_filename; + delete node_memory; goto apply_newNode; } @@ -3059,6 +3061,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (type == AST_FUNCTION || type == AST_TASK) return false; + if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast)) + { + log_assert(children[0]->type == AST_CONSTANT); + log_assert(children[1]->type == AST_CONSTANT); + log_assert(children[2]->type == AST_CONSTANT); + + int cursor = children[0]->asInt(false); + Const data = children[1]->bitsAsConst(); + int length = children[2]->asInt(false); + + if (length != 0) + { + AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK)); + mod->children.push_back(block); + block = block->children[0]; + + int wordsz = GetSize(data) / length; + + for (int i = 0; i < length; i++) { + block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false))); + block->children.back()->children[0]->str = str; + block->children.back()->children[0]->id2ast = id2ast; + block->children.back()->children[0]->was_checked = true; + } + } + + AstNode *newNode = new AstNode(AST_NONE); + newNode->cloneInto(this); + delete newNode; + + did_something = true; + } + if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set)) { if (async_block == NULL) { From ce6695e22c7d2b8856ec5bb93a94264555aa55b5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 2 Mar 2019 10:38:13 -0800 Subject: [PATCH 033/132] Fix $global_clock handling vs autowire Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 1c35516d4..d0b31078a 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -941,7 +941,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } if (current_scope.count(str) == 0) { - if (flag_autowire) { + if (flag_autowire || str == "\\$global_clock") { AstNode *auto_wire = new AstNode(AST_AUTOWIRE); auto_wire->str = str; current_ast_mod->children.push_back(auto_wire); From 3a51714451dbd5a0aec5d5167429f899950f2c4e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 2 Mar 2019 11:40:57 -0800 Subject: [PATCH 034/132] Fix error for wire decl in always block, fixes #763 Signed-off-by: Clifford Wolf --- frontends/ast/genrtlil.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 2d591b29d..13383845a 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -544,7 +544,11 @@ struct AST_INTERNAL::ProcessGenerator break; case AST_WIRE: - log_file_error(ast->filename, ast->linenum, "Found wire declaration in block without label!\n"); + log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n"); + break; + + case AST_ASSIGN: + log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n"); break; case AST_PARAMETER: From ae9286386de117991f887f919f5af3fac40173cc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 2 Mar 2019 12:36:46 -0800 Subject: [PATCH 035/132] Only run derive on blackbox modules when ports have dynamic size Signed-off-by: Clifford Wolf --- README.md | 3 +++ frontends/ast/ast.h | 1 + frontends/ast/simplify.cc | 19 +++++++++++++++++++ passes/hierarchy/hierarchy.cc | 2 +- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f17046488..9bac468a7 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,9 @@ Verilog Attributes and non-standard features passes to identify input and output ports of cells. The Verilog backend also does not output blackbox modules on default. +- The ``dynports'' attribute is used by the Verilog front-end to mark modules + that have ports with a width that depends on a parameter. + - 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 have hidden connections that are not part of the netlist, such as IO pads. diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 89f7e6e4f..8b185ff51 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -239,6 +239,7 @@ namespace AST bool has_const_only_constructs(bool &recommend_const_eval); void replace_variables(std::map &variables, AstNode *fcall); AstNode *eval_const_function(AstNode *fcall); + bool is_simple_const_expr(); // create a human-readable text representation of the AST (for debugging) void dumpAst(FILE *f, std::string indent) const; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index d0b31078a..7160c6c0f 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -328,6 +328,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, for (size_t i = 0; i < children.size(); i++) { AstNode *node = children[i]; if (node->type == AST_WIRE) { + if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { + for (auto c : node->children[0]->children) { + if (!c->is_simple_const_expr()) { + if (attributes.count("\\dynports")) + delete attributes.at("\\dynports"); + attributes["\\dynports"] = AstNode::mkconst_int(1, true); + } + } + } if (this_wire_scope.count(node->str) > 0) { AstNode *first_node = this_wire_scope[node->str]; if (first_node->is_input && node->is_reg) @@ -3323,6 +3332,16 @@ bool AstNode::has_const_only_constructs(bool &recommend_const_eval) return false; } +bool AstNode::is_simple_const_expr() +{ + if (type == AST_IDENTIFIER) + return false; + for (auto child : children) + if (!child->is_simple_const_expr()) + return false; + return true; +} + // helper function for AstNode::eval_const_function() void AstNode::replace_variables(std::map &variables, AstNode *fcall) { diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 2d8edebb5..88c339e8c 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -910,7 +910,7 @@ struct HierarchyPass : public Pass { if (m == nullptr) continue; - if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty()) { + if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { IdString new_m_name = m->derive(design, cell->parameters, true); if (new_m_name.empty()) continue; From a176ac95ded8b5aa9efb98b7a8e6981c90827d0e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 3 Mar 2019 21:35:57 -0800 Subject: [PATCH 036/132] Update igloo2 example to Libero v12.0 Signed-off-by: Clifford Wolf --- examples/igloo2/libero.tcl | 9 ++++----- examples/igloo2/runme.sh | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/igloo2/libero.tcl b/examples/igloo2/libero.tcl index 1f3476316..82e614cd4 100644 --- a/examples/igloo2/libero.tcl +++ b/examples/igloo2/libero.tcl @@ -15,6 +15,7 @@ new_project \ import_files -hdl_source {netlist.vm} import_files -sdc {example.sdc} import_files -io_pdc {example.pdc} +build_design_hierarchy set_option -synth 0 organize_tool_files -tool PLACEROUTE \ @@ -44,10 +45,8 @@ puts "**> VERIFYTIMING" run_tool -name {VERIFYTIMING} puts "<** VERIFYTIMING" -save_project - -# puts "**> export_bitstream" -# export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC} -# puts "<** export_bitstream" +puts "**> export_bitstream" +export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC} +puts "<** export_bitstream" exit 0 diff --git a/examples/igloo2/runme.sh b/examples/igloo2/runme.sh index 54247759f..95f2282ba 100644 --- a/examples/igloo2/runme.sh +++ b/examples/igloo2/runme.sh @@ -1,4 +1,4 @@ #!/bin/bash set -ex yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v -LM_LICENSE_FILE=1702@`hostname` /opt/microsemi/Libero_SoC_v11.9/Libero/bin/libero SCRIPT:libero.tcl +LM_LICENSE_FILE=1702@`hostname` /opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl From 107d8848041289bdf3ed85f2ca6c7e02fa9ec774 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 3 Mar 2019 23:54:35 -0800 Subject: [PATCH 037/132] Improve igloo2 example Signed-off-by: Clifford Wolf --- examples/igloo2/libero.tcl | 9 +++++++-- examples/igloo2/runme.sh | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/igloo2/libero.tcl b/examples/igloo2/libero.tcl index 82e614cd4..6f7d4e24b 100644 --- a/examples/igloo2/libero.tcl +++ b/examples/igloo2/libero.tcl @@ -33,20 +33,25 @@ configure_tool -name PLACEROUTE \ -params EFFORT_LEVEL:false \ -params REPAIR_MIN_DELAY:false +puts "" puts "**> COMPILE" run_tool -name {COMPILE} puts "<** COMPILE" +puts "" puts "**> PLACEROUTE" run_tool -name {PLACEROUTE} puts "<** PLACEROUTE" +puts "" puts "**> VERIFYTIMING" run_tool -name {VERIFYTIMING} puts "<** VERIFYTIMING" -puts "**> export_bitstream" +puts "" +puts "**> BITSTREAM" export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC} -puts "<** export_bitstream" +puts "<** BITSTREAM" +puts "" exit 0 diff --git a/examples/igloo2/runme.sh b/examples/igloo2/runme.sh index 95f2282ba..a08894e0a 100644 --- a/examples/igloo2/runme.sh +++ b/examples/igloo2/runme.sh @@ -1,4 +1,6 @@ #!/bin/bash set -ex yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v -LM_LICENSE_FILE=1702@`hostname` /opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl +export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost} +/opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl +cp proj/designer/example/export/example.stp . From 777864d02ea3382c822a764e928e06b6142da6ec Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 4 Mar 2019 11:18:53 +0000 Subject: [PATCH 038/132] ecp5: Demote conflicting FF init values to a warning Signed-off-by: David Shah --- techlibs/ecp5/ecp5_ffinit.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/techlibs/ecp5/ecp5_ffinit.cc b/techlibs/ecp5/ecp5_ffinit.cc index 02945fff4..dbd16cac9 100644 --- a/techlibs/ecp5/ecp5_ffinit.cc +++ b/techlibs/ecp5/ecp5_ffinit.cc @@ -79,10 +79,12 @@ struct Ecp5FfinitPass : public Pass { continue; if (initbits.count(bit)) { - if (initbits.at(bit) != val) - log_error("Conflicting init values for signal %s (%s = %s, %s = %s).\n", + if (initbits.at(bit) != val) { + 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(initbit_to_wire[bit]), log_signal(initbits.at(bit))); + initbits.at(bit) = State::Sx; + } continue; } @@ -121,6 +123,9 @@ struct Ecp5FfinitPass : public Pass { 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_signal(bit_q), val != State::S0 ? '1' : '0'); // Initval is the same as the reset state. Matches hardware, nowt more to do From 228f132ec388fd8d0791ed3f0944b850de054370 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Mon, 4 Mar 2019 09:22:22 -0800 Subject: [PATCH 039/132] Revert BRAM WRITE_MODE changes. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- techlibs/xilinx/brams_map.v | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/techlibs/xilinx/brams_map.v b/techlibs/xilinx/brams_map.v index 2a23b2553..7ea49158d 100644 --- a/techlibs/xilinx/brams_map.v +++ b/techlibs/xilinx/brams_map.v @@ -30,8 +30,8 @@ module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .RAM_MODE("SDP"), .READ_WIDTH_A(72), .WRITE_WIDTH_B(72), - .WRITE_MODE_A("WRITE_FIRST"), - .WRITE_MODE_B("WRITE_FIRST"), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_36.vh" @@ -95,8 +95,8 @@ module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .RAM_MODE("SDP"), .READ_WIDTH_A(36), .WRITE_WIDTH_B(36), - .WRITE_MODE_A("WRITE_FIRST"), - .WRITE_MODE_B("WRITE_FIRST"), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_18.vh" @@ -171,8 +171,8 @@ module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .READ_WIDTH_B(CFG_DBITS), .WRITE_WIDTH_A(CFG_DBITS), .WRITE_WIDTH_B(CFG_DBITS), - .WRITE_MODE_A("WRITE_FIRST"), - .WRITE_MODE_B("WRITE_FIRST"), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_36.vh" @@ -209,8 +209,8 @@ module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .READ_WIDTH_B(CFG_DBITS), .WRITE_WIDTH_A(CFG_DBITS), .WRITE_WIDTH_B(CFG_DBITS), - .WRITE_MODE_A("WRITE_FIRST"), - .WRITE_MODE_B("WRITE_FIRST"), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_32.vh" @@ -285,8 +285,8 @@ module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .READ_WIDTH_B(CFG_DBITS), .WRITE_WIDTH_A(CFG_DBITS), .WRITE_WIDTH_B(CFG_DBITS), - .WRITE_MODE_A("WRITE_FIRST"), - .WRITE_MODE_B("WRITE_FIRST"), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_18.vh" @@ -323,8 +323,8 @@ module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, .READ_WIDTH_B(CFG_DBITS), .WRITE_WIDTH_A(CFG_DBITS), .WRITE_WIDTH_B(CFG_DBITS), - .WRITE_MODE_A("WRITE_FIRST"), - .WRITE_MODE_B("WRITE_FIRST"), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), .IS_CLKARDCLK_INVERTED(!CLKPOL2), .IS_CLKBWRCLK_INVERTED(!CLKPOL3), `include "brams_init_16.vh" From 32a901ddf21711e2b2fe2a0a8719ff7f69fd9489 Mon Sep 17 00:00:00 2001 From: Kali Prasad Date: Mon, 4 Mar 2019 23:26:56 +0530 Subject: [PATCH 040/132] Added examples/anlogic/ --- examples/anlogic/.gitignore | 4 ++++ examples/anlogic/README | 13 +++++++++++++ examples/anlogic/build.sh | 4 ++++ examples/anlogic/build.tcl | 11 +++++++++++ examples/anlogic/demo.adc | 2 ++ examples/anlogic/demo.v | 18 ++++++++++++++++++ examples/anlogic/demo.ys | 3 +++ 7 files changed, 55 insertions(+) create mode 100644 examples/anlogic/.gitignore create mode 100644 examples/anlogic/README create mode 100755 examples/anlogic/build.sh create mode 100644 examples/anlogic/build.tcl create mode 100644 examples/anlogic/demo.adc create mode 100644 examples/anlogic/demo.v create mode 100644 examples/anlogic/demo.ys diff --git a/examples/anlogic/.gitignore b/examples/anlogic/.gitignore new file mode 100644 index 000000000..fa9424cd8 --- /dev/null +++ b/examples/anlogic/.gitignore @@ -0,0 +1,4 @@ +demo.bit +demo_phy.area +full.v +*.log \ No newline at end of file diff --git a/examples/anlogic/README b/examples/anlogic/README new file mode 100644 index 000000000..99143cce0 --- /dev/null +++ b/examples/anlogic/README @@ -0,0 +1,13 @@ +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 as follow. + +export TD_HOME= + +then run "bash build.sh" in this directory. + diff --git a/examples/anlogic/build.sh b/examples/anlogic/build.sh new file mode 100755 index 000000000..8b77a32d6 --- /dev/null +++ b/examples/anlogic/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -ex +yosys demo.ys +$TD_HOME/bin/td build.tcl \ No newline at end of file diff --git a/examples/anlogic/build.tcl b/examples/anlogic/build.tcl new file mode 100644 index 000000000..db8c3b347 --- /dev/null +++ b/examples/anlogic/build.tcl @@ -0,0 +1,11 @@ +import_device eagle_s20.db -package BG256 +read_verilog full.v -top demo +read_adc demo.adc +optimize_rtl +map_macro +map +pack +place +route +report_area -io_info -file demo_phy.area +bitgen -bit demo.bit -version 0X00 -g ucode:00000000000000000000000000000000 diff --git a/examples/anlogic/demo.adc b/examples/anlogic/demo.adc new file mode 100644 index 000000000..c8fbaed3e --- /dev/null +++ b/examples/anlogic/demo.adc @@ -0,0 +1,2 @@ +set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ +set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED \ No newline at end of file diff --git a/examples/anlogic/demo.v b/examples/anlogic/demo.v new file mode 100644 index 000000000..a7edf4e37 --- /dev/null +++ b/examples/anlogic/demo.v @@ -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 \ No newline at end of file diff --git a/examples/anlogic/demo.ys b/examples/anlogic/demo.ys new file mode 100644 index 000000000..5687bcd31 --- /dev/null +++ b/examples/anlogic/demo.ys @@ -0,0 +1,3 @@ +read_verilog demo.v +synth_anlogic -top demo +write_verilog full.v \ No newline at end of file From d6c4dfb9020ee19eebe3adadca89b65627184d81 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 4 Mar 2019 13:23:58 -0800 Subject: [PATCH 041/132] Ensure fid() calls make_id() for consistency; tests/simple/dff_init.v fails Mark dff_init.v as expected to fail since it uses "initial value". --- backends/firrtl/firrtl.cc | 3 +-- tests/simple/xfirrtl | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 88c1038b7..eef6401b2 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -165,8 +165,7 @@ struct FirrtlWorker std::string fid(RTLIL::IdString internal_id) { - const char *str = internal_id.c_str(); - return *str == '\\' ? str + 1 : str; + return make_id(internal_id); } std::string cellname(RTLIL::Cell *cell) diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl index 5bc75347b..50d693513 100644 --- a/tests/simple/xfirrtl +++ b/tests/simple/xfirrtl @@ -1,6 +1,7 @@ # This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. arraycells.v inst id[0] of dff_different_styles.v +dff_init.v Initial value not supported generate.v combinational loop hierdefparam.v inst id[0] of i2c_master_tests.v $adff From 13844c765818b5d8c0d16d62dcc530f688d2c28a Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 5 Mar 2019 15:16:13 -0800 Subject: [PATCH 042/132] Use "write_edif -pvector bra" for Xilinx EDIF files Signed-off-by: Clifford Wolf --- techlibs/xilinx/synth_xilinx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 6c11d885d..3632f348f 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -252,7 +252,7 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "edif")) { 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")) { From 3ef427f4a96ac8f890cf94079315e172db409526 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 5 Mar 2019 15:21:04 -0800 Subject: [PATCH 043/132] Add missing newline Signed-off-by: Clifford Wolf --- examples/anlogic/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/anlogic/build.sh b/examples/anlogic/build.sh index 8b77a32d6..e0f6b4cfe 100755 --- a/examples/anlogic/build.sh +++ b/examples/anlogic/build.sh @@ -1,4 +1,4 @@ #!/bin/bash set -ex yosys demo.ys -$TD_HOME/bin/td build.tcl \ No newline at end of file +$TD_HOME/bin/td build.tcl From 24d1b92eda20269da7ee7ae713f3ab92b8865349 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 5 Mar 2019 17:27:58 -0800 Subject: [PATCH 044/132] Improve igloo2 exmaple Signed-off-by: Clifford Wolf --- examples/igloo2/example.pdc | 7 +++++++ examples/igloo2/example.sdc | 1 + examples/igloo2/example.v | 12 ++++++------ examples/igloo2/libero.tcl | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/examples/igloo2/example.pdc b/examples/igloo2/example.pdc index e6ffd53db..0cf34adb3 100644 --- a/examples/igloo2/example.pdc +++ b/examples/igloo2/example.pdc @@ -1 +1,8 @@ # 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 diff --git a/examples/igloo2/example.sdc b/examples/igloo2/example.sdc index c6ff94161..f8b487316 100644 --- a/examples/igloo2/example.sdc +++ b/examples/igloo2/example.sdc @@ -1 +1,2 @@ # Add timing constraints here +create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}] diff --git a/examples/igloo2/example.v b/examples/igloo2/example.v index 1a1967d5a..b701c707d 100644 --- a/examples/igloo2/example.v +++ b/examples/igloo2/example.v @@ -1,23 +1,23 @@ module example ( input clk, - input EN, + input SW1, + input SW2, output LED1, output LED2, output LED3, - output LED4, - output LED5 + output LED4 ); - localparam BITS = 5; + localparam BITS = 4; localparam LOG2DELAY = 22; reg [BITS+LOG2DELAY-1:0] counter = 0; reg [BITS-1:0] outcnt; always @(posedge clk) begin - counter <= counter + EN; + counter <= counter + SW1 + SW2 + 1; outcnt <= counter >> LOG2DELAY; end - assign {LED1, LED2, LED3, LED4, LED5} = outcnt ^ (outcnt >> 1); + assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1); endmodule diff --git a/examples/igloo2/libero.tcl b/examples/igloo2/libero.tcl index 6f7d4e24b..abc94e479 100644 --- a/examples/igloo2/libero.tcl +++ b/examples/igloo2/libero.tcl @@ -8,8 +8,8 @@ new_project \ -block_mode 0 \ -hdl "VERILOG" \ -family IGLOO2 \ - -die PA4MGL500 \ - -package tq144 \ + -die PA4MGL2500 \ + -package vf256 \ -speed -1 import_files -hdl_source {netlist.vm} From d03780c3f463bb8ac2c5d300ba7a591f1bc90a8f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 5 Mar 2019 17:55:29 -0800 Subject: [PATCH 045/132] Fix spelling in pmgen/README.md --- passes/pmgen/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index a1007dc62..223b43059 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -16,7 +16,7 @@ API of Generated Matcher ======================== 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: 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` 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 -`select` lines. +in `select` lines. Index lines are using the `index expr1 === expr2` syntax. `expr1` is evaluated during matcher initialization and the same restrictions apply as for From 7c03b0b08209c7e1b3972a05db63b23c0b1d7a5e Mon Sep 17 00:00:00 2001 From: Kali Prasad Date: Wed, 6 Mar 2019 09:51:11 +0530 Subject: [PATCH 046/132] examples/anlogic/ now also output the SVF file. --- examples/anlogic/.gitignore | 5 ++++- examples/anlogic/README | 1 - examples/anlogic/build.tcl | 2 +- examples/anlogic/demo.adc | 2 +- examples/anlogic/demo.v | 10 +++++----- examples/anlogic/demo.ys | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/examples/anlogic/.gitignore b/examples/anlogic/.gitignore index fa9424cd8..97c978a15 100644 --- a/examples/anlogic/.gitignore +++ b/examples/anlogic/.gitignore @@ -1,4 +1,7 @@ demo.bit demo_phy.area full.v -*.log \ No newline at end of file +*.log +*.h +*.tde +*.svf diff --git a/examples/anlogic/README b/examples/anlogic/README index 99143cce0..35d8e9cb1 100644 --- a/examples/anlogic/README +++ b/examples/anlogic/README @@ -10,4 +10,3 @@ set TD_HOME env variable to the full path to the TD as fo export TD_HOME= then run "bash build.sh" in this directory. - diff --git a/examples/anlogic/build.tcl b/examples/anlogic/build.tcl index db8c3b347..06db525c9 100644 --- a/examples/anlogic/build.tcl +++ b/examples/anlogic/build.tcl @@ -8,4 +8,4 @@ pack place route report_area -io_info -file demo_phy.area -bitgen -bit demo.bit -version 0X00 -g ucode:00000000000000000000000000000000 +bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000 diff --git a/examples/anlogic/demo.adc b/examples/anlogic/demo.adc index c8fbaed3e..ec802502e 100644 --- a/examples/anlogic/demo.adc +++ b/examples/anlogic/demo.adc @@ -1,2 +1,2 @@ set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ -set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED \ No newline at end of file +set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED diff --git a/examples/anlogic/demo.v b/examples/anlogic/demo.v index a7edf4e37..e17db771e 100644 --- a/examples/anlogic/demo.v +++ b/examples/anlogic/demo.v @@ -1,18 +1,18 @@ module demo ( - input wire CLK_IN, - output wire R_LED + 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; + count<= 30'd0; led_state <= ~led_state; end else count <= count + 1'b1; end assign R_LED = led_state; -endmodule \ No newline at end of file +endmodule diff --git a/examples/anlogic/demo.ys b/examples/anlogic/demo.ys index 5687bcd31..cb396cc2b 100644 --- a/examples/anlogic/demo.ys +++ b/examples/anlogic/demo.ys @@ -1,3 +1,3 @@ read_verilog demo.v synth_anlogic -top demo -write_verilog full.v \ No newline at end of file +write_verilog full.v From da5181a3df6ceed96f1762e4cdaec5cbe3ea23db Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 5 Mar 2019 19:49:39 -0800 Subject: [PATCH 047/132] Improvements in SF2 flow and demo Signed-off-by: Clifford Wolf --- examples/igloo2/.gitignore | 1 + examples/igloo2/runme.sh | 2 +- techlibs/sf2/sf2_iobs.cc | 15 ++++++++++----- techlibs/sf2/synth_sf2.cc | 16 +++++++++++++--- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/examples/igloo2/.gitignore b/examples/igloo2/.gitignore index ea58efc9f..33b7182d3 100644 --- a/examples/igloo2/.gitignore +++ b/examples/igloo2/.gitignore @@ -1,3 +1,4 @@ /netlist.edn /netlist.vm +/example.stp /proj diff --git a/examples/igloo2/runme.sh b/examples/igloo2/runme.sh index a08894e0a..838f027db 100644 --- a/examples/igloo2/runme.sh +++ b/examples/igloo2/runme.sh @@ -1,6 +1,6 @@ #!/bin/bash set -ex -yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v +yosys -p 'synth_sf2 -noclkbuf -top example -edif netlist.edn -vlog netlist.vm' example.v export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost} /opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl cp proj/designer/example/export/example.stp . diff --git a/techlibs/sf2/sf2_iobs.cc b/techlibs/sf2/sf2_iobs.cc index 27141430c..a85552575 100644 --- a/techlibs/sf2/sf2_iobs.cc +++ b/techlibs/sf2/sf2_iobs.cc @@ -33,18 +33,23 @@ struct Sf2IobsPass : public Pass { log("\n"); log("Add SF2 I/O buffers to top module IOs as needed.\n"); log("\n"); + log(" -noclkbuf\n"); + log(" Do not insert clock buffers\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { + bool noclkbuf_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] == "-singleton") { - // singleton_mode = true; - // continue; - // } + if (args[argidx] == "-noclkbuf") { + noclkbuf_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -94,7 +99,7 @@ struct Sf2IobsPass : public Pass { if (wire->port_output) { buf_type = "\\OUTBUF"; buf_port = "\\D"; - } else if (clk_bits.count(canonical_bit)) { + } else if (clk_bits.count(canonical_bit) && !noclkbuf_mode) { buf_type = "\\CLKBUF"; buf_port = "\\Y"; } else { diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index bdc20456d..b834af07d 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -63,6 +63,9 @@ struct SynthSf2Pass : public ScriptPass log(" -noiobs\n"); log(" run synthesis in \"block mode\", i.e. do not insert IO buffers\n"); log("\n"); + log(" -noclkbuf\n"); + log(" do not inser clock buffers, only simpe IO buffers\n"); + log("\n"); log(" -retime\n"); log(" run 'abc' with -dff option\n"); log("\n"); @@ -73,7 +76,7 @@ struct SynthSf2Pass : public ScriptPass } string top_opt, edif_file, vlog_file, json_file; - bool flatten, retime, iobs; + bool flatten, retime, iobs, clkbuf; void clear_flags() YS_OVERRIDE { @@ -84,6 +87,7 @@ struct SynthSf2Pass : public ScriptPass flatten = true; retime = false; iobs = true; + clkbuf = true; } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -130,6 +134,10 @@ struct SynthSf2Pass : public ScriptPass iobs = false; continue; } + if (args[argidx] == "-noclkbuf") { + clkbuf = false; + continue; + } break; } extra_args(args, argidx, design); @@ -201,8 +209,10 @@ struct SynthSf2Pass : public ScriptPass if (check_label("map_iobs")) { - if (iobs || help_mode) - run("sf2_iobs", "(unless -noiobs)"); + if (help_mode) + run("sf2_iobs [-noclkbuf]", "(unless -noiobs)"); + else if (iobs) + run(clkbuf ? "sf2_iobs" : "sf2_iobs -noclkbuf"); run("clean"); } From e22afeae907e6340aac7797f60c309916fd72097 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 5 Mar 2019 20:35:48 -0800 Subject: [PATCH 048/132] Improve igloo2 example Signed-off-by: Clifford Wolf --- examples/igloo2/example.pdc | 12 ++++++++++ examples/igloo2/example.v | 44 +++++++++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/examples/igloo2/example.pdc b/examples/igloo2/example.pdc index 0cf34adb3..298d9e934 100644 --- a/examples/igloo2/example.pdc +++ b/examples/igloo2/example.pdc @@ -1,8 +1,20 @@ # 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 diff --git a/examples/igloo2/example.v b/examples/igloo2/example.v index b701c707d..05b6ced5e 100644 --- a/examples/igloo2/example.v +++ b/examples/igloo2/example.v @@ -5,10 +5,13 @@ module example ( output LED1, output LED2, output LED3, - output LED4 + output LED4, + + output AA, AB, AC, AD, + output AE, AF, AG, CA ); - localparam BITS = 4; + localparam BITS = 8; localparam LOG2DELAY = 22; reg [BITS+LOG2DELAY-1:0] counter = 0; @@ -20,4 +23,41 @@ module example ( end assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1); + + // 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[7:4]); + assign CA = counter[10]; +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 From b1b9edf5cc9e280346ffa0132d570a8ff656eb22 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 5 Mar 2019 20:47:07 -0800 Subject: [PATCH 049/132] Improve igloo2 example Signed-off-by: Clifford Wolf --- examples/igloo2/example.v | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/igloo2/example.v b/examples/igloo2/example.v index 05b6ced5e..4a9486e50 100644 --- a/examples/igloo2/example.v +++ b/examples/igloo2/example.v @@ -24,13 +24,14 @@ module example ( 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[7:4]); - assign CA = counter[10]; + assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]); + assign CA = outcnt[7]; endmodule module seg7enc ( From 78762316aabf6d6fb55cfd4ab5b5a161a69ba203 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 6 Mar 2019 00:41:02 -0800 Subject: [PATCH 050/132] Refactor SF2 iobuf insertion, Add clkint insertion Signed-off-by: Clifford Wolf --- examples/igloo2/runme.sh | 2 +- techlibs/sf2/cells_sim.v | 7 ++ techlibs/sf2/sf2_iobs.cc | 214 ++++++++++++++++++++++++-------------- techlibs/sf2/synth_sf2.cc | 14 +-- 4 files changed, 153 insertions(+), 84 deletions(-) diff --git a/examples/igloo2/runme.sh b/examples/igloo2/runme.sh index 838f027db..a08894e0a 100644 --- a/examples/igloo2/runme.sh +++ b/examples/igloo2/runme.sh @@ -1,6 +1,6 @@ #!/bin/bash set -ex -yosys -p 'synth_sf2 -noclkbuf -top example -edif netlist.edn -vlog netlist.vm' example.v +yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost} /opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl cp proj/designer/example/export/example.stp . diff --git a/techlibs/sf2/cells_sim.v b/techlibs/sf2/cells_sim.v index f967068af..b49101616 100644 --- a/techlibs/sf2/cells_sim.v +++ b/techlibs/sf2/cells_sim.v @@ -74,6 +74,13 @@ module CFG4 ( assign Y = INIT >> {D, C, B, A}; endmodule +module CLKINT ( + input A, + output Y +); + assign Y = A; +endmodule + module CLKBUF ( input PAD, output Y diff --git a/techlibs/sf2/sf2_iobs.cc b/techlibs/sf2/sf2_iobs.cc index a85552575..dea8e353b 100644 --- a/techlibs/sf2/sf2_iobs.cc +++ b/techlibs/sf2/sf2_iobs.cc @@ -23,6 +23,136 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +static void handle_iobufs(Module *module, bool clkbuf_mode) +{ + SigMap sigmap(module); + + pool clk_bits; + pool handled_io_bits; + dict rewrite_bits; + vector> pad_bits; + + for (auto cell : module->cells()) + { + if (clkbuf_mode && cell->type == "\\SLE") { + for (auto bit : sigmap(cell->getPort("\\CLK"))) + clk_bits.insert(bit); + } + if (cell->type.in("\\INBUF", "\\OUTBUF", "\\TRIBUF", "\\BIBUF", "\\CLKBUF", "\\CLKBIBUF", + "\\INBUF_DIFF", "\\OUTBUF_DIFF", "\\BIBUFF_DIFF", "\\TRIBUF_DIFF", "\\CLKBUF_DIFF", + "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF")) { + for (auto bit : sigmap(cell->getPort("\\PAD"))) + handled_io_bits.insert(bit); + } + } + + for (auto wire : vector(module->wires())) + { + if (!wire->port_input && !wire->port_output) + continue; + + for (int index = 0; index < GetSize(wire); index++) + { + SigBit bit(wire, index); + SigBit canonical_bit = sigmap(bit); + + if (handled_io_bits.count(canonical_bit)) + continue; + + if (wire->port_input && wire->port_output) + log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit)); + + IdString buf_type, buf_port; + + if (wire->port_output) { + buf_type = "\\OUTBUF"; + buf_port = "\\D"; + } else if (clkbuf_mode && clk_bits.count(canonical_bit)) { + buf_type = "\\CLKBUF"; + buf_port = "\\Y"; + } else { + buf_type = "\\INBUF"; + buf_port = "\\Y"; + } + + Cell *c = module->addCell(NEW_ID, buf_type); + SigBit new_bit = module->addWire(NEW_ID); + c->setPort(buf_port, new_bit); + pad_bits.push_back(make_pair(c, bit)); + rewrite_bits[canonical_bit] = new_bit; + + log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); + } + } + + auto rewrite_function = [&](SigSpec &s) { + for (auto &bit : s) { + SigBit canonical_bit = sigmap(bit); + if (rewrite_bits.count(canonical_bit)) + bit = rewrite_bits.at(canonical_bit); + } + }; + + module->rewrite_sigspecs(rewrite_function); + + for (auto &it : pad_bits) + it.first->setPort("\\PAD", it.second); +} + +static void handle_clkint(Module *module) +{ + SigMap sigmap(module); + + pool clk_bits; + vector 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(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 @@ -31,23 +161,23 @@ struct Sf2IobsPass : public Pass { log("\n"); log(" sf2_iobs [options] [selection]\n"); log("\n"); - log("Add SF2 I/O buffers to top module IOs as needed.\n"); + log("Add SF2 I/O buffers and global buffers to top module as needed.\n"); log("\n"); - log(" -noclkbuf\n"); - log(" Do not insert clock buffers\n"); + log(" -clkbuf\n"); + log(" Insert PAD->global_net clock buffers\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - bool noclkbuf_mode = false; + 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] == "-noclkbuf") { - noclkbuf_mode = true; + if (args[argidx] == "-clkbuf") { + clkbuf_mode = true; continue; } break; @@ -59,76 +189,8 @@ struct Sf2IobsPass : public Pass { if (module == nullptr) log_cmd_error("No top module found.\n"); - SigMap sigmap(module); - - pool clk_bits; - pool handled_io_bits; - dict rewrite_bits; - vector> pad_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("\\INBUF", "\\OUTBUF", "\\CLKBUF")) { - for (auto bit : sigmap(cell->getPort("\\PAD"))) - handled_io_bits.insert(bit); - } - } - - for (auto wire : vector(module->wires())) - { - if (!wire->port_input && !wire->port_output) - continue; - - for (int index = 0; index < GetSize(wire); index++) - { - SigBit bit(wire, index); - SigBit canonical_bit = sigmap(bit); - - if (handled_io_bits.count(canonical_bit)) - continue; - - if (wire->port_input && wire->port_output) - log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit)); - - IdString buf_type, buf_port; - - if (wire->port_output) { - buf_type = "\\OUTBUF"; - buf_port = "\\D"; - } else if (clk_bits.count(canonical_bit) && !noclkbuf_mode) { - buf_type = "\\CLKBUF"; - buf_port = "\\Y"; - } else { - buf_type = "\\INBUF"; - buf_port = "\\Y"; - } - - Cell *c = module->addCell(NEW_ID, buf_type); - SigBit new_bit = module->addWire(NEW_ID); - c->setPort(buf_port, new_bit); - pad_bits.push_back(make_pair(c, bit)); - rewrite_bits[canonical_bit] = new_bit; - - log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); - } - } - - auto rewrite_function = [&](SigSpec &s) { - for (auto &bit : s) { - SigBit canonical_bit = sigmap(bit); - if (rewrite_bits.count(canonical_bit)) - bit = rewrite_bits.at(canonical_bit); - } - }; - - module->rewrite_sigspecs(rewrite_function); - - for (auto &it : pad_bits) - it.first->setPort("\\PAD", it.second); + handle_iobufs(module, clkbuf_mode); + handle_clkint(module); } } Sf2IobsPass; diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index b834af07d..0924df7a6 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -63,8 +63,8 @@ struct SynthSf2Pass : public ScriptPass log(" -noiobs\n"); log(" run synthesis in \"block mode\", i.e. do not insert IO buffers\n"); log("\n"); - log(" -noclkbuf\n"); - log(" do not inser clock buffers, only simpe IO buffers\n"); + log(" -clkbuf\n"); + log(" insert direct PAD->global_net buffers\n"); log("\n"); log(" -retime\n"); log(" run 'abc' with -dff option\n"); @@ -87,7 +87,7 @@ struct SynthSf2Pass : public ScriptPass flatten = true; retime = false; iobs = true; - clkbuf = true; + clkbuf = false; } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -134,8 +134,8 @@ struct SynthSf2Pass : public ScriptPass iobs = false; continue; } - if (args[argidx] == "-noclkbuf") { - clkbuf = false; + if (args[argidx] == "-clkbuf") { + clkbuf = true; continue; } break; @@ -210,9 +210,9 @@ struct SynthSf2Pass : public ScriptPass if (check_label("map_iobs")) { if (help_mode) - run("sf2_iobs [-noclkbuf]", "(unless -noiobs)"); + run("sf2_iobs [-clkbuf]", "(unless -noiobs)"); else if (iobs) - run(clkbuf ? "sf2_iobs" : "sf2_iobs -noclkbuf"); + run(clkbuf ? "sf2_iobs -clkbuf" : "sf2_iobs"); run("clean"); } From 2d2c1617ee3015368336ceb014a9cd98c60181ed Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 6 Mar 2019 15:47:54 -0800 Subject: [PATCH 051/132] Add sf2 techmap rules for more FF types Signed-off-by: Clifford Wolf --- techlibs/sf2/cells_map.v | 64 ++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/techlibs/sf2/cells_map.v b/techlibs/sf2/cells_map.v index 5b8888294..6ad7807d2 100644 --- a/techlibs/sf2/cells_map.v +++ b/techlibs/sf2/cells_map.v @@ -1,40 +1,54 @@ -// 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); - 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) - ); + 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_NN0_ (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_NN1_ (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_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 // module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule // module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _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 \$_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_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_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule -// +// // module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule // module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule // module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule From 8b0719d1e328751a50c0c07ec1fc65884fd119fc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 6 Mar 2019 16:18:49 -0800 Subject: [PATCH 052/132] Improvements in sf2 cells_sim.v Signed-off-by: Clifford Wolf --- techlibs/sf2/cells_sim.v | 297 ++++++++++++++++++++++++++++++++++----- techlibs/sf2/sf2_iobs.cc | 4 +- 2 files changed, 261 insertions(+), 40 deletions(-) diff --git a/techlibs/sf2/cells_sim.v b/techlibs/sf2/cells_sim.v index b49101616..f3f7695cf 100644 --- a/techlibs/sf2/cells_sim.v +++ b/techlibs/sf2/cells_sim.v @@ -1,41 +1,3 @@ -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 CFG1 ( output Y, input A @@ -74,6 +36,41 @@ module CFG4 ( assign Y = INIT >> {D, C, B, A}; endmodule +module ADD2 ( + input A, B, + output Y +); + assign Y = A & B; +endmodule + +module ADD3 ( + input A, B, C, + output Y +); + assign Y = A & B & C; +endmodule + +module ADD4 ( + input A, B, C, D, + output Y +); + assign Y = A & B & C & D; +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 @@ -81,6 +78,217 @@ module CLKINT ( 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 ( input PAD, output Y @@ -88,6 +296,8 @@ module CLKBUF ( assign Y = PAD; endmodule +// module CLKBUF_DIFF + module INBUF ( input PAD, output Y @@ -95,9 +305,20 @@ module INBUF ( assign Y = PAD; endmodule +// module INBUF_DIFF + module OUTBUF ( input D, output PAD ); assign PAD = D; endmodule + +// module OUTBUF_DIFF +// module TRIBUFF +// module TRIBUFF_DIFF +// module DDR_IN +// module DDR_OUT +// module RAM1K18 +// module RAM64x18 +// module MACC diff --git a/techlibs/sf2/sf2_iobs.cc b/techlibs/sf2/sf2_iobs.cc index dea8e353b..3d43332e2 100644 --- a/techlibs/sf2/sf2_iobs.cc +++ b/techlibs/sf2/sf2_iobs.cc @@ -38,8 +38,8 @@ static void handle_iobufs(Module *module, bool clkbuf_mode) for (auto bit : sigmap(cell->getPort("\\CLK"))) clk_bits.insert(bit); } - if (cell->type.in("\\INBUF", "\\OUTBUF", "\\TRIBUF", "\\BIBUF", "\\CLKBUF", "\\CLKBIBUF", - "\\INBUF_DIFF", "\\OUTBUF_DIFF", "\\BIBUFF_DIFF", "\\TRIBUF_DIFF", "\\CLKBUF_DIFF", + 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"))) handled_io_bits.insert(bit); From 350dfd3745ec2efa92a601d3bab7712fd9bec07c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 7 Mar 2019 09:08:26 -0800 Subject: [PATCH 053/132] Add link to SF2 / igloo2 macro library guide Signed-off-by: Clifford Wolf --- techlibs/sf2/cells_sim.v | 45 +++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/techlibs/sf2/cells_sim.v b/techlibs/sf2/cells_sim.v index f3f7695cf..c62748b11 100644 --- a/techlibs/sf2/cells_sim.v +++ b/techlibs/sf2/cells_sim.v @@ -1,3 +1,27 @@ +// https://coredocs.s3.amazonaws.com/Libero/12_0_0/Tool/sf2_mlg.pdf + +module ADD2 ( + + input A, B, + output Y +); + assign Y = A & B; +endmodule + +module ADD3 ( + input A, B, C, + output Y +); + assign Y = A & B & C; +endmodule + +module ADD4 ( + input A, B, C, D, + output Y +); + assign Y = A & B & C & D; +endmodule + module CFG1 ( output Y, input A @@ -36,27 +60,6 @@ module CFG4 ( assign Y = INIT >> {D, C, B, A}; endmodule -module ADD2 ( - input A, B, - output Y -); - assign Y = A & B; -endmodule - -module ADD3 ( - input A, B, C, - output Y -); - assign Y = A & B & C; -endmodule - -module ADD4 ( - input A, B, C, D, - output Y -); - assign Y = A & B & C & D; -endmodule - module BUFF ( input A, output Y From cda37830b060fd46834d8eb7af1171a1ffaee8ca Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 7 Mar 2019 10:52:44 -0800 Subject: [PATCH 054/132] Add hack for handling SVA labels via Verific Signed-off-by: Clifford Wolf --- frontends/verific/verificsva.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index 6681115df..8ea8372d3 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -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(), 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 From 22ff60850e68b5e98d4693a9a06ec688dac6d5ee Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 7 Mar 2019 11:17:32 -0800 Subject: [PATCH 055/132] Add support for SVA labels in read_verilog Signed-off-by: Clifford Wolf --- frontends/ast/genrtlil.cc | 12 +++- frontends/ast/simplify.cc | 1 + frontends/verilog/verilog_parser.y | 102 ++++++++++++++++++++++------- 3 files changed, 89 insertions(+), 26 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 13383845a..d7da6fb40 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1413,10 +1413,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (GetSize(en) != 1) en = current_module->ReduceBool(NEW_ID, en); - std::stringstream sstr; - sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++); + IdString cellname; + if (str.empty()) { + std::stringstream sstr; + 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); for (auto &attr : attributes) { diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 7160c6c0f..bdd8ccb17 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1511,6 +1511,7 @@ skip_dynamic_range_lvalue_expansion:; newNode->children.push_back(assign_en); 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[0]->str = id_check; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index a6718b020..2258f3f6f 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -126,7 +126,7 @@ static void free_attr(std::map *al) %type range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list -%type opt_label tok_prim_wrapper hierarchical_id +%type opt_label opt_stmt_label tok_prim_wrapper hierarchical_id %type opt_signed opt_property unique_case_attr %type attr case_attr @@ -1338,7 +1338,12 @@ opt_property: }; opt_stmt_label: - TOK_ID ':' | /* empty */; + TOK_ID ':' { + $$ = $1; + } | + /* empty */ { + $$ = NULL; + }; modport_stmt: TOK_MODPORT TOK_ID { @@ -1377,53 +1382,104 @@ modport_type_token: assert: opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' { - if (noassert_mode) + if (noassert_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); + } else { + 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 ')' ';' { - if (noassume_mode) + if (noassume_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5)); + } else { + 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 ')' ';' { - if (noassert_mode) + if (noassert_mode) { delete $6; - else - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); + } else { + 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 ')' ';' { - if (noassume_mode) + if (noassume_mode) { delete $6; - else - ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6)); + } else { + 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 ')' ';' { - 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 '(' ')' ';' { - 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 ';' { - 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 ')' ';' { - if (norestrict_mode) + if (norestrict_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + } else { + AstNode *node = new AstNode(AST_ASSUME, $5); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } if (!$3) 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 ')' ';' { - if (norestrict_mode) + if (norestrict_mode) { delete $6; - else - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + } else { + AstNode *node = new AstNode(AST_FAIR, $6); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } if (!$3) log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + if ($1 != nullptr) + delete $1; }; assert_property: From 5dfc7becca1f1faf6e77fb3b5d07d97171613d90 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 7 Mar 2019 11:31:46 -0800 Subject: [PATCH 056/132] Use SVA label in smt export if available Signed-off-by: Clifford Wolf --- backends/smt2/smt2.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 7f3cc94ca..a26bff57b 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -887,8 +887,8 @@ struct Smt2Worker string name_a = get_bool(cell->getPort("\\A")); string name_en = get_bool(cell->getPort("\\EN")); - decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, - cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell))); + string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : 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") decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n", From e71055cfe8f3d90e157174b1fd83a06487a0a6a2 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 7 Mar 2019 23:48:10 +0100 Subject: [PATCH 057/132] ice40: Add ice40_braminit pass to allow initialization of BRAM from file This adds a INIT_FILE attribute to the SB_RAM40_4K blocks that will initialize content from a hex file. Same behavior is imlemented in the simulation model and in a new pass for actual synthesis Signed-off-by: Sylvain Munaut --- techlibs/ice40/Makefile.inc | 1 + techlibs/ice40/cells_sim.v | 88 ++++++++++------- techlibs/ice40/ice40_braminit.cc | 159 +++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+), 37 deletions(-) create mode 100644 techlibs/ice40/ice40_braminit.cc diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc index 2750901c8..723b59d6f 100644 --- a/techlibs/ice40/Makefile.inc +++ b/techlibs/ice40/Makefile.inc @@ -1,5 +1,6 @@ OBJS += techlibs/ice40/synth_ice40.o +OBJS += techlibs/ice40/ice40_braminit.o OBJS += techlibs/ice40/ice40_ffssr.o OBJS += techlibs/ice40/ice40_ffinit.o OBJS += techlibs/ice40/ice40_opt.o diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 2041693cc..bc36cdd14 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -326,6 +326,8 @@ module SB_RAM40_4K ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + `ifndef BLACKBOX wire [15:0] WMASK_I; wire [15:0] RMASK_I; @@ -408,43 +410,46 @@ module SB_RAM40_4K ( reg [15:0] memory [0:255]; initial begin - for (i=0; i<16; i=i+1) begin + if (INIT_FILE != "") + $readmemh(INIT_FILE, memory); + else + 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]; + 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[ 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]; + 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]; `endif - end + end end always @(posedge WCLK) begin @@ -504,6 +509,8 @@ module SB_RAM40_4KNR ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -522,7 +529,8 @@ module SB_RAM40_4KNR ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (~RCLKN), @@ -566,6 +574,8 @@ module SB_RAM40_4KNW ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -584,7 +594,8 @@ module SB_RAM40_4KNW ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (RCLK ), @@ -628,6 +639,8 @@ module SB_RAM40_4KNRNW ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -646,7 +659,8 @@ module SB_RAM40_4KNRNW ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (~RCLKN), diff --git a/techlibs/ice40/ice40_braminit.cc b/techlibs/ice40/ice40_braminit.cc new file mode 100644 index 000000000..bf12f9148 --- /dev/null +++ b/techlibs/ice40/ice40_braminit.cc @@ -0,0 +1,159 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 +#include +#include + +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 inti the required INIT_x attributes\n"); + log("\n"); + } + void execute(std::vector 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 From 5b6f59103374413e9c64c4f228853ce06b03ce29 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 8 Mar 2019 00:11:17 +0100 Subject: [PATCH 058/132] ice40: Run ice40_braminit pass by default Signed-off-by: Sylvain Munaut --- techlibs/ice40/synth_ice40.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 34501b335..8899bfcc4 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -257,6 +257,7 @@ struct SynthIce40Pass : public ScriptPass { run("memory_bram -rules +/ice40/brams.txt"); run("techmap -map +/ice40/brams_map.v"); + run("ice40_braminit"); } if (check_label("map")) From a330c6836318d43d52cda68959f2b86c2b2ede9c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 7 Mar 2019 22:44:37 -0800 Subject: [PATCH 059/132] Fix handling of task output ports in clocked always blocks, fixes #857 Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 35 +++++++++++++++++++---------------- tests/simple/task_func.v | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 7160c6c0f..d0274cf78 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2224,6 +2224,8 @@ skip_dynamic_range_lvalue_expansion:; std::map replace_rules; vector added_mod_children; dict wire_cache; + vector new_stmts; + vector output_assignments; if (current_block == NULL) { @@ -2348,8 +2350,8 @@ skip_dynamic_range_lvalue_expansion:; wire->port_id = 0; wire->is_input = false; wire->is_output = false; - if (!child->is_output) - wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire->is_reg = true; + wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); wire_cache[child->str] = wire; current_ast_mod->children.push_back(wire); @@ -2371,13 +2373,10 @@ skip_dynamic_range_lvalue_expansion:; new AstNode(AST_ASSIGN_EQ, wire_id, arg) : new AstNode(AST_ASSIGN_EQ, arg, wire_id); assign->children[0]->was_checked = true; - - for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { - if (*it != current_block_child) - continue; - current_block->children.insert(it, assign); - break; - } + if (child->is_input) + new_stmts.push_back(assign); + else + output_assignments.push_back(assign); } } @@ -2391,15 +2390,19 @@ skip_dynamic_range_lvalue_expansion:; { AstNode *stmt = child->clone(); stmt->replace_ids(prefix, replace_rules); - - for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { - if (*it != current_block_child) - continue; - current_block->children.insert(it, stmt); - break; - } + new_stmts.push_back(stmt); } + new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end()); + + for (auto it = current_block->children.begin(); ; it++) { + log_assert(it != current_block->children.end()); + if (*it == current_block_child) { + current_block->children.insert(it, new_stmts.begin(), new_stmts.end()); + break; + } + } + replace_fcall_with_id: if (type == AST_FCALL) { delete_children(); diff --git a/tests/simple/task_func.v b/tests/simple/task_func.v index fa50c1d5c..f6e902f63 100644 --- a/tests/simple/task_func.v +++ b/tests/simple/task_func.v @@ -120,3 +120,22 @@ module task_func_test04(input [7:0] in, output [7:0] out1, out2, out3, out4); assign out3 = test3(in); assign out4 = test4(in); endmodule + +// ------------------------------------------------------------------- + +// https://github.com/YosysHQ/yosys/issues/857 +module task_func_test05(data_in,data_out,clk); + output reg data_out; + input data_in; + input clk; + + task myTask; + output out; + input in; + out = in; + endtask + + always @(posedge clk) begin + myTask(data_out,data_in); + end +endmodule From 1dc060f32eea0df2ba45770365060251163b2857 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 9 Mar 2019 00:43:50 +0000 Subject: [PATCH 060/132] Fix spelling --- frontends/verific/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verific/README b/frontends/verific/README index c76cdd637..89584f2e8 100644 --- a/frontends/verific/README +++ b/frontends/verific/README @@ -21,7 +21,7 @@ Then run in the following command in this directory: 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: SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0) From 2aa3903757642616f38d1069e1b706fcbf3168c4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 9 Mar 2019 01:54:01 +0000 Subject: [PATCH 061/132] Add -chparam option to verific command --- frontends/verific/verific.cc | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 9f52ffdc2..4ba96d251 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1855,6 +1855,12 @@ struct VerificPass : public Pass { log(" -autocover\n"); log(" Generate automatic cover statements for all asserts\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, for modules where this parameter exists. 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(" Verbose log messages. (-vv is even more verbose than -v.)\n"); log("\n"); @@ -2109,6 +2115,7 @@ struct VerificPass : public Pass { bool mode_autocover = false; bool flatten = false, extnets = false; string dumpfile; + Map parameters(STRING_HASH); for (argidx++; argidx < GetSize(args); argidx++) { if (args[argidx] == "-all") { @@ -2147,6 +2154,15 @@ struct VerificPass : public Pass { mode_autocover = true; 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") { mode_verific = true; continue; @@ -2180,7 +2196,7 @@ struct VerificPass : public Pass { if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); if (veri_lib) veri_libs.InsertLast(veri_lib); - Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs); + Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, ¶meters); Netlist *nl; int i; @@ -2217,7 +2233,7 @@ struct VerificPass : public Pass { } log("Running hier_tree::Elaborate().\n"); - Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units); + Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); Netlist *nl; int i; From ee013fba54f8bca0940143f655f5b4ad3d7b7b96 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 9 Mar 2019 01:56:16 +0000 Subject: [PATCH 062/132] Update help message for -chparam --- frontends/verific/verific.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 4ba96d251..c412cd3a3 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1857,7 +1857,8 @@ struct VerificPass : public Pass { log("\n"); log(" -chparam name value \n"); log(" Elaborate the specified top modules (all modules when -all given) using\n"); - log(" this parameter value, for modules where this parameter exists. This option\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"); From e7a34d342ed1dd01074acdafca4f8f5557f8150f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 8 Mar 2019 22:53:58 -0800 Subject: [PATCH 063/132] Also add support for labels on sva module items, fixes #699 Signed-off-by: Clifford Wolf --- frontends/verilog/verilog_lexer.l | 57 +++++++++++-- frontends/verilog/verilog_parser.y | 132 +++++++++++++++++------------ 2 files changed, 129 insertions(+), 60 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 1b1873e24..e51a12f76 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -189,10 +189,57 @@ YOSYS_NAMESPACE_END "always_ff" { SV_KEYWORD(TOK_ALWAYS); } "always_latch" { SV_KEYWORD(TOK_ALWAYS); } -"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } -"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } -"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } -"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); } + /* parse labels on assert, assume, cover, and restrict right here because it's insanley complex + to do it in the parser (because we force the parser too early to reduce when parsing cells..) */ +([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(yytext); + auto &str = *frontend_verilog_yylval.string; + std::string keyword; + int cursor = 0; + + while (1) { + if (cursor == GetSize(str)) { + keyword = str; + delete frontend_verilog_yylval.string; + frontend_verilog_yylval.string = nullptr; + goto sva_without_label; + } + char c = str[cursor]; + if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ':') { + cursor++; + continue; + } + + keyword = str.substr(cursor); + str = "\\" + str.substr(0, cursor); + break; + } + + cursor = 0; + while (1) { + log_assert(cursor < GetSize(keyword)); + char c = keyword[cursor]; + if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ':') { + keyword = keyword.substr(cursor); + break; + } + cursor++; + } + + if (keyword == "assert") { return TOK_ASSERT; } + else if (keyword == "assume") { return TOK_ASSUME; } + else if (keyword == "cover") { return TOK_COVER; } + else if (keyword == "restrict") { return TOK_RESTRICT; } + else log_abort(); + +sva_without_label: + if (keyword == "assert") { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } + else if (keyword == "assume") { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } + else if (keyword == "cover") { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } + else if (keyword == "restrict") { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); } + else log_abort(); +} + "property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); } "rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); } "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } @@ -303,7 +350,7 @@ supply1 { return TOK_SUPPLY1; } [a-zA-Z_$][a-zA-Z0-9_$\.]* { frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); - return TOK_ID; + return TOK_ID; } "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 2258f3f6f..649dd384f 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -106,6 +106,7 @@ static void free_attr(std::map *al) } %token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE +%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP @@ -119,14 +120,13 @@ static void free_attr(std::map *al) %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED -%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME -%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF +%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF %token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY %token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY %type range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list -%type opt_label opt_stmt_label tok_prim_wrapper hierarchical_id +%type opt_label tok_prim_wrapper hierarchical_id %type opt_signed opt_property unique_case_attr %type attr case_attr @@ -1337,14 +1337,6 @@ opt_property: $$ = false; }; -opt_stmt_label: - TOK_ID ':' { - $$ = $1; - } | - /* empty */ { - $$ = NULL; - }; - modport_stmt: TOK_MODPORT TOK_ID { AstNode *modport = new AstNode(AST_MODPORT); @@ -1381,11 +1373,35 @@ modport_type_token: TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;} assert: - opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' { + TOK_ASSERT opt_property '(' expr ')' ';' { + if (noassert_mode) { + delete $4; + } else { + AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; + } | + TOK_ASSUME opt_property '(' expr ')' ';' { + if (noassume_mode) { + delete $4; + } else { + AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $4); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; + } | + TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { if (noassert_mode) { delete $5; } else { - AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1393,11 +1409,11 @@ assert: if ($1 != nullptr) delete $1; } | - opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' { + TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { if (noassume_mode) { delete $5; } else { - AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5); + AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $5); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); @@ -1405,39 +1421,15 @@ assert: if ($1 != nullptr) delete $1; } | - opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (noassert_mode) { - delete $6; - } else { - 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 ')' ';' { - if (noassume_mode) { - delete $6; - } else { - 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 ')' ';' { - AstNode *node = new AstNode(AST_COVER, $5); + TOK_COVER opt_property '(' expr ')' ';' { + AstNode *node = new AstNode(AST_COVER, $4); if ($1 != nullptr) { node->str = *$1; delete $1; } ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_COVER opt_property '(' ')' ';' { + TOK_COVER opt_property '(' ')' ';' { AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); if ($1 != nullptr) { node->str = *$1; @@ -1445,7 +1437,7 @@ assert: } ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_COVER ';' { + TOK_COVER ';' { AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); if ($1 != nullptr) { node->str = *$1; @@ -1453,30 +1445,30 @@ assert: } ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' { + TOK_RESTRICT opt_property '(' expr ')' ';' { if (norestrict_mode) { - delete $5; + delete $4; } else { - AstNode *node = new AstNode(AST_ASSUME, $5); + AstNode *node = new AstNode(AST_ASSUME, $4); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); } - if (!$3) + if (!$2) 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 ')' ';' { + TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { if (norestrict_mode) { - delete $6; + delete $5; } else { - AstNode *node = new AstNode(AST_FAIR, $6); + AstNode *node = new AstNode(AST_FAIR, $5); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); } - if (!$3) + if (!$2) log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); if ($1 != nullptr) delete $1; @@ -1485,30 +1477,60 @@ assert: assert_property: TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | TOK_COVER TOK_PROPERTY '(' expr ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { - if (norestrict_mode) + if (norestrict_mode) { delete $4; - else + } else { ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } + } } | TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) + if (norestrict_mode) { delete $5; - else + } else { ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } + } }; simple_behavioral_stmt: From 399ab16315468df95fc8a180d384d2ce8eed8049 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 9 Mar 2019 11:52:00 -0800 Subject: [PATCH 064/132] Add $dffsr support to async2sync Signed-off-by: Clifford Wolf --- passes/sat/async2sync.cc | 53 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc index c92db7118..d045d0dcb 100644 --- a/passes/sat/async2sync.cc +++ b/passes/sat/async2sync.cc @@ -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("the clock edge.\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"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -84,7 +84,7 @@ struct Async2syncPass : public Pass { bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool(); 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_d = cell->getPort("\\D"); SigSpec sig_q = cell->getPort("\\Q"); @@ -120,6 +120,55 @@ struct Async2syncPass : public Pass { cell->type = "$dff"; 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()) From 94f995ee3784e1a94a484fd399be2be4793d4e41 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 9 Mar 2019 13:19:41 -0800 Subject: [PATCH 065/132] Fix signed $shift/$shiftx handling in write_smt2 Signed-off-by: Clifford Wolf --- backends/smt2/smt2.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index a26bff57b..688535f33 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -416,6 +416,7 @@ struct Smt2Worker for (char ch : expr) { if (ch == 'A') processed_expr += get_bv(sig_a); 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 == 'U') processed_expr += is_signed ? "s" : "u"; else processed_expr += ch; @@ -554,7 +555,7 @@ struct Smt2Worker if (cell->type.in("$shift", "$shiftx")) { 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)))", GetSize(cell->getPort("\\B")), 0), 's'); } else { From ff4c2a14ae34eeb899c3cf0ca1109f0106b41679 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 9 Mar 2019 13:24:55 -0800 Subject: [PATCH 066/132] Fix typo in ice40_braminit help msg Signed-off-by: Clifford Wolf --- techlibs/ice40/ice40_braminit.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/ice40/ice40_braminit.cc b/techlibs/ice40/ice40_braminit.cc index bf12f9148..4fa6b0792 100644 --- a/techlibs/ice40/ice40_braminit.cc +++ b/techlibs/ice40/ice40_braminit.cc @@ -135,7 +135,7 @@ struct Ice40BRAMInitPass : public Pass { 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 inti the required INIT_x attributes\n"); + log("parameter and converts it into the required INIT_x attributes\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE From b02d9c2634de0898b2c483c438ba56540e0f3f69 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 10 Mar 2019 16:27:18 -0700 Subject: [PATCH 067/132] Fix handling of cases that look like sva labels, fixes #862 Signed-off-by: Clifford Wolf --- frontends/verilog/verilog_lexer.l | 59 +++---------- frontends/verilog/verilog_parser.y | 131 ++++++++++++++++------------- 2 files changed, 82 insertions(+), 108 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index e51a12f76..6ef38252a 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -189,57 +189,18 @@ YOSYS_NAMESPACE_END "always_ff" { SV_KEYWORD(TOK_ALWAYS); } "always_latch" { SV_KEYWORD(TOK_ALWAYS); } - /* parse labels on assert, assume, cover, and restrict right here because it's insanley complex - to do it in the parser (because we force the parser too early to reduce when parsing cells..) */ -([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(yytext); - auto &str = *frontend_verilog_yylval.string; - std::string keyword; - int cursor = 0; - - while (1) { - if (cursor == GetSize(str)) { - keyword = str; - delete frontend_verilog_yylval.string; - frontend_verilog_yylval.string = nullptr; - goto sva_without_label; - } - char c = str[cursor]; - if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ':') { - cursor++; - continue; - } - - keyword = str.substr(cursor); - str = "\\" + str.substr(0, cursor); - break; - } - - cursor = 0; - while (1) { - log_assert(cursor < GetSize(keyword)); - char c = keyword[cursor]; - if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ':') { - keyword = keyword.substr(cursor); - break; - } - cursor++; - } - - if (keyword == "assert") { return TOK_ASSERT; } - else if (keyword == "assume") { return TOK_ASSUME; } - else if (keyword == "cover") { return TOK_COVER; } - else if (keyword == "restrict") { return TOK_RESTRICT; } - else log_abort(); - -sva_without_label: - if (keyword == "assert") { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } - else if (keyword == "assume") { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } - else if (keyword == "cover") { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } - else if (keyword == "restrict") { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); } - else log_abort(); + /* 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); } +"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } +"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } +"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); } "property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); } "rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); } "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 649dd384f..52685f637 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -105,8 +105,8 @@ static void free_attr(std::map *al) bool boolean; } -%token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE -%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER +%token 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 TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP @@ -126,7 +126,7 @@ static void free_attr(std::map *al) %type range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list -%type opt_label tok_prim_wrapper hierarchical_id +%type opt_label opt_sva_label tok_prim_wrapper hierarchical_id %type opt_signed opt_property unique_case_attr %type attr case_attr @@ -1329,6 +1329,14 @@ opt_label: $$ = NULL; }; +opt_sva_label: + TOK_SVA_LABEL ':' { + $$ = $1; + } | + /* empty */ { + $$ = NULL; + }; + opt_property: TOK_PROPERTY { $$ = true; @@ -1373,35 +1381,11 @@ modport_type_token: TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;} assert: - TOK_ASSERT opt_property '(' expr ')' ';' { - if (noassert_mode) { - delete $4; - } else { - AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4); - if ($1 != nullptr) - node->str = *$1; - ast_stack.back()->children.push_back(node); - } - if ($1 != nullptr) - delete $1; - } | - TOK_ASSUME opt_property '(' expr ')' ';' { - if (noassume_mode) { - delete $4; - } else { - AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $4); - if ($1 != nullptr) - node->str = *$1; - ast_stack.back()->children.push_back(node); - } - if ($1 != nullptr) - delete $1; - } | - TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { + opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' { if (noassert_mode) { delete $5; } else { - AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $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); @@ -1409,11 +1393,11 @@ assert: if ($1 != nullptr) delete $1; } | - TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { + opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' { if (noassume_mode) { delete $5; } else { - AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $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); @@ -1421,15 +1405,39 @@ assert: if ($1 != nullptr) delete $1; } | - TOK_COVER opt_property '(' expr ')' ';' { - AstNode *node = new AstNode(AST_COVER, $4); + opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (noassert_mode) { + delete $6; + } else { + 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_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (noassume_mode) { + delete $6; + } else { + 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_sva_label TOK_COVER opt_property '(' expr ')' ';' { + AstNode *node = new AstNode(AST_COVER, $5); if ($1 != nullptr) { node->str = *$1; delete $1; } ast_stack.back()->children.push_back(node); } | - TOK_COVER opt_property '(' ')' ';' { + opt_sva_label TOK_COVER opt_property '(' ')' ';' { AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); if ($1 != nullptr) { node->str = *$1; @@ -1437,7 +1445,7 @@ assert: } ast_stack.back()->children.push_back(node); } | - TOK_COVER ';' { + opt_sva_label TOK_COVER ';' { AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); if ($1 != nullptr) { node->str = *$1; @@ -1445,87 +1453,87 @@ assert: } ast_stack.back()->children.push_back(node); } | - TOK_RESTRICT opt_property '(' expr ')' ';' { + opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' { if (norestrict_mode) { - delete $4; + delete $5; } else { - AstNode *node = new AstNode(AST_ASSUME, $4); + AstNode *node = new AstNode(AST_ASSUME, $5); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); } - if (!$2) + if (!$3) log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); if ($1 != nullptr) delete $1; } | - TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { + opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { if (norestrict_mode) { - delete $5; + delete $6; } else { - AstNode *node = new AstNode(AST_FAIR, $5); + AstNode *node = new AstNode(AST_FAIR, $6); if ($1 != nullptr) node->str = *$1; ast_stack.back()->children.push_back(node); } - if (!$2) + if (!$3) log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); if ($1 != nullptr) delete $1; }; assert_property: - TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4)); + opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { + 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 ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); + opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { + 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 ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5)); + 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, $6)); if ($1 != nullptr) { ast_stack.back()->children.back()->str = *$1; delete $1; } } | - TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); + opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + 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 ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4)); + opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { + 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) { - delete $4; + delete $5; } else { - 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_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { if (norestrict_mode) { - delete $5; + delete $6; } else { - 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; @@ -1748,6 +1756,11 @@ case_expr_list: TOK_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 { ast_stack.back()->children.push_back($1); } | From d9bb5f3637634ea214194b612aee4bb0c62d7a5c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 11 Mar 2019 01:08:36 -0700 Subject: [PATCH 068/132] Add ENABLE_GLOB Makefile switch Signed-off-by: Clifford Wolf --- Makefile | 5 +++++ kernel/yosys.cc | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 8e93cd285..b8fbcc040 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ CONFIG := clang # features (the more the better) ENABLE_TCL := 1 ENABLE_ABC := 1 +ENABLE_GLOB := 1 ENABLE_PLUGINS := 1 ENABLE_READLINE := 1 ENABLE_EDITLINE := 0 @@ -298,6 +299,10 @@ LDLIBS += -ldl endif endif +ifeq ($(ENABLE_GLOB),1) +CXXFLAGS += -DYOSYS_ENABLE_GLOB +endif + ifeq ($(ENABLE_TCL),1) TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") ifeq ($(OS), FreeBSD) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 2ed0f4db4..6fd53f85e 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -33,7 +33,7 @@ # include #endif -#ifdef _WIN32 +#if defined(_WIN32) # include # include #elif defined(__APPLE__) @@ -41,13 +41,15 @@ # include # include # include -# include #else # include # include # include # include # include +#endif + +#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB) # include #endif @@ -564,7 +566,7 @@ std::vector glob_filename(const std::string &filename_pattern) { std::vector results; -#ifdef _WIN32 +#if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB) results.push_back(filename_pattern); #else glob_t globbuf; From 20c6a8c9b0abb384517c4cc6f58cd29a90bda6ff Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 11 Mar 2019 20:12:28 +0100 Subject: [PATCH 069/132] Improve determinism of IdString DB for similar scripts Signed-off-by: Clifford Wolf --- backends/verilog/verilog_backend.cc | 4 ++ kernel/log.cc | 4 ++ kernel/register.cc | 2 + kernel/rtlil.cc | 2 + kernel/rtlil.h | 64 ++++++++++++++++++++++++++--- 5 files changed, 71 insertions(+), 5 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 6818edb7a..83d83f488 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1673,6 +1673,8 @@ struct VerilogBackend : public Backend { bool blackboxes = false; bool selected = false; + auto_name_map.clear(); + reg_wires.clear(); reg_ct.clear(); reg_ct.insert("$dff"); @@ -1779,6 +1781,8 @@ struct VerilogBackend : public Backend { dump_module(*f, "", it->second); } + auto_name_map.clear(); + reg_wires.clear(); reg_ct.clear(); } } VerilogBackend; diff --git a/kernel/log.cc b/kernel/log.cc index 0ee2170a0..400a549dd 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -196,7 +196,11 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap) if (log_hdump.count(header_id) && design != nullptr) for (auto &filename : log_hdump.at(header_id)) { log("Dumping current design to '%s'.\n", filename.c_str()); + if (yosys_xtrace) + IdString::xtrace_db_dump(); Pass::call(design, {"dump", "-o", filename}); + if (yosys_xtrace) + log("#X# -- end of dump --\n"); } if (pop_errfile) diff --git a/kernel/register.cc b/kernel/register.cc index 402a5b3ea..64956401f 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -86,6 +86,8 @@ Pass::pre_post_exec_state_t Pass::pre_execute() void Pass::post_execute(Pass::pre_post_exec_state_t state) { + IdString::checkpoint(); + int64_t time_ns = PerformanceTimer::query() - state.begin_ns; runtime_ns += time_ns; current_pass = state.parent_pass; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d4aebcda9..7f1816190 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -33,6 +33,8 @@ std::vector RTLIL::IdString::global_refcount_storage_; std::vector RTLIL::IdString::global_id_storage_; dict RTLIL::IdString::global_id_index_; std::vector RTLIL::IdString::global_free_idx_list_; +int RTLIL::IdString::last_created_idx_[8]; +int RTLIL::IdString::last_created_idx_ptr_; RTLIL::Const::Const() { diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f877622aa..01323d112 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -76,6 +76,9 @@ namespace RTLIL struct IdString { + #undef YOSYS_XTRACE_GET_PUT + #undef YOSYS_SORT_ID_FREE_LIST + // the global id string cache static struct destruct_guard_t { @@ -89,9 +92,43 @@ namespace RTLIL static dict global_id_index_; static std::vector 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()); + #endif + } + static inline int get_reference(int 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; } @@ -107,6 +144,11 @@ namespace RTLIL auto it = global_id_index_.find((char*)p); if (it != global_id_index_.end()) { 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; } @@ -124,16 +166,22 @@ namespace RTLIL global_refcount_storage_.at(idx)++; // Avoid Create->Delete->Create pattern - static IdString last_created_id; - put_reference(last_created_id.index_); - last_created_id.index_ = idx; - get_reference(last_created_id.index_); + if (last_created_idx_[last_created_idx_ptr_]) + put_reference(last_created_idx_[last_created_idx_ptr_]); + last_created_idx_[last_created_idx_ptr_] = idx; + get_reference(last_created_idx_[last_created_idx_ptr_]); + last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7; if (yosys_xtrace) { log("#X# New IdString '%s' with index %d.\n", p, idx); 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; } @@ -144,6 +192,12 @@ namespace RTLIL if (!destruct_guard.ok) 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); if (--global_refcount_storage_.at(idx) != 0) @@ -1282,7 +1336,7 @@ inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { return wire ? (offset < other.offset) : (data < other.data); if (wire != nullptr && other.wire != nullptr) 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 { From ab5b50ae3c9e63fe3da3ae0451500c1cb5be1743 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 12 Mar 2019 20:09:47 +0100 Subject: [PATCH 070/132] Only set MEM2REG_FL_CONST_LHS/MEM2REG_FL_VAR_LHS for non-init writes, fixes #867 Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index ae7dec88d..f747a07cd 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2954,12 +2954,14 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; } - // remember if this is a constant index or not - 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) - mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS; - else - mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS; + // 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[0]->children[0]->type == AST_CONSTANT) + mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS; + else + mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS; + } } // remember where this is From a4ddc569b4c0e51e89317ade8c4183f41acc1cb5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 12 Mar 2019 20:10:55 +0100 Subject: [PATCH 071/132] Remove outdated "blocking assignment to memory" warning Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index f747a07cd..de300bbce 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -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) { static int recursion_counter = 0; - static pair last_blocking_assignment_warn; static bool deep_recursion_warning = false; 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) { log_assert(type == AST_MODULE || type == AST_INTERFACE); - last_blocking_assignment_warn = pair(); deep_recursion_warning = true; while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { } @@ -1592,14 +1590,6 @@ skip_dynamic_range_lvalue_expansion:; 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"; - if (type == AST_ASSIGN_EQ) { - pair 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; bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); From d25a0c8adeb421246732539b19738a8e68fc1315 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 12 Mar 2019 20:12:02 +0100 Subject: [PATCH 072/132] Improve handling of memories used in mem index expressions on LHS of an assignment Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index de300bbce..1c9932ee0 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2918,7 +2918,7 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg dict &mem2reg_candidates, dict &proc_flags, uint32_t &flags) { 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) { @@ -2966,7 +2966,7 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg } } - ignore_children_counter = 1; + lhs_children_counter = 1; } if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY) @@ -3009,12 +3009,23 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg log_assert((flags & ~0x000000ff) == 0); for (auto child : children) - if (ignore_children_counter > 0) - ignore_children_counter--; - else if (proc_flags_p) + { + if (lhs_children_counter > 0) { + 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); else child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags); + } flags &= ~children_flags | backup_flags; From 9284cf92b8dcb510a2a9511965e587e42944c543 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 12 Mar 2019 20:14:18 +0100 Subject: [PATCH 073/132] Remove ice40/cells_sim.v hack to avoid warning for blocking memory writes Signed-off-by: Clifford Wolf --- techlibs/ice40/cells_sim.v | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index bc36cdd14..62a28364b 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -414,24 +414,6 @@ module SB_RAM40_4K ( $readmemh(INIT_FILE, memory); else 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[ 1*16 + i] = INIT_1[16*i +: 16]; memory[ 2*16 + i] = INIT_2[16*i +: 16]; @@ -448,7 +430,6 @@ module SB_RAM40_4K ( 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]; -`endif end end From 1cd04a68389671c91dddb56cc3d2f9032f9b44e3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 12 Mar 2019 21:14:50 +0100 Subject: [PATCH 074/132] Fix a bug in handling quotes in multi-cmd lines in Yosys scripts Signed-off-by: Clifford Wolf --- kernel/yosys.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 6fd53f85e..450e4e4cf 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -218,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] == '"') { 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)) { std::string token = text.substr(pos_begin, i-pos_begin+1); text = text.substr(i+1); 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); From ff15cf9b1f8208d8c6e22beb9aebedc8bdae213f Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Tue, 12 Mar 2019 17:55:47 -0400 Subject: [PATCH 075/132] Install launcher executable when running yosys-smtbmc on Windows. Signed-off-by: William D. Jones --- .gitignore | 2 + backends/smt2/Makefile.inc | 18 +- misc/launcher.c | 358 +++++++++++++++++++++++++++++++++++++ 3 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 misc/launcher.c diff --git a/.gitignore b/.gitignore index 48ce458c7..e24f7975a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,8 @@ /yosys-abc.exe /yosys-config /yosys-smtbmc +/yosys-smtbmc.exe +/yosys-smtbmc-script.py /yosys-filterlib /yosys-filterlib.exe /kernel/version_*.cc diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc index dce82f01a..92941d4cf 100644 --- a/backends/smt2/Makefile.inc +++ b/backends/smt2/Makefile.inc @@ -3,14 +3,30 @@ OBJS += backends/smt2/smt2.o ifneq ($(CONFIG),mxe) 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 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 $(Q) chmod +x $@.new $(Q) mv $@.new $@ +endif $(eval $(call add_share_file,share/python3,backends/smt2/smtio.py)) endif endif - diff --git a/misc/launcher.c b/misc/launcher.c new file mode 100644 index 000000000..157d68cf3 --- /dev/null +++ b/misc/launcher.c @@ -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 + +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 + "true" 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 +#include +#include +#include +#include +#include + +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; counterscript && *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 Date: Thu, 14 Mar 2019 17:50:20 +0100 Subject: [PATCH 076/132] Fix a syntax bug in ilang backend related to process case statements Signed-off-by: Clifford Wolf --- backends/ilang/ilang_backend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc index 4c58ea087..dc39e5e08 100644 --- a/backends/ilang/ilang_backend.cc +++ b/backends/ilang/ilang_backend.cc @@ -204,7 +204,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const f << stringf("%s case ", indent.c_str()); for (size_t i = 0; i < (*it)->compare.size(); i++) { if (i > 0) - f << stringf(", "); + f << stringf(" , "); dump_sigspec(f, (*it)->compare[i]); } f << stringf("\n"); From 17caaa3fa898e39d1dbcfd8b92750a9d713a24af Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 17:51:21 +0100 Subject: [PATCH 077/132] Improve handling of "full_case" attributes Signed-off-by: Clifford Wolf --- frontends/ast/genrtlil.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index d7da6fb40..b3a2a84be 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -525,7 +525,16 @@ struct AST_INTERNAL::ProcessGenerator } 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(); + #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 { if (default_case == NULL) { default_case = new RTLIL::CaseRule; From f806b95ed6a2f2c1a0e5c8884676fd384e510143 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 20:35:15 +0100 Subject: [PATCH 078/132] Improve handling of and-with-1 and or-with-0 in opt_expr, fixes #327 Signed-off-by: Clifford Wolf --- passes/opt/opt_expr.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 26a3ca7bc..a05db2a4f 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -155,6 +155,13 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ 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); c->setPort("\\A", new_a); From ea8ee2414053101bae26cfc2a537d42daf57f5e0 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 12 Mar 2019 17:01:59 +0100 Subject: [PATCH 079/132] Add basic "mutate -list N" framework Signed-off-by: Clifford Wolf --- passes/sat/Makefile.inc | 1 + passes/sat/mutate.cc | 229 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 passes/sat/mutate.cc diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index 6cb1ea644..e91df1eb0 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -9,4 +9,5 @@ OBJS += passes/sat/assertpmux.o OBJS += passes/sat/clk2fflogic.o OBJS += passes/sat/async2sync.o OBJS += passes/sat/supercover.o +OBJS += passes/sat/mutate.o diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc new file mode 100644 index 000000000..5fd89b7d0 --- /dev/null +++ b/passes/sat/mutate.cc @@ -0,0 +1,229 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 { + std::string mode, src; + IdString modname, cellname, celltype, cellport; + SigBit outsigbit; + int portbit = -1; +}; + +struct mutate_opts_t { + std::string mode; + IdString module, cell, port; + int bit = -1; +}; + +void database_add(std::vector &database, const mutate_opts_t &opts, const mutate_t &entry) +{ + if (!opts.module.empty() && opts.module != entry.modname) + return; + + if (!opts.cell.empty() && opts.cell != entry.cellname) + return; + + if (!opts.port.empty() && opts.port != entry.cellport) + return; + + if (opts.bit >= 0 && opts.bit != entry.portbit) + return; + + database.push_back(entry); +} + +void database_reduce(std::vector &database, const mutate_opts_t &opts, int N) +{ +} + +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("\n"); + log(" mutate -mode MODE [options]\n"); + log("\n"); + log("Apply the given mutation.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + mutate_opts_t opts; + string filename; + 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] == "-mode" && argidx+1 < args.size()) { + opts.mode = args[++argidx]; + 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] == "-bit" && argidx+1 < args.size()) { + opts.bit = atoi(args[++argidx].c_str()); + continue; + } + break; + } + extra_args(args, argidx, design); + + if (N >= 0) + { + std::vector database; + + for (auto module : design->selected_modules()) + { + if (!opts.module.empty() && module->name != opts.module) + continue; + + SigMap sigmap(module); + + 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.mode = "inv"; + entry.src = cell->get_src_attribute(); + entry.modname = module->name; + entry.cellname = cell->name; + entry.celltype = cell->type; + entry.cellport = conn.first; + entry.portbit = i; + + if (cell->output(conn.first)) { + SigBit bit = sigmap(conn.second[i]); + if (bit.wire && bit.wire->name[0] == '\\') + entry.outsigbit = bit; + } + + database_add(database, opts, entry); + } + } + } + } + + log("Raw database size: %d\n", GetSize(database)); + if (N != 0) { + database_reduce(database, opts, N); + log("Reduced database size: %d\n", GetSize(database)); + } + + 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()); + } + + for (auto &entry : database) { + string str = stringf("mutate -mode %s", entry.mode.c_str()); + if (!entry.modname.empty()) + str += stringf(" -module %s", log_id(entry.modname)); + if (!entry.cellname.empty()) + str += stringf(" -cell %s", log_id(entry.cellname)); + if (!entry.cellport.empty()) + str += stringf(" -port %s", log_id(entry.cellport)); + if (entry.portbit >= 0) + str += stringf(" -bit %d", entry.portbit); + if (entry.outsigbit.wire || !entry.src.empty()) { + str += " #"; + if (!entry.src.empty()) + str += stringf(" %s", entry.src.c_str()); + if (entry.outsigbit.wire) + str += stringf(" %s", log_signal(entry.outsigbit)); + } + if (filename.empty()) + log("%s\n", str.c_str()); + else + fout << str << std::endl; + } + + return; + } + + log_cmd_error("Invalid mode: %s\n", opts.mode.c_str()); + } +} MutatePass; + +PRIVATE_NAMESPACE_END From 8e6b69d7bba21dd3fa01064ee698dcd409b5dcc8 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 13 Mar 2019 16:09:47 +0100 Subject: [PATCH 080/132] Add "mutate -mode inv", various other mutate improvements Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 312 +++++++++++++++++++++++++++++-------------- 1 file changed, 213 insertions(+), 99 deletions(-) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 5fd89b7d0..04aebd897 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -34,10 +34,16 @@ struct mutate_opts_t { std::string mode; IdString module, cell, port; int bit = -1; + + IdString ctrl_name; + int ctrl_width, ctrl_value; }; void database_add(std::vector &database, const mutate_opts_t &opts, const mutate_t &entry) { + if (!opts.mode.empty() && opts.mode != entry.mode) + return; + if (!opts.module.empty() && opts.module != entry.modname) return; @@ -57,6 +63,183 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, { } +void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N) +{ + std::vector database; + + for (auto module : design->selected_modules()) + { + if (!opts.module.empty() && module->name != opts.module) + continue; + + SigMap sigmap(module); + + 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.mode = "inv"; + entry.src = cell->get_src_attribute(); + entry.modname = module->name; + entry.cellname = cell->name; + entry.celltype = cell->type; + entry.cellport = conn.first; + entry.portbit = i; + + if (cell->output(conn.first)) { + SigBit bit = sigmap(conn.second[i]); + if (bit.wire && bit.wire->name[0] == '\\') + entry.outsigbit = bit; + } + + database_add(database, opts, entry); + } + } + } + } + + log("Raw database size: %d\n", GetSize(database)); + if (N != 0) { + database_reduce(database, opts, N); + log("Reduced database size: %d\n", GetSize(database)); + } + + 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()); + } + + for (auto &entry : database) { + string str = stringf("mutate -mode %s", entry.mode.c_str()); + if (!entry.modname.empty()) + str += stringf(" -module %s", log_id(entry.modname)); + if (!entry.cellname.empty()) + str += stringf(" -cell %s", log_id(entry.cellname)); + if (!entry.cellport.empty()) + str += stringf(" -port %s", log_id(entry.cellport)); + if (entry.portbit >= 0) + str += stringf(" -bit %d", entry.portbit); + if (entry.outsigbit.wire || !entry.src.empty()) { + str += " #"; + if (!entry.src.empty()) + str += stringf(" %s", entry.src.c_str()); + if (entry.outsigbit.wire) + str += stringf(" %s", log_signal(entry.outsigbit)); + } + 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.bit]; + 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.bit); + 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.bit); + 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.bit] = bit; + cell->setPort(opts.port, s); +} + struct MutatePass : public Pass { MutatePass() : Pass("mutate", "generate or apply design mutations") { } void help() YS_OVERRIDE @@ -70,11 +253,29 @@ struct MutatePass : public Pass { log(" -o filename\n"); log(" Write list to this file instead of console output\n"); log("\n"); + log(" -mode name\n"); + log(" -module name\n"); + log(" -cell name\n"); + log(" -port name\n"); + log(" -bit int\n"); + log(" Filter list of mutation candidates to those matching\n"); + log(" the given parameters.\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(" -bit int\n"); + log(" Mutation parameters, as generated by 'mutate -list N'.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { @@ -99,6 +300,12 @@ struct MutatePass : public Pass { 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; @@ -119,106 +326,13 @@ struct MutatePass : public Pass { } extra_args(args, argidx, design); - if (N >= 0) - { - std::vector database; - - for (auto module : design->selected_modules()) - { - if (!opts.module.empty() && module->name != opts.module) - continue; - - SigMap sigmap(module); - - 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.mode = "inv"; - entry.src = cell->get_src_attribute(); - entry.modname = module->name; - entry.cellname = cell->name; - entry.celltype = cell->type; - entry.cellport = conn.first; - entry.portbit = i; - - if (cell->output(conn.first)) { - SigBit bit = sigmap(conn.second[i]); - if (bit.wire && bit.wire->name[0] == '\\') - entry.outsigbit = bit; - } - - database_add(database, opts, entry); - } - } - } - } - - log("Raw database size: %d\n", GetSize(database)); - if (N != 0) { - database_reduce(database, opts, N); - log("Reduced database size: %d\n", GetSize(database)); - } - - 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()); - } - - for (auto &entry : database) { - string str = stringf("mutate -mode %s", entry.mode.c_str()); - if (!entry.modname.empty()) - str += stringf(" -module %s", log_id(entry.modname)); - if (!entry.cellname.empty()) - str += stringf(" -cell %s", log_id(entry.cellname)); - if (!entry.cellport.empty()) - str += stringf(" -port %s", log_id(entry.cellport)); - if (entry.portbit >= 0) - str += stringf(" -bit %d", entry.portbit); - if (entry.outsigbit.wire || !entry.src.empty()) { - str += " #"; - if (!entry.src.empty()) - str += stringf(" %s", entry.src.c_str()); - if (entry.outsigbit.wire) - str += stringf(" %s", log_signal(entry.outsigbit)); - } - if (filename.empty()) - log("%s\n", str.c_str()); - else - fout << str << std::endl; - } + if (N >= 0) { + mutate_list(design, opts, filename, N); + return; + } + if (opts.mode == "inv") { + mutate_inv(design, opts); return; } From 76c9c350e7d0dfc11b609d98bdcd1ea0d845cb06 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 13 Mar 2019 17:36:06 +0100 Subject: [PATCH 081/132] Add hashlib "::element(int n)" methods Signed-off-by: Clifford Wolf --- kernel/hashlib.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index df534ec1b..e7cb312ed 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -557,9 +557,11 @@ public: void clear() { hashtable.clear(); entries.clear(); } 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); } 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); } }; @@ -881,9 +883,11 @@ public: void clear() { hashtable.clear(); entries.clear(); } 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); } 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); } }; @@ -952,6 +956,7 @@ public: void clear() { database.clear(); } const_iterator begin() const { return database.begin(); } + const_iterator element(int n) const { return database.element(n); } const_iterator end() const { return database.end(); } }; @@ -1051,6 +1056,7 @@ public: void clear() { database.clear(); parents.clear(); } const_iterator begin() const { return database.begin(); } + const_iterator element(int n) const { return database.element(n); } const_iterator end() const { return database.end(); } }; From 6ad5d036c58766b2bd0a705c7adfcbf9af4a7d16 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 13 Mar 2019 17:36:37 +0100 Subject: [PATCH 082/132] Add "mutate" command DB reduce functionality Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 193 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 181 insertions(+), 12 deletions(-) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 04aebd897..3ecb955f0 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -25,16 +25,19 @@ PRIVATE_NAMESPACE_BEGIN struct mutate_t { std::string mode, src; - IdString modname, cellname, celltype, cellport; + Module *module; + Cell *cell; + IdString cellport; SigBit outsigbit; int portbit = -1; + bool used = false; }; struct mutate_opts_t { + int seed = 0; std::string mode; IdString module, cell, port; int bit = -1; - IdString ctrl_name; int ctrl_width, ctrl_value; }; @@ -44,10 +47,10 @@ void database_add(std::vector &database, const mutate_opts_t &opts, co if (!opts.mode.empty() && opts.mode != entry.mode) return; - if (!opts.module.empty() && opts.module != entry.modname) + if (!opts.module.empty() && opts.module != entry.module->name) return; - if (!opts.cell.empty() && opts.cell != entry.cellname) + if (!opts.cell.empty() && opts.cell != entry.cell->name) return; if (!opts.port.empty() && opts.port != entry.cellport) @@ -59,8 +62,159 @@ void database_add(std::vector &database, const mutate_opts_t &opts, co 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 mutate_leaf_queue_t +{ + pool db; + + mutate_t *pick(xs128_t &rng) { + while (!db.empty()) { + int i = rng(GetSize(db)); + auto it = db.element(i); + mutate_t *m = *it; + db.erase(it); + if (m->used == false) { + m->used = true; + return m; + } + } + return nullptr; + } + + void add(mutate_t *m) { + db.insert(m); + } +}; + +template +struct mutate_inner_queue_t +{ + dict db; + + mutate_t *pick(xs128_t &rng) { + while (!db.empty()) { + int i = rng(GetSize(db)); + auto it = db.element(i); + mutate_t *m = it->second.pick(rng); + if (m != nullptr) + return m; + db.erase(it); + } + return nullptr; + } + + template + void add(mutate_t *m, K key, Args... args) { + db[key].add(m, args...); + } +}; + void database_reduce(std::vector &database, const mutate_opts_t &opts, int N) { + if (N >= GetSize(database)) + return; + + mutate_inner_queue_t primary_queue_wire; + mutate_inner_queue_t primary_queue_bit; + mutate_inner_queue_t primary_queue_cell; + mutate_inner_queue_t primary_queue_src; + + mutate_inner_queue_t> primary_queue_module_wire; + mutate_inner_queue_t> primary_queue_module_bit; + mutate_inner_queue_t> primary_queue_module_cell; + mutate_inner_queue_t> primary_queue_module_src; + + for (auto &m : database) + { + if (m.outsigbit.wire) { + primary_queue_wire.add(&m, m.outsigbit.wire); + primary_queue_bit.add(&m, m.outsigbit); + primary_queue_module_wire.add(&m, m.module, m.outsigbit.wire); + primary_queue_module_bit.add(&m, m.module, m.outsigbit); + } + + primary_queue_cell.add(&m, m.cell); + primary_queue_module_cell.add(&m, m.module, m.cell); + + if (!m.src.empty()) { + primary_queue_src.add(&m, m.src); + primary_queue_module_src.add(&m, m.module, m.src); + } + } + + 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; + + int total_weight = weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; + total_weight += weight_pq_mw + weight_pq_mb + weight_pq_mc + weight_pq_ms; + + std::vector new_database; + xs128_t rng(opts.seed); + + while (GetSize(new_database) < N) + { + int k = rng(total_weight); + +#define X(__wght, __queue) \ + k -= __wght; \ + if (k < 0) { \ + mutate_t *m = __queue.pick(rng); \ + if (m != nullptr) \ + new_database.push_back(*m); \ + continue; \ + } + + X(weight_pq_w, primary_queue_wire) + X(weight_pq_b, primary_queue_bit) + X(weight_pq_c, primary_queue_cell) + X(weight_pq_s, primary_queue_src) + + X(weight_pq_mw, primary_queue_module_wire) + X(weight_pq_mb, primary_queue_module_bit) + X(weight_pq_mc, primary_queue_module_cell) + X(weight_pq_ms, primary_queue_module_src) + } + + std::swap(new_database, database); } void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N) @@ -108,9 +262,8 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena mutate_t entry; entry.mode = "inv"; entry.src = cell->get_src_attribute(); - entry.modname = module->name; - entry.cellname = cell->name; - entry.celltype = cell->type; + entry.module = module; + entry.cell = cell; entry.cellport = conn.first; entry.portbit = i; @@ -140,12 +293,17 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena log_error("Could not open file \"%s\" with write access.\n", filename.c_str()); } + int ctrl_value = opts.ctrl_value; + for (auto &entry : database) { - string str = stringf("mutate -mode %s", entry.mode.c_str()); - if (!entry.modname.empty()) - str += stringf(" -module %s", log_id(entry.modname)); - if (!entry.cellname.empty()) - str += stringf(" -cell %s", log_id(entry.cellname)); + 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) + str += stringf(" -module %s", log_id(entry.module)); + if (entry.cell) + str += stringf(" -cell %s", log_id(entry.cell)); if (!entry.cellport.empty()) str += stringf(" -port %s", log_id(entry.cellport)); if (entry.portbit >= 0) @@ -253,6 +411,13 @@ struct MutatePass : public Pass { log(" -o filename\n"); log(" Write list to this file instead of console output\n"); log("\n"); + log(" -seed N\n"); + log(" RNG seed for selecting mutations\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"); @@ -296,6 +461,10 @@ struct MutatePass : public Pass { filename = args[++argidx]; continue; } + if (args[argidx] == "-seed" && argidx+1 < args.size()) { + opts.seed = atoi(args[++argidx].c_str()); + continue; + } if (args[argidx] == "-mode" && argidx+1 < args.size()) { opts.mode = args[++argidx]; continue; From bacca5753775bfabed955a9772a5d86d85007c58 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 13 Mar 2019 19:27:17 +0100 Subject: [PATCH 083/132] Fix smtbmc.py handling of zero appended steps Signed-off-by: Clifford Wolf --- backends/smt2/smtbmc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index 94a5e2da0..445a42e0d 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -1484,11 +1484,11 @@ else: # not tempind, covermode smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i)) smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i)) smt_assert_consequent(get_constr_expr(constr_assumes, i)) - print_msg("Re-solving with appended steps..") - if smt_check_sat() == "unsat": - print("%s Cannot appended steps without violating assumptions!" % smt.timestamp()) - retstatus = False - break + print_msg("Re-solving with appended steps..") + if smt_check_sat() == "unsat": + print("%s Cannot appended steps without violating assumptions!" % smt.timestamp()) + retstatus = False + break print_anyconsts(step) for i in range(step, last_check_step+1): print_failed_asserts(i) From 1b4fdbb0d881040220cdf1591f415cd2176481ad Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 19:52:02 +0100 Subject: [PATCH 084/132] Add more mutation types, improve mutation src cover Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 362 ++++++++++++++++++++++++++++++++----------- 1 file changed, 269 insertions(+), 93 deletions(-) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 3ecb955f0..eac00948a 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -24,20 +24,24 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct mutate_t { - std::string mode, src; - Module *module; - Cell *cell; - IdString cellport; - SigBit outsigbit; + string mode; + pool 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; - IdString module, cell, port; - int bit = -1; + pool src; + IdString module, cell, port, wire; + int portbit = -1; + int ctrlbit = -1; + int wirebit = -1; IdString ctrl_name; int ctrl_width, ctrl_value; }; @@ -47,16 +51,35 @@ void database_add(std::vector &database, const mutate_opts_t &opts, co if (!opts.mode.empty() && opts.mode != entry.mode) return; - if (!opts.module.empty() && opts.module != entry.module->name) + 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->name) + if (!opts.cell.empty() && opts.cell != entry.cell) return; - if (!opts.port.empty() && opts.port != entry.cellport) + if (!opts.port.empty() && opts.port != entry.port) return; - if (opts.bit >= 0 && opts.bit != entry.portbit) + 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); @@ -99,18 +122,48 @@ struct mutate_leaf_queue_t { pool db; - mutate_t *pick(xs128_t &rng) { - while (!db.empty()) { - int i = rng(GetSize(db)); - auto it = db.element(i); - mutate_t *m = *it; - db.erase(it); - if (m->used == false) { - m->used = true; - return m; + mutate_t *pick(xs128_t &rng, dict &coverdb) { + mutate_t *m = nullptr; + if (rng(3)) { + vector candidates; + int best_score = -1; + for (auto p : db) { + if (p->used || p->src.empty()) + continue; + int this_score = -1; + for (auto &s : p->src) { + if (this_score == -1 || this_score > coverdb.at(s)) + this_score = coverdb.at(s); + } + log_assert(this_score != -1); + if (best_score == -1 || this_score < best_score) { + candidates.clear(); + best_score = this_score; + } + if (best_score == this_score) + candidates.push_back(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 nullptr; + if (m != nullptr) { + m->used = true; + for (auto &s : m->src) + coverdb[s]++; + } + return m; } void add(mutate_t *m) { @@ -123,11 +176,11 @@ struct mutate_inner_queue_t { dict db; - mutate_t *pick(xs128_t &rng) { + mutate_t *pick(xs128_t &rng, dict &coverdb) { while (!db.empty()) { int i = rng(GetSize(db)); auto it = db.element(i); - mutate_t *m = it->second.pick(rng); + mutate_t *m = it->second.pick(rng, coverdb); if (m != nullptr) return m; db.erase(it); @@ -141,38 +194,10 @@ struct mutate_inner_queue_t } }; -void database_reduce(std::vector &database, const mutate_opts_t &opts, int N) +void database_reduce(std::vector &database, const mutate_opts_t &/* opts */, int N, xs128_t &rng) { - if (N >= GetSize(database)) - return; - - mutate_inner_queue_t primary_queue_wire; - mutate_inner_queue_t primary_queue_bit; - mutate_inner_queue_t primary_queue_cell; - mutate_inner_queue_t primary_queue_src; - - mutate_inner_queue_t> primary_queue_module_wire; - mutate_inner_queue_t> primary_queue_module_bit; - mutate_inner_queue_t> primary_queue_module_cell; - mutate_inner_queue_t> primary_queue_module_src; - - for (auto &m : database) - { - if (m.outsigbit.wire) { - primary_queue_wire.add(&m, m.outsigbit.wire); - primary_queue_bit.add(&m, m.outsigbit); - primary_queue_module_wire.add(&m, m.module, m.outsigbit.wire); - primary_queue_module_bit.add(&m, m.module, m.outsigbit); - } - - primary_queue_cell.add(&m, m.cell); - primary_queue_module_cell.add(&m, m.module, m.cell); - - if (!m.src.empty()) { - primary_queue_src.add(&m, m.src); - primary_queue_module_src.add(&m, m.module, m.src); - } - } + std::vector new_database; + dict coverdb; int weight_pq_w = 100; int weight_pq_b = 100; @@ -187,20 +212,49 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, int total_weight = weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; total_weight += weight_pq_mw + weight_pq_mb + weight_pq_mc + weight_pq_ms; - std::vector new_database; - xs128_t rng(opts.seed); + if (N >= GetSize(database)) + return; + + mutate_inner_queue_t primary_queue_wire; + mutate_inner_queue_t, mutate_leaf_queue_t> primary_queue_bit; + mutate_inner_queue_t primary_queue_cell; + mutate_inner_queue_t primary_queue_src; + + mutate_inner_queue_t> primary_queue_module_wire; + mutate_inner_queue_t, mutate_leaf_queue_t>> primary_queue_module_bit; + mutate_inner_queue_t> primary_queue_module_cell; + mutate_inner_queue_t> primary_queue_module_src; + + for (auto &m : database) + { + if (!m.wire.empty()) { + primary_queue_wire.add(&m, m.wire); + primary_queue_bit.add(&m, pair(m.wire, m.wirebit)); + primary_queue_module_wire.add(&m, m.module, m.wire); + primary_queue_module_bit.add(&m, m.module, pair(m.wire, m.wirebit)); + } + + primary_queue_cell.add(&m, m.cell); + primary_queue_module_cell.add(&m, m.module, m.cell); + + for (auto &s : m.src) { + coverdb[s] = 0; + primary_queue_src.add(&m, s); + primary_queue_module_src.add(&m, m.module, s); + } + } while (GetSize(new_database) < N) { int k = rng(total_weight); -#define X(__wght, __queue) \ - k -= __wght; \ - if (k < 0) { \ - mutate_t *m = __queue.pick(rng); \ - if (m != nullptr) \ - new_database.push_back(*m); \ - continue; \ +#define X(__wght, __queue) \ + k -= __wght; \ + if (k < 0) { \ + mutate_t *m = __queue.pick(rng, coverdb); \ + if (m != nullptr) \ + new_database.push_back(*m); \ + continue; \ } X(weight_pq_w, primary_queue_wire) @@ -215,11 +269,19 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, } std::swap(new_database, database); + + int covered_cnt = 0; + for (auto &it : coverdb) + if (it.second) + covered_cnt++; + + log("Covered %d/%d src attributes (%.2f%%).\n", covered_cnt, GetSize(coverdb), 100.0 * covered_cnt / GetSize(coverdb)); } void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N) { std::vector database; + xs128_t rng(opts.seed); for (auto module : design->selected_modules()) { @@ -260,20 +322,40 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena { for (int i = 0; i < GetSize(conn.second); i++) { mutate_t entry; - entry.mode = "inv"; - entry.src = cell->get_src_attribute(); - entry.module = module; - entry.cell = cell; - entry.cellport = conn.first; + entry.module = module->name; + entry.cell = cell->name; + entry.port = conn.first; entry.portbit = i; - if (cell->output(conn.first)) { - SigBit bit = sigmap(conn.second[i]); - if (bit.wire && bit.wire->name[0] == '\\') - entry.outsigbit = bit; + 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] == '\\') { + for (auto &s : bit.wire->get_strpool_attribute("\\src")) + entry.src.insert(s); + entry.wire = bit.wire->name; + entry.wirebit = bit.offset; } + 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); } } } @@ -281,7 +363,7 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena log("Raw database size: %d\n", GetSize(database)); if (N != 0) { - database_reduce(database, opts, N); + database_reduce(database, opts, N, rng); log("Reduced database size: %d\n", GetSize(database)); } @@ -300,21 +382,22 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena 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) + if (!entry.module.empty()) str += stringf(" -module %s", log_id(entry.module)); - if (entry.cell) + if (!entry.cell.empty()) str += stringf(" -cell %s", log_id(entry.cell)); - if (!entry.cellport.empty()) - str += stringf(" -port %s", log_id(entry.cellport)); + if (!entry.port.empty()) + str += stringf(" -port %s", log_id(entry.port)); if (entry.portbit >= 0) - str += stringf(" -bit %d", entry.portbit); - if (entry.outsigbit.wire || !entry.src.empty()) { - str += " #"; - if (!entry.src.empty()) - str += stringf(" %s", entry.src.c_str()); - if (entry.outsigbit.wire) - str += stringf(" %s", log_signal(entry.outsigbit)); - } + 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 @@ -375,18 +458,18 @@ 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.bit]; + 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.bit); + 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.bit); + 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)); @@ -394,7 +477,64 @@ void mutate_inv(Design *design, const mutate_opts_t &opts) } SigSpec s = cell->getPort(opts.port); - s[opts.bit] = bit; + 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); } @@ -422,7 +562,11 @@ struct MutatePass : public Pass { log(" -module name\n"); log(" -cell name\n"); log(" -port name\n"); - log(" -bit int\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"); @@ -438,9 +582,15 @@ struct MutatePass : public Pass { log(" -module name\n"); log(" -cell name\n"); log(" -port name\n"); - log(" -bit int\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 args, RTLIL::Design *design) YS_OVERRIDE { @@ -487,8 +637,24 @@ struct MutatePass : public Pass { opts.port = RTLIL::escape_id(args[++argidx]); continue; } - if (args[argidx] == "-bit" && argidx+1 < args.size()) { - opts.bit = atoi(args[++argidx].c_str()); + 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; } break; @@ -505,6 +671,16 @@ struct MutatePass : public Pass { 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; From 2a4263a75d0bbbc5b8f2de797b572d6f1d64818b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 23:01:01 +0100 Subject: [PATCH 085/132] Improve "mutate" wire coverage metric Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index eac00948a..243a1b48a 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -289,6 +289,21 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena continue; SigMap sigmap(module); + dict 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()) { @@ -331,7 +346,7 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena entry.src.insert(s); SigBit bit = sigmap(conn.second[i]); - if (bit.wire && bit.wire->name[0] == '\\') { + 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; From 4d304e3da77a571d1febfebca1409f522177af38 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 23:01:55 +0100 Subject: [PATCH 086/132] Add a strictly coverage-driven mutation selection strategy Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 71 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 243a1b48a..440e8b056 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -199,6 +199,8 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op std::vector new_database; dict coverdb; + int weight_cover = 500; + int weight_pq_w = 100; int weight_pq_b = 100; int weight_pq_c = 100; @@ -209,7 +211,7 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op int weight_pq_mc = 100; int weight_pq_ms = 100; - int total_weight = weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; + int total_weight = weight_cover + weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; total_weight += weight_pq_mw + weight_pq_mb + weight_pq_mc + weight_pq_ms; if (N >= GetSize(database)) @@ -244,10 +246,76 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op } } + vector cover_candidates; + int best_cover_score = -1; + bool skip_cover = false; + while (GetSize(new_database) < N) { int k = rng(total_weight); + k -= 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.at(s)) + this_score = coverdb.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.at(s)) + this_score = coverdb.at(s); + } + + if (this_score != best_cover_score) + continue; + + m = p; + break; + } + + if (m != nullptr) { + m->used = true; + for (auto &s : m->src) + coverdb[s]++; + new_database.push_back(*m); + break; + } + } + continue; + } + #define X(__wght, __queue) \ k -= __wght; \ if (k < 0) { \ @@ -266,6 +334,7 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op X(weight_pq_mb, primary_queue_module_bit) X(weight_pq_mc, primary_queue_module_cell) X(weight_pq_ms, primary_queue_module_src) +#undef X } std::swap(new_database, database); From 27a5d9c91e44dd04fa45e1e2aeff8c6d1cd50872 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 23:20:41 +0100 Subject: [PATCH 087/132] Add "mutate -cfg", improve pick_cover behavior Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 147 +++++++++++++++++++++++++++++-------------- 1 file changed, 101 insertions(+), 46 deletions(-) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 440e8b056..6b9eb3c04 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -42,8 +42,23 @@ struct mutate_opts_t { int portbit = -1; int ctrlbit = -1; int wirebit = -1; + IdString ctrl_name; - int ctrl_width, ctrl_value; + int ctrl_width = -1, ctrl_value = -1; + + int pick_cover_prcnt = 50; + + 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 &database, const mutate_opts_t &opts, const mutate_t &entry) @@ -122,25 +137,19 @@ struct mutate_leaf_queue_t { pool db; - mutate_t *pick(xs128_t &rng, dict &coverdb) { + mutate_t *pick(xs128_t &rng, dict &coverdb, const mutate_opts_t &opts) { mutate_t *m = nullptr; - if (rng(3)) { + if (rng(100) < opts.pick_cover_prcnt) { vector candidates; - int best_score = -1; for (auto p : db) { if (p->used || p->src.empty()) continue; - int this_score = -1; + bool is_covered = false; for (auto &s : p->src) { - if (this_score == -1 || this_score > coverdb.at(s)) - this_score = coverdb.at(s); + if (coverdb.at(s)) + is_covered = true; } - log_assert(this_score != -1); - if (best_score == -1 || this_score < best_score) { - candidates.clear(); - best_score = this_score; - } - if (best_score == this_score) + if (!is_covered) candidates.push_back(p); } if (!candidates.empty()) @@ -176,11 +185,11 @@ struct mutate_inner_queue_t { dict db; - mutate_t *pick(xs128_t &rng, dict &coverdb) { + mutate_t *pick(xs128_t &rng, dict &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); + mutate_t *m = it->second.pick(rng, coverdb, opts); if (m != nullptr) return m; db.erase(it); @@ -194,25 +203,13 @@ struct mutate_inner_queue_t } }; -void database_reduce(std::vector &database, const mutate_opts_t &/* opts */, int N, xs128_t &rng) +void database_reduce(std::vector &database, const mutate_opts_t &opts, int N, xs128_t &rng) { std::vector new_database; dict coverdb; - 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; - - int total_weight = weight_cover + weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; - total_weight += weight_pq_mw + weight_pq_mb + weight_pq_mc + weight_pq_ms; + 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; @@ -254,7 +251,7 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op { int k = rng(total_weight); - k -= weight_cover; + k -= opts.weight_cover; if (k < 0) { while (!skip_cover) { if (cover_candidates.empty()) { @@ -316,24 +313,24 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op continue; } -#define X(__wght, __queue) \ - k -= __wght; \ - if (k < 0) { \ - mutate_t *m = __queue.pick(rng, coverdb); \ - if (m != nullptr) \ - new_database.push_back(*m); \ - continue; \ +#define X(__wght, __queue) \ + k -= __wght; \ + if (k < 0) { \ + mutate_t *m = __queue.pick(rng, coverdb, opts); \ + if (m != nullptr) \ + new_database.push_back(*m); \ + continue; \ } - X(weight_pq_w, primary_queue_wire) - X(weight_pq_b, primary_queue_bit) - X(weight_pq_c, primary_queue_cell) - X(weight_pq_s, primary_queue_src) + 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(weight_pq_mw, primary_queue_module_wire) - X(weight_pq_mb, primary_queue_module_bit) - X(weight_pq_mc, primary_queue_module_cell) - X(weight_pq_ms, primary_queue_module_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 } @@ -654,6 +651,12 @@ struct MutatePass : public Pass { 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"); @@ -741,6 +744,58 @@ struct MutatePass : public Pass { 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); From d1985f6a223d18e0ae8545a620e4117fd4ca23b3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 15 Mar 2019 00:18:31 +0100 Subject: [PATCH 088/132] Improvements in "mutate" list-reduce algorithm Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 49 ++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 6b9eb3c04..4c103dcd5 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -133,7 +133,7 @@ struct xs128_t } }; -struct mutate_leaf_queue_t +struct mutate_queue_t { pool db; @@ -181,7 +181,7 @@ struct mutate_leaf_queue_t }; template -struct mutate_inner_queue_t +struct mutate_chain_queue_t { dict db; @@ -203,6 +203,29 @@ struct mutate_inner_queue_t } }; +template +struct mutate_once_queue_t +{ + dict db; + + mutate_t *pick(xs128_t &rng, dict &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 + void add(mutate_t *m, K key, Args... args) { + db[key].add(m, args...); + } +}; + void database_reduce(std::vector &database, const mutate_opts_t &opts, int N, xs128_t &rng) { std::vector new_database; @@ -214,26 +237,26 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, if (N >= GetSize(database)) return; - mutate_inner_queue_t primary_queue_wire; - mutate_inner_queue_t, mutate_leaf_queue_t> primary_queue_bit; - mutate_inner_queue_t primary_queue_cell; - mutate_inner_queue_t primary_queue_src; + mutate_once_queue_t, mutate_queue_t> primary_queue_wire; + mutate_once_queue_t, mutate_queue_t> primary_queue_bit; + mutate_once_queue_t, mutate_queue_t> primary_queue_cell; + mutate_once_queue_t primary_queue_src; - mutate_inner_queue_t> primary_queue_module_wire; - mutate_inner_queue_t, mutate_leaf_queue_t>> primary_queue_module_bit; - mutate_inner_queue_t> primary_queue_module_cell; - mutate_inner_queue_t> primary_queue_module_src; + mutate_chain_queue_t> primary_queue_module_wire; + mutate_chain_queue_t, mutate_queue_t>> primary_queue_module_bit; + mutate_chain_queue_t> primary_queue_module_cell; + mutate_chain_queue_t> primary_queue_module_src; for (auto &m : database) { if (!m.wire.empty()) { - primary_queue_wire.add(&m, m.wire); - primary_queue_bit.add(&m, pair(m.wire, m.wirebit)); + primary_queue_wire.add(&m, tuple(m.module, m.wire)); + primary_queue_bit.add(&m, tuple(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(m.wire, m.wirebit)); } - primary_queue_cell.add(&m, m.cell); + primary_queue_cell.add(&m, tuple(m.module, m.cell)); primary_queue_module_cell.add(&m, m.module, m.cell); for (auto &s : m.src) { From 9820ed6531f8bd3e30f44f59ae9c82bdc896f57c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 15 Mar 2019 00:48:23 +0100 Subject: [PATCH 089/132] Disable realmath tests Signed-off-by: Clifford Wolf --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b8fbcc040..2e4605f8b 100644 --- a/Makefile +++ b/Makefile @@ -575,7 +575,7 @@ test: $(TARGETS) $(EXTRA_TARGETS) +cd tests/simple && bash run-test.sh $(SEEDOPT) +cd tests/hana && 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/fsm && bash run-test.sh $(SEEDOPT) +cd tests/techmap && bash run-test.sh From 370db33a4c347049cb8f66c181d39fd2f2ce5e3a Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 15 Mar 2019 20:18:38 +0100 Subject: [PATCH 090/132] Add fmcombine pass Signed-off-by: Clifford Wolf --- kernel/celltypes.h | 45 ++++--- kernel/rtlil.cc | 4 +- passes/sat/Makefile.inc | 1 + passes/sat/fmcombine.cc | 292 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 325 insertions(+), 17 deletions(-) create mode 100644 passes/sat/fmcombine.cc diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 8b8a56111..ae88f4aaf 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -81,6 +81,27 @@ struct CellTypes } 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(), true); + setup_type("$assume", {A, EN}, pool(), true); + setup_type("$live", {A, EN}, pool(), true); + setup_type("$fair", {A, EN}, pool(), true); + setup_type("$cover", {A, EN}, pool(), true); + setup_type("$initstate", pool(), {Y}, true); + setup_type("$anyconst", pool(), {Y}, true); + setup_type("$anyseq", pool(), {Y}, true); + setup_type("$allconst", pool(), {Y}, true); + setup_type("$allseq", pool(), {Y}, true); + setup_type("$equiv", {A, B}, {Y}, true); + } + + void setup_internals_eval() { std::vector unary_ops = { "$not", "$pos", "$neg", @@ -111,20 +132,6 @@ struct CellTypes setup_type("$lcu", {P, G, CI}, {CO}, true); setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true); setup_type("$fa", {A, B, C}, {X, Y}, true); - - setup_type("$tribuf", {A, EN}, {Y}, true); - - setup_type("$assert", {A, EN}, pool(), true); - setup_type("$assume", {A, EN}, pool(), true); - setup_type("$live", {A, EN}, pool(), true); - setup_type("$fair", {A, EN}, pool(), true); - setup_type("$cover", {A, EN}, pool(), true); - setup_type("$initstate", pool(), {Y}, true); - setup_type("$anyconst", pool(), {Y}, true); - setup_type("$anyseq", pool(), {Y}, true); - setup_type("$allconst", pool(), {Y}, true); - setup_type("$allseq", pool(), {Y}, true); - setup_type("$equiv", {A, B}, {Y}, true); } void setup_internals_mem() @@ -153,6 +160,15 @@ struct CellTypes } 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 E = "\\E", F = "\\F", G = "\\G", H = "\\H"; @@ -179,7 +195,6 @@ struct CellTypes setup_type("$_OAI3_", {A, B, C}, {Y}, true); setup_type("$_AOI4_", {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() diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 7f1816190..d0fa88890 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -760,7 +760,7 @@ namespace { 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:") return; @@ -2360,7 +2360,7 @@ void RTLIL::Cell::check() 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:") return; diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index e91df1eb0..4eced2ff1 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -9,5 +9,6 @@ OBJS += passes/sat/assertpmux.o OBJS += passes/sat/clk2fflogic.o OBJS += passes/sat/async2sync.o OBJS += passes/sat/supercover.o +OBJS += passes/sat/fmcombine.o OBJS += passes/sat/mutate.o diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc new file mode 100644 index 000000000..b8a0e94c8 --- /dev/null +++ b/passes/sat/fmcombine.cc @@ -0,0 +1,292 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 FmcombineWorker +{ + Design *design; + Module *original = nullptr; + Module *module = nullptr; + IdString orig_type, combined_type; + + FmcombineWorker(Design *design, IdString orig_type) : + 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); + 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")); + } + + CellTypes ct; + ct.setup_internals_eval(); + ct.setup_stdcells_eval(); + + SigMap sigmap(module); + + dict data_bit_to_eq_net; + dict cell_to_eq_nets; + dict reduce_db; + dict 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 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); + } + + module->addAssume(NEW_ID, consequent, antecedent); + + 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"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + 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; + // } + 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 (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); + 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 From dacaebae35c81b4f4970af3ef8bfdb73691fa215 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 15 Mar 2019 21:45:37 +0100 Subject: [PATCH 091/132] Add "fmcombine -fwd -bwd -nop" Signed-off-by: Clifford Wolf --- passes/sat/fmcombine.cc | 69 +++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc index b8a0e94c8..cd75ca860 100644 --- a/passes/sat/fmcombine.cc +++ b/passes/sat/fmcombine.cc @@ -24,15 +24,23 @@ 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) : - design(design), original(design->module(orig_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()) { } @@ -63,7 +71,7 @@ struct FmcombineWorker 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); + FmcombineWorker sub_worker(design, cell->type, opts); sub_worker.generate(); Cell *c = module->addCell(cell->name.str() + "_combined", sub_worker.combined_type); @@ -106,6 +114,9 @@ struct FmcombineWorker 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(); @@ -184,15 +195,19 @@ struct FmcombineWorker consequent = reduce_db.at(consequent); } - module->addAssume(NEW_ID, consequent, antecedent); + if (opts.fwd) + module->addAssume(NEW_ID, consequent, antecedent); - if (invert_db.count(antecedent) == 0) - invert_db[antecedent] = module->Not(NEW_ID, 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); + 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)); + module->addAssume(NEW_ID, invert_db.at(antecedent), invert_db.at(consequent)); + } } } } @@ -214,9 +229,25 @@ struct FmcombinePass : public Pass { 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 args, RTLIL::Design *design) YS_OVERRIDE { + opts_t opts; Module *module = nullptr; Cell *gold_cell = nullptr; Cell *gate_cell = nullptr; @@ -230,6 +261,18 @@ struct FmcombinePass : public Pass { // 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()) @@ -262,6 +305,12 @@ struct FmcombinePass : public Pass { } // 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()) @@ -269,7 +318,7 @@ struct FmcombinePass : public Pass { if (!gate_cell->parameters.empty()) log_cmd_error("Gold cell has unresolved instance parameters.\n"); - FmcombineWorker worker(design, gold_cell->type); + 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))); From aa65d3fe65bd45994f8cb053daef3a5e52b31cd3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 16 Mar 2019 00:55:46 +0100 Subject: [PATCH 092/132] Improve mix of src/wire/wirebit coverage in "mutate -list" Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 115 ++++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 30 deletions(-) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 4c103dcd5..9621d2855 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -46,7 +46,7 @@ struct mutate_opts_t { IdString ctrl_name; int ctrl_width = -1, ctrl_value = -1; - int pick_cover_prcnt = 50; + int pick_cover_prcnt = 80; int weight_cover = 500; @@ -133,25 +133,69 @@ struct xs128_t } }; +struct coverdb_t +{ + dict src_db; + dict, int> wire_db; + dict, int> wirebit_db; + + void insert(const mutate_t &m) { + if (!m.wire.empty()) { + wire_db[tuple(m.module, m.wire)] = 0; + wirebit_db[tuple(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(m.module, m.wire))++; + wirebit_db.at(tuple(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(m.module, m.wire)) ? 0 : 5; + this_score += wirebit_db.at(tuple(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 db; - mutate_t *pick(xs128_t &rng, dict &coverdb, const mutate_opts_t &opts) { + 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 candidates; + vector candidates, rmqueue; + int best_score = -1; for (auto p : db) { - if (p->used || p->src.empty()) + if (p->used) { + rmqueue.push_back(p); continue; - bool is_covered = false; - for (auto &s : p->src) { - if (coverdb.at(s)) - is_covered = true; } - if (!is_covered) + 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))]; } @@ -167,11 +211,6 @@ struct mutate_queue_t } } } - if (m != nullptr) { - m->used = true; - for (auto &s : m->src) - coverdb[s]++; - } return m; } @@ -185,7 +224,7 @@ struct mutate_chain_queue_t { dict db; - mutate_t *pick(xs128_t &rng, dict &coverdb, const mutate_opts_t &opts) { + 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); @@ -208,7 +247,7 @@ struct mutate_once_queue_t { dict db; - mutate_t *pick(xs128_t &rng, dict &coverdb, const mutate_opts_t &opts) { + 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); @@ -229,7 +268,7 @@ struct mutate_once_queue_t void database_reduce(std::vector &database, const mutate_opts_t &opts, int N, xs128_t &rng) { std::vector new_database; - dict coverdb; + 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; @@ -249,6 +288,8 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, for (auto &m : database) { + coverdb.insert(m); + if (!m.wire.empty()) { primary_queue_wire.add(&m, tuple(m.module, m.wire)); primary_queue_bit.add(&m, tuple(m.module, m.wire, m.wirebit)); @@ -260,7 +301,6 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, primary_queue_module_cell.add(&m, m.module, m.cell); for (auto &s : m.src) { - coverdb[s] = 0; primary_queue_src.add(&m, s); primary_queue_module_src.add(&m, m.module, s); } @@ -284,8 +324,8 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, continue; int this_score = -1; for (auto &s : m.src) { - if (this_score == -1 || this_score > coverdb.at(s)) - this_score = coverdb.at(s); + 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) { @@ -314,8 +354,8 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, int this_score = -1; for (auto &s : p->src) { - if (this_score == -1 || this_score > coverdb.at(s)) - this_score = coverdb.at(s); + if (this_score == -1 || this_score > coverdb.src_db.at(s)) + this_score = coverdb.src_db.at(s); } if (this_score != best_cover_score) @@ -327,8 +367,7 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, if (m != nullptr) { m->used = true; - for (auto &s : m->src) - coverdb[s]++; + coverdb.update(*m); new_database.push_back(*m); break; } @@ -340,8 +379,11 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, k -= __wght; \ if (k < 0) { \ mutate_t *m = __queue.pick(rng, coverdb, opts); \ - if (m != nullptr) \ + if (m != nullptr) { \ + m->used = true; \ + coverdb.update(*m); \ new_database.push_back(*m); \ + }; \ continue; \ } @@ -359,12 +401,25 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, std::swap(new_database, database); - int covered_cnt = 0; - for (auto &it : coverdb) - if (it.second) - covered_cnt++; + int covered_src_cnt = 0; + int covered_wire_cnt = 0; + int covered_wirebit_cnt = 0; - log("Covered %d/%d src attributes (%.2f%%).\n", covered_cnt, GetSize(coverdb), 100.0 * covered_cnt / GetSize(coverdb)); + 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, int N) From a71c38f163a1972b2da8883b7043b25dd8e2662d Mon Sep 17 00:00:00 2001 From: Felix Vietmeyer Date: Sat, 16 Mar 2019 06:20:59 -0600 Subject: [PATCH 093/132] Add note about test requirements in README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9bac468a7..c5cd47707 100644 --- a/README.md +++ b/README.md @@ -105,12 +105,15 @@ Makefile. To build Yosys simply type 'make' in this directory. $ make - $ make test $ sudo make install Note that this also downloads, builds and installs ABC (using yosys-abc 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 =============== From 6aae502a3647b50e3f5c0f7d02e8056acf080920 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 17 Mar 2019 12:44:23 +0100 Subject: [PATCH 094/132] Update issue template Signed-off-by: Clifford Wolf --- .github/issue_template.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/issue_template.md b/.github/issue_template.md index 4563a71de..22ad6f839 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -4,6 +4,14 @@ all necessary source files. (You can simply drag&drop a .zip file into the issue editor.)* +Also, make sure that the issue is actually reproducable in current git +master of Yosys. + +Please do not waste our time with issues that don't contain 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 *Please describe the behavior you would have expected from the tool.* From 90bce0415622a3d7a64bca5914a0fb3abdd3cc5c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 17 Mar 2019 12:53:47 +0100 Subject: [PATCH 095/132] Update issue template Signed-off-by: Clifford Wolf --- .github/issue_template.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/issue_template.md b/.github/issue_template.md index 22ad6f839..5a0723c3e 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -7,8 +7,11 @@ the issue editor.)* Also, make sure that the issue is actually reproducable in current git master of Yosys. -Please do not waste our time with issues that don't contain sufficient -information to reproduce the issue easily. We will simply close those issues. +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. @@ -19,6 +22,3 @@ Contact https://www.symbioticeda.com/ if you need commercial support for Yosys. ## Actual 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. From a5f4b836376e1457847da4946c1e12d2d41dc4f4 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 18 Mar 2019 20:34:21 -0400 Subject: [PATCH 096/132] fix local name resolution in prefix constructs --- frontends/ast/simplify.cc | 6 +++- tests/simple/generate.v | 58 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 1c9932ee0..d525c6b8a 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2863,7 +2863,11 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma for (size_t i = 0; i < children.size(); 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); } diff --git a/tests/simple/generate.v b/tests/simple/generate.v index 24eb4462c..3c55682cb 100644 --- a/tests/simple/generate.v +++ b/tests/simple/generate.v @@ -90,5 +90,61 @@ generate endcase end endgenerate - +endmodule + +// ------------------------------------------ + +module gen_test4(a, b); + +input [3:0] a; +output [3:0] b; + +genvar i; +generate + for (i=0; i < 3; i=i+1) begin : foo + localparam PREV = i - 1; + wire temp; + if (i == 0) + assign temp = a[0]; + else + assign temp = foo[PREV].temp & a[i]; + assign b[i] = temp; + end +endgenerate +endmodule + +// ------------------------------------------ + +module gen_test5(input_bits, out); + +parameter WIDTH = 256; +parameter CHUNK = 4; + +input [WIDTH-1:0] input_bits; +output out; + +genvar step, i, j; +generate + for (step = 1; step <= WIDTH; step = step * CHUNK) begin : steps + localparam PREV = step / CHUNK; + localparam DIM = WIDTH / step; + for (i = 0; i < DIM; i = i + 1) begin : outer + localparam LAST_START = i * CHUNK; + for (j = 0; j < CHUNK; j = j + 1) begin : inner + wire temp; + if (step == 1) + assign temp = input_bits[i]; + else if (j == 0) + assign temp = steps[PREV].outer[LAST_START].val; + else + assign temp + = steps[step].outer[i].inner[j-1].temp + & steps[PREV].outer[LAST_START + j].val; + end + wire val; + assign val = steps[step].outer[i].inner[CHUNK - 1].temp; + end + end +endgenerate +assign out = steps[WIDTH].outer[0].val; endmodule From 3e89cf68bdc4e9eeb55bd9450121f421bcdc554a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Mar 2019 08:52:06 -0700 Subject: [PATCH 097/132] Add author name --- frontends/aiger/aigerparse.h | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h index 39a77bd93..c49cd152d 100644 --- a/frontends/aiger/aigerparse.h +++ b/frontends/aiger/aigerparse.h @@ -2,6 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf + * Eddie Hung * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above From fe1fb1336b44bb073125aa4b42f12baa316e9fea Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 19 Mar 2019 20:29:54 +0100 Subject: [PATCH 098/132] Add Xilinx negedge FFs to synth_xilinx dffinit call, fixes #873 Signed-off-by: Clifford Wolf --- techlibs/xilinx/synth_xilinx.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index accc7a259..805ae8e6e 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -120,7 +120,8 @@ struct SynthXilinxPass : public Pass log("\n"); log(" map_cells:\n"); log(" techmap -map +/xilinx/cells_map.v\n"); - log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE 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("\n"); log(" check:\n"); @@ -274,7 +275,8 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "map_cells")) { Pass::call(design, "techmap -map +/xilinx/cells_map.v"); - Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT"); + Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " + "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); Pass::call(design, "clean"); } From 9b0e7af6d7c84d9b252acbe0fbbf596c75fc1498 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Mar 2019 20:52:29 +0100 Subject: [PATCH 099/132] Improve read_verilog debug output capabilities Signed-off-by: Clifford Wolf --- frontends/ast/ast.cc | 26 +++++++++++++++--------- frontends/ast/ast.h | 2 +- frontends/verilog/verilog_frontend.cc | 29 ++++++++++++++++++++++----- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 5a1bae7a7..0442ea0db 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -45,7 +45,7 @@ namespace AST { // instantiate global variables (private API) 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; AstNode *current_ast, *current_ast_mod; std::map current_scope; @@ -562,7 +562,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const case AST_CONCAT: fprintf(f, "{"); - for (auto child : children) { + for (int i = GetSize(children)-1; i >= 0; i--) { + auto child = children[i]; if (!first) fprintf(f, ", "); child->dumpVlog(f, ""); @@ -926,23 +927,28 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast ast_before_simplify = ast->clone(); if (flag_dump_ast1) { - log("Dumping Verilog AST before simplification:\n"); + log("Dumping AST before simplification:\n"); ast->dumpAst(NULL, " "); 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) { while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { } if (flag_dump_ast2) { - log("Dumping Verilog AST after simplification:\n"); + log("Dumping AST after simplification:\n"); ast->dumpAst(NULL, " "); log("--- END OF AST DUMP ---\n"); } - if (flag_dump_vlog) { - log("Dumping Verilog AST (as requested by dump_vlog option):\n"); + if (flag_dump_vlog2) { + log("Dumping Verilog AST after simplification:\n"); ast->dumpVlog(NULL, " "); log("--- END OF AST DUMP ---\n"); } @@ -1016,14 +1022,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' -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) { current_ast = ast; flag_dump_ast1 = dump_ast1; flag_dump_ast2 = dump_ast2; 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_nolatches = nolatches; flag_nomeminit = nomeminit; @@ -1357,7 +1364,8 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict Date: Thu, 21 Mar 2019 22:20:16 +0100 Subject: [PATCH 100/132] Improve "read_verilog -dump_vlog[12]" handling of upto ranges Signed-off-by: Clifford Wolf --- frontends/ast/ast.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 0442ea0db..d48996167 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -431,9 +431,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const break; case AST_RANGE: - if (range_valid) - fprintf(f, "[%d:%d]", range_left, range_right); - else { + if (range_valid) { + if (range_swapped) + fprintf(f, "[%d:%d]", range_right, range_left); + else + fprintf(f, "[%d:%d]", range_left, range_right); + } else { for (auto child : children) { fprintf(f, "%c", first ? '[' : ':'); child->dumpVlog(f, ""); From 638be461c3a6d33aa294700249ee0bc27da69403 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Mar 2019 22:19:17 +0100 Subject: [PATCH 101/132] Fix mem2reg handling of memories with upto data ports, fixes #888 Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index d525c6b8a..63b71b800 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -138,9 +138,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int 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++) { 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->is_reg = true; reg->is_signed = node->is_signed; @@ -976,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_right = id2ast->children[0]->range_right; + if (id2ast->children[0]->range_swapped) + std::swap(data_range_left, data_range_right); + std::stringstream sstr; sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string wire_id = sstr.str(); From 7cfd83c3415dd3d576539e00b91b6e283997fe52 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 22 Mar 2019 11:42:19 +0100 Subject: [PATCH 102/132] Trim init attributes when resizing FFs in "wreduce", fixes #887 Signed-off-by: Clifford Wolf --- passes/opt/wreduce.cc | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 1f7222e49..52245ce3e 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -54,6 +54,7 @@ struct WreduceWorker std::set work_queue_bits; pool keep_bits; dict init_bits; + pool remove_init_bits; WreduceWorker(WreduceConfig *config, Module *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)) { module->connect(sig_q[i], State::S0); + remove_init_bits.insert(sig_q[i]); sig_d.remove(i); sig_q.remove(i); continue; @@ -171,6 +173,7 @@ struct WreduceWorker 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]); + remove_init_bits.insert(sig_q[i]); sig_d.remove(i); sig_q.remove(i); continue; @@ -178,6 +181,7 @@ struct WreduceWorker auto info = mi.query(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_q.remove(i); zero_ext = false; @@ -387,13 +391,16 @@ struct WreduceWorker 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()) { if (w->get_bool_attribute("\\keep")) for (auto bit : mi.sigmap(w)) keep_bits.insert(bit); if (w->attributes.count("\\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)); for (int i = 0; i < width; i++) init_bits[initsig[i]] = initval[i]; @@ -446,6 +453,24 @@ struct WreduceWorker module->connect(nw, SigSpec(w).extract(0, GetSize(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); + } + } + } } }; From 46f6a60d583d32289d70ed532c27e6cbc5ee47ed Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Mar 2019 13:57:17 +0000 Subject: [PATCH 103/132] xilinx: Add keep attribute where appropriate Signed-off-by: David Shah --- techlibs/xilinx/cells_xtra.sh | 13 ++++++----- techlibs/xilinx/cells_xtra.v | 43 +++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh index 37c3e5480..56520ea10 100644 --- a/techlibs/xilinx/cells_xtra.sh +++ b/techlibs/xilinx/cells_xtra.sh @@ -7,6 +7,7 @@ function xtract_cell_decl() { for dir in $libdir/xeclib $libdir/retarget; do [ -f $dir/$1.v ] || continue + [ -z "$2" ] || echo $2 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; s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/; @@ -37,10 +38,10 @@ function xtract_cell_decl() xtract_cell_decl BUFMR xtract_cell_decl BUFMRCE xtract_cell_decl BUFR - xtract_cell_decl CAPTUREE2 + xtract_cell_decl CAPTUREE2 "(* keep *)" # xtract_cell_decl CARRY4 xtract_cell_decl CFGLUT5 - xtract_cell_decl DCIRESET + xtract_cell_decl DCIRESET "(* keep *)" xtract_cell_decl DNA_PORT xtract_cell_decl DSP48E1 xtract_cell_decl EFUSE_USR @@ -67,10 +68,10 @@ function xtract_cell_decl() xtract_cell_decl IBUFDS_GTE2 xtract_cell_decl IBUFDS_IBUFDISABLE xtract_cell_decl IBUFDS_INTERMDISABLE - xtract_cell_decl ICAPE2 + xtract_cell_decl ICAPE2 "(* keep *)" xtract_cell_decl IDDR xtract_cell_decl IDDR_2CLK - xtract_cell_decl IDELAYCTRL + xtract_cell_decl IDELAYCTRL "(* keep *)" xtract_cell_decl IDELAYE2 xtract_cell_decl IN_FIFO xtract_cell_decl IOBUF @@ -112,7 +113,7 @@ function xtract_cell_decl() xtract_cell_decl PHY_CONTROL xtract_cell_decl PLLE2_ADV xtract_cell_decl PLLE2_BASE - xtract_cell_decl PS7 + xtract_cell_decl PS7 "(* keep *)" xtract_cell_decl PULLDOWN xtract_cell_decl PULLUP xtract_cell_decl RAM128X1D @@ -136,7 +137,7 @@ function xtract_cell_decl() xtract_cell_decl ROM64X1 xtract_cell_decl SRL16E xtract_cell_decl SRLC32E - xtract_cell_decl STARTUPE2 + xtract_cell_decl STARTUPE2 "(* keep *)" xtract_cell_decl USR_ACCESSE2 xtract_cell_decl XADC } > cells_xtra.new diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index 995d62e18..497518d35 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -114,6 +114,7 @@ module BUFR (...); parameter SIM_DEVICE = "7SERIES"; endmodule +(* keep *) module CAPTUREE2 (...); parameter ONESHOT = "TRUE"; input CAP; @@ -130,6 +131,7 @@ module CFGLUT5 (...); input CDI, CE, CLK; endmodule +(* keep *) module DCIRESET (...); output LOCKED; input RST; @@ -2102,6 +2104,7 @@ module IBUFDS_INTERMDISABLE (...); input INTERMDISABLE; endmodule +(* keep *) module ICAPE2 (...); parameter [31:0] DEVICE_ID = 32'h04244093; parameter ICAP_WIDTH = "X32"; @@ -2149,6 +2152,7 @@ module IDDR_2CLK (...); input S; endmodule +(* keep *) module IDELAYCTRL (...); parameter SIM_DEVICE = "7SERIES"; output RDY; @@ -3057,6 +3061,7 @@ module PLLE2_BASE (...); input RST; endmodule +(* keep *) module PS7 (...); output DMA0DAVALID; output DMA0DRREADY; @@ -3688,6 +3693,17 @@ module PULLUP (...); output O; 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 (...); parameter [127:0] INIT = 128'h00000000000000000000000000000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; @@ -3695,25 +3711,6 @@ module RAM128X1S (...); input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE; endmodule -module RAM128X1D ( - output DPO, SPO, - input D, WCLK, WE, - input [6:0] A, DPRA -); - parameter [127:0] INIT = 128'bx; - parameter IS_WCLK_INVERTED = 0; -endmodule - -module RAM64X1D ( - output DPO, SPO, - input D, WCLK, WE, - input A0, A1, A2, A3, A4, A5, - input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 -); - parameter [63:0] INIT = 64'bx; - parameter IS_WCLK_INVERTED = 0; -endmodule - module RAM256X1S (...); parameter [255:0] INIT = 256'h0; parameter [0:0] IS_WCLK_INVERTED = 1'b0; @@ -3797,6 +3794,13 @@ module RAM64M (...); input WE; 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 (...); parameter [63:0] INIT = 64'h0000000000000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; @@ -3859,6 +3863,7 @@ module SRLC32E (...); input CE, CLK, D; endmodule +(* keep *) module STARTUPE2 (...); parameter PROG_USR = "FALSE"; parameter real SIM_CCLK_FREQ = 0.0; From 3b796c033cc40a753e24f21b25b2701a30f022f1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 23 Mar 2019 14:38:48 +0100 Subject: [PATCH 104/132] Add RTLIL::Const::ext[su](), fix RTLIL::SigSpec::extend_u0 for 0-size signals Signed-off-by: Clifford Wolf --- kernel/rtlil.cc | 2 +- kernel/rtlil.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d0fa88890..b3214579d 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3237,7 +3237,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) remove(width, 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) padding = RTLIL::State::S0; while (width_ < width) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 01323d112..52496e702 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -546,6 +546,14 @@ struct RTLIL::Const 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 { unsigned int h = mkhash_init; for (auto b : bits) From e78f5a3055cae54c44303bab187ad2ef11205ca3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 23 Mar 2019 14:39:42 +0100 Subject: [PATCH 105/132] Fix BTOR output tags syntax in writye_btor Signed-off-by: Clifford Wolf --- backends/btor/btor.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 53359bd7b..96044e339 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -932,9 +932,8 @@ struct BtorWorker btorf_push(stringf("output %s", log_id(wire))); - int sid = get_bv_sid(GetSize(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))); } From 1eff8be8f018bd6b94efd14a959d6f1807dd056d Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 23 Mar 2019 14:40:01 +0100 Subject: [PATCH 106/132] Add support for memory initialization to write_btor Signed-off-by: Clifford Wolf --- backends/btor/btor.cc | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 96044e339..55c494996 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -615,6 +615,7 @@ struct BtorWorker { int abits = cell->getParam("\\ABITS").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 wrports = cell->getParam("\\WR_PORTS").as_int(); @@ -641,6 +642,52 @@ struct BtorWorker int data_sid = get_bv_sid(width); int bool_sid = get_bv_sid(1); 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_head = nid; @@ -649,6 +696,12 @@ struct BtorWorker else 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) { for (int port = 0; port < wrports; port++) From 59c44bb61ab1a69a7ba4cd8d2b6d8d3e3408d9ca Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 23 Mar 2019 17:53:09 +0100 Subject: [PATCH 107/132] Add "mutate -s " Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 9621d2855..7025a7aca 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -422,8 +422,9 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, 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, int N) +void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, const string &srcsfile, int N) { + pool sources; std::vector database; xs128_t rng(opts.seed); @@ -497,6 +498,9 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena entry.wirebit = bit.offset; } + if (!srcsfile.empty()) + sources.insert(entry.src.begin(), entry.src.end()); + entry.mode = "inv"; database_add(database, opts, entry); @@ -526,6 +530,16 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena 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()) { @@ -710,6 +724,9 @@ struct MutatePass : public Pass { 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"); @@ -761,6 +778,7 @@ struct MutatePass : public Pass { { mutate_opts_t opts; string filename; + string srcsfile; int N = -1; log_header(design, "Executing MUTATE pass.\n"); @@ -776,6 +794,10 @@ struct MutatePass : public Pass { 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; @@ -879,7 +901,7 @@ struct MutatePass : public Pass { extra_args(args, argidx, design); if (N >= 0) { - mutate_list(design, opts, filename, N); + mutate_list(design, opts, filename, srcsfile, N); return; } From ccfa2fe01cffcc4d23bc989e558bd33addfea58e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 23 Mar 2019 20:20:32 +0100 Subject: [PATCH 108/132] Add "mutate -none -mode", "mutate -mode none" Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 7025a7aca..c50678c51 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -46,6 +46,8 @@ struct mutate_opts_t { IdString ctrl_name; int ctrl_width = -1, ctrl_value = -1; + bool none = false; + int pick_cover_prcnt = 80; int weight_cover = 500; @@ -526,7 +528,7 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena log("Raw database size: %d\n", GetSize(database)); if (N != 0) { - database_reduce(database, opts, N, rng); + database_reduce(database, opts, opts.none ? N-1 : N, rng); log("Reduced database size: %d\n", GetSize(database)); } @@ -550,6 +552,17 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena 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()) @@ -730,6 +743,9 @@ struct MutatePass : public Pass { 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"); @@ -802,6 +818,10 @@ struct MutatePass : public Pass { 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; @@ -905,6 +925,15 @@ struct MutatePass : public Pass { 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; From 2507d01b03cb4ec0a1345532d22688dd9a623948 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 23 Mar 2019 16:45:36 -0700 Subject: [PATCH 109/132] Add a pmux-to-shiftx optimisation to proc_mux --- passes/proc/proc_mux.cc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index 1329c1fef..7cac0327b 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -340,6 +340,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d // evaluate in reverse order to give the first entry the top priority RTLIL::SigSpec initial_val = result; RTLIL::Cell *last_mux_cell = NULL; + bool shiftx = true; for (size_t i = 0; i < sw->cases.size(); i++) { int case_idx = sw->cases.size() - i - 1; RTLIL::CaseRule *cs2 = sw->cases[case_idx]; @@ -348,6 +349,26 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode); else result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode); + + // Ignore output values which are entirely don't care + if (shiftx && !value.is_fully_undef()) { + // Keep checking if case condition is the same as the current case index + if (cs2->compare.size() == 1 && cs2->compare.front().is_fully_const()) + shiftx = (cs2->compare.front().as_int() == case_idx); + } + } + + // Transform into a $shiftx if possible + if (shiftx && last_mux_cell->type == "$pmux") { + // Sanity check that A port of $pmux should be 'bx + log_assert(last_mux_cell->getPort("\\A").is_fully_undef()); + // Because we went in reverse order above, un-reverse its B port here + auto b_port = last_mux_cell->getPort("\\B").chunks(); + std::reverse(b_port.begin(), b_port.end()); + // Create a $shiftx that shifts by the address line used in the case statement + mod->addShiftx(NEW_ID, b_port, sw->signal, last_mux_cell->getPort("\\Y")); + // Disconnect $pmux by replacing its output port with a floating wire + last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, last_mux_cell->getParam("\\WIDTH").as_int())); } } From ac6cc88db352938d8dd9f2f9c6d404663674538e Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 24 Mar 2019 16:21:36 +0000 Subject: [PATCH 110/132] memory_bram: Fix multiclock make_transp Signed-off-by: David Shah --- passes/memory/memory_bram.cc | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index cf4095d06..c38eabaee 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -542,7 +542,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, } // assign write ports - + pair wr_clkdom; 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; @@ -552,7 +552,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, pair clkdom(clksig, clkpol); if (!clken) clkdom = pair(State::S1, false); - + wr_clkdom = clkdom; log(" Write port #%d is in clock domain %s%s.\n", cell_port_i, clkdom.second ? "" : "!", clken ? log_signal(clkdom.first) : "~async~"); @@ -718,7 +718,13 @@ grow_read_ports:; if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) { if (match.make_transp && wr_ports <= 1) { pi.make_transp = true; - enable_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; + } } else { log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); goto skip_bram_rport; @@ -913,17 +919,18 @@ grow_read_ports:; } else { SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits); c->setPort(stringf("\\%sDATA", pf), bram_dout); - - if (pi.make_outreg) { + if (pi.make_outreg && pi.make_transp) { + 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); if (!pi.sig_en.empty()) 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); bram_dout = bram_dout_q; - } - - if (pi.make_transp) - { + } else if (pi.make_transp) { 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), From 3b3b77291a21ed23a2763c79335501beebb10746 Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Sun, 24 Mar 2019 22:54:18 +0100 Subject: [PATCH 111/132] Updated the liberty parser to accept [A:B] ranges (AST has not been updated). Liberty parser now also accepts key : value pair lines that do not end in ';'. --- passes/techmap/libparse.cc | 87 +++++++- passes/techmap/libparse.h | 10 +- tests/liberty/.gitignore | 2 + tests/liberty/busdef.lib | 81 +++++++ tests/liberty/normal.lib | 360 +++++++++++++++++++++++++++++++ tests/liberty/run-test.sh | 10 + tests/liberty/semicolmissing.lib | 72 +++++++ tests/liberty/small.v | 16 ++ 8 files changed, 631 insertions(+), 7 deletions(-) create mode 100644 tests/liberty/.gitignore create mode 100644 tests/liberty/busdef.lib create mode 100644 tests/liberty/normal.lib create mode 100755 tests/liberty/run-test.sh create mode 100644 tests/liberty/semicolmissing.lib create mode 100644 tests/liberty/small.v diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 3927a657b..878ca3160 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -24,6 +24,7 @@ #include #include #include +#include #ifndef FILTERLIB #include "kernel/log.h" @@ -86,15 +87,17 @@ int LibertyParser::lexer(std::string &str) { int c; + // eat whitespace do { c = f.get(); } 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; while (1) { 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; else 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 == '"') { str = ""; while (1) { @@ -125,9 +130,10 @@ int LibertyParser::lexer(std::string &str) return 'v'; } + // if it wasn't a string, perhaps it's a comment or a forward slash? if (c == '/') { c = f.get(); - if (c == '*') { + if (c == '*') { // start of '/*' block comment int last_c = 0; while (c > 0 && (last_c != '*' || c != '/')) { last_c = c; @@ -136,7 +142,7 @@ int LibertyParser::lexer(std::string &str) line++; } return lexer(str); - } else if (c == '/') { + } else if (c == '/') { // start of '//' line comment while (c > 0 && c != '\n') c = f.get(); line++; @@ -144,9 +150,10 @@ int LibertyParser::lexer(std::string &str) } f.unget(); // fprintf(stderr, "LEX: char >>/<<\n"); - return '/'; + return '/'; // a single '/' charater. } + // check for a backslash if (c == '\\') { c = f.get(); if (c == '\r') @@ -157,11 +164,15 @@ int LibertyParser::lexer(std::string &str) return '\\'; } + // check for a new line if (c == '\n') { line++; return 'n'; } + // anything else, such as ';' will get passed + // through as literal items. + // if (c >= 32 && c < 255) // fprintf(stderr, "LEX: char >>%c<<\n", c); // else @@ -210,7 +221,12 @@ LibertyAst *LibertyParser::parse() ast->value += 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; else error(); @@ -225,6 +241,48 @@ LibertyAst *LibertyParser::parse() continue; if (tok == ')') 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') + { + // 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') error(); ast->args.push_back(arg); @@ -255,6 +313,14 @@ void LibertyParser::error() 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 void LibertyParser::error() @@ -263,6 +329,15 @@ void LibertyParser::error() 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 ****/ #define CHECK_NV(result, check) \ diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index cf6325570..c9ebd06c5 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -46,9 +46,17 @@ namespace Yosys LibertyAst *ast; LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {} ~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); - LibertyAst *parse(); + + LibertyAst *parse(); void error(); + void error(const std::string &str); }; } diff --git a/tests/liberty/.gitignore b/tests/liberty/.gitignore new file mode 100644 index 000000000..e6ec49c4a --- /dev/null +++ b/tests/liberty/.gitignore @@ -0,0 +1,2 @@ +*.log +test.ys diff --git a/tests/liberty/busdef.lib b/tests/liberty/busdef.lib new file mode 100644 index 000000000..b5e3d50b9 --- /dev/null +++ b/tests/liberty/busdef.lib @@ -0,0 +1,81 @@ +/********************************************/ +/* */ +/* Supergate cell library for Bench marking */ +/* */ +/* Symbiotic EDA GmbH / Moseley Instruments */ +/* Niels A. Moseley */ +/* */ +/* Process: none */ +/* */ +/* Date : 02-11-2018 */ +/* Version: 1.0 */ +/* */ +/********************************************/ + +library(supergate) { + technology (cmos); + revision : 1.0; + + time_unit : "1ps"; + pulling_resistance_unit : "1kohm"; + voltage_unit : "1V"; + current_unit : "1uA"; + + capacitive_load_unit(1,ff); + + default_inout_pin_cap : 7.0; + default_input_pin_cap : 7.0; + default_output_pin_cap : 0.0; + default_fanout_load : 1.0; + + default_wire_load_capacitance : 0.1; + default_wire_load_resistance : 1.0e-3; + default_wire_load_area : 0.0; + + nom_process : 1.0; + nom_temperature : 25.0; + nom_voltage : 1.2; + + delay_model : generic_cmos; + + type( IO_bus_3_to_0 ) { + base_type : array ; + data_type : bit ; + bit_width : 4; + bit_from : 3 ; + bit_to : 0 ; + downto : true ; + } + + cell (SRAM) { + area : 1 ; + memory() { + type : ram; + address_width : 4; + word_width : 4; + } + pin(CE1) { + direction : input; + capacitance : 0.021; + max_transition : 1.024; + switch_pin : true; + } + bus(I1) { + bus_type : IO_bus_3_to_0 ; + direction : input; + pin (I1[3:0]) { + timing() { + related_pin : "CE1" ; + timing_type : setup_rising ; + rise_constraint (scalar) { + values("0.0507786"); + } + fall_constraint (scalar) { + values("0.0507786"); + } + } + } + } + } + +} /* end */ diff --git a/tests/liberty/normal.lib b/tests/liberty/normal.lib new file mode 100644 index 000000000..1474e2b59 --- /dev/null +++ b/tests/liberty/normal.lib @@ -0,0 +1,360 @@ +/********************************************/ +/* */ +/* Supergate cell library for Bench marking */ +/* */ +/* Symbiotic EDA GmbH / Moseley Instruments */ +/* Niels A. Moseley */ +/* */ +/* Process: none */ +/* */ +/* Date : 02-11-2018 */ +/* Version: 1.0 */ +/* */ +/********************************************/ + +library(supergate) { + technology (cmos); + revision : 1.0; + + time_unit : "1ps"; + pulling_resistance_unit : "1kohm"; + voltage_unit : "1V"; + current_unit : "1uA"; + + capacitive_load_unit(1,ff); + + default_inout_pin_cap : 7.0; + default_input_pin_cap : 7.0; + default_output_pin_cap : 0.0; + default_fanout_load : 1.0; + + default_wire_load_capacitance : 0.1; + default_wire_load_resistance : 1.0e-3; + default_wire_load_area : 0.0; + + nom_process : 1.0; + nom_temperature : 25.0; + nom_voltage : 1.2; + + delay_model : generic_cmos; + + /* Inverter */ + cell (inv) { + area : 1; + pin(A) { + direction : input; + } + + pin(Y) { + direction : output; + function : "A'"; + } + } + + /* tri-state inverter */ + cell (tri_inv) { + area : 4; + pin(A) { + direction : input; + } + pin(S) { + direction : input; + } + pin(Z) { + direction : output; + function : "A'"; + three_State : "S'"; + } + } + + cell (buffer) { + area : 5; + pin(A) { + direction : input; + } + pin(Y) { + direction : output; + function : "A"; + } + } + + /* 2-input NAND gate */ + cell (nand2) { + area : 3; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(Y) { + direction: output; + function : "(A * B)'"; + } + } + + /* 2-input NOR gate */ + cell (nor2) { + area : 3; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(Y) { + direction: output; + function : "(A + B)'"; + } + } + + /* 2-input XOR */ + cell (xor2) { + area : 6; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(Y) { + direction: output; + function : "(A *B') + (A' * B)"; + } + } + + /* 2-input inverting MUX */ + cell (imux2) { + area : 5; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(S) { + direction : input; + } + pin(Y) { + direction: output; + function : "( (A * S) + (B * S') )'"; + } + } + + /* D-type flip-flop with asynchronous reset and preset */ + cell (dff) + { + area : 6; + ff("IQ", "IQN") { + next_state : "D"; + clocked_on : "CLK"; + clear : "RESET"; + preset : "PRESET"; + clear_preset_var1 : L; + clear_preset_var2 : L; + } + pin(D) { + direction : input; + } + pin(CLK) { + direction : input; + } + pin(RESET) { + direction : input; + } + pin(PRESET) { + direction : input; + } + pin(Q) { + direction: output; + function : "IQ"; + timing() { + timing_type : rising_edge; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "CLK"; + } + timing () { + timing_type : clear; + timing_sense : positive_unate; + intrinsic_fall : 75; + related_pin : "RESET"; + } + timing () { + timing_type : preset; + timing_sense : negative_unate; + intrinsic_rise : 75; + related_pin : "PRESET"; + } + } + pin(QN) { + direction: output; + function : "IQN"; + timing() { + timing_type : rising_edge; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "CLK"; + } + timing () { + timing_type : preset; + timing_sense : negative_unate; + intrinsic_rise : 75; + related_pin : "RESET"; + } + timing () { + timing_type : clear; + timing_sense : positive_unate; + intrinsic_fall : 75; + related_pin : "PRESET"; + } + } + } + + /* Latch */ + cell(latch) { + area : 5; + latch ("IQ","IQN") { + enable : "G"; + data_in : "D"; + } + + pin(D) { + direction : input; + } + pin(G) { + direction : input; + } + + pin(Q) { + direction : output; + function : "IQ"; + internal_node : "Q"; + + timing() { + timing_type : rising_edge; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "G"; + } + + timing() { + timing_sense : positive_unate; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "D"; + } + } + + pin(QN) { + direction : output; + function : "IQN"; + internal_node : "QN"; + + timing() { + timing_type : rising_edge; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "G"; + } + + timing() { + timing_sense : negative_unate; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "D"; + } + } + } + + /* 3 input AND-OR-INVERT gate */ + cell (aoi211) { + area : 3; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(C) { + direction : input; + } + pin(Y) { + direction: output; + function : "((A * B) + C)'"; + } + } + + + /* 3 input OR-AND-INVERT gate */ + cell (oai211) { + area : 3; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(C) { + direction : input; + } + pin(Y) { + direction: output; + function : "((A + B) * C)'"; + } + } + + /* half adder */ + cell (halfadder) { + area : 5; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(C) { + direction : output; + function : "(A * B)"; + } + pin(Y) { + direction: output; + function : "(A *B') + (A' * B)"; + } + } + + /* full adder */ + cell (fulladder) { + area : 8; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(CI) { + direction : input; + } + pin(CO) { + direction : output; + function : "(((A * B)+(B * CI))+(CI * A))"; + } + pin(Y) { + direction: output; + function : "((A^B)^CI)"; + } + } + +} /* end */ diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh new file mode 100755 index 000000000..7e2ed2370 --- /dev/null +++ b/tests/liberty/run-test.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -e + +for x in *.lib; do + echo "Running $x.." + echo "read_verilog small.v" > test.ys + echo "synth -top small" >> test.ys + echo "dfflibmap -liberty ${x}" >> test.ys + ../../yosys -ql ${x%.lib}.log -s test.ys +done diff --git a/tests/liberty/semicolmissing.lib b/tests/liberty/semicolmissing.lib new file mode 100644 index 000000000..f7c20750a --- /dev/null +++ b/tests/liberty/semicolmissing.lib @@ -0,0 +1,72 @@ +/********************************************/ +/* */ +/* Supergate cell library for Bench marking */ +/* */ +/* Symbiotic EDA GmbH / Moseley Instruments */ +/* Niels A. Moseley */ +/* */ +/* Process: none */ +/* */ +/* Date : 24-03-2019 */ +/* Version: 1.0 */ +/* Version: 1.1 - Removed semicolons in */ +/* full adder */ +/* */ +/********************************************/ + +/* + semi colon is missing in full-adder specification + some TSMC liberty files are formatted this way.. +*/ + +library(supergate) { + technology (cmos); + revision : 1.0; + + time_unit : "1ps"; + pulling_resistance_unit : "1kohm"; + voltage_unit : "1V"; + current_unit : "1uA"; + + capacitive_load_unit(1,ff); + + default_inout_pin_cap : 7.0; + default_input_pin_cap : 7.0; + default_output_pin_cap : 0.0; + default_fanout_load : 1.0; + + default_wire_load_capacitance : 0.1; + default_wire_load_resistance : 1.0e-3; + default_wire_load_area : 0.0; + + nom_process : 1.0; + nom_temperature : 25.0; + nom_voltage : 1.2; + + delay_model : generic_cmos; + + /* full adder */ + cell (fulladder) { + area : 8 + pin(A) { + direction : input + } + pin(B) { + direction : input + } + pin(CI) { + direction : input + } + pin(CO) { + direction : output + function : "(((A * B)+(B * CI))+(CI * A))" + } + pin(Y) { + direction: output + function : "((A^B)^CI)" + } + } + +} /* end */ + + diff --git a/tests/liberty/small.v b/tests/liberty/small.v new file mode 100644 index 000000000..bd94be4fc --- /dev/null +++ b/tests/liberty/small.v @@ -0,0 +1,16 @@ +/** small, meaningless design to test loading of liberty files */ + +module small +( + input clk, + output reg[7:0] count +); + +initial count = 0; + +always @ (posedge clk) +begin + count <= count + 1'b1; +end + +endmodule From 9d9cc8a3140cdbc2d976a5b06b5a057845da739a Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Mon, 25 Mar 2019 12:15:10 +0100 Subject: [PATCH 112/132] EOL is now accepted as ';' replacement on lines that look like: feature_xyz(option) --- passes/techmap/libparse.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 878ca3160..9dc3e96ab 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -202,12 +202,11 @@ LibertyAst *LibertyParser::parse() { tok = lexer(str); - if (tok == ';') + // allow both ';' and new lines to + // terminate a statement. + if ((tok == ';') || (tok == 'n')) break; - if (tok == 'n') - continue; - if (tok == ':' && ast->value.empty()) { tok = lexer(ast->value); if (tok != 'v') From 1f7f54e68eb201976ddd42cb906492bf9e611030 Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Mon, 25 Mar 2019 14:12:04 +0100 Subject: [PATCH 113/132] spaces -> tabs --- passes/techmap/libparse.cc | 156 ++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 9dc3e96ab..8eadd8735 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -87,12 +87,12 @@ int LibertyParser::lexer(std::string &str) { int c; - // eat whitespace + // eat whitespace do { c = f.get(); } while (c == ' ' || c == '\t' || c == '\r'); - // search for identifiers, numbers, plus or minus. + // 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; while (1) { @@ -114,8 +114,8 @@ int LibertyParser::lexer(std::string &str) } } - // if it wasn't an identifer, number of array range, - // maybe it's a string? + // if it wasn't an identifer, number of array range, + // maybe it's a string? if (c == '"') { str = ""; while (1) { @@ -130,7 +130,7 @@ int LibertyParser::lexer(std::string &str) return 'v'; } - // if it wasn't a string, perhaps it's a comment or a forward slash? + // if it wasn't a string, perhaps it's a comment or a forward slash? if (c == '/') { c = f.get(); if (c == '*') { // start of '/*' block comment @@ -153,7 +153,7 @@ int LibertyParser::lexer(std::string &str) return '/'; // a single '/' charater. } - // check for a backslash + // check for a backslash if (c == '\\') { c = f.get(); if (c == '\r') @@ -164,14 +164,14 @@ int LibertyParser::lexer(std::string &str) return '\\'; } - // check for a new line + // check for a new line if (c == '\n') { line++; return 'n'; } - // anything else, such as ';' will get passed - // through as literal items. + // anything else, such as ';' will get passed + // through as literal items. // if (c >= 32 && c < 255) // fprintf(stderr, "LEX: char >>%c<<\n", c); @@ -202,8 +202,8 @@ LibertyAst *LibertyParser::parse() { tok = lexer(str); - // allow both ';' and new lines to - // terminate a statement. + // allow both ';' and new lines to + // terminate a statement. if ((tok == ';') || (tok == 'n')) break; @@ -220,11 +220,11 @@ LibertyAst *LibertyParser::parse() ast->value += str; tok = lexer(str); } - - // 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.. + + // 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; else @@ -240,48 +240,48 @@ LibertyAst *LibertyParser::parse() continue; if (tok == ')') 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') - { - // 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; - } + + // 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') + { + // 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') error(); ast->args.push_back(arg); @@ -314,10 +314,10 @@ void LibertyParser::error() 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()); + std::stringstream ss; + ss << "Syntax error in liberty file on line " << line << ".\n"; + ss << " " << str << "\n"; + log_error("%s", ss.str().c_str()); } #else @@ -330,32 +330,32 @@ void LibertyParser::error() 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); + 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 ****/ #define CHECK_NV(result, check) \ do { \ - auto _R = (result); \ - if (!(_R check)) { \ - fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \ - #result, (long int)_R, #check, __FILE__, __LINE__); \ - abort(); \ - } \ + auto _R = (result); \ + if (!(_R check)) { \ + fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \ + #result, (long int)_R, #check, __FILE__, __LINE__); \ + abort(); \ + } \ } while(0) #define CHECK_COND(result) \ do { \ - if (!(result)) { \ - fprintf(stderr, "Error from '%s' in %s:%d.\n", \ - #result, __FILE__, __LINE__); \ - abort(); \ - } \ + if (!(result)) { \ + fprintf(stderr, "Error from '%s' in %s:%d.\n", \ + #result, __FILE__, __LINE__); \ + abort(); \ + } \ } while(0) /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/ From b7a3d35c6b02f44dcad4052e2efe05c32fdada6b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 25 Mar 2019 11:16:56 -0700 Subject: [PATCH 114/132] Create one $shiftx per bit in width --- passes/proc/proc_mux.cc | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index 7cac0327b..7d3d23408 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -340,7 +340,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d // evaluate in reverse order to give the first entry the top priority RTLIL::SigSpec initial_val = result; RTLIL::Cell *last_mux_cell = NULL; - bool shiftx = true; + bool shiftx = initial_val.is_fully_undef(); for (size_t i = 0; i < sw->cases.size(); i++) { int case_idx = sw->cases.size() - i - 1; RTLIL::CaseRule *cs2 = sw->cases[case_idx]; @@ -355,20 +355,27 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d // Keep checking if case condition is the same as the current case index if (cs2->compare.size() == 1 && cs2->compare.front().is_fully_const()) shiftx = (cs2->compare.front().as_int() == case_idx); + else + shiftx = false; } } - // Transform into a $shiftx if possible + // Transform into a $shiftx where possible if (shiftx && last_mux_cell->type == "$pmux") { - // Sanity check that A port of $pmux should be 'bx - log_assert(last_mux_cell->getPort("\\A").is_fully_undef()); - // Because we went in reverse order above, un-reverse its B port here - auto b_port = last_mux_cell->getPort("\\B").chunks(); - std::reverse(b_port.begin(), b_port.end()); - // Create a $shiftx that shifts by the address line used in the case statement - mod->addShiftx(NEW_ID, b_port, sw->signal, last_mux_cell->getPort("\\Y")); + // Create bit-blasted $shiftx-es that shifts by the address line used in the case statement + auto pmux_b_port = last_mux_cell->getPort("\\B"); + auto pmux_y_port = last_mux_cell->getPort("\\Y"); + int width = last_mux_cell->getParam("\\WIDTH").as_int(); + for (int i = 0; i < width; ++i) { + RTLIL::SigSpec a_port; + // Because we went in reverse order above, un-reverse $pmux's B port here + for (int j = pmux_b_port.size()/width-1; j >= 0; --j) + a_port.append(pmux_b_port.extract(j*width+i, 1)); + // Create a $shiftx that shifts by the address line used in the case statement + mod->addShiftx(NEW_ID, a_port, sw->signal, pmux_y_port.extract(i, 1)); + } // Disconnect $pmux by replacing its output port with a floating wire - last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, last_mux_cell->getParam("\\WIDTH").as_int())); + last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, width)); } } From ddc1a4488e9fc10f557e4260df0becbc1cf43f72 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 25 Mar 2019 19:49:00 +0100 Subject: [PATCH 115/132] Add "cutpoint" pass Signed-off-by: Clifford Wolf --- passes/sat/Makefile.inc | 1 + passes/sat/cutpoint.cc | 164 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 passes/sat/cutpoint.cc diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index 4eced2ff1..fc3ac879e 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -11,4 +11,5 @@ OBJS += passes/sat/async2sync.o OBJS += passes/sat/supercover.o OBJS += passes/sat/fmcombine.o OBJS += passes/sat/mutate.o +OBJS += passes/sat/cutpoint.o diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc new file mode 100644 index 000000000..3a38ebac0 --- /dev/null +++ b/passes/sat/cutpoint.cc @@ -0,0 +1,164 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + // bool flag_noinit = false; + + log_header(design, "Executing CUTPOINT pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-noinit") { + // flag_noinit = 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()); + for (auto cell : vector(module->cells())) + module->remove(cell); + vector output_wires; + for (auto wire : module->wires()) + if (wire->port_output) + output_wires.push_back(wire); + for (auto wire : output_wires) + module->connect(wire, module->Anyseq(NEW_ID, GetSize(wire))); + continue; + } + + SigMap sigmap(module); + pool 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, 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, 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 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, module->Anyseq(NEW_ID, GetSize(s))); + } + } + } + } +} CutpointPass; + +PRIVATE_NAMESPACE_END From c863796e9ff91c76f0f8679b6871b8ffcb75edb6 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 26 Mar 2019 14:17:46 +0100 Subject: [PATCH 116/132] Fix "verific -extnets" for more complex situations Signed-off-by: Clifford Wolf --- frontends/verific/verific.cc | 86 +++++++++++++++++++++++++++++------- tests/sva/extnets.sv | 22 +++++++++ 2 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 tests/sva/extnets.sv diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index c412cd3a3..95b7d3586 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1619,30 +1619,35 @@ struct VerificExtNets int portname_cnt = 0; // a map from Net to the same Net one level up in the design hierarchy - std::map net_level_up; + std::map net_level_up_drive_up; + std::map 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) { Netlist *nl = net->Owner(); // Simply return if Netlist is not unique - if (nl->NumOfRefs() != 1) - return net; + log_assert(nl->NumOfRefs() == 1); Instance *up_inst = (Instance*)nl->GetReferences()->GetLast(); Netlist *up_nl = up_inst->Owner(); // create new Port 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); net->Connect(new_port); // create new Net in up Netlist - Net *new_net = new Net(name.c_str()); - up_nl->Add(new_net); + 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_inst->Connect(new_port, new_net); net_level_up[net] = new_net; @@ -1651,6 +1656,39 @@ struct VerificExtNets 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 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) { MapIter mi, mi2; @@ -1674,19 +1712,37 @@ struct VerificExtNets 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()); - while (net->IsExternalTo(nl)) - { - Net *newnet = get_net_level_up(net); - if (newnet == net) break; + Netlist *ext_nl = net->Owner(); + if (verific_verbose) + log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str()); + + 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(" external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name()); - net = newnet; + 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) - log(" final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : ""); - todo_connect.push_back(tuple(inst, port, net)); + log(" new local net: %s\n", new_net->Name()); + + log_assert(!new_net->IsExternalTo(nl)); + todo_connect.push_back(tuple(inst, port, new_net)); } for (auto it : todo_connect) { diff --git a/tests/sva/extnets.sv b/tests/sva/extnets.sv new file mode 100644 index 000000000..47312de7a --- /dev/null +++ b/tests/sva/extnets.sv @@ -0,0 +1,22 @@ +module top(input i, output o); + A A(); + B B(); + assign A.i = i; + assign o = B.o; + always @* assert(o == i); +endmodule + +module A; + wire i, y; +`ifdef FAIL + assign B.x = i; +`else + assign B.x = !i; +`endif + assign y = !B.y; +endmodule + +module B; + wire x, y, o; + assign y = x, o = A.y; +endmodule From d0b9b1bece9866fd7b0e153c991fc7e9b57a1efc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 26 Mar 2019 14:51:35 +0100 Subject: [PATCH 117/132] Add "hdlname" attribute Signed-off-by: Clifford Wolf --- README.md | 3 +++ passes/hierarchy/uniquify.cc | 2 ++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index c5cd47707..4048ecbc7 100644 --- a/README.md +++ b/README.md @@ -315,6 +315,9 @@ Verilog Attributes and non-standard features - The ``dynports'' attribute is used by the Verilog front-end to mark modules 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 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. diff --git a/passes/hierarchy/uniquify.cc b/passes/hierarchy/uniquify.cc index c88ecd82e..e6154e94f 100644 --- a/passes/hierarchy/uniquify.cc +++ b/passes/hierarchy/uniquify.cc @@ -87,6 +87,8 @@ struct UniquifyPass : public Pass { smod->name = newname; cell->type = newname; smod->set_bool_attribute("\\unique"); + if (smod->attributes.count("\\hdlname") == 0) + smod->attributes["\\hdlname"] = string(log_id(tmod->name)); design->add(smod); did_something = true; From 38b3fbd3f0bbdace11a3ab7b3d153b1a05059378 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 26 Mar 2019 16:01:14 +0100 Subject: [PATCH 118/132] Add "cutpoint -undef" Signed-off-by: Clifford Wolf --- passes/sat/cutpoint.cc | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index 3a38ebac0..048aec7f3 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -33,20 +33,24 @@ struct CutpointPass : public Pass { 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 args, RTLIL::Design *design) YS_OVERRIDE { - // bool flag_noinit = false; + bool flag_undef = false; log_header(design, "Executing CUTPOINT pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - // if (args[argidx] == "-noinit") { - // flag_noinit = true; - // continue; - // } + if (args[argidx] == "-undef") { + flag_undef = true; + continue; + } break; } extra_args(args, argidx, design); @@ -63,7 +67,7 @@ struct CutpointPass : public Pass { if (wire->port_output) output_wires.push_back(wire); for (auto wire : output_wires) - module->connect(wire, module->Anyseq(NEW_ID, GetSize(wire))); + module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire))); continue; } @@ -76,7 +80,7 @@ struct CutpointPass : public Pass { 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, module->Anyseq(NEW_ID, GetSize(conn.second))); + module->connect(conn.second, flag_undef ? Const(State::Sx, GetSize(conn.second)) : module->Anyseq(NEW_ID, GetSize(conn.second))); } module->remove(cell); } @@ -86,7 +90,7 @@ struct CutpointPass : public Pass { 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, module->Anyseq(NEW_ID, GetSize(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; @@ -142,7 +146,7 @@ struct CutpointPass : public Pass { rhs.append(SigBit(new_wire, i)); } if (GetSize(lhs)) - module->connect(lhs, rhs); + module->connect(lhs, rhs); module->swap_names(wire, new_wire); wire->port_id = 0; wire->port_input = false; @@ -154,7 +158,7 @@ struct CutpointPass : public Pass { for (auto chunk : sig.chunks()) { SigSpec s(chunk); - module->connect(s, module->Anyseq(NEW_ID, GetSize(s))); + module->connect(s, flag_undef ? Const(State::Sx, GetSize(s)) : module->Anyseq(NEW_ID, GetSize(s))); } } } From d351b7cb99efe8c412ef7fa8bc0b99b72bc56726 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 27 Mar 2019 13:33:26 +0100 Subject: [PATCH 119/132] Improve "rename" help message Signed-off-by: Clifford Wolf --- passes/cmds/rename.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index 698ce7235..466a5da53 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -108,15 +108,19 @@ struct RenamePass : public Pass { log("Rename the specified object. Note that selection patterns are not supported\n"); log("by this command.\n"); log("\n"); + log("\n"); log(" rename -src [selection]\n"); log("\n"); log("Assign names auto-generated from the src attribute to all selected wires and\n"); log("cells with private names.\n"); log("\n"); + log("\n"); log(" rename -wire [selection]\n"); + log("\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("\n"); + log("\n"); log(" rename -enumerate [-pattern ] [selection]\n"); log("\n"); log("Assign short auto-generated names to all selected wires and cells with private\n"); @@ -124,11 +128,13 @@ struct RenamePass : public Pass { log("The character %% in the pattern is replaced with a integer number. The default\n"); log("pattern is '_%%_'.\n"); log("\n"); + log("\n"); log(" rename -hide [selection]\n"); log("\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("\n"); + log("\n"); log(" rename -top new_name\n"); log("\n"); log("Rename top module.\n"); From 2c7fe42ad158a9859895399bdd876f5dbb2c7376 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 27 Mar 2019 13:47:42 +0100 Subject: [PATCH 120/132] Add "rename -output" Signed-off-by: Clifford Wolf --- passes/cmds/rename.cc | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index 466a5da53..9b1830b7b 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -24,7 +24,7 @@ USING_YOSYS_NAMESPACE 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); 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; 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); - if (w->port_id) + if (w->port_id || flag_output) { + if (flag_output) + w->port_output = true; module->fixup_ports(); + } return; } for (auto &it : module->cells_) 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)); module->rename(it.second, to_name); return; @@ -109,6 +114,13 @@ struct RenamePass : public Pass { log("by this command.\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("\n"); log("Assign names auto-generated from the src attribute to all selected wires and\n"); @@ -148,6 +160,7 @@ struct RenamePass : public Pass { bool flag_enumerate = false; bool flag_hide = false; bool flag_top = false; + bool flag_output = false; bool got_mode = false; size_t argidx; @@ -159,6 +172,11 @@ struct RenamePass : public Pass { got_mode = true; continue; } + if (arg == "-output" && !got_mode) { + flag_output = true; + got_mode = true; + continue; + } if (arg == "-wire" && !got_mode) { flag_wire = true; got_mode = true; @@ -328,10 +346,12 @@ struct RenamePass : public Pass { if (!design->selected_active_module.empty()) { 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 { + if (flag_output) + log_cmd_error("Mode -output requires that there is an active module selected.\n"); for (auto &mod : design->modules_) { if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) { to_name = RTLIL::escape_id(to_name); From 7682629b79fd59f5ed49fb35a3a2441a405bfd63 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 27 Mar 2019 14:03:35 +0100 Subject: [PATCH 121/132] Add "read -verific" and "read -noverific" Signed-off-by: Clifford Wolf --- frontends/verific/verific.cc | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 95b7d3586..ed9727b88 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2386,21 +2386,43 @@ struct ReadPass : public Pass { log("\n"); log("Add directory to global Verilog/SystemVerilog include directories.\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 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] != '-') 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) 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 (use_verific) { args[0] = "verific"; From 487cb45b87ce1cbcc8c2b8127e37d85dd192dceb Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Wed, 27 Mar 2019 15:15:53 +0100 Subject: [PATCH 122/132] Liberty file parser now accepts superfluous ; --- passes/techmap/libparse.cc | 61 ++++++++++++++++++++++++++++++---- tests/liberty/normal.lib | 3 +- tests/liberty/processdefs.lib | 48 ++++++++++++++++++++++++++ tests/liberty/semicolextra.lib | 48 ++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 tests/liberty/processdefs.lib create mode 100644 tests/liberty/semicolextra.lib diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 8eadd8735..510a24c24 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -155,11 +155,13 @@ int LibertyParser::lexer(std::string &str) // check for a backslash if (c == '\\') { - c = f.get(); + c = f.get(); if (c == '\r') c = f.get(); - if (c == '\n') + if (c == '\n') { + line++; return lexer(str); + } f.unget(); return '\\'; } @@ -186,14 +188,39 @@ LibertyAst *LibertyParser::parse() int tok = lexer(str); - while (tok == 'n') + // there are liberty files in the while 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); if (tok == '}' || tok < 0) return NULL; - if (tok != 'v') - error(); + 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(tok); + eReport += "'."; + error(eReport); + break; + default: + error(); + } + } LibertyAst *ast = new LibertyAst; ast->id = str; @@ -282,8 +309,28 @@ LibertyAst *LibertyParser::parse() } continue; } - if (tok != 'v') - error(); + 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(tok); + eReport += "'."; + error(eReport); + break; + default: + error(); + } + } ast->args.push_back(arg); } continue; diff --git a/tests/liberty/normal.lib b/tests/liberty/normal.lib index 1474e2b59..4621194dd 100644 --- a/tests/liberty/normal.lib +++ b/tests/liberty/normal.lib @@ -142,8 +142,7 @@ library(supergate) { } /* D-type flip-flop with asynchronous reset and preset */ - cell (dff) - { + cell (dff) { area : 6; ff("IQ", "IQN") { next_state : "D"; diff --git a/tests/liberty/processdefs.lib b/tests/liberty/processdefs.lib new file mode 100644 index 000000000..37a6bbaf8 --- /dev/null +++ b/tests/liberty/processdefs.lib @@ -0,0 +1,48 @@ +/********************************************/ +/* */ +/* Supergate cell library for Bench marking */ +/* */ +/* Symbiotic EDA GmbH / Moseley Instruments */ +/* Niels A. Moseley */ +/* */ +/* Process: none */ +/* */ +/* Date : 25-03-2019 */ +/* Version: 1.0 */ +/* */ +/********************************************/ + +library(processdefs) { + technology (cmos); + revision : 1.0; + + time_unit : "1ps"; + pulling_resistance_unit : "1kohm"; + voltage_unit : "1V"; + current_unit : "1uA"; + + capacitive_load_unit(1,ff); + + default_inout_pin_cap : 7.0; + default_input_pin_cap : 7.0; + default_output_pin_cap : 0.0; + default_fanout_load : 1.0; + + default_wire_load_capacitance : 0.1; + default_wire_load_resistance : 1.0e-3; + default_wire_load_area : 0.0; + + nom_process : 1.0; + nom_temperature : 25.0; + nom_voltage : 1.2; + + delay_model : generic_cmos; + + define_cell_area(bond_pads,pad_slots) + input_voltage(cmos) { + vil : 0.3 * VDD ; + vih : 0.7 * VDD ; + vimin : -0.5 ; + vimax : VDD + 0.5 ; + } +} diff --git a/tests/liberty/semicolextra.lib b/tests/liberty/semicolextra.lib new file mode 100644 index 000000000..0144fa3ac --- /dev/null +++ b/tests/liberty/semicolextra.lib @@ -0,0 +1,48 @@ +/* + + Test case for https://www.reddit.com/r/yosys/comments/b5texg/yosys_fails_to_parse_apparentlycorrect_liberty/ + + fall_constraint (SETUP_HOLD) formatting. + +*/ + +library(supergate) { + technology (cmos); + revision : 1.0; + + cell (DFF) { + cell_footprint : dff; + area : 50; + pin(D) { + direction : input; + capacitance : 0.002; + timing() { + related_pin : "CK"; + timing_type : setup_rising; + + fall_constraint (SETUP_HOLD) { values ("0.4000, 0.3000, 0.2000, 0.1000, 0.0000", \ + "0.4000, 0.3000, 0.2000, 0.1000, 0.000", \ + "0.5000, 0.4000, 0.3000, 0.2000, 0.0000", \ + "0.7000, 0.6000, 0.5000, 0.4000, 0.2000", \ + "1.0000, 1.0000, 0.9000, 0.8000, 0.6000"); } ; + } + } + + pin(CK) { + direction : input; + clock : true; + capacitance : 0.00290; + } + + ff(IQ,IQN) { + clocked_on : "CK"; + next_state : "D"; + } + pin(Q) { + direction : output; + capacitance : 0.003; + max_capacitance : 0.3; + } + cell_leakage_power : 0.3; + } +} From ee130f67cdd2ea40defa873e9a6511329850bf8e Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Wed, 27 Mar 2019 15:16:19 +0100 Subject: [PATCH 123/132] Liberty file parser now accepts superfluous ; --- tests/liberty/semicolextra.lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/liberty/semicolextra.lib b/tests/liberty/semicolextra.lib index 0144fa3ac..6a7fa77cc 100644 --- a/tests/liberty/semicolextra.lib +++ b/tests/liberty/semicolextra.lib @@ -24,7 +24,7 @@ library(supergate) { "0.4000, 0.3000, 0.2000, 0.1000, 0.000", \ "0.5000, 0.4000, 0.3000, 0.2000, 0.0000", \ "0.7000, 0.6000, 0.5000, 0.4000, 0.2000", \ - "1.0000, 1.0000, 0.9000, 0.8000, 0.6000"); } ; + "1.0000, 1.0000, 0.9000, 0.8000, 0.6000"); }; } } From 263ab60b43f3994e83bfa46b793669147d765bcc Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Wed, 27 Mar 2019 15:17:58 +0100 Subject: [PATCH 124/132] Liberty file parser now accepts superfluous ; --- passes/techmap/libparse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 510a24c24..991cc4498 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -188,7 +188,7 @@ LibertyAst *LibertyParser::parse() int tok = lexer(str); - // there are liberty files in the while that + // 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. From 60594ad40cb51f6cf8a5e6ce61377b3405b873a8 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 27 Mar 2019 17:19:14 +0000 Subject: [PATCH 125/132] memory_bram: Reset make_transp when growing read ports Signed-off-by: David Shah --- passes/memory/memory_bram.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index c38eabaee..85ed1c053 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -641,6 +641,7 @@ grow_read_ports:; pi.sig_data = SigSpec(); pi.sig_en = SigSpec(); pi.make_outreg = false; + pi.make_transp = false; } new_portinfos.push_back(pi); if (pi.dupidx == dup_count-1) { From 584d2030bf53c703febe8fda9cae73c72416c6cc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 29 Mar 2019 16:32:44 +0100 Subject: [PATCH 126/132] Build Verilog parser with -DYYMAXDEPTH=100000, fixes #906 Signed-off-by: Clifford Wolf --- frontends/verilog/Makefile.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index dbaace585..0a1f97ac0 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -14,6 +14,8 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l $(Q) mkdir -p $(dir $@) $(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_lexer.o OBJS += frontends/verilog/preproc.o From 73b87e780798fe2c7958b75e4dfddc0dc2169d20 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 1 Apr 2019 15:02:12 -0700 Subject: [PATCH 127/132] Refine memory support to deal with general Verilog memory definitions. --- backends/firrtl/firrtl.cc | 203 ++++++++++++++++++++++++++++++++------ 1 file changed, 173 insertions(+), 30 deletions(-) diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index eef6401b2..ed6e9f8ee 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -106,6 +106,95 @@ struct FirrtlWorker RTLIL::Design *design; std::string indent; + // Define read/write ports and memories. + // We'll collect their definitions and emit the corresponding FIRRTL definitions at the appropriate point in module construction. + // For the moment, we don't handle $readmemh or $readmemb. + // These will be part of a subsequent PR. + struct read_port { + string name; + bool clk_enable; + bool clk_parity; + bool transparent; + RTLIL::SigSpec clk; + RTLIL::SigSpec ena; + RTLIL::SigSpec addr; + read_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr) : name(name), clk_enable(clk_enable), clk_parity(clk_parity), transparent(transparent), clk(clk), ena(ena), addr(addr) { + // Current (3/13/2019) conventions: + // generate a constant 0 for clock and a constant 1 for enable if they are undefined. + if (!clk.is_fully_def()) + this->clk = SigSpec(RTLIL::Const(0, 1)); + if (!ena.is_fully_def()) + this->ena = SigSpec(RTLIL::Const(1, 1)); + } + string gen_read(const char * indent) { + string addr_expr = make_expr(addr); + string ena_expr = make_expr(ena); + string clk_expr = make_expr(clk); + string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str()); + string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str()); + string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str()); + return addr_str + ena_str + clk_str; + } + }; + struct write_port : read_port { + RTLIL::SigSpec mask; + write_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr, RTLIL::SigSpec mask) : read_port(name, clk_enable, clk_parity, transparent, clk, ena, addr), mask(mask) { + if (!clk.is_fully_def()) + this->clk = SigSpec(RTLIL::Const(0)); + if (!ena.is_fully_def()) + this->ena = SigSpec(RTLIL::Const(0)); + if (!mask.is_fully_def()) + this->ena = SigSpec(RTLIL::Const(1)); + } + string gen_read(const char * /* indent */) { + log_error("gen_read called on write_port: %s\n", name.c_str()); + return stringf("gen_read called on write_port: %s\n", name.c_str()); + } + string gen_write(const char * indent) { + string addr_expr = make_expr(addr); + string ena_expr = make_expr(ena); + string clk_expr = make_expr(clk); + string mask_expr = make_expr(mask); + string mask_str = stringf("%s%s.mask <= %s\n", indent, name.c_str(), mask_expr.c_str()); + string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str()); + string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str()); + string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str()); + return addr_str + ena_str + clk_str + mask_str; + } + }; + /* Memories defined within this module. */ + struct memory { + string name; // memory name + int abits; // number of address bits + int size; // size (in units) of the memory + int width; // size (in bits) of each element + int read_latency; + int write_latency; + vector read_ports; + vector write_ports; + std::string init_file; + std::string init_file_srcFileSpec; + memory(string name, int abits, int size, int width) : name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {} + memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} + void add_memory_read_port(read_port &rp) { + read_ports.push_back(rp); + } + void add_memory_write_port(write_port &wp) { + write_ports.push_back(wp); + } + void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { + this->init_file = init_file; + this->init_file_srcFileSpec = init_file_srcFileSpec; + } + + }; + dict memories; + + void register_memory(memory &m) + { + memories[m.name] = m; + } + void register_reverse_wire_map(string id, SigSpec sig) { for (int i = 0; i < GetSize(sig); i++) @@ -116,7 +205,7 @@ struct FirrtlWorker { } - string make_expr(const SigSpec &sig) + static string make_expr(const SigSpec &sig) { string expr; @@ -515,6 +604,7 @@ struct FirrtlWorker int abits = cell->parameters.at("\\ABITS").as_int(); int width = cell->parameters.at("\\WIDTH").as_int(); int size = cell->parameters.at("\\SIZE").as_int(); + memory m(mem_id, abits, size, width); int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); @@ -531,33 +621,24 @@ struct FirrtlWorker if (offset != 0) log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell)); - cell_exprs.push_back(stringf(" mem %s:\n", mem_id.c_str())); - cell_exprs.push_back(stringf(" data-type => UInt<%d>\n", width)); - cell_exprs.push_back(stringf(" depth => %d\n", size)); - - for (int i = 0; i < rd_ports; i++) - cell_exprs.push_back(stringf(" reader => r%d\n", i)); - - for (int i = 0; i < wr_ports; i++) - cell_exprs.push_back(stringf(" writer => w%d\n", i)); - - cell_exprs.push_back(stringf(" read-latency => 0\n")); - cell_exprs.push_back(stringf(" write-latency => 1\n")); - cell_exprs.push_back(stringf(" read-under-write => undefined\n")); - for (int i = 0; i < rd_ports; i++) { if (rd_clk_enable[i] != State::S0) log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); + SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(i*abits, abits); SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width); - string addr_expr = make_expr(cell->getPort("\\RD_ADDR").extract(i*abits, abits)); - - cell_exprs.push_back(stringf(" %s.r%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str())); - cell_exprs.push_back(stringf(" %s.r%d.en <= UInt<1>(1)\n", mem_id.c_str(), i)); - cell_exprs.push_back(stringf(" %s.r%d.clk <= asClock(UInt<1>(0))\n", mem_id.c_str(), i)); - - register_reverse_wire_map(stringf("%s.r%d.data", mem_id.c_str(), i), data_sig); + string addr_expr = make_expr(addr_sig); + string name(stringf("%s.r%d", m.name.c_str(), i)); + bool clk_enable = false; + bool clk_parity = true; + bool transparency = false; + SigSpec ena_sig = RTLIL::SigSpec(RTLIL::State::S1, 1); + SigSpec clk_sig = RTLIL::SigSpec(RTLIL::State::S0, 1); + read_port rp(name, clk_enable, clk_parity, transparency, clk_sig, ena_sig, addr_sig); + m.add_memory_read_port(rp); + cell_exprs.push_back(rp.gen_read(indent.c_str())); + register_reverse_wire_map(stringf("%s.data", name.c_str()), data_sig); } for (int i = 0; i < wr_ports; i++) @@ -568,9 +649,16 @@ struct FirrtlWorker if (wr_clk_polarity[i] != State::S1) log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); - string addr_expr = make_expr(cell->getPort("\\WR_ADDR").extract(i*abits, abits)); - string data_expr = make_expr(cell->getPort("\\WR_DATA").extract(i*width, width)); - string clk_expr = make_expr(cell->getPort("\\WR_CLK").extract(i)); + string name(stringf("%s.w%d", m.name.c_str(), i)); + bool clk_enable = true; + bool clk_parity = true; + bool transparency = false; + SigSpec addr_sig =cell->getPort("\\WR_ADDR").extract(i*abits, abits); + string addr_expr = make_expr(addr_sig); + SigSpec data_sig =cell->getPort("\\WR_DATA").extract(i*width, width); + string data_expr = make_expr(data_sig); + SigSpec clk_sig = cell->getPort("\\WR_CLK").extract(i); + string clk_expr = make_expr(clk_sig); SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width); string wen_expr = make_expr(wen_sig[0]); @@ -579,13 +667,50 @@ struct FirrtlWorker if (wen_sig[0] != wen_sig[i]) log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); - cell_exprs.push_back(stringf(" %s.w%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str())); - cell_exprs.push_back(stringf(" %s.w%d.data <= %s\n", mem_id.c_str(), i, data_expr.c_str())); - cell_exprs.push_back(stringf(" %s.w%d.en <= %s\n", mem_id.c_str(), i, wen_expr.c_str())); - cell_exprs.push_back(stringf(" %s.w%d.mask <= UInt<1>(1)\n", mem_id.c_str(), i)); - cell_exprs.push_back(stringf(" %s.w%d.clk <= asClock(%s)\n", mem_id.c_str(), i, clk_expr.c_str())); + SigSpec mask_sig = RTLIL::SigSpec(RTLIL::State::S1, 1); + write_port wp(name, clk_enable, clk_parity, transparency, clk_sig, wen_sig[0], addr_sig, mask_sig); + m.add_memory_write_port(wp); + cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), name.c_str(), data_expr.c_str())); + cell_exprs.push_back(wp.gen_write(indent.c_str())); } + register_memory(m); + continue; + } + if (cell->type.in("$memwr", "$memrd", "$meminit")) + { + std::string cell_type = fid(cell->type); + std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string()); + memory *mp = nullptr; + if (cell->type == "$meminit" ) { + log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str()); + } else { + // It's a $memwr or $memrd. Remember the read/write port parameters for the eventual FIRRTL memory definition. + auto addrSig = cell->getPort("\\ADDR"); + auto dataSig = cell->getPort("\\DATA"); + auto enableSig = cell->getPort("\\EN"); + auto clockSig = cell->getPort("\\CLK"); + Const clk_enable = cell->parameters.at("\\CLK_ENABLE"); + Const clk_polarity = cell->parameters.at("\\CLK_POLARITY"); + + mp = &memories.at(mem_id); + int portNum = 0; + bool transparency = false; + string data_expr = make_expr(dataSig); + if (cell->type.in("$memwr")) { + portNum = (int) mp->write_ports.size(); + write_port wp(stringf("%s.w%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig, dataSig); + mp->add_memory_write_port(wp); + cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), wp.name.c_str(), data_expr.c_str())); + cell_exprs.push_back(wp.gen_write(indent.c_str())); + } else if (cell->type.in("$memrd")) { + portNum = (int) mp->read_ports.size(); + read_port rp(stringf("%s.r%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig); + mp->add_memory_read_port(rp); + cell_exprs.push_back(rp.gen_read(indent.c_str())); + register_reverse_wire_map(stringf("%s.data", rp.name.c_str()), dataSig); + } + } continue; } @@ -763,6 +888,24 @@ struct FirrtlWorker f << stringf("\n"); + // If we have any memory definitions, output them. + for (auto kv : memories) { + memory m = kv.second; + f << stringf(" mem %s:\n", m.name.c_str()); + f << stringf(" data-type => UInt<%d>\n", m.width); + f << stringf(" depth => %d\n", m.size); + for (int i = 0; i < (int) m.read_ports.size(); i += 1) { + f << stringf(" reader => r%d\n", i); + } + for (int i = 0; i < (int) m.write_ports.size(); i += 1) { + f << stringf(" writer => w%d\n", i); + } + f << stringf(" read-latency => %d\n", m.read_latency); + f << stringf(" write-latency => %d\n", m.write_latency); + f << stringf(" read-under-write => undefined\n"); + } + f << stringf("\n"); + for (auto str : cell_exprs) f << str; From 6acbc016f43b1464e6322b895f16d01ed51eea18 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 2 Apr 2019 19:47:50 +0100 Subject: [PATCH 128/132] memory_bram: Consider read enable for address expansion register Signed-off-by: David Shah --- passes/memory/memory_bram.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index 85ed1c053..804aa21f9 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -957,6 +957,8 @@ grow_read_ports:; SigSpec addr_ok_q = addr_ok; if ((pi.clocks || pi.make_outreg) && !addr_ok.empty()) { addr_ok_q = module->addWire(NEW_ID); + if (!pi.sig_en.empty()) + addr_ok = module->Mux(NEW_ID, addr_ok_q, addr_ok, pi.sig_en); module->addDff(NEW_ID, pi.sig_clock, addr_ok, addr_ok_q, pi.effective_clkpol); } From 39380c45ba6cb4d2aa3f8c5757a2f1a61f85f8eb Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 3 Apr 2019 14:50:12 +0200 Subject: [PATCH 129/132] proc_mux: Fix crash when trying to optimize non-existant mux to shiftx last_mux_cell can be NULL ... Signed-off-by: Sylvain Munaut --- passes/proc/proc_mux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index 7d3d23408..bac2dc2cd 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -361,7 +361,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d } // Transform into a $shiftx where possible - if (shiftx && last_mux_cell->type == "$pmux") { + if (shiftx && last_mux_cell && last_mux_cell->type == "$pmux") { // Create bit-blasted $shiftx-es that shifts by the address line used in the case statement auto pmux_b_port = last_mux_cell->getPort("\\B"); auto pmux_y_port = last_mux_cell->getPort("\\Y"); From 75ca06526a29dfac447265a52014305fb96d7ebf Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 4 Apr 2019 18:10:10 +0200 Subject: [PATCH 130/132] Added missing argument checking to "mutate" command Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index c50678c51..b53bbfeb2 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -934,6 +934,32 @@ struct MutatePass : public Pass { return; } + if (opts.module.empty()) + log_cmd_error("Missing -module argument.\n"); + + Module *module = design->module(opts.module); + if (module == nullptr) + log_cmd_error("Module %s not found.\n", log_id(opts.module)); + + if (opts.cell.empty()) + log_cmd_error("Missing -cell argument.\n"); + + Cell *cell = module->cell(opts.cell); + if (cell == nullptr) + log_cmd_error("Cell %s not found in module %s.\n", log_id(opts.cell), log_id(opts.module)); + + if (opts.port.empty()) + log_cmd_error("Missing -port argument.\n"); + + if (!cell->hasPort(opts.port)) + log_cmd_error("Port %s not found on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell)); + + if (opts.portbit < 0) + log_cmd_error("Missing -portbit argument.\n"); + + if (GetSize(cell->getPort(opts.port)) <= opts.portbit) + log_cmd_error("Out-of-range -portbit argument for port %s on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell)); + if (opts.mode == "inv") { mutate_inv(design, opts); return; @@ -944,6 +970,12 @@ struct MutatePass : public Pass { return; } + if (opts.ctrlbit < 0) + log_cmd_error("Missing -ctrlbit argument.\n"); + + if (GetSize(cell->getPort(opts.port)) <= opts.ctrlbit) + log_cmd_error("Out-of-range -ctrlbit argument for port %s on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell)); + if (opts.mode == "cnot0" || opts.mode == "cnot1") { mutate_cnot(design, opts, opts.mode == "cnot1"); return; From dfb242c905ff10bb4038f080aeb74a820e8fbd00 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 5 Apr 2019 17:31:49 +0200 Subject: [PATCH 131/132] Add "read_ilang -lib" Signed-off-by: Clifford Wolf --- frontends/ilang/ilang_frontend.cc | 10 +++++++++- frontends/ilang/ilang_frontend.h | 1 + frontends/ilang/ilang_parser.y | 6 ++++-- kernel/rtlil.cc | 24 ++++++++++++++++++++++++ kernel/rtlil.h | 1 + 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc index 6b302a796..30d9ff79d 100644 --- a/frontends/ilang/ilang_frontend.cc +++ b/frontends/ilang/ilang_frontend.cc @@ -47,16 +47,20 @@ struct IlangFrontend : public Frontend { log(" -nooverwrite\n"); log(" ignore re-definitions of modules. (the default behavior is to\n"); log(" create an error message if the existing module is not a blackbox\n"); - log(" module, and overwrite the existing module if it is a blackbox module.)\n"); + log(" module, and overwrite the existing module if it is a blackbox module.)\n"); log("\n"); log(" -overwrite\n"); log(" overwrite existing modules with the same name\n"); log("\n"); + log(" -lib\n"); + log(" only create empty blackbox modules\n"); + log("\n"); } void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE { ILANG_FRONTEND::flag_nooverwrite = false; ILANG_FRONTEND::flag_overwrite = false; + ILANG_FRONTEND::flag_lib = false; log_header(design, "Executing ILANG frontend.\n"); @@ -73,6 +77,10 @@ struct IlangFrontend : public Frontend { ILANG_FRONTEND::flag_overwrite = true; continue; } + if (arg == "-lib") { + ILANG_FRONTEND::flag_lib = true; + continue; + } break; } extra_args(f, filename, args, argidx); diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h index 052dd4cb2..f8a152841 100644 --- a/frontends/ilang/ilang_frontend.h +++ b/frontends/ilang/ilang_frontend.h @@ -34,6 +34,7 @@ namespace ILANG_FRONTEND { extern RTLIL::Design *current_design; extern bool flag_nooverwrite; extern bool flag_overwrite; + extern bool flag_lib; } YOSYS_NAMESPACE_END diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index 5bcc01f42..f83824088 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y @@ -37,7 +37,7 @@ namespace ILANG_FRONTEND { std::vector*> switch_stack; std::vector case_stack; dict attrbuf; - bool flag_nooverwrite, flag_overwrite; + bool flag_nooverwrite, flag_overwrite, flag_lib; bool delete_current_module; } using namespace ILANG_FRONTEND; @@ -98,7 +98,7 @@ module: delete_current_module = false; if (current_design->has($2)) { RTLIL::Module *existing_mod = current_design->module($2); - if (!flag_overwrite && attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()) { + if (!flag_overwrite && (flag_lib || (attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()))) { log("Ignoring blackbox re-definition of module %s.\n", $2); delete_current_module = true; } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { @@ -124,6 +124,8 @@ module: current_module->fixup_ports(); if (delete_current_module) delete current_module; + else if (flag_lib) + current_module->makeblackbox(); current_module = nullptr; } EOL; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index b3214579d..9ae20a317 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -641,6 +641,30 @@ RTLIL::Module::~Module() delete it->second; } +void RTLIL::Module::makeblackbox() +{ + pool delwires; + + for (auto it = wires_.begin(); it != wires_.end(); ++it) + if (!it->second->port_input && !it->second->port_output) + delwires.insert(it->second); + + for (auto it = memories.begin(); it != memories.end(); ++it) + delete it->second; + memories.clear(); + + for (auto it = cells_.begin(); it != cells_.end(); ++it) + delete it->second; + cells_.clear(); + + for (auto it = processes.begin(); it != processes.end(); ++it) + delete it->second; + processes.clear(); + + remove(delwires); + set_bool_attribute("\\blackbox"); +} + void RTLIL::Module::reprocess_module(RTLIL::Design *, dict) { log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name)); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 52496e702..fb045bc72 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -976,6 +976,7 @@ public: virtual void sort(); virtual void check(); virtual void optimize(); + virtual void makeblackbox(); void connect(const RTLIL::SigSig &conn); void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs); From 2bf3ca64435b11726d87cc0d34e887a79351ec45 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 7 Apr 2019 16:56:31 +0100 Subject: [PATCH 132/132] memory_bram: Fix multiport make_transp Signed-off-by: David Shah --- passes/memory/memory_bram.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index 804aa21f9..ddc56d9b5 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -744,7 +744,8 @@ grow_read_ports:; if (clken) { clock_domains[pi.clocks] = clkdom; clock_polarities[pi.clkpol] = clkdom.second; - read_transp[pi.transp] = transp; + if (!pi.make_transp) + read_transp[pi.transp] = transp; pi.sig_clock = clkdom.first; pi.sig_en = rd_en[cell_port_i]; pi.effective_clkpol = clkdom.second;