diff options
Diffstat (limited to 'techlibs')
53 files changed, 2386 insertions, 457 deletions
diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc index 1dc6bdb2f..262a5e700 100644 --- a/techlibs/achronix/synth_achronix.cc +++ b/techlibs/achronix/synth_achronix.cc @@ -144,7 +144,6 @@ struct SynthAchronixPass : public ScriptPass { run("opt -fast -mux_undef -undriven -fine -full"); run("memory_map"); run("opt -undriven -fine"); - run("dffsr2dff"); run("dff2dffe -direct-match $_DFF_*"); run("opt -fine"); run("techmap -map +/techmap.v"); diff --git a/techlibs/anlogic/anlogic_eqn.cc b/techlibs/anlogic/anlogic_eqn.cc index 070d39a20..e4fa4413f 100644 --- a/techlibs/anlogic/anlogic_eqn.cc +++ b/techlibs/anlogic/anlogic_eqn.cc @@ -74,34 +74,34 @@ struct AnlogicEqnPass : public Pass { { for (auto cell : module->selected_cells()) { - if (cell->type == "\\AL_MAP_LUT1") + if (cell->type == ID(AL_MAP_LUT1)) { - cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),1)); + cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT),1)); cnt++; } - if (cell->type == "\\AL_MAP_LUT2") + if (cell->type == ID(AL_MAP_LUT2)) { - cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),2)); + cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT),2)); cnt++; } - if (cell->type == "\\AL_MAP_LUT3") + if (cell->type == ID(AL_MAP_LUT3)) { - cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),3)); + cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT),3)); cnt++; } - if (cell->type == "\\AL_MAP_LUT4") + if (cell->type == ID(AL_MAP_LUT4)) { - cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),4)); + cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT),4)); cnt++; } - if (cell->type == "\\AL_MAP_LUT5") + if (cell->type == ID(AL_MAP_LUT5)) { - cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),5)); + cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT),5)); cnt++; } - if (cell->type == "\\AL_MAP_LUT6") + if (cell->type == ID(AL_MAP_LUT6)) { - cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),6)); + cell->setParam(ID(EQN), init2eqn(cell->getParam(ID::INIT),6)); cnt++; } } diff --git a/techlibs/anlogic/anlogic_fixcarry.cc b/techlibs/anlogic/anlogic_fixcarry.cc index 87164d375..f8e70260c 100644 --- a/techlibs/anlogic/anlogic_fixcarry.cc +++ b/techlibs/anlogic/anlogic_fixcarry.cc @@ -39,13 +39,13 @@ static void fix_carry_chain(Module *module) for (auto cell : module->cells()) { - if (cell->type == "\\AL_MAP_ADDER") { - if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue; - SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a")); - SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b")); + if (cell->type == ID(AL_MAP_ADDER)) { + if (cell->getParam(ID(ALUTYPE)) != Const("ADD")) continue; + SigBit bit_i0 = get_bit_or_zero(cell->getPort(ID(a))); + SigBit bit_i1 = get_bit_or_zero(cell->getPort(ID(b))); if (bit_i0 == State::S0 && bit_i1== State::S0) { - SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c")); - SigSpec o = cell->getPort("\\o"); + SigBit bit_ci = get_bit_or_zero(cell->getPort(ID(c))); + SigSpec o = cell->getPort(ID(o)); if (GetSize(o) == 2) { SigBit bit_o = o[0]; ci_bits.insert(bit_ci); @@ -57,11 +57,11 @@ static void fix_carry_chain(Module *module) vector<Cell*> adders_to_fix_cells; for (auto cell : module->cells()) { - if (cell->type == "\\AL_MAP_ADDER") { - if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue; - SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c")); - SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a")); - SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b")); + if (cell->type == ID(AL_MAP_ADDER)) { + if (cell->getParam(ID(ALUTYPE)) != Const("ADD")) continue; + SigBit bit_ci = get_bit_or_zero(cell->getPort(ID(c))); + SigBit bit_i0 = get_bit_or_zero(cell->getPort(ID(a))); + SigBit bit_i1 = get_bit_or_zero(cell->getPort(ID(b))); SigBit canonical_bit = sigmap(bit_ci); if (!ci_bits.count(canonical_bit)) continue; @@ -75,23 +75,23 @@ static void fix_carry_chain(Module *module) for (auto cell : adders_to_fix_cells) { - SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c")); + SigBit bit_ci = get_bit_or_zero(cell->getPort(ID(c))); SigBit canonical_bit = sigmap(bit_ci); auto bit = mapping_bits.at(canonical_bit); log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell)); - Cell *c = module->addCell(NEW_ID, "\\AL_MAP_ADDER"); + Cell *c = module->addCell(NEW_ID, ID(AL_MAP_ADDER)); SigBit new_bit = module->addWire(NEW_ID); SigBit dummy_bit = module->addWire(NEW_ID); SigSpec bits; bits.append(dummy_bit); bits.append(new_bit); - c->setParam("\\ALUTYPE", Const("ADD_CARRY")); - c->setPort("\\a", bit); - c->setPort("\\b", State::S0); - c->setPort("\\c", State::S0); - c->setPort("\\o", bits); + c->setParam(ID(ALUTYPE), Const("ADD_CARRY")); + c->setPort(ID(a), bit); + c->setPort(ID(b), State::S0); + c->setPort(ID(c), State::S0); + c->setPort(ID(o), bits); - cell->setPort("\\c", new_bit); + cell->setPort(ID(c), new_bit); } } diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc index 96a231286..791dc922f 100644 --- a/techlibs/anlogic/synth_anlogic.cc +++ b/techlibs/anlogic/synth_anlogic.cc @@ -182,7 +182,6 @@ struct SynthAnlogicPass : public ScriptPass if (check_label("map_ffs")) { - run("dffsr2dff"); run("techmap -D NO_LUT -map +/anlogic/cells_map.v"); run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit"); run("opt_expr -mux_undef"); diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index d5e69a241..7b1e4b430 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -30,3 +30,4 @@ $(eval $(call add_share_file,share,techlibs/common/cmp2lut.v)) $(eval $(call add_share_file,share,techlibs/common/cells.lib)) $(eval $(call add_share_file,share,techlibs/common/mul2dsp.v)) $(eval $(call add_share_file,share,techlibs/common/abc9_model.v)) +$(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v)) diff --git a/techlibs/common/cmp2lcu.v b/techlibs/common/cmp2lcu.v new file mode 100644 index 000000000..b6f4aeed6 --- /dev/null +++ b/techlibs/common/cmp2lcu.v @@ -0,0 +1,116 @@ +// This pass performs an optimisation that decomposes wide arithmetic +// comparisons into LUT-size chunks (as guided by the `LUT_WIDTH +// macro) connected to a single lookahead-carry-unit $lcu cell, +// which is typically mapped to dedicated (and fast) FPGA +// carry-chains. +(* techmap_celltype = "$lt $le $gt $ge" *) +module _80_lcu_cmp_ (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +parameter _TECHMAP_CELLTYPE_ = ""; + +generate + if (_TECHMAP_CELLTYPE_ == "" || `LUT_WIDTH < 2) + wire _TECHMAP_FAIL_ = 1; + else if (_TECHMAP_CELLTYPE_ == "$lt") begin + // Transform $lt into $gt by swapping A and B + $gt #(.A_SIGNED(B_SIGNED), .B_SIGNED(A_SIGNED), .A_WIDTH(B_WIDTH), .B_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(B), .B(A), .Y(Y)); + end + else if (_TECHMAP_CELLTYPE_ == "$le") begin + // Transform $le into $ge by swapping A and B + $ge #(.A_SIGNED(B_SIGNED), .B_SIGNED(A_SIGNED), .A_WIDTH(B_WIDTH), .B_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(B), .B(A), .Y(Y)); + end + else begin + // Perform sign extension on A and B + localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; + wire [WIDTH-1:0] AA = {{(WIDTH-A_WIDTH){A_SIGNED ? A[A_WIDTH-1] : 1'b0}}, A}; + wire [WIDTH-1:0] BB = {{(WIDTH-B_WIDTH){B_SIGNED ? B[B_WIDTH-1] : 1'b0}}, B}; + // For $ge operation, start with the assumption that A and B are + // equal (propagating this equality if A and B turn out to be so) + if (_TECHMAP_CELLTYPE_ == "$ge") + localparam CI = 1'b1; + else + localparam CI = 1'b0; + $__CMP2LCU #(.AB_WIDTH(WIDTH), .AB_SIGNED(A_SIGNED && B_SIGNED), .LCU_WIDTH(1), .BUDGET(`LUT_WIDTH), .CI(CI)) + _TECHMAP_REPLACE_ (.A(AA), .B(BB), .P(1'b1), .G(1'b0), .Y(Y)); + end +endgenerate +endmodule + +module $__CMP2LCU (A, B, P, G, Y); + +parameter AB_WIDTH = 0; +parameter AB_SIGNED = 0; +parameter LCU_WIDTH = 1; +parameter BUDGET = 0; +parameter CI = 0; + +input [AB_WIDTH-1:0] A; // A from original $gt/$ge +input [AB_WIDTH-1:0] B; // B from original $gt/$ge +input [LCU_WIDTH-1:0] P; // P of $lcu +input [LCU_WIDTH-1:0] G; // G of $lcu +output Y; + +parameter [AB_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0; +parameter [AB_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0; +parameter [LCU_WIDTH-1:0] _TECHMAP_CONSTMSK_P_ = 0; + +generate + if (AB_WIDTH == 0) begin + wire [LCU_WIDTH-1:0] CO; + $lcu #(.WIDTH(LCU_WIDTH)) _TECHMAP_REPLACE_ (.P(P), .G(G), .CI(CI), .CO(CO)); + assign Y = CO[LCU_WIDTH-1]; + end + else begin + if (_TECHMAP_CONSTMSK_A_[AB_WIDTH-1:0] && _TECHMAP_CONSTMSK_B_[AB_WIDTH-1:0]) + localparam COST = 0; + else if (_TECHMAP_CONSTMSK_A_[AB_WIDTH-1:0] || _TECHMAP_CONSTMSK_B_[AB_WIDTH-1:0]) + localparam COST = 1; + else + localparam COST = 2; + + if (BUDGET < COST) + $__CMP2LCU #(.AB_WIDTH(AB_WIDTH), .AB_SIGNED(AB_SIGNED), .LCU_WIDTH(LCU_WIDTH+1), .BUDGET(`LUT_WIDTH), .CI(CI)) + _TECHMAP_REPLACE_ (.A(A), .B(B), .P({P, 1'b1}), .G({G, 1'b0}), .Y(Y)); + else begin + wire PP, GG; + // Bit-wise equality (xnor) of A and B + assign PP = A[AB_WIDTH-1] ^~ B[AB_WIDTH-1]; + if (AB_SIGNED) + assign GG = ~A[AB_WIDTH-1] & B[AB_WIDTH-1]; + else if (_TECHMAP_CONSTMSK_P_[LCU_WIDTH-1]) // First compare for LUT if P (and G) is constant + assign GG = A[AB_WIDTH-1] & ~B[AB_WIDTH-1]; + else + // Priority "encoder" that checks A[i] == 1'b1 && B[i] == 1'b0 + // from MSB down, deferring to less significant bits if the + // MSBs are equal + assign GG = P[0] & (A[AB_WIDTH-1] & ~B[AB_WIDTH-1]); + if (LCU_WIDTH == 1) begin + // Propagate only if all pairs are equal + // (inconclusive evidence to say A >= B) + wire P_ = P[0] & PP; + // Generate if any comparisons call for it + wire G_ = G[0] | GG; + end + else begin + // Propagate only if all pairs are equal + // (inconclusive evidence to say A >= B) + wire [LCU_WIDTH-1:0] P_ = {P[LCU_WIDTH-1:1], P[0] & PP}; + // Generate if any comparisons call for it + wire [LCU_WIDTH-1:0] G_ = {G[LCU_WIDTH-1:1], G[0] | GG}; + end + $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) + _TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P_), .G(G_), .Y(Y)); + end + end +endgenerate +endmodule diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v index 1c8192b85..8ecd356cc 100644 --- a/techlibs/common/cmp2lut.v +++ b/techlibs/common/cmp2lut.v @@ -57,10 +57,6 @@ function automatic [(1 << `LUT_WIDTH)-1:0] gen_lut; o_bit = (lhs > rhs); if (operation == 3) o_bit = (lhs >= rhs); - if (operation == 4) - o_bit = (lhs == rhs); - if (operation == 5) - o_bit = (lhs != rhs); gen_lut = gen_lut | (o_bit << n); end end @@ -75,10 +71,6 @@ generate localparam operation = 2; if (_TECHMAP_CELLTYPE_ == "$ge") localparam operation = 3; - if (_TECHMAP_CELLTYPE_ == "$eq") - localparam operation = 4; - if (_TECHMAP_CELLTYPE_ == "$ne") - localparam operation = 5; if (A_WIDTH > `LUT_WIDTH || B_WIDTH > `LUT_WIDTH || Y_WIDTH != 1) wire _TECHMAP_FAIL_ = 1; diff --git a/techlibs/common/gen_fine_ffs.py b/techlibs/common/gen_fine_ffs.py new file mode 100644 index 000000000..0abe48f61 --- /dev/null +++ b/techlibs/common/gen_fine_ffs.py @@ -0,0 +1,238 @@ +TEMPLATES = [ +""" +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_SR_{S:N|P}{R:N|P}_ (S, R, Q) +//- +//- A set-reset latch with {S:negative|positive} polarity SET and {R:negative|positive} polarity RESET. +//- +//- Truth table: S R | Q +//- -----+--- +//- - {R:0|1} | 0 +//- {S:0|1} - | 1 +//- - - | q +//- +module \$_SR_{S:N|P}{R:N|P}_ (S, R, Q); +input S, R; +output reg Q; +always @* begin + if (R == {R:0|1}) + Q <= 0; + else if (S == {S:0|1}) + Q <= 1; +end +endmodule +""", +""" +`ifdef SIMCELLS_FF +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_FF_ (D, Q) +//- +//- A D-type flip-flop that is clocked from the implicit global clock. (This cell +//- type is usually only used in netlists for formal verification.) +//- +module \$_FF_ (D, Q); +input D; +output reg Q; +always @($global_clock) begin + Q <= D; +end +endmodule +`endif +""", +""" +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_DFF_{C:N|P}_ (D, C, Q) +//- +//- A {C:negative|positive} edge D-type flip-flop. +//- +//- Truth table: D C | Q +//- -----+--- +//- d {C:\\|/} | d +//- - - | q +//- +module \$_DFF_{C:N|P}_ (D, C, Q); +input D, C; +output reg Q; +always @({C:neg|pos}edge C) begin + Q <= D; +end +endmodule +""", +""" +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_DFFE_{C:N|P}{E:N|P}_ (D, C, E, Q) +//- +//- A {C:negative|positive} edge D-type flip-flop with {E:negative|positive} polarity enable. +//- +//- Truth table: D C E | Q +//- -------+--- +//- d {C:\\|/} {E:0|1} | d +//- - - - | q +//- +module \$_DFFE_{C:N|P}{E:N|P}_ (D, C, E, Q); +input D, C, E; +output reg Q; +always @({C:neg|pos}edge C) begin + if ({E:!E|E}) Q <= D; +end +endmodule +""", +""" +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_DFF_{C:N|P}{R:N|P}{V:0|1}_ (D, C, R, Q) +//- +//- A {C:negative|positive} edge D-type flip-flop with {R:negative|positive} polarity {V:reset|set}. +//- +//- Truth table: D C R | Q +//- -------+--- +//- - - {R:0|1} | {V:0|1} +//- d {C:\\|/} - | d +//- - - - | q +//- +module \$_DFF_{C:N|P}{R:N|P}{V:0|1}_ (D, C, R, Q); +input D, C, R; +output reg Q; +always @({C:neg|pos}edge C or {R:neg|pos}edge R) begin + if (R == {R:0|1}) + Q <= {V:0|1}; + else + Q <= D; +end +endmodule +""", +""" +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_DFFSR_{C:N|P}{S:N|P}{R:N|P}_ (C, S, R, D, Q) +//- +//- A {C:negative|positive} edge D-type flip-flop with {S:negative|positive} polarity set and {R:negative|positive} +//- polarity reset. +//- +//- Truth table: C S R D | Q +//- ---------+--- +//- - - {R:0|1} - | 0 +//- - {S:0|1} - - | 1 +//- {C:\\|/} - - d | d +//- - - - - | q +//- +module \$_DFFSR_{C:N|P}{S:N|P}{R:N|P}_ (C, S, R, D, Q); +input C, S, R, D; +output reg Q; +always @({C:neg|pos}edge C, {S:neg|pos}edge S, {R:neg|pos}edge R) begin + if (R == {R:0|1}) + Q <= 0; + else if (S == {S:0|1}) + Q <= 1; + else + Q <= D; +end +endmodule +""", +""" +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_DLATCH_{E:N|P}_ (E, D, Q) +//- +//- A {E:negative|positive} enable D-type latch. +//- +//- Truth table: E D | Q +//- -----+--- +//- {E:0|1} d | d +//- - - | q +//- +module \$_DLATCH_{E:N|P}_ (E, D, Q); +input E, D; +output reg Q; +always @* begin + if (E == {E:0|1}) + Q <= D; +end +endmodule +""", +""" +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_DLATCHSR_{E:N|P}{S:N|P}{R:N|P}_ (E, S, R, D, Q) +//- +//- A {E:negative|positive} enable D-type latch with {S:negative|positive} polarity set and {R:negative|positive} +//- polarity reset. +//- +//- Truth table: E S R D | Q +//- ---------+--- +//- - - {R:0|1} - | 0 +//- - {S:0|1} - - | 1 +//- {E:0|1} - - d | d +//- - - - - | q +//- +module \$_DLATCHSR_{E:N|P}{S:N|P}{R:N|P}_ (E, S, R, D, Q); +input E, S, R, D; +output reg Q; +always @* begin + if (R == {R:0|1}) + Q <= 0; + else if (S == {S:0|1}) + Q <= 1; + else if (E == {E:0|1}) + Q <= D; +end +endmodule +""", +] + +lines = [] +with open('simcells.v') as f: + for l in f: + lines.append(l) + if 'START AUTOGENERATED CELL TYPES' in l: + break + +with open('simcells.v', 'w') as f: + for l in lines: + f.write(l) + for template in TEMPLATES: + chunks = [] + vars = {} + pos = 0 + while pos < len(template): + if template[pos] != '{': + np = template.find('{', pos) + if np == -1: + np = len(template) + chunks.append(template[pos:np]) + pos = np + else: + np = template.index('}', pos) + sub = template[pos + 1:np] + pos = np + 1 + var, _, vals = sub.partition(':') + if not vals: + raise ValueError(sub) + vals = vals.split('|') + if var not in vars: + vars[var] = len(vals) + else: + if vars[var] != len(vals): + raise ValueError(vars[var], vals) + chunks.append((var, vals)) + combs = [{}] + for var in vars: + combs = [ + { + var: i, + **comb, + } + for comb in combs + for i in range(vars[var]) + ] + for comb in combs: + f.write( + ''.join( + c if isinstance(c, str) else c[1][comb[c[0]]] + for c in chunks + ) + ) diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v index 64720e598..157e8d23b 100644 --- a/techlibs/common/simcells.v +++ b/techlibs/common/simcells.v @@ -456,23 +456,27 @@ output Y; assign Y = E ? A : 1'bz; endmodule +// NOTE: the following cell types are autogenerated. DO NOT EDIT them manually, +// instead edit the templates in gen_ff_types.py and rerun it. + +// START AUTOGENERATED CELL TYPES + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- //- $_SR_NN_ (S, R, Q) //- -//- A set-reset latch with negative polarity SET and RESET. +//- A set-reset latch with negative polarity SET and negative polarity RESET. //- //- Truth table: S R | Q //- -----+--- -//- 0 0 | x -//- 0 1 | 1 -//- 1 0 | 0 -//- 1 1 | y +//- - 0 | 0 +//- 0 - | 1 +//- - - | q //- module \$_SR_NN_ (S, R, Q); input S, R; output reg Q; -always @(negedge S, negedge R) begin +always @* begin if (R == 0) Q <= 0; else if (S == 0) @@ -488,15 +492,14 @@ endmodule //- //- Truth table: S R | Q //- -----+--- -//- 0 1 | x -//- 0 0 | 1 -//- 1 1 | 0 -//- 1 0 | y +//- - 1 | 0 +//- 0 - | 1 +//- - - | q //- module \$_SR_NP_ (S, R, Q); input S, R; output reg Q; -always @(negedge S, posedge R) begin +always @* begin if (R == 1) Q <= 0; else if (S == 0) @@ -512,15 +515,14 @@ endmodule //- //- Truth table: S R | Q //- -----+--- -//- 1 0 | x -//- 1 1 | 1 -//- 0 0 | 0 -//- 0 1 | y +//- - 0 | 0 +//- 1 - | 1 +//- - - | q //- module \$_SR_PN_ (S, R, Q); input S, R; output reg Q; -always @(posedge S, negedge R) begin +always @* begin if (R == 0) Q <= 0; else if (S == 1) @@ -532,19 +534,18 @@ endmodule //- //- $_SR_PP_ (S, R, Q) //- -//- A set-reset latch with positive polarity SET and RESET. +//- A set-reset latch with positive polarity SET and positive polarity RESET. //- //- Truth table: S R | Q //- -----+--- -//- 1 1 | x -//- 1 0 | 1 -//- 0 1 | 0 -//- 0 0 | y +//- - 1 | 0 +//- 1 - | 1 +//- - - | q //- module \$_SR_PP_ (S, R, Q); input S, R; output reg Q; -always @(posedge S, posedge R) begin +always @* begin if (R == 1) Q <= 0; else if (S == 1) @@ -871,7 +872,8 @@ endmodule //- //- $_DFFSR_NNN_ (C, S, R, D, Q) //- -//- A negative edge D-type flip-flop with negative polarity set and reset. +//- A negative edge D-type flip-flop with negative polarity set and negative +//- polarity reset. //- //- Truth table: C S R D | Q //- ---------+--- @@ -951,7 +953,8 @@ endmodule //- //- $_DFFSR_NPP_ (C, S, R, D, Q) //- -//- A negative edge D-type flip-flop with positive polarity set and reset. +//- A negative edge D-type flip-flop with positive polarity set and positive +//- polarity reset. //- //- Truth table: C S R D | Q //- ---------+--- @@ -977,7 +980,8 @@ endmodule //- //- $_DFFSR_PNN_ (C, S, R, D, Q) //- -//- A positive edge D-type flip-flop with negative polarity set and reset. +//- A positive edge D-type flip-flop with negative polarity set and negative +//- polarity reset. //- //- Truth table: C S R D | Q //- ---------+--- @@ -1057,7 +1061,8 @@ endmodule //- //- $_DFFSR_PPP_ (C, S, R, D, Q) //- -//- A positive edge D-type flip-flop with positive polarity set and reset. +//- A positive edge D-type flip-flop with positive polarity set and positive +//- polarity reset. //- //- Truth table: C S R D | Q //- ---------+--- @@ -1123,7 +1128,8 @@ endmodule //- //- $_DLATCHSR_NNN_ (E, S, R, D, Q) //- -//- A negative enable D-type latch with negative polarity set and reset. +//- A negative enable D-type latch with negative polarity set and negative +//- polarity reset. //- //- Truth table: E S R D | Q //- ---------+--- @@ -1149,8 +1155,8 @@ endmodule //- //- $_DLATCHSR_NNP_ (E, S, R, D, Q) //- -//- A negative enable D-type latch with negative polarity set and positive polarity -//- reset. +//- A negative enable D-type latch with negative polarity set and positive +//- polarity reset. //- //- Truth table: E S R D | Q //- ---------+--- @@ -1176,8 +1182,8 @@ endmodule //- //- $_DLATCHSR_NPN_ (E, S, R, D, Q) //- -//- A negative enable D-type latch with positive polarity set and negative polarity -//- reset. +//- A negative enable D-type latch with positive polarity set and negative +//- polarity reset. //- //- Truth table: E S R D | Q //- ---------+--- @@ -1203,7 +1209,8 @@ endmodule //- //- $_DLATCHSR_NPP_ (E, S, R, D, Q) //- -//- A negative enable D-type latch with positive polarity set and reset. +//- A negative enable D-type latch with positive polarity set and positive +//- polarity reset. //- //- Truth table: E S R D | Q //- ---------+--- @@ -1229,7 +1236,8 @@ endmodule //- //- $_DLATCHSR_PNN_ (E, S, R, D, Q) //- -//- A positive enable D-type latch with negative polarity set and reset. +//- A positive enable D-type latch with negative polarity set and negative +//- polarity reset. //- //- Truth table: E S R D | Q //- ---------+--- @@ -1255,8 +1263,8 @@ endmodule //- //- $_DLATCHSR_PNP_ (E, S, R, D, Q) //- -//- A positive enable D-type latch with negative polarity set and positive polarity -//- reset. +//- A positive enable D-type latch with negative polarity set and positive +//- polarity reset. //- //- Truth table: E S R D | Q //- ---------+--- @@ -1282,8 +1290,8 @@ endmodule //- //- $_DLATCHSR_PPN_ (E, S, R, D, Q) //- -//- A positive enable D-type latch with positive polarity set and negative polarity -//- reset. +//- A positive enable D-type latch with positive polarity set and negative +//- polarity reset. //- //- Truth table: E S R D | Q //- ---------+--- @@ -1309,7 +1317,8 @@ endmodule //- //- $_DLATCHSR_PPP_ (E, S, R, D, Q) //- -//- A positive enable D-type latch with positive polarity set and reset. +//- A positive enable D-type latch with positive polarity set and positive +//- polarity reset. //- //- Truth table: E S R D | Q //- ---------+--- @@ -1330,4 +1339,3 @@ always @* begin Q <= D; end endmodule - diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 7845a3fed..2cdddeabb 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1633,7 +1633,7 @@ wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; genvar i; generate for (i = 0; i < WIDTH; i = i+1) begin:bitslices - always @(posedge pos_set[i], posedge pos_clr[i]) + always @* if (pos_clr[i]) Q[i] <= 0; else if (pos_set[i]) diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index e7a192c07..d6dffdd7f 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -225,9 +225,9 @@ struct SynthPass : public ScriptPass run("peepopt"); run("opt_clean"); if (help_mode) - run("techmap -map +/cmp2lut.v", " (if -lut)"); - else - run(stringf("techmap -map +/cmp2lut.v -D LUT_WIDTH=%d", lut)); + run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v", " (if -lut)"); + else if (lut) + run(stringf("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=%d", lut)); if (!noalumacc) run("alumacc", " (unless -noalumacc)"); if (!noshare) diff --git a/techlibs/coolrunner2/coolrunner2_fixup.cc b/techlibs/coolrunner2/coolrunner2_fixup.cc index a71a1227e..8bbff9ba5 100644 --- a/techlibs/coolrunner2/coolrunner2_fixup.cc +++ b/techlibs/coolrunner2/coolrunner2_fixup.cc @@ -34,9 +34,9 @@ RTLIL::Wire *makexorbuffer(RTLIL::Module *module, SigBit inwire, const char *cel module->uniquify(stringf("$xc2fix$%s_BUF1_XOR_OUT", cellname))); auto xor_cell = module->addCell( module->uniquify(stringf("$xc2fix$%s_BUF1_XOR", cellname)), - "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_OUT", true); - xor_cell->setPort("\\OUT", outwire); + ID(MACROCELL_XOR)); + xor_cell->setParam(ID(INVERT_OUT), true); + xor_cell->setPort(ID(OUT), outwire); } else if (inwire == SigBit(false)) { @@ -45,9 +45,9 @@ RTLIL::Wire *makexorbuffer(RTLIL::Module *module, SigBit inwire, const char *cel module->uniquify(stringf("$xc2fix$%s_BUF0_XOR_OUT", cellname))); auto xor_cell = module->addCell( module->uniquify(stringf("$xc2fix$%s_BUF0_XOR", cellname)), - "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_OUT", false); - xor_cell->setPort("\\OUT", outwire); + ID(MACROCELL_XOR)); + xor_cell->setParam(ID(INVERT_OUT), false); + xor_cell->setPort(ID(OUT), outwire); } else if (inwire == SigBit(RTLIL::State::Sx)) { @@ -57,9 +57,9 @@ RTLIL::Wire *makexorbuffer(RTLIL::Module *module, SigBit inwire, const char *cel module->uniquify(stringf("$xc2fix$%s_BUF0_XOR_OUT", cellname))); auto xor_cell = module->addCell( module->uniquify(stringf("$xc2fix$%s_BUF0_XOR", cellname)), - "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_OUT", false); - xor_cell->setPort("\\OUT", outwire); + ID(MACROCELL_XOR)); + xor_cell->setParam(ID(INVERT_OUT), false); + xor_cell->setPort(ID(OUT), outwire); } else { @@ -73,19 +73,19 @@ RTLIL::Wire *makexorbuffer(RTLIL::Module *module, SigBit inwire, const char *cel auto and_cell = module->addCell( module->uniquify(stringf("$xc2fix$%s_BUF_AND", inwire_name)), - "\\ANDTERM"); - and_cell->setParam("\\TRUE_INP", 1); - and_cell->setParam("\\COMP_INP", 0); - and_cell->setPort("\\OUT", and_to_xor_wire); - and_cell->setPort("\\IN", inwire); - and_cell->setPort("\\IN_B", SigSpec()); + ID(ANDTERM)); + and_cell->setParam(ID(TRUE_INP), 1); + and_cell->setParam(ID(COMP_INP), 0); + and_cell->setPort(ID(OUT), and_to_xor_wire); + and_cell->setPort(ID(IN), inwire); + and_cell->setPort(ID(IN_B), SigSpec()); auto xor_cell = module->addCell( module->uniquify(stringf("$xc2fix$%s_BUF_XOR", inwire_name)), - "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_OUT", false); - xor_cell->setPort("\\IN_PTC", and_to_xor_wire); - xor_cell->setPort("\\OUT", outwire); + ID(MACROCELL_XOR)); + xor_cell->setParam(ID(INVERT_OUT), false); + xor_cell->setPort(ID(IN_PTC), and_to_xor_wire); + xor_cell->setPort(ID(OUT), outwire); } return outwire; @@ -100,12 +100,12 @@ RTLIL::Wire *makeptermbuffer(RTLIL::Module *module, SigBit inwire) auto and_cell = module->addCell( module->uniquify(stringf("$xc2fix$%s_BUF_AND", inwire_name)), - "\\ANDTERM"); - and_cell->setParam("\\TRUE_INP", 1); - and_cell->setParam("\\COMP_INP", 0); - and_cell->setPort("\\OUT", outwire); - and_cell->setPort("\\IN", inwire); - and_cell->setPort("\\IN_B", SigSpec()); + ID(ANDTERM)); + and_cell->setParam(ID(TRUE_INP), 1); + and_cell->setParam(ID(COMP_INP), 0); + and_cell->setPort(ID(OUT), outwire); + and_cell->setPort(ID(IN), inwire); + and_cell->setPort(ID(IN_B), SigSpec()); return outwire; } @@ -133,10 +133,10 @@ struct Coolrunner2FixupPass : public Pass { pool<SigBit> sig_fed_by_ff; for (auto cell : module->selected_cells()) { - if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N", - "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE")) + if (cell->type.in(ID(FDCP), ID(FDCP_N), ID(FDDCP), ID(LDCP), ID(LDCP_N), + ID(FTCP), ID(FTCP_N), ID(FTDCP), ID(FDCPE), ID(FDCPE_N), ID(FDDCPE))) { - auto output = sigmap(cell->getPort("\\Q")[0]); + auto output = sigmap(cell->getPort(ID::Q)[0]); sig_fed_by_ff.insert(output); } } @@ -145,9 +145,9 @@ struct Coolrunner2FixupPass : public Pass { pool<SigBit> sig_fed_by_xor; for (auto cell : module->selected_cells()) { - if (cell->type == "\\MACROCELL_XOR") + if (cell->type == ID(MACROCELL_XOR)) { - auto output = sigmap(cell->getPort("\\OUT")[0]); + auto output = sigmap(cell->getPort(ID(OUT))[0]); sig_fed_by_xor.insert(output); } } @@ -156,10 +156,10 @@ struct Coolrunner2FixupPass : public Pass { pool<SigBit> sig_fed_by_io; for (auto cell : module->selected_cells()) { - if (cell->type.in("\\IBUF", "\\IOBUFE")) + if (cell->type.in(ID(IBUF), ID(IOBUFE))) { - if (cell->hasPort("\\O")) { - auto output = sigmap(cell->getPort("\\O")[0]); + if (cell->hasPort(ID::O)) { + auto output = sigmap(cell->getPort(ID::O)[0]); sig_fed_by_io.insert(output); } } @@ -169,9 +169,9 @@ struct Coolrunner2FixupPass : public Pass { pool<SigBit> sig_fed_by_pterm; for (auto cell : module->selected_cells()) { - if (cell->type == "\\ANDTERM") + if (cell->type == ID(ANDTERM)) { - auto output = sigmap(cell->getPort("\\OUT")[0]); + auto output = sigmap(cell->getPort(ID(OUT))[0]); sig_fed_by_pterm.insert(output); } } @@ -180,9 +180,9 @@ struct Coolrunner2FixupPass : public Pass { pool<SigBit> sig_fed_by_bufg; for (auto cell : module->selected_cells()) { - if (cell->type == "\\BUFG") + if (cell->type == ID(BUFG)) { - auto output = sigmap(cell->getPort("\\O")[0]); + auto output = sigmap(cell->getPort(ID::O)[0]); sig_fed_by_bufg.insert(output); } } @@ -191,9 +191,9 @@ struct Coolrunner2FixupPass : public Pass { pool<SigBit> sig_fed_by_bufgsr; for (auto cell : module->selected_cells()) { - if (cell->type == "\\BUFGSR") + if (cell->type == ID(BUFGSR)) { - auto output = sigmap(cell->getPort("\\O")[0]); + auto output = sigmap(cell->getPort(ID::O)[0]); sig_fed_by_bufgsr.insert(output); } } @@ -202,9 +202,9 @@ struct Coolrunner2FixupPass : public Pass { pool<SigBit> sig_fed_by_bufgts; for (auto cell : module->selected_cells()) { - if (cell->type == "\\BUFGTS") + if (cell->type == ID(BUFGTS)) { - auto output = sigmap(cell->getPort("\\O")[0]); + auto output = sigmap(cell->getPort(ID::O)[0]); sig_fed_by_bufgts.insert(output); } } @@ -213,9 +213,9 @@ struct Coolrunner2FixupPass : public Pass { pool<SigBit> sig_fed_by_ibuf; for (auto cell : module->selected_cells()) { - if (cell->type == "\\IBUF") + if (cell->type == ID(IBUF)) { - auto output = sigmap(cell->getPort("\\O")[0]); + auto output = sigmap(cell->getPort(ID::O)[0]); sig_fed_by_ibuf.insert(output); } } @@ -254,15 +254,15 @@ struct Coolrunner2FixupPass : public Pass { // the pad-to-zia path has to be used up and the register // can't be packed with the ibuf. if (fanout_count == 1 && maybe_ff_cell->type.in( - "\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N", - "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE")) + ID(FDCP), ID(FDCP_N), ID(FDDCP), ID(LDCP), ID(LDCP_N), + ID(FTCP), ID(FTCP_N), ID(FTDCP), ID(FDCPE), ID(FDCPE_N), ID(FDDCPE))) { SigBit input; - if (maybe_ff_cell->type.in("\\FTCP", "\\FTCP_N", "\\FTDCP")) - input = sigmap(maybe_ff_cell->getPort("\\T")[0]); + if (maybe_ff_cell->type.in(ID(FTCP), ID(FTCP_N), ID(FTDCP))) + input = sigmap(maybe_ff_cell->getPort(ID::T)[0]); else - input = sigmap(maybe_ff_cell->getPort("\\D")[0]); - SigBit output = sigmap(maybe_ff_cell->getPort("\\Q")[0]); + input = sigmap(maybe_ff_cell->getPort(ID::D)[0]); + SigBit output = sigmap(maybe_ff_cell->getPort(ID::Q)[0]); if (input == ibuf_out_wire) { @@ -279,17 +279,17 @@ struct Coolrunner2FixupPass : public Pass { for (auto cell : module->selected_cells()) { - if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N", - "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE")) + if (cell->type.in(ID(FDCP), ID(FDCP_N), ID(FDDCP), ID(LDCP), ID(LDCP_N), + ID(FTCP), ID(FTCP_N), ID(FTDCP), ID(FDCPE), ID(FDCPE_N), ID(FDDCPE))) { // Buffering FF inputs. FF inputs can only come from either // an IO pin or from an XOR. Otherwise AND/XOR cells need // to be inserted. SigBit input; - if (cell->type.in("\\FTCP", "\\FTCP_N", "\\FTDCP")) - input = sigmap(cell->getPort("\\T")[0]); + if (cell->type.in(ID(FTCP), ID(FTCP_N), ID(FTDCP))) + input = sigmap(cell->getPort(ID::T)[0]); else - input = sigmap(cell->getPort("\\D")[0]); + input = sigmap(cell->getPort(ID::D)[0]); // If the input wasn't an XOR nor an IO, then a buffer // definitely needs to be added. @@ -302,10 +302,10 @@ struct Coolrunner2FixupPass : public Pass { auto xor_to_ff_wire = makexorbuffer(module, input, cell->name.c_str()); - if (cell->type.in("\\FTCP", "\\FTCP_N", "\\FTDCP")) - cell->setPort("\\T", xor_to_ff_wire); + if (cell->type.in(ID(FTCP), ID(FTCP_N), ID(FTDCP))) + cell->setPort(ID::T, xor_to_ff_wire); else - cell->setPort("\\D", xor_to_ff_wire); + cell->setPort(ID::D, xor_to_ff_wire); } // Buffering FF clocks. FF clocks can only come from either @@ -313,10 +313,10 @@ struct Coolrunner2FixupPass : public Pass { // in coolrunner2_sop (e.g. if clock is generated from // AND-ing two signals) but not in all cases. SigBit clock; - if (cell->type.in("\\LDCP", "\\LDCP_N")) - clock = sigmap(cell->getPort("\\G")[0]); + if (cell->type.in(ID(LDCP), ID(LDCP_N))) + clock = sigmap(cell->getPort(ID::G)[0]); else - clock = sigmap(cell->getPort("\\C")[0]); + clock = sigmap(cell->getPort(ID::C)[0]); if (!sig_fed_by_pterm[clock] && !sig_fed_by_bufg[clock]) { @@ -324,16 +324,16 @@ struct Coolrunner2FixupPass : public Pass { auto pterm_to_ff_wire = makeptermbuffer(module, clock); - if (cell->type.in("\\LDCP", "\\LDCP_N")) - cell->setPort("\\G", pterm_to_ff_wire); + if (cell->type.in(ID(LDCP), ID(LDCP_N))) + cell->setPort(ID::G, pterm_to_ff_wire); else - cell->setPort("\\C", pterm_to_ff_wire); + cell->setPort(ID::C, pterm_to_ff_wire); } // Buffering FF set/reset. This can only come from either // a pterm or a bufgsr. SigBit set; - set = sigmap(cell->getPort("\\PRE")[0]); + set = sigmap(cell->getPort(ID(PRE))[0]); if (set != SigBit(false)) { if (!sig_fed_by_pterm[set] && !sig_fed_by_bufgsr[set]) @@ -342,12 +342,12 @@ struct Coolrunner2FixupPass : public Pass { auto pterm_to_ff_wire = makeptermbuffer(module, set); - cell->setPort("\\PRE", pterm_to_ff_wire); + cell->setPort(ID(PRE), pterm_to_ff_wire); } } SigBit reset; - reset = sigmap(cell->getPort("\\CLR")[0]); + reset = sigmap(cell->getPort(ID::CLR)[0]); if (reset != SigBit(false)) { if (!sig_fed_by_pterm[reset] && !sig_fed_by_bufgsr[reset]) @@ -356,24 +356,24 @@ struct Coolrunner2FixupPass : public Pass { auto pterm_to_ff_wire = makeptermbuffer(module, reset); - cell->setPort("\\CLR", pterm_to_ff_wire); + cell->setPort(ID::CLR, pterm_to_ff_wire); } } // Buffering FF clock enable // FIXME: This doesn't fully fix PTC conflicts // FIXME: Need to ensure constant enables are optimized out - if (cell->type.in("\\FDCPE", "\\FDCPE_N", "\\FDDCPE")) + if (cell->type.in(ID(FDCPE), ID(FDCPE_N), ID(FDDCPE))) { SigBit ce; - ce = sigmap(cell->getPort("\\CE")[0]); + ce = sigmap(cell->getPort(ID(CE))[0]); if (!sig_fed_by_pterm[ce]) { log("Buffering clock enable to \"%s\"\n", cell->name.c_str()); auto pterm_to_ff_wire = makeptermbuffer(module, ce); - cell->setPort("\\CE", pterm_to_ff_wire); + cell->setPort(ID(CE), pterm_to_ff_wire); } } } @@ -381,10 +381,10 @@ struct Coolrunner2FixupPass : public Pass { for (auto cell : module->selected_cells()) { - if (cell->type == "\\IOBUFE") + if (cell->type == ID(IOBUFE)) { // Buffer IOBUFE inputs. This can only be fed from an XOR or FF. - SigBit input = sigmap(cell->getPort("\\I")[0]); + SigBit input = sigmap(cell->getPort(ID::I)[0]); if ((!sig_fed_by_xor[input] && !sig_fed_by_ff[input]) || packed_reg_out[input]) @@ -393,22 +393,22 @@ struct Coolrunner2FixupPass : public Pass { auto xor_to_io_wire = makexorbuffer(module, input, cell->name.c_str()); - cell->setPort("\\I", xor_to_io_wire); + cell->setPort(ID::I, xor_to_io_wire); } // Buffer IOBUFE enables. This can only be fed from a pterm // or a bufgts. - if (cell->hasPort("\\E")) + if (cell->hasPort(ID::E)) { SigBit oe; - oe = sigmap(cell->getPort("\\E")[0]); + oe = sigmap(cell->getPort(ID::E)[0]); if (!sig_fed_by_pterm[oe] && !sig_fed_by_bufgts[oe]) { log("Buffering output enable to \"%s\"\n", cell->name.c_str()); auto pterm_to_oe_wire = makeptermbuffer(module, oe); - cell->setPort("\\E", pterm_to_oe_wire); + cell->setPort(ID::E, pterm_to_oe_wire); } } } @@ -422,9 +422,9 @@ struct Coolrunner2FixupPass : public Pass { dict<SigBit, RTLIL::Cell *> xor_out_to_xor_cell; for (auto cell : module->selected_cells()) { - if (cell->type == "\\MACROCELL_XOR") + if (cell->type == ID(MACROCELL_XOR)) { - auto output = sigmap(cell->getPort("\\OUT")[0]); + auto output = sigmap(cell->getPort(ID(OUT))[0]); xor_out_to_xor_cell[output] = cell; } } @@ -433,7 +433,7 @@ struct Coolrunner2FixupPass : public Pass { pool<SigBit> xor_fanout_once; for (auto cell : module->selected_cells()) { - if (cell->type == "\\ANDTERM") + if (cell->type == ID(ANDTERM)) continue; for (auto &conn : cell->connections()) @@ -456,7 +456,7 @@ struct Coolrunner2FixupPass : public Pass { module->uniquify(xor_cell->name), xor_cell); auto new_wire = module->addWire( module->uniquify(wire_in.wire->name)); - new_xor_cell->setPort("\\OUT", new_wire); + new_xor_cell->setPort(ID(OUT), new_wire); cell->setPort(conn.first, new_wire); } xor_fanout_once.insert(wire_in); @@ -473,9 +473,9 @@ struct Coolrunner2FixupPass : public Pass { dict<SigBit, RTLIL::Cell *> or_out_to_or_cell; for (auto cell : module->selected_cells()) { - if (cell->type == "\\ORTERM") + if (cell->type == ID(ORTERM)) { - auto output = sigmap(cell->getPort("\\OUT")[0]); + auto output = sigmap(cell->getPort(ID(OUT))[0]); or_out_to_or_cell[output] = cell; } } @@ -504,7 +504,7 @@ struct Coolrunner2FixupPass : public Pass { module->uniquify(or_cell->name), or_cell); auto new_wire = module->addWire( module->uniquify(wire_in.wire->name)); - new_or_cell->setPort("\\OUT", new_wire); + new_or_cell->setPort(ID(OUT), new_wire); cell->setPort(conn.first, new_wire); } or_fanout_once.insert(wire_in); diff --git a/techlibs/coolrunner2/coolrunner2_sop.cc b/techlibs/coolrunner2/coolrunner2_sop.cc index 581477473..045c73978 100644 --- a/techlibs/coolrunner2/coolrunner2_sop.cc +++ b/techlibs/coolrunner2/coolrunner2_sop.cc @@ -47,52 +47,52 @@ struct Coolrunner2SopPass : public Pass { dict<SigBit, tuple<SigBit, Cell*>> not_cells; for (auto cell : module->selected_cells()) { - if (cell->type == "$_NOT_") + if (cell->type == ID($_NOT_)) { - auto not_input = sigmap(cell->getPort("\\A")[0]); - auto not_output = sigmap(cell->getPort("\\Y")[0]); + auto not_input = sigmap(cell->getPort(ID::A)[0]); + auto not_output = sigmap(cell->getPort(ID::Y)[0]); not_cells[not_input] = tuple<SigBit, Cell*>(not_output, cell); } } // Find wires that need to become special product terms - dict<SigBit, pool<tuple<Cell*, std::string>>> special_pterms_no_inv; - dict<SigBit, pool<tuple<Cell*, std::string>>> special_pterms_inv; + dict<SigBit, pool<tuple<Cell*, IdString>>> special_pterms_no_inv; + dict<SigBit, pool<tuple<Cell*, IdString>>> special_pterms_inv; for (auto cell : module->selected_cells()) { - if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\FTCP", "\\FTCP_N", "\\FTDCP", - "\\FDCPE", "\\FDCPE_N", "\\FDDCPE", "\\LDCP", "\\LDCP_N")) + if (cell->type.in(ID(FDCP), ID(FDCP_N), ID(FDDCP), ID(FTCP), ID(FTCP_N), ID(FTDCP), + ID(FDCPE), ID(FDCPE_N), ID(FDDCPE), ID(LDCP), ID(LDCP_N))) { - if (cell->hasPort("\\PRE")) - special_pterms_no_inv[sigmap(cell->getPort("\\PRE")[0])].insert( - tuple<Cell*, const char *>(cell, "\\PRE")); - if (cell->hasPort("\\CLR")) - special_pterms_no_inv[sigmap(cell->getPort("\\CLR")[0])].insert( - tuple<Cell*, const char *>(cell, "\\CLR")); - if (cell->hasPort("\\CE")) - special_pterms_no_inv[sigmap(cell->getPort("\\CE")[0])].insert( - tuple<Cell*, const char *>(cell, "\\CE")); - - if (cell->hasPort("\\C")) - special_pterms_inv[sigmap(cell->getPort("\\C")[0])].insert( - tuple<Cell*, const char *>(cell, "\\C")); - if (cell->hasPort("\\G")) - special_pterms_inv[sigmap(cell->getPort("\\G")[0])].insert( - tuple<Cell*, const char *>(cell, "\\G")); + if (cell->hasPort(ID(PRE))) + special_pterms_no_inv[sigmap(cell->getPort(ID(PRE))[0])].insert( + make_tuple(cell, ID(PRE))); + if (cell->hasPort(ID::CLR)) + special_pterms_no_inv[sigmap(cell->getPort(ID::CLR)[0])].insert( + make_tuple(cell, ID::CLR)); + if (cell->hasPort(ID(CE))) + special_pterms_no_inv[sigmap(cell->getPort(ID(CE))[0])].insert( + make_tuple(cell, ID(CE))); + + if (cell->hasPort(ID::C)) + special_pterms_inv[sigmap(cell->getPort(ID::C)[0])].insert( + make_tuple(cell, ID::C)); + if (cell->hasPort(ID::G)) + special_pterms_inv[sigmap(cell->getPort(ID::G)[0])].insert( + make_tuple(cell, ID::G)); } } // Process $sop cells for (auto cell : module->selected_cells()) { - if (cell->type == "$sop") + if (cell->type == ID($sop)) { // Read the inputs/outputs/parameters of the $sop cell - auto sop_inputs = sigmap(cell->getPort("\\A")); - auto sop_output = sigmap(cell->getPort("\\Y"))[0]; - auto sop_depth = cell->getParam("\\DEPTH").as_int(); - auto sop_width = cell->getParam("\\WIDTH").as_int(); - auto sop_table = cell->getParam("\\TABLE"); + auto sop_inputs = sigmap(cell->getPort(ID::A)); + auto sop_output = sigmap(cell->getPort(ID::Y))[0]; + auto sop_depth = cell->getParam(ID::DEPTH).as_int(); + auto sop_width = cell->getParam(ID::WIDTH).as_int(); + auto sop_table = cell->getParam(ID::TABLE); auto sop_output_wire_name = sop_output.wire->name.c_str(); @@ -139,12 +139,12 @@ struct Coolrunner2SopPass : public Pass { // Construct the cell auto and_cell = module->addCell( module->uniquify(stringf("$xc2sop$%s_AND%d", sop_output_wire_name, i)), - "\\ANDTERM"); - and_cell->setParam("\\TRUE_INP", GetSize(and_in_true)); - and_cell->setParam("\\COMP_INP", GetSize(and_in_comp)); - and_cell->setPort("\\OUT", and_out); - and_cell->setPort("\\IN", and_in_true); - and_cell->setPort("\\IN_B", and_in_comp); + ID(ANDTERM)); + and_cell->setParam(ID(TRUE_INP), GetSize(and_in_true)); + and_cell->setParam(ID(COMP_INP), GetSize(and_in_comp)); + and_cell->setPort(ID(OUT), and_out); + and_cell->setPort(ID(IN), and_in_true); + and_cell->setPort(ID(IN_B), and_in_comp); } if (sop_depth == 1) @@ -152,17 +152,17 @@ struct Coolrunner2SopPass : public Pass { // If there is only one term, don't construct an OR cell. Directly construct the XOR gate auto xor_cell = module->addCell( module->uniquify(stringf("$xc2sop$%s_XOR", sop_output_wire_name)), - "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_OUT", has_invert); - xor_cell->setPort("\\IN_PTC", *intermed_wires.begin()); - xor_cell->setPort("\\OUT", sop_output); + ID(MACROCELL_XOR)); + xor_cell->setParam(ID(INVERT_OUT), has_invert); + xor_cell->setPort(ID(IN_PTC), *intermed_wires.begin()); + xor_cell->setPort(ID(OUT), sop_output); // Special P-term handling if (is_special_pterm) { // Can always connect the P-term directly if it's going // into something invert-capable - for (auto x : special_pterms_inv[sop_output]) + for (const auto &x : special_pterms_inv[sop_output]) { std::get<0>(x)->setPort(std::get<1>(x), *intermed_wires.begin()); @@ -170,14 +170,14 @@ struct Coolrunner2SopPass : public Pass { if (has_invert) { auto cell = std::get<0>(x); - if (cell->type == "\\FDCP") cell->type = "\\FDCP_N"; - else if (cell->type == "\\FDCP_N") cell->type = "\\FDCP"; - else if (cell->type == "\\FTCP") cell->type = "\\FTCP_N"; - else if (cell->type == "\\FTCP_N") cell->type = "\\FTCP"; - else if (cell->type == "\\FDCPE") cell->type = "\\FDCPE_N"; - else if (cell->type == "\\FDCPE_N") cell->type = "\\FDCPE"; - else if (cell->type == "\\LDCP") cell->type = "\\LDCP_N"; - else if (cell->type == "\\LDCP_N") cell->type = "\\LDCP"; + if (cell->type == ID(FDCP)) cell->type = ID(FDCP_N); + else if (cell->type == ID(FDCP_N)) cell->type = ID(FDCP); + else if (cell->type == ID(FTCP)) cell->type = ID(FTCP_N); + else if (cell->type == ID(FTCP_N)) cell->type = ID(FTCP); + else if (cell->type == ID(FDCPE)) cell->type = ID(FDCPE_N); + else if (cell->type == ID(FDCPE_N)) cell->type = ID(FDCPE); + else if (cell->type == ID(LDCP)) cell->type = ID(LDCP_N); + else if (cell->type == ID(LDCP_N)) cell->type = ID(LDCP); else log_assert(!"Internal error! Bad cell type!"); } } @@ -203,18 +203,18 @@ struct Coolrunner2SopPass : public Pass { // Construct the OR cell auto or_cell = module->addCell( module->uniquify(stringf("$xc2sop$%s_OR", sop_output_wire_name)), - "\\ORTERM"); - or_cell->setParam("\\WIDTH", sop_depth); - or_cell->setPort("\\IN", intermed_wires); - or_cell->setPort("\\OUT", or_to_xor_wire); + ID(ORTERM)); + or_cell->setParam(ID::WIDTH, sop_depth); + or_cell->setPort(ID(IN), intermed_wires); + or_cell->setPort(ID(OUT), or_to_xor_wire); // Construct the XOR cell auto xor_cell = module->addCell( module->uniquify(stringf("$xc2sop$%s_XOR", sop_output_wire_name)), - "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_OUT", has_invert); - xor_cell->setPort("\\IN_ORTERM", or_to_xor_wire); - xor_cell->setPort("\\OUT", sop_output); + ID(MACROCELL_XOR)); + xor_cell->setParam(ID(INVERT_OUT), has_invert); + xor_cell->setPort(ID(IN_ORTERM), or_to_xor_wire); + xor_cell->setPort(ID(OUT), sop_output); } // Finally, remove the $sop cell diff --git a/techlibs/ecp5/brams.txt b/techlibs/ecp5/brams.txt index 777ccaa2e..d34d9ec07 100644 --- a/techlibs/ecp5/brams.txt +++ b/techlibs/ecp5/brams.txt @@ -37,7 +37,17 @@ bram $__ECP5_DP16KD clkpol 2 3 endbram +# The syn_* attributes are described in: +# https://www.latticesemi.com/-/media/LatticeSemi/Documents/Tutorials/AK/LatticeDiamondTutorial311.ashx +attr_icase 1 + match $__ECP5_PDPW16KD + # implicitly requested RAM or ROM + attribute !syn_ramstyle syn_ramstyle=auto + attribute !syn_romstyle syn_romstyle=auto + attribute !ram_block + attribute !rom_block + attribute !logic_block min bits 2048 min efficiency 5 shuffle_enable A @@ -45,8 +55,60 @@ match $__ECP5_PDPW16KD or_next_if_better endmatch +match $__ECP5_PDPW16KD + # explicitly requested RAM + attribute syn_ramstyle=block_ram ram_block + attribute !syn_romstyle + attribute !rom_block + attribute !logic_block + min wports 1 + shuffle_enable A + make_transp + or_next_if_better +endmatch + +match $__ECP5_PDPW16KD + # explicitly requested ROM + attribute syn_romstyle=ebr rom_block + attribute !syn_ramstyle + attribute !ram_block + attribute !logic_block + max wports 0 + shuffle_enable A + make_transp + or_next_if_better +endmatch + match $__ECP5_DP16KD + # implicitly requested RAM or ROM + attribute !syn_ramstyle syn_ramstyle=auto + attribute !syn_romstyle syn_romstyle=auto + attribute !ram_block + attribute !rom_block + attribute !logic_block min bits 2048 min efficiency 5 shuffle_enable A + or_next_if_better +endmatch + +match $__ECP5_DP16KD + # explicitly requested RAM + attribute syn_ramstyle=block_ram ram_block + attribute !syn_romstyle + attribute !rom_block + attribute !logic_block + min wports 1 + shuffle_enable A + or_next_if_better +endmatch + +match $__ECP5_DP16KD + # explicitly requested ROM + attribute syn_romstyle=ebr rom_block + attribute !syn_ramstyle + attribute !ram_block + attribute !logic_block + max wports 0 + shuffle_enable A endmatch diff --git a/techlibs/ecp5/ecp5_ffinit.cc b/techlibs/ecp5/ecp5_ffinit.cc index dbd16cac9..e85bee64e 100644 --- a/techlibs/ecp5/ecp5_ffinit.cc +++ b/techlibs/ecp5/ecp5_ffinit.cc @@ -63,11 +63,11 @@ struct Ecp5FfinitPass : public Pass { for (auto wire : module->selected_wires()) { - if (wire->attributes.count("\\init") == 0) + if (wire->attributes.count(ID::init) == 0) continue; SigSpec wirebits = sigmap(wire); - Const initval = wire->attributes.at("\\init"); + Const initval = wire->attributes.at(ID::init); init_wires.insert(wire); for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) @@ -94,11 +94,11 @@ struct Ecp5FfinitPass : public Pass { } for (auto cell : module->selected_cells()) { - if (cell->type != "\\TRELLIS_FF") + if (cell->type != ID(TRELLIS_FF)) continue; - SigSpec sig_d = cell->getPort("\\DI"); - SigSpec sig_q = cell->getPort("\\Q"); - SigSpec sig_lsr = cell->getPort("\\LSR"); + SigSpec sig_d = cell->getPort(ID(DI)); + SigSpec sig_q = cell->getPort(ID::Q); + SigSpec sig_lsr = cell->getPort(ID(LSR)); if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) continue; @@ -107,8 +107,8 @@ struct Ecp5FfinitPass : public Pass { SigBit bit_q = sigmap(sig_q[0]); std::string regset = "RESET"; - if (cell->hasParam("\\REGSET")) - regset = cell->getParam("\\REGSET").decode_string(); + if (cell->hasParam(ID(REGSET))) + regset = cell->getParam(ID(REGSET)).decode_string(); State resetState; if (regset == "SET") resetState = State::S1; @@ -136,8 +136,8 @@ struct Ecp5FfinitPass : public Pass { 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 (cell->hasParam(ID(SRMODE))) + srmode = cell->getParam(ID(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'); @@ -150,14 +150,14 @@ struct Ecp5FfinitPass : public Pass { module->addOrGate(NEW_ID, bit_d, bit_lsr, new_bit_d); } - cell->setPort("\\DI", new_bit_d); - cell->setPort("\\LSR", State::S0); + cell->setPort(ID(DI), new_bit_d); + cell->setPort(ID(LSR), State::S0); - if(cell->hasPort("\\CE")) { + if(cell->hasPort(ID(CE))) { std::string cemux = "CE"; - if (cell->hasParam("\\CEMUX")) - cemux = cell->getParam("\\CEMUX").decode_string(); - SigSpec sig_ce = cell->getPort("\\CE"); + if (cell->hasParam(ID(CEMUX))) + cemux = cell->getParam(ID(CEMUX)).decode_string(); + SigSpec sig_ce = cell->getPort(ID(CE)); if (GetSize(sig_ce) >= 1) { SigBit bit_ce = sigmap(sig_ce[0]); Wire *new_bit_ce = module->addWire(NEW_ID); @@ -165,25 +165,25 @@ struct Ecp5FfinitPass : public Pass { 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->setPort(ID(CE), new_bit_ce); } } - cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET")); + cell->setParam(ID(REGSET), val != State::S0 ? Const("SET") : Const("RESET")); handled_initbits.insert(bit_q); } } else { - cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET")); + cell->setParam(ID(REGSET), val != State::S0 ? Const("SET") : Const("RESET")); handled_initbits.insert(bit_q); } } for (auto wire : init_wires) { - if (wire->attributes.count("\\init") == 0) + if (wire->attributes.count(ID::init) == 0) continue; SigSpec wirebits = sigmap(wire); - Const &initval = wire->attributes.at("\\init"); + Const &initval = wire->attributes.at(ID::init); bool remove_attribute = true; for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) { @@ -194,7 +194,7 @@ struct Ecp5FfinitPass : public Pass { } if (remove_attribute) - wire->attributes.erase("\\init"); + wire->attributes.erase(ID::init); } } } diff --git a/techlibs/ecp5/ecp5_gsr.cc b/techlibs/ecp5/ecp5_gsr.cc index 2bc714b6f..d1503f71f 100644 --- a/techlibs/ecp5/ecp5_gsr.cc +++ b/techlibs/ecp5/ecp5_gsr.cc @@ -85,7 +85,7 @@ struct Ecp5GsrPass : public Pass { continue; bool gsren = found_gsr; - if (cell->get_bool_attribute("\\nogsr")) + if (cell->get_bool_attribute(ID(nogsr))) gsren = false; cell->setParam(ID(GSR), gsren ? Const("ENABLED") : Const("DISABLED")); @@ -102,7 +102,7 @@ struct Ecp5GsrPass : public Pass { { if (cell->type != ID($_NOT_)) continue; - SigSpec sig_a = cell->getPort(ID(A)), sig_y = cell->getPort(ID(Y)); + SigSpec sig_a = cell->getPort(ID::A), sig_y = cell->getPort(ID::Y); if (GetSize(sig_a) < 1 || GetSize(sig_y) < 1) continue; SigBit a = sigmap(sig_a[0]); diff --git a/techlibs/ecp5/lutrams.txt b/techlibs/ecp5/lutrams.txt index b94357429..9e6a23eba 100644 --- a/techlibs/ecp5/lutrams.txt +++ b/techlibs/ecp5/lutrams.txt @@ -11,7 +11,16 @@ bram $__TRELLIS_DPR16X4 clkpol 0 2 endbram +# The syn_* attributes are described in: +# https://www.latticesemi.com/-/media/LatticeSemi/Documents/Tutorials/AK/LatticeDiamondTutorial311.ashx +attr_icase 1 + match $__TRELLIS_DPR16X4 + attribute !syn_ramstyle syn_ramstyle=auto syn_ramstyle=distributed + attribute !syn_romstyle syn_romstyle=auto + attribute !ram_block + attribute !rom_block + attribute !logic_block make_outreg min wports 1 endmatch diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 9916fdafb..ab740ea0d 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -279,7 +279,9 @@ struct SynthEcp5Pass : public ScriptPass if (check_label("map_ffram")) { run("opt -fast -mux_undef -undriven -fine"); - run("memory_map"); + run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block " + "-attr syn_ramstyle=auto -attr syn_ramstyle=registers " + "-attr syn_romstyle=auto -attr syn_romstyle=logic"); run("opt -undriven -fine"); } @@ -296,7 +298,6 @@ struct SynthEcp5Pass : public ScriptPass if (check_label("map_ffs")) { - run("dffsr2dff"); run("dff2dffs"); run("opt_clean"); if (!nodffe) diff --git a/techlibs/efinix/efinix_fixcarry.cc b/techlibs/efinix/efinix_fixcarry.cc index b7cd995b8..1a1733a17 100644 --- a/techlibs/efinix/efinix_fixcarry.cc +++ b/techlibs/efinix/efinix_fixcarry.cc @@ -39,12 +39,12 @@ static void fix_carry_chain(Module *module) for (auto cell : module->cells()) { - if (cell->type == "\\EFX_ADD") { - SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0")); - SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1")); + if (cell->type == ID(EFX_ADD)) { + SigBit bit_i0 = get_bit_or_zero(cell->getPort(ID(I0))); + SigBit bit_i1 = get_bit_or_zero(cell->getPort(ID(I1))); if (bit_i0 == State::S0 && bit_i1== State::S0) { - SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI")); - SigBit bit_o = sigmap(cell->getPort("\\O")); + SigBit bit_ci = get_bit_or_zero(cell->getPort(ID::CI)); + SigBit bit_o = sigmap(cell->getPort(ID::O)); ci_bits.insert(bit_ci); mapping_bits[bit_ci] = bit_o; } @@ -54,10 +54,10 @@ static void fix_carry_chain(Module *module) vector<Cell*> adders_to_fix_cells; for (auto cell : module->cells()) { - if (cell->type == "\\EFX_ADD") { - SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI")); - SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0")); - SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1")); + if (cell->type == ID(EFX_ADD)) { + SigBit bit_ci = get_bit_or_zero(cell->getPort(ID::CI)); + SigBit bit_i0 = get_bit_or_zero(cell->getPort(ID(I0))); + SigBit bit_i1 = get_bit_or_zero(cell->getPort(ID(I1))); SigBit canonical_bit = sigmap(bit_ci); if (!ci_bits.count(canonical_bit)) continue; @@ -71,20 +71,20 @@ static void fix_carry_chain(Module *module) for (auto cell : adders_to_fix_cells) { - SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI")); + SigBit bit_ci = get_bit_or_zero(cell->getPort(ID::CI)); SigBit canonical_bit = sigmap(bit_ci); auto bit = mapping_bits.at(canonical_bit); log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell)); - Cell *c = module->addCell(NEW_ID, "\\EFX_ADD"); + Cell *c = module->addCell(NEW_ID, ID(EFX_ADD)); SigBit new_bit = module->addWire(NEW_ID); - c->setParam("\\I0_POLARITY", State::S1); - c->setParam("\\I1_POLARITY", State::S1); - c->setPort("\\I0", bit); - c->setPort("\\I1", State::S1); - c->setPort("\\CI", State::S0); - c->setPort("\\CO", new_bit); + c->setParam(ID(I0_POLARITY), State::S1); + c->setParam(ID(I1_POLARITY), State::S1); + c->setPort(ID(I0), bit); + c->setPort(ID(I1), State::S1); + c->setPort(ID::CI, State::S0); + c->setPort(ID::CO, new_bit); - cell->setPort("\\CI", new_bit); + cell->setPort(ID::CI, new_bit); } } @@ -101,7 +101,7 @@ struct EfinixCarryFixPass : public Pass { } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - log_header(design, "Executing efinix_fixcarry pass (fix invalid carry chain).\n"); + log_header(design, "Executing EFINIX_FIXCARRY pass (fix invalid carry chain).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) diff --git a/techlibs/efinix/efinix_gbuf.cc b/techlibs/efinix/efinix_gbuf.cc index e75fb3f4d..55dfb3c79 100644 --- a/techlibs/efinix/efinix_gbuf.cc +++ b/techlibs/efinix/efinix_gbuf.cc @@ -34,14 +34,14 @@ static void handle_gbufs(Module *module) for (auto cell : module->cells()) { - if (cell->type == "\\EFX_FF") { - for (auto bit : sigmap(cell->getPort("\\CLK"))) + if (cell->type == ID(EFX_FF)) { + for (auto bit : sigmap(cell->getPort(ID::CLK))) clk_bits.insert(bit); } - if (cell->type == "\\EFX_RAM_5K") { - for (auto bit : sigmap(cell->getPort("\\RCLK"))) + if (cell->type == ID(EFX_RAM_5K)) { + for (auto bit : sigmap(cell->getPort(ID(RCLK)))) clk_bits.insert(bit); - for (auto bit : sigmap(cell->getPort("\\WCLK"))) + for (auto bit : sigmap(cell->getPort(ID(WCLK)))) clk_bits.insert(bit); } } @@ -59,11 +59,11 @@ static void handle_gbufs(Module *module) if (!clk_bits.count(canonical_bit)) continue; - Cell *c = module->addCell(NEW_ID, "\\EFX_GBUFCE"); + Cell *c = module->addCell(NEW_ID, ID(EFX_GBUFCE)); SigBit new_bit = module->addWire(NEW_ID); - c->setParam("\\CE_POLARITY", State::S1); - c->setPort("\\O", new_bit); - c->setPort("\\CE", State::S1); + c->setParam(ID(CE_POLARITY), State::S1); + c->setPort(ID::O, new_bit); + c->setPort(ID(CE), State::S1); pad_bits.push_back(make_pair(c, bit)); rewrite_bits[canonical_bit] = new_bit; @@ -82,7 +82,7 @@ static void handle_gbufs(Module *module) module->rewrite_sigspecs(rewrite_function); for (auto &it : pad_bits) - it.first->setPort("\\I", it.second); + it.first->setPort(ID::I, it.second); } struct EfinixGbufPass : public Pass { diff --git a/techlibs/efinix/synth_efinix.cc b/techlibs/efinix/synth_efinix.cc index 637d7c00d..f9a7ef865 100644 --- a/techlibs/efinix/synth_efinix.cc +++ b/techlibs/efinix/synth_efinix.cc @@ -182,7 +182,6 @@ struct SynthEfinixPass : public ScriptPass if (check_label("map_ffs")) { - run("dffsr2dff"); run("techmap -D NO_LUT -map +/efinix/cells_map.v"); run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit"); run("opt_expr -mux_undef"); diff --git a/techlibs/gowin/determine_init.cc b/techlibs/gowin/determine_init.cc index d9a0880f6..18a64e451 100644 --- a/techlibs/gowin/determine_init.cc +++ b/techlibs/gowin/determine_init.cc @@ -55,12 +55,12 @@ struct DetermineInitPass : public Pass { { for (auto cell : module->selected_cells()) { - if (cell->type == "\\RAM16S4") + if (cell->type == ID(RAM16S4)) { - cell->setParam("\\INIT_0", determine_init(cell->getParam("\\INIT_0"))); - cell->setParam("\\INIT_1", determine_init(cell->getParam("\\INIT_1"))); - cell->setParam("\\INIT_2", determine_init(cell->getParam("\\INIT_2"))); - cell->setParam("\\INIT_3", determine_init(cell->getParam("\\INIT_3"))); + cell->setParam(ID(INIT_0), determine_init(cell->getParam(ID(INIT_0)))); + cell->setParam(ID(INIT_1), determine_init(cell->getParam(ID(INIT_1)))); + cell->setParam(ID(INIT_2), determine_init(cell->getParam(ID(INIT_2)))); + cell->setParam(ID(INIT_3), determine_init(cell->getParam(ID(INIT_3)))); cnt++; } } diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 86ec9cdc2..dd965c0b8 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -219,7 +219,6 @@ struct SynthGowinPass : public ScriptPass if (check_label("map_ffs")) { - run("dffsr2dff"); run("dff2dffs -match-init"); run("opt_clean"); if (!nodffe) diff --git a/techlibs/greenpak4/greenpak4_dffinv.cc b/techlibs/greenpak4/greenpak4_dffinv.cc index d57e978a0..62057318b 100644 --- a/techlibs/greenpak4/greenpak4_dffinv.cc +++ b/techlibs/greenpak4/greenpak4_dffinv.cc @@ -33,37 +33,37 @@ void invert_gp_dff(Cell *cell, bool invert_input) if (!invert_input) { - Const initval = cell->getParam("\\INIT"); + Const initval = cell->getParam(ID::INIT); if (GetSize(initval) >= 1) { if (initval.bits[0] == State::S0) initval.bits[0] = State::S1; else if (initval.bits[0] == State::S1) initval.bits[0] = State::S0; - cell->setParam("\\INIT", initval); + cell->setParam(ID::INIT, initval); } if (cell_type_r && cell_type_s) { - Const srmode = cell->getParam("\\SRMODE"); + Const srmode = cell->getParam(ID(SRMODE)); if (GetSize(srmode) >= 1) { if (srmode.bits[0] == State::S0) srmode.bits[0] = State::S1; else if (srmode.bits[0] == State::S1) srmode.bits[0] = State::S0; - cell->setParam("\\SRMODE", srmode); + cell->setParam(ID(SRMODE), srmode); } } else { if (cell_type_r) { - cell->setPort("\\nSET", cell->getPort("\\nRST")); - cell->unsetPort("\\nRST"); + cell->setPort(ID(nSET), cell->getPort(ID(nRST))); + cell->unsetPort(ID(nRST)); cell_type_r = false; cell_type_s = true; } else if (cell_type_s) { - cell->setPort("\\nRST", cell->getPort("\\nSET")); - cell->unsetPort("\\nSET"); + cell->setPort(ID(nRST), cell->getPort(ID(nSET))); + cell->unsetPort(ID(nSET)); cell_type_r = true; cell_type_s = false; } @@ -71,12 +71,12 @@ void invert_gp_dff(Cell *cell, bool invert_input) } if (cell_type_i) { - cell->setPort("\\Q", cell->getPort("\\nQ")); - cell->unsetPort("\\nQ"); + cell->setPort(ID::Q, cell->getPort(ID(nQ))); + cell->unsetPort(ID(nQ)); cell_type_i = false; } else { - cell->setPort("\\nQ", cell->getPort("\\Q")); - cell->unsetPort("\\Q"); + cell->setPort(ID(nQ), cell->getPort(ID::Q)); + cell->unsetPort(ID::Q); cell_type_i = true; } @@ -115,23 +115,23 @@ struct Greenpak4DffInvPass : public Pass { extra_args(args, argidx, design); pool<IdString> gp_dff_types; - gp_dff_types.insert("\\GP_DFF"); - gp_dff_types.insert("\\GP_DFFI"); - gp_dff_types.insert("\\GP_DFFR"); - gp_dff_types.insert("\\GP_DFFRI"); - gp_dff_types.insert("\\GP_DFFS"); - gp_dff_types.insert("\\GP_DFFSI"); - gp_dff_types.insert("\\GP_DFFSR"); - gp_dff_types.insert("\\GP_DFFSRI"); - - gp_dff_types.insert("\\GP_DLATCH"); - gp_dff_types.insert("\\GP_DLATCHI"); - gp_dff_types.insert("\\GP_DLATCHR"); - gp_dff_types.insert("\\GP_DLATCHRI"); - gp_dff_types.insert("\\GP_DLATCHS"); - gp_dff_types.insert("\\GP_DLATCHSI"); - gp_dff_types.insert("\\GP_DLATCHSR"); - gp_dff_types.insert("\\GP_DLATCHSRI"); + gp_dff_types.insert(ID(GP_DFF)); + gp_dff_types.insert(ID(GP_DFFI)); + gp_dff_types.insert(ID(GP_DFFR)); + gp_dff_types.insert(ID(GP_DFFRI)); + gp_dff_types.insert(ID(GP_DFFS)); + gp_dff_types.insert(ID(GP_DFFSI)); + gp_dff_types.insert(ID(GP_DFFSR)); + gp_dff_types.insert(ID(GP_DFFSRI)); + + gp_dff_types.insert(ID(GP_DLATCH)); + gp_dff_types.insert(ID(GP_DLATCHI)); + gp_dff_types.insert(ID(GP_DLATCHR)); + gp_dff_types.insert(ID(GP_DLATCHRI)); + gp_dff_types.insert(ID(GP_DLATCHS)); + gp_dff_types.insert(ID(GP_DLATCHSI)); + gp_dff_types.insert(ID(GP_DLATCHSR)); + gp_dff_types.insert(ID(GP_DLATCHSRI)); for (auto module : design->selected_modules()) { @@ -163,9 +163,9 @@ struct Greenpak4DffInvPass : public Pass { continue; } - if (cell->type == "\\GP_INV") { - SigBit in_bit = sigmap(cell->getPort("\\IN")); - SigBit out_bit = sigmap(cell->getPort("\\OUT")); + if (cell->type == ID(GP_INV)) { + SigBit in_bit = sigmap(cell->getPort(ID(IN))); + SigBit out_bit = sigmap(cell->getPort(ID(OUT))); inv_in2out[in_bit] = out_bit; inv_out2in[out_bit] = in_bit; inv_in2cell[in_bit] = cell; @@ -175,15 +175,15 @@ struct Greenpak4DffInvPass : public Pass { for (auto cell : dff_cells) { - SigBit d_bit = sigmap(cell->getPort("\\D")); - SigBit q_bit = sigmap(cell->hasPort("\\Q") ? cell->getPort("\\Q") : cell->getPort("\\nQ")); + SigBit d_bit = sigmap(cell->getPort(ID::D)); + SigBit q_bit = sigmap(cell->hasPort(ID::Q) ? cell->getPort(ID::Q) : cell->getPort(ID(nQ))); while (inv_out2in.count(d_bit)) { sig_use_cnt[d_bit]--; invert_gp_dff(cell, true); d_bit = inv_out2in.at(d_bit); - cell->setPort("\\D", d_bit); + cell->setPort(ID::D, d_bit); sig_use_cnt[d_bit]++; } @@ -197,10 +197,10 @@ struct Greenpak4DffInvPass : public Pass { inv_in2cell.erase(q_bit); invert_gp_dff(cell, false); - if (cell->hasPort("\\Q")) - cell->setPort("\\Q", new_q_bit); + if (cell->hasPort(ID::Q)) + cell->setPort(ID::Q, new_q_bit); else - cell->setPort("\\nQ", new_q_bit); + cell->setPort(ID(nQ), new_q_bit); } } } diff --git a/techlibs/ice40/brams.txt b/techlibs/ice40/brams.txt index 03d596111..36dfddab2 100644 --- a/techlibs/ice40/brams.txt +++ b/techlibs/ice40/brams.txt @@ -28,13 +28,73 @@ bram $__ICE40_RAM4K_M123 clkpol 2 3 endbram +# The syn_* attributes are described in: +# https://www.latticesemi.com/-/media/LatticeSemi/Documents/Tutorials/AK/LatticeDiamondTutorial311.ashx +attr_icase 1 + match $__ICE40_RAM4K_M0 + # implicitly requested RAM or ROM + attribute !syn_ramstyle syn_ramstyle=auto + attribute !syn_romstyle syn_romstyle=auto + attribute !ram_block + attribute !rom_block + attribute !logic_block min efficiency 2 make_transp or_next_if_better endmatch +match $__ICE40_RAM4K_M0 + # explicitly requested RAM + attribute syn_ramstyle=block_ram ram_block + attribute !syn_romstyle + attribute !rom_block + attribute !logic_block + min wports 1 + make_transp + or_next_if_better +endmatch + +match $__ICE40_RAM4K_M0 + # explicitly requested ROM + attribute syn_romstyle=ebr rom_block + attribute !syn_ramstyle + attribute !ram_block + attribute !logic_block + max wports 0 + make_transp + or_next_if_better +endmatch + match $__ICE40_RAM4K_M123 + # implicitly requested RAM or ROM + attribute !syn_ramstyle syn_ramstyle=auto + attribute !syn_romstyle syn_romstyle=auto + attribute !ram_block + attribute !rom_block + attribute !logic_block min efficiency 2 make_transp + or_next_if_better +endmatch + +match $__ICE40_RAM4K_M123 + # explicitly requested RAM + attribute syn_ramstyle=block_ram ram_block + attribute !syn_romstyle + attribute !rom_block + attribute !logic_block + min wports 1 + make_transp + or_next_if_better +endmatch + +match $__ICE40_RAM4K_M123 + # explicitly requested ROM + attribute syn_romstyle=ebr rom_block + attribute !syn_ramstyle + attribute !ram_block + attribute !logic_block + max wports 0 + make_transp endmatch diff --git a/techlibs/ice40/ice40_braminit.cc b/techlibs/ice40/ice40_braminit.cc index 1a139ffea..936c189ea 100644 --- a/techlibs/ice40/ice40_braminit.cc +++ b/techlibs/ice40/ice40_braminit.cc @@ -33,15 +33,15 @@ static void run_ice40_braminit(Module *module) 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") + if (cell->type != ID(SB_RAM40_4K) && + cell->type != ID(SB_RAM40_4KNR) && + cell->type != ID(SB_RAM40_4KNW) && + cell->type != ID(SB_RAM40_4KNRNW)) continue; - if (!cell->hasParam("\\INIT_FILE")) + if (!cell->hasParam(ID(INIT_FILE))) continue; - std::string init_file = cell->getParam("\\INIT_FILE").decode_string(); - cell->unsetParam("\\INIT_FILE"); + std::string init_file = cell->getParam(ID(INIT_FILE)).decode_string(); + cell->unsetParam(ID(INIT_FILE)); if (init_file == "") continue; diff --git a/techlibs/ice40/ice40_ffinit.cc b/techlibs/ice40/ice40_ffinit.cc index c098736e9..d7715135e 100644 --- a/techlibs/ice40/ice40_ffinit.cc +++ b/techlibs/ice40/ice40_ffinit.cc @@ -62,11 +62,11 @@ struct Ice40FfinitPass : public Pass { for (auto wire : module->selected_wires()) { - if (wire->attributes.count("\\init") == 0) + if (wire->attributes.count(ID::init) == 0) continue; SigSpec wirebits = sigmap(wire); - Const initval = wire->attributes.at("\\init"); + Const initval = wire->attributes.at(ID::init); init_wires.insert(wire); for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) @@ -93,9 +93,9 @@ struct Ice40FfinitPass : public Pass { } pool<IdString> sb_dff_types = { - "\\SB_DFF", "\\SB_DFFE", "\\SB_DFFSR", "\\SB_DFFR", "\\SB_DFFSS", "\\SB_DFFS", "\\SB_DFFESR", - "\\SB_DFFER", "\\SB_DFFESS", "\\SB_DFFES", "\\SB_DFFN", "\\SB_DFFNE", "\\SB_DFFNSR", "\\SB_DFFNR", - "\\SB_DFFNSS", "\\SB_DFFNS", "\\SB_DFFNESR", "\\SB_DFFNER", "\\SB_DFFNESS", "\\SB_DFFNES" + ID(SB_DFF), ID(SB_DFFE), ID(SB_DFFSR), ID(SB_DFFR), ID(SB_DFFSS), ID(SB_DFFS), ID(SB_DFFESR), + ID(SB_DFFER), ID(SB_DFFESS), ID(SB_DFFES), ID(SB_DFFN), ID(SB_DFFNE), ID(SB_DFFNSR), ID(SB_DFFNR), + ID(SB_DFFNSS), ID(SB_DFFNS), ID(SB_DFFNESR), ID(SB_DFFNER), ID(SB_DFFNESS), ID(SB_DFFNES) }; for (auto cell : module->selected_cells()) @@ -103,8 +103,8 @@ struct Ice40FfinitPass : public Pass { if (!sb_dff_types.count(cell->type)) continue; - SigSpec sig_d = cell->getPort("\\D"); - SigSpec sig_q = cell->getPort("\\Q"); + SigSpec sig_d = cell->getPort(ID::D); + SigSpec sig_q = cell->getPort(ID::Q); if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) continue; @@ -133,14 +133,14 @@ struct Ice40FfinitPass : public Pass { if (type_str.back() == 'S') { type_str.back() = 'R'; cell->type = type_str; - cell->setPort("\\R", cell->getPort("\\S")); - cell->unsetPort("\\S"); + cell->setPort(ID::R, cell->getPort(ID::S)); + cell->unsetPort(ID::S); } else if (type_str.back() == 'R') { type_str.back() = 'S'; cell->type = type_str; - cell->setPort("\\S", cell->getPort("\\R")); - cell->unsetPort("\\R"); + cell->setPort(ID::S, cell->getPort(ID::R)); + cell->unsetPort(ID::R); } Wire *new_bit_d = module->addWire(NEW_ID); @@ -149,17 +149,17 @@ struct Ice40FfinitPass : public Pass { module->addNotGate(NEW_ID, bit_d, new_bit_d); module->addNotGate(NEW_ID, new_bit_q, bit_q); - cell->setPort("\\D", new_bit_d); - cell->setPort("\\Q", new_bit_q); + cell->setPort(ID::D, new_bit_d); + cell->setPort(ID::Q, new_bit_q); } for (auto wire : init_wires) { - if (wire->attributes.count("\\init") == 0) + if (wire->attributes.count(ID::init) == 0) continue; SigSpec wirebits = sigmap(wire); - Const &initval = wire->attributes.at("\\init"); + Const &initval = wire->attributes.at(ID::init); bool remove_attribute = true; for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) { @@ -170,7 +170,7 @@ struct Ice40FfinitPass : public Pass { } if (remove_attribute) - wire->attributes.erase("\\init"); + wire->attributes.erase(ID::init); } } } diff --git a/techlibs/ice40/ice40_ffssr.cc b/techlibs/ice40/ice40_ffssr.cc index a7649d7a0..ffb8c74b1 100644 --- a/techlibs/ice40/ice40_ffssr.cc +++ b/techlibs/ice40/ice40_ffssr.cc @@ -49,10 +49,10 @@ struct Ice40FfssrPass : public Pass { extra_args(args, argidx, design); pool<IdString> sb_dff_types; - sb_dff_types.insert("\\SB_DFF"); - sb_dff_types.insert("\\SB_DFFE"); - sb_dff_types.insert("\\SB_DFFN"); - sb_dff_types.insert("\\SB_DFFNE"); + sb_dff_types.insert(ID(SB_DFF)); + sb_dff_types.insert(ID(SB_DFFE)); + sb_dff_types.insert(ID(SB_DFFN)); + sb_dff_types.insert(ID(SB_DFFNE)); for (auto module : design->selected_modules()) { @@ -69,22 +69,22 @@ struct Ice40FfssrPass : public Pass { continue; } - if (cell->type != "$_MUX_") + if (cell->type != ID($_MUX_)) continue; - SigBit bit_a = sigmap(cell->getPort("\\A")); - SigBit bit_b = sigmap(cell->getPort("\\B")); + SigBit bit_a = sigmap(cell->getPort(ID::A)); + SigBit bit_b = sigmap(cell->getPort(ID::B)); if (bit_a.wire == nullptr || bit_b.wire == nullptr) - sr_muxes[sigmap(cell->getPort("\\Y"))] = cell; + sr_muxes[sigmap(cell->getPort(ID::Y))] = cell; } for (auto cell : ff_cells) { - if (cell->get_bool_attribute("\\dont_touch")) + if (cell->get_bool_attribute(ID(dont_touch))) continue; - SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_d = cell->getPort(ID::D); if (GetSize(sig_d) < 1) continue; @@ -95,9 +95,9 @@ struct Ice40FfssrPass : public Pass { continue; Cell *mux_cell = sr_muxes.at(bit_d); - SigBit bit_a = sigmap(mux_cell->getPort("\\A")); - SigBit bit_b = sigmap(mux_cell->getPort("\\B")); - SigBit bit_s = sigmap(mux_cell->getPort("\\S")); + SigBit bit_a = sigmap(mux_cell->getPort(ID::A)); + SigBit bit_b = sigmap(mux_cell->getPort(ID::B)); + SigBit bit_s = sigmap(mux_cell->getPort(ID::S)); log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell), log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type)); @@ -116,12 +116,12 @@ struct Ice40FfssrPass : public Pass { if (sr_val == State::S1) { cell->type = cell->type.str() + "SS"; - cell->setPort("\\S", sr_sig); - cell->setPort("\\D", bit_d); + cell->setPort(ID::S, sr_sig); + cell->setPort(ID::D, bit_d); } else { cell->type = cell->type.str() + "SR"; - cell->setPort("\\R", sr_sig); - cell->setPort("\\D", bit_d); + cell->setPort(ID::R, sr_sig); + cell->setPort(ID::D, bit_d); } } } diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc index 925ab31bb..18c1a58cf 100644 --- a/techlibs/ice40/ice40_opt.cc +++ b/techlibs/ice40/ice40_opt.cc @@ -41,26 +41,26 @@ static void run_ice40_opts(Module *module) for (auto cell : module->selected_cells()) { - if (!cell->type.in("\\SB_LUT4", "\\SB_CARRY", "$__ICE40_CARRY_WRAPPER")) + if (!cell->type.in(ID(SB_LUT4), ID(SB_CARRY), ID($__ICE40_CARRY_WRAPPER))) continue; if (cell->has_keep_attr()) continue; - if (cell->type == "\\SB_LUT4") + if (cell->type == ID(SB_LUT4)) { sb_lut_cells.push_back(cell); continue; } - if (cell->type == "\\SB_CARRY") + if (cell->type == ID(SB_CARRY)) { SigSpec non_const_inputs, replacement_output; int count_zeros = 0, count_ones = 0; SigBit inbit[3] = { - get_bit_or_zero(cell->getPort("\\I0")), - get_bit_or_zero(cell->getPort("\\I1")), - get_bit_or_zero(cell->getPort("\\CI")) + get_bit_or_zero(cell->getPort(ID(I0))), + get_bit_or_zero(cell->getPort(ID(I1))), + get_bit_or_zero(cell->getPort(ID::CI)) }; for (int i = 0; i < 3; i++) if (inbit[i].wire == nullptr) { @@ -79,8 +79,8 @@ static void run_ice40_opts(Module *module) replacement_output = non_const_inputs; if (GetSize(replacement_output)) { - optimized_co.insert(sigmap(cell->getPort("\\CO")[0])); - module->connect(cell->getPort("\\CO")[0], replacement_output); + optimized_co.insert(sigmap(cell->getPort(ID::CO)[0])); + module->connect(cell->getPort(ID::CO)[0], replacement_output); module->design->scratchpad_set_bool("opt.did_something", true); log("Optimized away SB_CARRY cell %s.%s: CO=%s\n", log_id(module), log_id(cell), log_signal(replacement_output)); @@ -89,15 +89,15 @@ static void run_ice40_opts(Module *module) continue; } - if (cell->type == "$__ICE40_CARRY_WRAPPER") + if (cell->type == ID($__ICE40_CARRY_WRAPPER)) { SigSpec non_const_inputs, replacement_output; int count_zeros = 0, count_ones = 0; SigBit inbit[3] = { - cell->getPort("\\A"), - cell->getPort("\\B"), - cell->getPort("\\CI") + cell->getPort(ID::A), + cell->getPort(ID::B), + cell->getPort(ID::CI) }; for (int i = 0; i < 3; i++) if (inbit[i].wire == nullptr) { @@ -116,7 +116,7 @@ static void run_ice40_opts(Module *module) replacement_output = non_const_inputs; if (GetSize(replacement_output)) { - optimized_co.insert(sigmap(cell->getPort("\\CO")[0])); + optimized_co.insert(sigmap(cell->getPort(ID::CO)[0])); auto it = cell->attributes.find(ID(SB_LUT4.name)); if (it != cell->attributes.end()) { module->rename(cell, it->second.decode_string()); @@ -124,9 +124,9 @@ static void run_ice40_opts(Module *module) for (const auto &a : cell->attributes) if (a.first.begins_with("\\SB_LUT4.\\")) new_attr[a.first.c_str() + strlen("\\SB_LUT4.")] = a.second; - else if (a.first == ID(src)) + else if (a.first == ID::src) new_attr.insert(std::make_pair(a.first, a.second)); - else if (a.first.in(ID(SB_LUT4.name), ID::keep, ID(module_not_derived))) + else if (a.first.in(ID(SB_LUT4.name), ID::keep, ID::module_not_derived)) continue; else if (a.first.begins_with("\\SB_CARRY.\\")) continue; @@ -134,22 +134,22 @@ static void run_ice40_opts(Module *module) log_abort(); cell->attributes = std::move(new_attr); } - module->connect(cell->getPort("\\CO")[0], replacement_output); + module->connect(cell->getPort(ID::CO)[0], replacement_output); module->design->scratchpad_set_bool("opt.did_something", true); log("Optimized $__ICE40_CARRY_WRAPPER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n", log_id(module), log_id(cell), log_signal(replacement_output)); - cell->type = "$lut"; - auto I3 = get_bit_or_zero(cell->getPort(cell->getParam(ID(I3_IS_CI)).as_bool() ? ID(CI) : ID(I3))); - cell->setPort("\\A", { I3, inbit[1], inbit[0], get_bit_or_zero(cell->getPort("\\I0")) }); - cell->setPort("\\Y", cell->getPort("\\O")); - cell->unsetPort("\\B"); - cell->unsetPort("\\CI"); - cell->unsetPort("\\I0"); - cell->unsetPort("\\I3"); - cell->unsetPort("\\CO"); - cell->unsetPort("\\O"); - cell->setParam("\\WIDTH", 4); - cell->unsetParam("\\I3_IS_CI"); + cell->type = ID($lut); + auto I3 = get_bit_or_zero(cell->getPort(cell->getParam(ID(I3_IS_CI)).as_bool() ? ID::CI : ID(I3))); + cell->setPort(ID::A, { I3, inbit[1], inbit[0], get_bit_or_zero(cell->getPort(ID(I0))) }); + cell->setPort(ID::Y, cell->getPort(ID::O)); + cell->unsetPort(ID::B); + cell->unsetPort(ID::CI); + cell->unsetPort(ID(I0)); + cell->unsetPort(ID(I3)); + cell->unsetPort(ID::CO); + cell->unsetPort(ID::O); + cell->setParam(ID::WIDTH, 4); + cell->unsetParam(ID(I3_IS_CI)); } continue; } @@ -159,10 +159,10 @@ static void run_ice40_opts(Module *module) { SigSpec inbits; - inbits.append(get_bit_or_zero(cell->getPort("\\I0"))); - inbits.append(get_bit_or_zero(cell->getPort("\\I1"))); - inbits.append(get_bit_or_zero(cell->getPort("\\I2"))); - inbits.append(get_bit_or_zero(cell->getPort("\\I3"))); + inbits.append(get_bit_or_zero(cell->getPort(ID(I0)))); + inbits.append(get_bit_or_zero(cell->getPort(ID(I1)))); + inbits.append(get_bit_or_zero(cell->getPort(ID(I2)))); + inbits.append(get_bit_or_zero(cell->getPort(ID(I3)))); sigmap.apply(inbits); if (optimized_co.count(inbits[0])) goto remap_lut; @@ -177,23 +177,23 @@ static void run_ice40_opts(Module *module) module->design->scratchpad_set_bool("opt.did_something", true); log("Mapping SB_LUT4 cell %s.%s back to logic.\n", log_id(module), log_id(cell)); - cell->type ="$lut"; - cell->setParam("\\WIDTH", 4); - cell->setParam("\\LUT", cell->getParam("\\LUT_INIT")); - cell->unsetParam("\\LUT_INIT"); + cell->type = ID($lut); + cell->setParam(ID::WIDTH, 4); + cell->setParam(ID::LUT, cell->getParam(ID(LUT_INIT))); + cell->unsetParam(ID(LUT_INIT)); - cell->setPort("\\A", SigSpec({ - get_bit_or_zero(cell->getPort("\\I3")), - get_bit_or_zero(cell->getPort("\\I2")), - get_bit_or_zero(cell->getPort("\\I1")), - get_bit_or_zero(cell->getPort("\\I0")) + cell->setPort(ID::A, SigSpec({ + get_bit_or_zero(cell->getPort(ID(I3))), + get_bit_or_zero(cell->getPort(ID(I2))), + get_bit_or_zero(cell->getPort(ID(I1))), + get_bit_or_zero(cell->getPort(ID(I0))) })); - cell->setPort("\\Y", cell->getPort("\\O")[0]); - cell->unsetPort("\\I0"); - cell->unsetPort("\\I1"); - cell->unsetPort("\\I2"); - cell->unsetPort("\\I3"); - cell->unsetPort("\\O"); + cell->setPort(ID::Y, cell->getPort(ID::O)[0]); + cell->unsetPort(ID(I0)); + cell->unsetPort(ID(I1)); + cell->unsetPort(ID(I2)); + cell->unsetPort(ID(I3)); + cell->unsetPort(ID::O); cell->check(); simplemap_lut(module, cell); diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index b8aedaadf..9724b7dd5 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -96,9 +96,9 @@ struct SynthIce40Pass : public ScriptPass log(" -abc9\n"); log(" use new ABC9 flow (EXPERIMENTAL)\n"); log("\n"); - log(" -flowmap\n"); - log(" use FlowMap LUT techmapping instead of abc (EXPERIMENTAL)\n"); - log("\n"); + log(" -flowmap\n"); + log(" use FlowMap LUT techmapping instead of abc (EXPERIMENTAL)\n"); + log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); @@ -126,7 +126,7 @@ struct SynthIce40Pass : public ScriptPass abc2 = false; vpr = false; abc9 = false; - flowmap = false; + flowmap = false; device_opt = "hx"; } @@ -319,7 +319,9 @@ struct SynthIce40Pass : public ScriptPass if (check_label("map_ffram")) { run("opt -fast -mux_undef -undriven -fine"); - run("memory_map"); + run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block " + "-attr syn_ramstyle=auto -attr syn_ramstyle=registers " + "-attr syn_romstyle=auto -attr syn_romstyle=logic"); run("opt -undriven -fine"); } @@ -339,7 +341,6 @@ struct SynthIce40Pass : public ScriptPass if (check_label("map_ffs")) { - run("dffsr2dff"); if (!nodffe) run("dff2dffe -direct-match $_DFF_*"); if (min_ce_use >= 0) { diff --git a/techlibs/intel/Makefile.inc b/techlibs/intel/Makefile.inc index d97a9b58f..f751e341f 100644 --- a/techlibs/intel/Makefile.inc +++ b/techlibs/intel/Makefile.inc @@ -11,4 +11,3 @@ families := max10 arria10gx cyclonev cyclone10lp cycloneiv cycloneive $(foreach family,$(families), $(eval $(call add_share_file,share/intel/$(family),techlibs/intel/$(family)/cells_sim.v))) $(foreach family,$(families), $(eval $(call add_share_file,share/intel/$(family),techlibs/intel/$(family)/cells_map.v))) #$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/arith_map.v)) - diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc index 3689df70e..8601ebb37 100644 --- a/techlibs/intel/synth_intel.cc +++ b/techlibs/intel/synth_intel.cc @@ -202,7 +202,6 @@ struct SynthIntelPass : public ScriptPass { run("opt -fast -mux_undef -undriven -fine -full"); run("memory_map"); run("opt -undriven -fine"); - run("dffsr2dff"); run("dff2dffe -direct-match $_DFF_*"); run("opt -fine"); run("techmap -map +/techmap.v"); diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc new file mode 100644 index 000000000..66204c8fc --- /dev/null +++ b/techlibs/intel_alm/Makefile.inc @@ -0,0 +1,23 @@ + +OBJS += techlibs/intel_alm/synth_intel_alm.o + +# Techmap +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/alm_map.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/alm_sim.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/arith_alm_map.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_map.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_sim.v)) + +# RAM +bramtypes := m10k m20k +$(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype).txt))) +$(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype)_map.v))) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab_map.v)) + +families := cyclonev cyclone10gx + +# Miscellaneous +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/megafunction_bb.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/quartus_rename.v)) +$(foreach family, $(families), $(eval $(call add_share_file,share/intel_alm/$(family),techlibs/intel_alm/$(family)/quartus_rename.v))) diff --git a/techlibs/intel_alm/common/alm_map.v b/techlibs/intel_alm/common/alm_map.v new file mode 100644 index 000000000..fe646c5d6 --- /dev/null +++ b/techlibs/intel_alm/common/alm_map.v @@ -0,0 +1,56 @@ +module \$lut (A, Y); + +parameter WIDTH = 1; +parameter LUT = 0; + +input [WIDTH-1:0] A; +output Y; + +generate + if (WIDTH == 1) begin + generate + if (LUT == 2'b00) begin + assign Y = 1'b0; + end + else if (LUT == 2'b01) begin + MISTRAL_NOT _TECHMAP_REPLACE_( + .A(A[0]), .Q(Y) + ); + end + else if (LUT == 2'b10) begin + assign Y = A; + end + else if (LUT == 2'b11) begin + assign Y = 1'b1; + end + endgenerate + end else + if (WIDTH == 2) begin + MISTRAL_ALUT2 #(.LUT(LUT)) _TECHMAP_REPLACE_( + .A(A[0]), .B(A[1]), .Q(Y) + ); + end else + if (WIDTH == 3) begin + MISTRAL_ALUT3 #(.LUT(LUT)) _TECHMAP_REPLACE_( + .A(A[0]), .B(A[1]), .C(A[2]), .Q(Y) + ); + end else + if (WIDTH == 4) begin + MISTRAL_ALUT4 #(.LUT(LUT)) _TECHMAP_REPLACE_( + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .Q(Y) + ); + end else + if (WIDTH == 5) begin + MISTRAL_ALUT5 #(.LUT(LUT)) _TECHMAP_REPLACE_ ( + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .Q(Y) + ); + end else + if (WIDTH == 6) begin + MISTRAL_ALUT6 #(.LUT(LUT)) _TECHMAP_REPLACE_ ( + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .F(A[5]), .Q(Y) + ); + end else begin + wire _TECHMAP_FAIL_ = 1'b1; + end +endgenerate +endmodule diff --git a/techlibs/intel_alm/common/alm_sim.v b/techlibs/intel_alm/common/alm_sim.v new file mode 100644 index 000000000..69768d9f7 --- /dev/null +++ b/techlibs/intel_alm/common/alm_sim.v @@ -0,0 +1,482 @@ +`default_nettype none + +(* abc9_lut=2, lib_whitebox *) +module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); + +parameter [63:0] LUT = 64'h0000_0000_0000_0000; + +`ifdef cyclonev +specify + (A => Q) = 602; + (B => Q) = 584; + (C => Q) = 510; + (D => Q) = 510; + (E => Q) = 339; + (F => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 275; + (B => Q) = 272; + (C => Q) = 175; + (D => Q) = 165; + (E => Q) = 162; + (F => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {F, E, D, C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT5(input A, B, C, D, E, output Q); + +parameter [31:0] LUT = 32'h0000_0000; + +`ifdef cyclonev +specify + (A => Q) = 584; + (B => Q) = 510; + (C => Q) = 510; + (D => Q) = 339; + (E => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 272; + (B => Q) = 175; + (C => Q) = 165; + (D => Q) = 162; + (E => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {E, D, C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT4(input A, B, C, D, output Q); + +parameter [15:0] LUT = 16'h0000; + +`ifdef cyclonev +specify + (A => Q) = 510; + (B => Q) = 510; + (C => Q) = 339; + (D => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 175; + (B => Q) = 165; + (C => Q) = 162; + (D => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {D, C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT3(input A, B, C, output Q); + +parameter [7:0] LUT = 8'h00; + +`ifdef cyclonev +specify + (A => Q) = 510; + (B => Q) = 339; + (C => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 165; + (B => Q) = 162; + (C => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT2(input A, B, output Q); + +parameter [3:0] LUT = 4'h0; + +`ifdef cyclonev +specify + (A => Q) = 339; + (B => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 162; + (B => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_NOT(input A, output Q); + +`ifdef cyclonev +specify + (A => Q) = 94; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 53; +endspecify +`endif + +assign Q = ~A; + +endmodule + +(* abc9_box, lib_whitebox *) +module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, (* abc9_carry *) input CI, output SO, (* abc9_carry *) output CO); + +parameter LUT0 = 16'h0000; +parameter LUT1 = 16'h0000; + +`ifdef cyclonev +specify + (A => SO) = 1283; + (B => SO) = 1167; + (C => SO) = 866; + (D0 => SO) = 756; + (D1 => SO) = 756; + (CI => SO) = 355; + (A => CO) = 950; + (B => CO) = 1039; + (C => CO) = 820; + (D0 => CO) = 1006; + (D1 => CO) = 1006; + (CI => CO) = 23; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => SO) = 644; + (B => SO) = 477; + (C => SO) = 416; + (D0 => SO) = 380; + (D1 => SO) = 431; + (CI => SO) = 276; + (A => CO) = 525; + (B => CO) = 433; + (C => CO) = 712; + (D0 => CO) = 653; + (D1 => CO) = 593; + (CI => CO) = 16; +endspecify +`endif + +wire q0, q1; + +assign q0 = LUT0 >> {D0, C, B, A}; +assign q1 = LUT1 >> {D1, C, B, A}; + +assign {CO, SO} = q0 + !q1 + CI; + +endmodule + + +/* +// A, B, C0, C1, E0, E1, F0, F1: data inputs +// CARRYIN: carry input +// SHAREIN: shared-arithmetic input +// CLK0, CLK1, CLK2: clock inputs +// +// COMB0, COMB1: combinational outputs +// FF0, FF1, FF2, FF3: DFF outputs +// SUM0, SUM1: adder outputs +// CARRYOUT: carry output +// SHAREOUT: shared-arithmetic output +module MISTRAL_ALM( + input A, B, C0, C1, E0, E1, F0, F1, CARRYIN, SHAREIN, // LUT path + input CLK0, CLK1, CLK2, AC0, AC1, // FF path + output COMB0, COMB1, SUM0, SUM1, CARRYOUT, SHAREOUT, + output FF0, FF1, FF2, FF3 +); + +parameter LUT0 = 16'b0000; +parameter LUT1 = 16'b0000; +parameter LUT2 = 16'b0000; +parameter LUT3 = 16'b0000; + +parameter INIT0 = 1'b0; +parameter INIT1 = 1'b0; +parameter INIT2 = 1'b0; +parameter INIT3 = 1'b0; + +parameter C0_MUX = "C0"; +parameter C1_MUX = "C1"; + +parameter F0_MUX = "VCC"; +parameter F1_MUX = "GND"; + +parameter FEEDBACK0 = "FF0"; +parameter FEEDBACK1 = "FF2"; + +parameter ADD_MUX = "LUT"; + +parameter DFF01_DATA_MUX = "COMB"; +parameter DFF23_DATA_MUX = "COMB"; + +parameter DFF0_CLK = "CLK0"; +parameter DFF1_CLK = "CLK0"; +parameter DFF2_CLK = "CLK0"; +parameter DFF3_CLK = "CLK0"; + +parameter DFF0_AC = "AC0"; +parameter DFF1_AC = "AC0"; +parameter DFF2_AC = "AC0"; +parameter DFF3_AC = "AC0"; + +// Feedback muxes from the flip-flop outputs. +wire ff_feedback_mux0, ff_feedback_mux1; + +// C-input muxes which can be set to also use the F-input. +wire c0_input_mux, c1_input_mux; + +// F-input muxes which can be set to a constant to allow LUT5 use. +wire f0_input_mux, f1_input_mux; + +// Adder input muxes to select between shared-arithmetic mode and arithmetic mode. +wire add0_input_mux, add1_input_mux; + +// Combinational-output muxes for LUT #1 and LUT #3 +wire lut1_comb_mux, lut3_comb_mux; + +// Sum-output muxes for LUT #1 and LUT #3 +wire lut1_sum_mux, lut3_sum_mux; + +// DFF data-input muxes +wire dff01_data_mux, dff23_data_mux; + +// DFF clock selectors +wire dff0_clk, dff1_clk, dff2_clk, dff3_clk; + +// DFF asynchronous-clear selectors +wire dff0_ac, dff1_ac, dff2_ac, dff3_ac; + +// LUT, DFF and adder output wires for routing. +wire lut0_out, lut1a_out, lut1b_out, lut2_out, lut3a_out, lut3b_out; +wire dff0_out, dff1_out, dff2_out, dff3_out; +wire add0_sum, add1_sum, add0_carry, add1_carry; + +generate + if (FEEDBACK0 === "FF0") + assign ff_feedback_mux0 = dff0_out; + else if (FEEDBACK0 === "FF1") + assign ff_feedback_mux0 = dff1_out; + else + $error("Invalid FEEDBACK0 setting!"); + + if (FEEDBACK1 == "FF2") + assign ff_feedback_mux1 = dff2_out; + else if (FEEDBACK1 == "FF3") + assign ff_feedback_mux1 = dff3_out; + else + $error("Invalid FEEDBACK1 setting!"); + + if (C0_MUX === "C0") + assign c0_input_mux = C0; + else if (C0_MUX === "F1") + assign c0_input_mux = F1; + else if (C0_MUX === "FEEDBACK1") + assign c0_input_mux = ff_feedback_mux1; + else + $error("Invalid C0_MUX setting!"); + + if (C1_MUX === "C1") + assign c1_input_mux = C1; + else if (C1_MUX === "F0") + assign c1_input_mux = F0; + else if (C1_MUX === "FEEDBACK0") + assign c1_input_mux = ff_feedback_mux0; + else + $error("Invalid C1_MUX setting!"); + + // F0 == VCC is LUT5 + // F0 == F0 is LUT6 + // F0 == FEEDBACK is unknown + if (F0_MUX === "VCC") + assign f0_input_mux = 1'b1; + else if (F0_MUX === "F0") + assign f0_input_mux = F0; + else if (F0_MUX === "FEEDBACK0") + assign f0_input_mux = ff_feedback_mux0; + else + $error("Invalid F0_MUX setting!"); + + // F1 == GND is LUT5 + // F1 == F1 is LUT6 + // F1 == FEEDBACK is unknown + if (F1_MUX === "GND") + assign f1_input_mux = 1'b0; + else if (F1_MUX === "F1") + assign f1_input_mux = F1; + else if (F1_MUX === "FEEDBACK1") + assign f1_input_mux = ff_feedback_mux1; + else + $error("Invalid F1_MUX setting!"); + + if (ADD_MUX === "LUT") begin + assign add0_input_mux = ~lut1_sum_mux; + assign add1_input_mux = ~lut3_sum_mux; + end else if (ADD_MUX === "SHARE") begin + assign add0_input_mux = SHAREIN; + assign add1_input_mux = lut1_comb_mux; + end else + $error("Invalid ADD_MUX setting!"); + + if (DFF01_DATA_MUX === "COMB") + assign dff01_data_mux = COMB0; + else if (DFF01_DATA_MUX === "SUM") + assign dff01_data_mux = SUM0; + else + $error("Invalid DFF01_DATA_MUX setting!"); + + if (DFF23_DATA_MUX === "COMB") + assign dff23_data_mux = COMB0; + else if (DFF23_DATA_MUX === "SUM") + assign dff23_data_mux = SUM0; + else + $error("Invalid DFF23_DATA_MUX setting!"); + + if (DFF0_CLK === "CLK0") + assign dff0_clk = CLK0; + else if (DFF0_CLK === "CLK1") + assign dff0_clk = CLK1; + else if (DFF0_CLK === "CLK2") + assign dff0_clk = CLK2; + else + $error("Invalid DFF0_CLK setting!"); + + if (DFF1_CLK === "CLK0") + assign dff1_clk = CLK0; + else if (DFF1_CLK === "CLK1") + assign dff1_clk = CLK1; + else if (DFF1_CLK === "CLK2") + assign dff1_clk = CLK2; + else + $error("Invalid DFF1_CLK setting!"); + + if (DFF2_CLK === "CLK0") + assign dff2_clk = CLK0; + else if (DFF2_CLK === "CLK1") + assign dff2_clk = CLK1; + else if (DFF2_CLK === "CLK2") + assign dff2_clk = CLK2; + else + $error("Invalid DFF2_CLK setting!"); + + if (DFF3_CLK === "CLK0") + assign dff3_clk = CLK0; + else if (DFF3_CLK === "CLK1") + assign dff3_clk = CLK1; + else if (DFF3_CLK === "CLK2") + assign dff3_clk = CLK2; + else + $error("Invalid DFF3_CLK setting!"); + + if (DFF0_AC === "AC0") + assign dff0_ac = AC0; + else if (DFF0_AC === "AC1") + assign dff0_ac = AC1; + else + $error("Invalid DFF0_AC setting!"); + + if (DFF1_AC === "AC0") + assign dff1_ac = AC0; + else if (DFF1_AC === "AC1") + assign dff1_ac = AC1; + else + $error("Invalid DFF1_AC setting!"); + + if (DFF2_AC === "AC0") + assign dff2_ac = AC0; + else if (DFF2_AC === "AC1") + assign dff2_ac = AC1; + else + $error("Invalid DFF2_AC setting!"); + + if (DFF3_AC === "AC0") + assign dff3_ac = AC0; + else if (DFF3_AC === "AC1") + assign dff3_ac = AC1; + else + $error("Invalid DFF3_AC setting!"); + +endgenerate + +// F0 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT0)) lut0 (.A(A), .B(B), .C(C0), .D(c1_input_mux), .Q(lut0_out)); + +// F2 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT1)) lut1_comb (.A(A), .B(B), .C(C0), .D(c1_input_mux), .Q(lut1_comb_mux)); +MISTRAL_ALUT4 #(.LUT(LUT1)) lut1_sum (.A(A), .B(B), .C(C0), .D(E0), .Q(lut1_sum_mux)); + +// F1 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT2)) lut2 (.A(A), .B(B), .C(C1), .D(c0_input_mux), .Q(lut2_out)); + +// F3 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT3)) lut3_comb (.A(A), .B(B), .C(C1), .D(c0_input_mux), .Q(lut3_comb_mux)); +MISTRAL_ALUT4 #(.LUT(LUT3)) lut3_sum (.A(A), .B(B), .C(C1), .D(E1), .Q(lut3_sum_mux)); + +MISTRAL_FF #(.INIT(INIT0)) dff0 (.D(dff01_data_mux), .CLK(dff0_clk), .ACn(dff0_ac), .Q(dff0_out)); +MISTRAL_FF #(.INIT(INIT1)) dff1 (.D(dff01_data_mux), .CLK(dff1_clk), .ACn(dff1_ac), .Q(dff1_out)); +MISTRAL_FF #(.INIT(INIT2)) dff2 (.D(dff23_data_mux), .CLK(dff2_clk), .ACn(dff2_ac), .Q(dff2_out)); +MISTRAL_FF #(.INIT(INIT3)) dff3 (.D(dff23_data_mux), .CLK(dff3_clk), .ACn(dff3_ac), .Q(dff3_out)); + +// Adders +assign {add0_carry, add0_sum} = CARRYIN + lut0_out + lut1_sum_mux; +assign {add1_carry, add1_sum} = add0_carry + lut2_out + lut3_sum_mux; + +// COMBOUT outputs on the Quartus diagram +assign COMB0 = E0 ? (f0_input_mux ? lut3_comb_mux : lut1_comb_mux) + : (f0_input_mux ? lut2_out : lut0_out); + +assign COMB1 = E1 ? (f1_input_mux ? lut3_comb_mux : lut1_comb_mux) + : (f1_input_mux ? lut2_out : lut0_out); + +// SUMOUT output on the Quartus diagram +assign SUM0 = add0_sum; +assign SUM1 = add1_sum; + +// COUT output on the Quartus diagram +assign CARRYOUT = add1_carry; + +// SHAREOUT output on the Quartus diagram +assign SHAREOUT = lut3_comb_mux; + +// REGOUT outputs on the Quartus diagram +assign FF0 = dff0_out; +assign FF1 = dff1_out; +assign FF2 = dff2_out; +assign FF3 = dff3_out; + +endmodule +*/ diff --git a/techlibs/intel_alm/common/arith_alm_map.v b/techlibs/intel_alm/common/arith_alm_map.v new file mode 100644 index 000000000..ddf81d9d0 --- /dev/null +++ b/techlibs/intel_alm/common/arith_alm_map.v @@ -0,0 +1,64 @@ +`default_nettype none + +module \$alu (A, B, CI, BI, X, Y, CO); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 1; +parameter B_WIDTH = 1; +parameter Y_WIDTH = 1; + +parameter _TECHMAP_CONSTMSK_CI_ = 0; +parameter _TECHMAP_CONSTVAL_CI_ = 0; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +input CI, BI; +output [Y_WIDTH-1:0] X, Y, CO; + +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] BX = B_buf; +wire [Y_WIDTH:0] ALM_CARRY; + +// Start of carry chain +generate + if (_TECHMAP_CONSTMSK_CI_ == 1) begin + assign ALM_CARRY[0] = _TECHMAP_CONSTVAL_CI_; + end else begin + MISTRAL_ALUT_ARITH #( + .LUT0(16'b1010_1010_1010_1010), // Q = A + .LUT1(16'b0000_0000_0000_0000), // Q = 0 (LUT1's input to the adder is inverted) + ) alm_start ( + .A(CI), .B(1'b1), .C(1'b1), .D0(1'b1), .D1(1'b1), + .CI(1'b0), + .CO(ALM_CARRY[0]) + ); + end +endgenerate + +// Carry chain +genvar i; +generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice + // TODO: mwk suggests that a pass could merge pre-adder logic into this. + MISTRAL_ALUT_ARITH #( + .LUT0(16'b1010_1010_1010_1010), // Q = A + .LUT1(16'b1100_0011_1100_0011), // Q = C ? B : ~B (LUT1's input to the adder is inverted) + ) alm_i ( + .A(AA[i]), .B(BX[i]), .C(BI), .D0(1'b1), .D1(1'b1), + .CI(ALM_CARRY[i]), + .SO(Y[i]), + .CO(ALM_CARRY[i+1]) + ); + + // ALM carry chain is not directly accessible, so calculate the carry through soft logic if really needed. + assign CO[i] = (AA[i] && BB[i]) || ((Y[i] ^ AA[i] ^ BB[i]) && (AA[i] || BB[i])); +end endgenerate + +assign X = AA ^ BB; + +endmodule diff --git a/techlibs/intel_alm/common/bram_m10k.txt b/techlibs/intel_alm/common/bram_m10k.txt new file mode 100644 index 000000000..837e3a330 --- /dev/null +++ b/techlibs/intel_alm/common/bram_m10k.txt @@ -0,0 +1,33 @@ +bram __MISTRAL_M10K_SDP + init 0 # TODO: Re-enable when I figure out how BRAM init works + abits 13 @D8192x1 + dbits 1 @D8192x1 + abits 12 @D4096x2 + dbits 2 @D4096x2 + abits 11 @D2048x4 @D2048x5 + dbits 4 @D2048x4 + dbits 5 @D2048x5 + abits 10 @D1024x8 @D1024x10 + dbits 8 @D1024x8 + dbits 10 @D1024x10 + abits 9 @D512x16 @D512x20 + dbits 16 @D512x16 + dbits 20 @D512x20 + abits 8 @D256x32 @D256x40 + dbits 32 @D256x32 + dbits 40 @D256x40 + groups 2 + ports 1 1 + wrmode 1 0 + # read enable; write enable + byte enables (only for multiples of 8) + enable 1 1 + transp 0 0 + clocks 1 1 + clkpol 1 1 +endbram + + +match __MISTRAL_M10K_SDP + min efficiency 5 + make_transp +endmatch diff --git a/techlibs/intel_alm/common/bram_m10k_map.v b/techlibs/intel_alm/common/bram_m10k_map.v new file mode 100644 index 000000000..e5566010d --- /dev/null +++ b/techlibs/intel_alm/common/bram_m10k_map.v @@ -0,0 +1,31 @@ +module __MISTRAL_M10K_SDP(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+
+parameter CFG_ABITS = 10;
+parameter CFG_DBITS = 10;
+parameter CFG_ENABLE_A = 1;
+parameter CFG_ENABLE_B = 1;
+
+input CLK1;
+input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
+input [CFG_DBITS-1:0] A1DATA;
+output [CFG_DBITS-1:0] B1DATA;
+input [CFG_ENABLE_A-1:0] A1EN, B1EN;
+
+altsyncram #(
+ .operation_mode("dual_port"),
+ .ram_block_type("m10k"),
+ .widthad_a(CFG_ABITS),
+ .width_a(CFG_DBITS),
+ .widthad_b(CFG_ABITS),
+ .width_b(CFG_DBITS),
+) _TECHMAP_REPLACE_ (
+ .address_a(A1ADDR),
+ .data_a(A1DATA),
+ .wren_a(A1EN),
+ .address_b(B1ADDR),
+ .q_b(B1DATA),
+ .clock0(CLK1),
+ .clock1(CLK1)
+);
+
+endmodule diff --git a/techlibs/intel_alm/common/bram_m20k.txt b/techlibs/intel_alm/common/bram_m20k.txt new file mode 100644 index 000000000..b4c5a5372 --- /dev/null +++ b/techlibs/intel_alm/common/bram_m20k.txt @@ -0,0 +1,33 @@ +bram __MISTRAL_M20K_SDP + init 1 # TODO: Re-enable when I figure out how BRAM init works + abits 14 @D16384x1 + dbits 1 @D16384x1 + abits 13 @D8192x2 + dbits 2 @D8192x2 + abits 12 @D4096x4 @D4096x5 + dbits 4 @D4096x4 + dbits 5 @D4096x5 + abits 11 @D2048x8 @D2048x10 + dbits 8 @D2048x8 + dbits 10 @D2048x10 + abits 10 @D1024x16 @D1024x20 + dbits 16 @D1024x16 + dbits 20 @D1024x20 + abits 9 @D512x32 @D512x40 + dbits 32 @D512x32 + dbits 40 @D512x40 + groups 2 + ports 1 1 + wrmode 1 0 + # read enable; write enable + byte enables (only for multiples of 8) + enable 1 1 + transp 0 0 + clocks 1 1 + clkpol 1 1 +endbram + + +match __MISTRAL_M20K_SDP + min efficiency 5 + make_transp +endmatch diff --git a/techlibs/intel_alm/common/bram_m20k_map.v b/techlibs/intel_alm/common/bram_m20k_map.v new file mode 100644 index 000000000..92f41310f --- /dev/null +++ b/techlibs/intel_alm/common/bram_m20k_map.v @@ -0,0 +1,31 @@ +module __MISTRAL_M20K_SDP(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+
+parameter CFG_ABITS = 10;
+parameter CFG_DBITS = 20;
+parameter CFG_ENABLE_A = 1;
+parameter CFG_ENABLE_B = 1;
+
+input CLK1;
+input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
+input [CFG_DBITS-1:0] A1DATA;
+output [CFG_DBITS-1:0] B1DATA;
+input [CFG_ENABLE_A-1:0] A1EN, B1EN;
+
+altsyncram #(
+ .operation_mode("dual_port"),
+ .ram_block_type("m20k"),
+ .widthad_a(CFG_ABITS),
+ .width_a(CFG_DBITS),
+ .widthad_b(CFG_ABITS),
+ .width_b(CFG_DBITS),
+) _TECHMAP_REPLACE_ (
+ .address_a(A1ADDR),
+ .data_a(A1DATA),
+ .wren_a(A1EN),
+ .address_b(B1ADDR),
+ .q_b(B1DATA),
+ .clock0(CLK1),
+ .clock1(CLK1)
+);
+
+endmodule
diff --git a/techlibs/intel_alm/common/dff_map.v b/techlibs/intel_alm/common/dff_map.v new file mode 100644 index 000000000..f7f2fe3c3 --- /dev/null +++ b/techlibs/intel_alm/common/dff_map.v @@ -0,0 +1,124 @@ +`default_nettype none + +// D flip-flops +module \$_DFF_P_ (input D, C, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_P_ with INIT=1"); +endmodule + +module \$_DFF_N_ (input D, C, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_N_ with INIT=1"); +endmodule + +// D flip-flops with reset +module \$_DFF_PP0_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_PP0_ with INIT=1"); +endmodule + +module \$_DFF_PN0_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_PN0_ with INIT=1"); +endmodule + +module \$_DFF_NP0_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_NP0_ with INIT=1"); +endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFF_NN0_ with INIT=1"); +endmodule + +// D flip-flops with set +module \$_DFF_PP1_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b1; +if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + wire Q_tmp; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); + assign Q = ~Q_tmp; +end else $error("Unsupported flop: $_DFF_PP1_ with INIT=0"); +endmodule + +module \$_DFF_PN1_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b1; +if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + wire Q_tmp; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); +end else $error("Unsupported flop: $_DFF_PN1_ with INIT=0"); +endmodule + +module \$_DFF_NP1_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b1; +if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + wire Q_tmp; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); + assign Q = ~Q_tmp; +end else $error("Unsupported flop: $_DFF_NP1_ with INIT=0"); +endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b1; +if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + wire Q_tmp; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); + assign Q = ~Q_tmp; +end else $error("Unsupported flop: $_DFF_NN1_ with INIT=0"); +endmodule + +// D flip-flops with clock enable +module \$_DFFE_PP_ (input D, C, E, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFFE_PP_ with INIT=1"); +endmodule + +module \$_DFFE_PN_ (input D, C, E, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFFE_PN_ with INIT=1"); +endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFFE_NP_ with INIT=1"); +endmodule + +module \$_DFFE_NN_ (input D, C, E, output Q); +parameter _TECHMAP_WIREINIT_Q_ = 1'b0; +if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +end else $error("Unsupported flop: $_DFFE_NN_ with INIT=1"); +endmodule diff --git a/techlibs/intel_alm/common/dff_sim.v b/techlibs/intel_alm/common/dff_sim.v new file mode 100644 index 000000000..07865905f --- /dev/null +++ b/techlibs/intel_alm/common/dff_sim.v @@ -0,0 +1,48 @@ +// DATAIN: synchronous data input +// CLK: clock input (positive edge) +// ACLR: asynchronous clear (negative-true) +// ENA: clock-enable +// SCLR: synchronous clear +// SLOAD: synchronous load +// SDATA: synchronous load data +// +// Q: data output +// +// Note: the DFFEAS primitive is mostly emulated; it does not reflect what the hardware implements. +module MISTRAL_FF( + input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, + output reg Q +); + +`ifdef cyclonev +specify + (posedge CLK => (Q : DATAIN)) = 262; + $setup(DATAIN, posedge CLK, 522); +endspecify +`endif +`ifdef cyclone10gx +specify + (posedge CLK => (Q : DATAIN)) = 219; + $setup(DATAIN, posedge CLK, 268); +endspecify +`endif + +initial begin + // Altera flops initialise to zero. + Q = 0; +end + +always @(posedge CLK, negedge ACLR) begin + // Asynchronous clear + if (!ACLR) Q <= 0; + // Clock-enable + else if (ENA) begin + // Synchronous clear + if (SCLR) Q <= 0; + // Synchronous load + else if (SLOAD) Q <= SDATA; + else Q <= DATAIN; + end +end + +endmodule diff --git a/techlibs/intel_alm/common/lutram_mlab.txt b/techlibs/intel_alm/common/lutram_mlab.txt new file mode 100644 index 000000000..1d6174d85 --- /dev/null +++ b/techlibs/intel_alm/common/lutram_mlab.txt @@ -0,0 +1,20 @@ +bram __MISTRAL_MLAB
+ init 0 # TODO: Re-enable when I figure out how LUTRAM init works
+ abits 5
+ dbits 16 @D32x16
+ dbits 18 @D32x18
+ dbits 20 @D32x20
+ groups 2
+ ports 1 1
+ wrmode 1 0
+ # read enable
+ enable 1 0
+ transp 1 0
+ clocks 1 2
+ clkpol 1 1
+endbram
+
+match __MISTRAL_MLAB
+ min efficiency 5
+ make_outreg
+endmatch
diff --git a/techlibs/intel_alm/common/lutram_mlab_map.v b/techlibs/intel_alm/common/lutram_mlab_map.v new file mode 100644 index 000000000..3a9c8590e --- /dev/null +++ b/techlibs/intel_alm/common/lutram_mlab_map.v @@ -0,0 +1,29 @@ +module __MISTRAL_MLAB(CLK1, CLK2, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA);
+
+parameter CFG_ABITS = 5;
+parameter CFG_DBITS = 20;
+
+input CLK1, CLK2;
+input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
+input [CFG_DBITS-1:0] A1DATA;
+input A1EN;
+output [CFG_DBITS-1:0] B1DATA;
+
+altsyncram #(
+ .operation_mode("dual_port"),
+ .ram_block_type("mlab"),
+ .widthad_a(CFG_ABITS),
+ .width_a(CFG_DBITS),
+ .widthad_b(CFG_ABITS),
+ .width_b(CFG_DBITS),
+) _TECHMAP_REPLACE_ (
+ .address_a(A1ADDR),
+ .data_a(A1DATA),
+ .wren_a(A1EN),
+ .address_b(B1ADDR),
+ .q_b(B1DATA),
+ .clock0(CLK1),
+ .clock1(CLK1),
+);
+
+endmodule
diff --git a/techlibs/intel_alm/common/megafunction_bb.v b/techlibs/intel_alm/common/megafunction_bb.v new file mode 100644 index 000000000..21ba73a09 --- /dev/null +++ b/techlibs/intel_alm/common/megafunction_bb.v @@ -0,0 +1,108 @@ +// Intel megafunction declarations, to avoid Yosys complaining. +`default_nettype none + +(* blackbox *) +module altera_std_synchronizer(clk, din, dout, reset_n); + +parameter depth = 2; + +input clk; +input reset_n; +input din; +output dout; + +endmodule + +(* blackbox *) +module altiobuf_in(datain, dataout); + +parameter enable_bus_hold = "FALSE"; +parameter use_differential_mode = "FALSE"; +parameter number_of_channels = 1; + +input [number_of_channels-1:0] datain; +output [number_of_channels-1:0] dataout; + +endmodule + +(* blackbox *) +module altiobuf_out(datain, dataout); + +parameter enable_bus_hold = "FALSE"; +parameter use_differential_mode = "FALSE"; +parameter use_oe = "FALSE"; +parameter number_of_channels = 1; + +input [number_of_channels-1:0] datain; +output [number_of_channels-1:0] dataout; + +endmodule + +(* blackbox *) +module altiobuf_bidir(dataio, oe, datain, dataout); + +parameter number_of_channels = 1; +parameter enable_bus_hold = "OFF"; + +inout [number_of_channels-1:0] dataio; +input [number_of_channels-1:0] datain; +output [number_of_channels-1:0] dataout; +input [number_of_channels-1:0] oe; + +endmodule + +(* blackbox *) +module altsyncram(clock0, clock1, address_a, data_a, rden_a, wren_a, byteena_a, q_a, addressstall_a, address_b, data_b, rden_b, wren_b, byteena_b, q_b, addressstall_b, clocken0, clocken1, clocken2, clocken3, aclr0, aclr1, eccstatus); + +parameter lpm_type = "altsyncram"; +parameter operation_mode = "dual_port"; +parameter ram_block_type = "auto"; +parameter intended_device_family = "auto"; +parameter power_up_uninitialized = "false"; +parameter read_during_write_mode_mixed_ports = "dontcare"; +parameter byte_size = 8; +parameter widthad_a = 1; +parameter width_a = 1; +parameter width_byteena_a = 1; +parameter numwords_a = 1; +parameter clock_enable_input_a = "clocken0"; +parameter widthad_b = 1; +parameter width_b = 1; +parameter numwords_b = 1; +parameter address_aclr_b = "aclr0"; +parameter address_reg_b = ""; +parameter outdata_aclr_b = "aclr0"; +parameter outdata_reg_b = ""; +parameter clock_enable_input_b = "clocken0"; +parameter clock_enable_output_b = "clocken0"; + +input clock0, clock1; +input [widthad_a-1:0] address_a; +input [width_a-1:0] data_a; +input rden_a; +input wren_a; +input [(width_a/8)-1:0] byteena_a; +input addressstall_a; + +output [width_a-1:0] q_a; + +input wren_b; +input rden_b; +input [widthad_b-1:0] address_b; +input [width_b-1:0] data_b; +input [(width_b/8)-1:0] byteena_b; +input addressstall_b; + +output [width_b-1:0] q_b; + +input clocken0; +input clocken1; +input clocken2; +input clocken3; + +input aclr0; +input aclr1; + +output eccstatus; + +endmodule diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v new file mode 100644 index 000000000..d9961c174 --- /dev/null +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -0,0 +1,19 @@ +module __MISTRAL_VCC(output Q); + +MISTRAL_ALUT2 #(.LUT(4'b1111)) _TECHMAP_REPLACE_ (.A(1'b1), .B(1'b1), .Q(Q)); + +endmodule + + +module __MISTRAL_GND(output Q); + +MISTRAL_ALUT2 #(.LUT(4'b0000)) _TECHMAP_REPLACE_ (.A(1'b1), .B(1'b1), .Q(Q)); + +endmodule + + +module MISTRAL_FF(input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, output reg Q); + +dffeas #(.power_up("low"), .is_wysiwyg("true")) _TECHMAP_REPLACE_ (.d(DATAIN), .clk(CLK), .clrn(ACLR), .ena(ENA), .sclr(SCLR), .sload(SLOAD), .asdata(SDATA), .q(Q)); + +endmodule diff --git a/techlibs/intel_alm/cyclone10gx/quartus_rename.v b/techlibs/intel_alm/cyclone10gx/quartus_rename.v new file mode 100644 index 000000000..3fbc508ed --- /dev/null +++ b/techlibs/intel_alm/cyclone10gx/quartus_rename.v @@ -0,0 +1,54 @@ +module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); +parameter LUT = 64'h0000_0000_0000_0000; + +cyclone10gx_lcell_comb #(.lut_mask(LUT)) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .dataf(F), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT5(input A, B, C, D, E, output Q); +parameter LUT = 32'h0000_0000; + +cyclone10gx_lcell_comb #(.lut_mask({2{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT4(input A, B, C, D, output Q); +parameter LUT = 16'h0000; + +cyclone10gx_lcell_comb #(.lut_mask({4{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT3(input A, B, C, output Q); +parameter LUT = 8'h00; + +cyclone10gx_lcell_comb #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT2(input A, B, output Q); +parameter LUT = 4'h0; + +cyclone10gx_lcell_comb #(.lut_mask({16{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q)); + +endmodule + + +module MISTRAL_NOT(input A, output Q); + +NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q)); + +endmodule + + +module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, CI, output SO, CO); +parameter LUT0 = 16'h0000; +parameter LUT1 = 16'h0000; + +cyclone10gx_lcell_comb #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO)); + +endmodule diff --git a/techlibs/intel_alm/cyclonev/quartus_rename.v b/techlibs/intel_alm/cyclonev/quartus_rename.v new file mode 100644 index 000000000..6eff375e1 --- /dev/null +++ b/techlibs/intel_alm/cyclonev/quartus_rename.v @@ -0,0 +1,54 @@ +module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); +parameter LUT = 64'h0000_0000_0000_0000; + +cyclonev_lcell_comb #(.lut_mask(LUT)) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .dataf(F), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT5(input A, B, C, D, E, output Q); +parameter LUT = 32'h0000_0000; + +cyclonev_lcell_comb #(.lut_mask({2{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT4(input A, B, C, D, output Q); +parameter LUT = 16'h0000; + +cyclonev_lcell_comb #(.lut_mask({4{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT3(input A, B, C, output Q); +parameter LUT = 8'h00; + +cyclonev_lcell_comb #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT2(input A, B, output Q); +parameter LUT = 4'h0; + +cyclonev_lcell_comb #(.lut_mask({16{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q)); + +endmodule + + +module MISTRAL_NOT(input A, output Q); + +NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q)); + +endmodule + + +module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, CI, output SO, CO); +parameter LUT0 = 16'h0000; +parameter LUT1 = 16'h0000; + +cyclonev_lcell_comb #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO)); + +endmodule diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc new file mode 100644 index 000000000..47aa11500 --- /dev/null +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -0,0 +1,241 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Wolf <claire@symbioticeda.com> + * Copyright (C) 2019 Dan Ravensloft <dan.ravensloft@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/celltypes.h" +#include "kernel/log.h" +#include "kernel/register.h" +#include "kernel/rtlil.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SynthIntelALMPass : public ScriptPass { + SynthIntelALMPass() : ScriptPass("synth_intel_alm", "synthesis for ALM-based Intel (Altera) FPGAs.") {} + + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_intel_alm [options]\n"); + log("\n"); + log("This command runs synthesis for ALM-based Intel FPGAs.\n"); + log("\n"); + log(" -top <module>\n"); + log(" use the specified module as top module (default='top')\n"); + log("\n"); + log(" -family <family>\n"); + log(" target one of:\n"); + log(" \"cyclonev\" - Cyclone V (default)\n"); + log(" \"cyclone10gx\" - Cyclone 10GX\n"); + log("\n"); + log(" -quartus\n"); + log(" output a netlist using Quartus cells instead of MISTRAL_* cells\n"); + log("\n"); + log(" -vqm <file>\n"); + log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n"); + log(" output file is omitted if this parameter is not specified. Implies -quartus.\n"); + log("\n"); + log(" -run <from_label>:<to_label>\n"); + log(" only run the commands between the labels (see below). an empty\n"); + log(" from label is synonymous to 'begin', and empty to label is\n"); + log(" synonymous to the end of the command list.\n"); + log("\n"); + log(" -nolutram\n"); + log(" do not use LUT RAM cells in output netlist\n"); + log("\n"); + log(" -nobram\n"); + log(" do not use block RAM cells in output netlist\n"); + log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } + + string top_opt, family_opt, bram_type, vout_file; + bool flatten, quartus, nolutram, nobram; + + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + family_opt = "cyclonev"; + bram_type = "m10k"; + vout_file = ""; + flatten = true; + quartus = false; + nolutram = false; + nobram = false; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + string run_from, run_to; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-family" && argidx + 1 < args.size()) { + family_opt = args[++argidx]; + continue; + } + if (args[argidx] == "-top" && argidx + 1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if (args[argidx] == "-vqm" && argidx + 1 < args.size()) { + quartus = true; + vout_file = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx + 1 < args.size()) { + size_t pos = args[argidx + 1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos + 1); + continue; + } + if (args[argidx] == "-quartus") { + quartus = true; + continue; + } + if (args[argidx] == "-nolutram") { + nolutram = true; + continue; + } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + if (family_opt == "cyclonev") { + bram_type = "m10k"; + } else if (family_opt == "cyclone10gx") { + bram_type = "m20k"; + } else { + log_cmd_error("Invalid family specified: '%s'\n", family_opt.c_str()); + } + + log_header(design, "Executing SYNTH_INTEL_ALM pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() YS_OVERRIDE + { + if (help_mode) { + family_opt = "<family>"; + bram_type = "<bram_type>"; + } + + if (check_label("begin")) { + run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str())); + + // Misc and common cells + run("read_verilog -lib +/intel/common/altpll_bb.v"); + run("read_verilog -lib +/intel_alm/common/megafunction_bb.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); + } + + if (flatten && check_label("flatten", "(unless -noflatten)")) { + run("proc"); + run("flatten"); + run("tribuf -logic"); + run("deminout"); + } + + if (check_label("coarse")) { + run("synth -run coarse -lut 6"); + run("techmap -map +/intel_alm/common/arith_alm_map.v"); + } + + if (!nobram && check_label("map_bram", "(skip if -nobram)")) { + run(stringf("memory_bram -rules +/intel_alm/common/bram_%s.txt", bram_type.c_str())); + run(stringf("techmap -map +/intel_alm/common/bram_%s_map.v", bram_type.c_str())); + } + + if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { + run("memory_bram -rules +/intel_alm/common/lutram_mlab.txt", "(for Cyclone V / Cyclone 10GX)"); + run("techmap -map +/intel_alm/common/lutram_mlab_map.v", "(for Cyclone V / Cyclone 10GX)"); + } + + if (check_label("map_ffram")) { + run("memory_map"); + run("opt -full"); + } + + if (check_label("map_ffs")) { + run("dff2dffe -direct-match $_DFF_*"); + run("zinit"); + run("techmap -map +/techmap.v -map +/intel_alm/common/dff_map.v"); + run("opt -full -undriven -mux_undef"); + run("clean -purge"); + } + + if (check_label("map_luts")) { + run("read_verilog -icells -specify -lib +/abc9_model.v"); + run("abc9 -maxlut 6 -W 200"); + run("techmap -map +/intel_alm/common/alm_map.v"); + run("opt -fast"); + run("autoname"); + run("clean"); + } + + if (check_label("check")) { + run("hierarchy -check"); + run("stat"); + run("check"); + } + + if (check_label("quartus")) { + if (quartus || help_mode) { + run("setundef -zero"); + run("hilomap -singleton -hicell __MISTRAL_VCC Q -locell __MISTRAL_GND Q"); + run("techmap -map +/intel_alm/common/quartus_rename.v"); + run(stringf("techmap -map +/intel_alm/%s/quartus_rename.v", family_opt.c_str())); + } + } + + if (check_label("vqm")) { + if (!vout_file.empty() || help_mode) { + run(stringf("write_verilog -attr2comment -defparam -nohex -decimal %s", help_mode ? "<file-name>" : vout_file.c_str())); + } + } + } +} SynthIntelALMPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/sf2/sf2_iobs.cc b/techlibs/sf2/sf2_iobs.cc index 3d43332e2..619888d38 100644 --- a/techlibs/sf2/sf2_iobs.cc +++ b/techlibs/sf2/sf2_iobs.cc @@ -34,14 +34,14 @@ static void handle_iobufs(Module *module, bool clkbuf_mode) for (auto cell : module->cells()) { - if (clkbuf_mode && cell->type == "\\SLE") { - for (auto bit : sigmap(cell->getPort("\\CLK"))) + if (clkbuf_mode && cell->type == ID(SLE)) { + for (auto bit : sigmap(cell->getPort(ID::CLK))) clk_bits.insert(bit); } - 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"))) + if (cell->type.in(ID(INBUF), ID(OUTBUF), ID(TRIBUFF), ID(BIBUF), ID(CLKBUF), ID(CLKBIBUF), + ID(INBUF_DIFF), ID(OUTBUF_DIFF), ID(BIBUFF_DIFF), ID(TRIBUFF_DIFF), ID(CLKBUF_DIFF), + ID(GCLKBUF), ID(GCLKBUF_DIFF), ID(GCLKBIBUF))) { + for (auto bit : sigmap(cell->getPort(ID(PAD)))) handled_io_bits.insert(bit); } } @@ -65,14 +65,14 @@ static void handle_iobufs(Module *module, bool clkbuf_mode) IdString buf_type, buf_port; if (wire->port_output) { - buf_type = "\\OUTBUF"; - buf_port = "\\D"; + buf_type = ID(OUTBUF); + buf_port = ID::D; } else if (clkbuf_mode && clk_bits.count(canonical_bit)) { - buf_type = "\\CLKBUF"; - buf_port = "\\Y"; + buf_type = ID(CLKBUF); + buf_port = ID::Y; } else { - buf_type = "\\INBUF"; - buf_port = "\\Y"; + buf_type = ID(INBUF); + buf_port = ID::Y; } Cell *c = module->addCell(NEW_ID, buf_type); @@ -96,7 +96,7 @@ static void handle_iobufs(Module *module, bool clkbuf_mode) module->rewrite_sigspecs(rewrite_function); for (auto &it : pad_bits) - it.first->setPort("\\PAD", it.second); + it.first->setPort(ID(PAD), it.second); } static void handle_clkint(Module *module) @@ -108,13 +108,13 @@ static void handle_clkint(Module *module) for (auto cell : module->cells()) { - if (cell->type == "\\SLE") { - for (auto bit : sigmap(cell->getPort("\\CLK"))) + if (cell->type == ID(SLE)) { + for (auto bit : sigmap(cell->getPort(ID::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"))) + if (cell->type.in(ID(CLKBUF), ID(CLKBIBUF), ID(CLKBUF_DIFF), ID(GCLKBUF), ID(GCLKBUF_DIFF), ID(GCLKBIBUF), + ID(CLKINT), ID(CLKINT_PRESERVE), ID(GCLKINT), ID(RCLKINT), ID(RGCLKINT))) { + for (auto bit : sigmap(cell->getPort(ID::Y))) handled_clk_bits.push_back(bit); } } @@ -134,10 +134,10 @@ static void handle_clkint(Module *module) for (auto &bit : sig) { SigBit canonical_bit = sigmap(bit); if (clk_bits.count(canonical_bit)) { - Cell *c = module->addCell(NEW_ID, "\\CLKINT"); + Cell *c = module->addCell(NEW_ID, ID(CLKINT)); SigBit new_bit = module->addWire(NEW_ID); - c->setPort("\\A", new_bit); - c->setPort("\\Y", bit); + c->setPort(ID::A, new_bit); + c->setPort(ID::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; diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index 5efa005c8..34a7e68be 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -187,7 +187,6 @@ struct SynthSf2Pass : public ScriptPass if (check_label("map_ffs")) { - run("dffsr2dff"); run("techmap -D NO_LUT -map +/sf2/cells_map.v"); run("opt_expr -mux_undef"); run("simplemap"); diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 8553efd6b..1c190d37e 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -393,8 +393,6 @@ struct SynthXilinxPass : public ScriptPass run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')"); run("clean", " (skip if '-nosrl' and '-widemux=0')"); } - - run("techmap -map +/cmp2lut.v -D LUT_WIDTH=" + lut_size_s); } if (check_label("map_dsp", "(skip if '-nodsp')")) { @@ -460,6 +458,7 @@ struct SynthXilinxPass : public ScriptPass } if (check_label("coarse")) { + run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=" + lut_size_s); run("alumacc"); run("share"); run("opt"); @@ -523,10 +522,9 @@ struct SynthXilinxPass : public ScriptPass } if (check_label("map_ffram")) { - // Required for dffsr2dff to work. + // Required for dff2dffs to work. run("simplemap t:$dff t:$adff t:$mux"); // Needs to be done before opt -mux_bool happens. - run("dffsr2dff"); if (help_mode) run("dff2dffs [-match-init]", "(-match-init for xc6s only)"); else if (family == "xc6s") diff --git a/techlibs/xilinx/xilinx_dffopt.cc b/techlibs/xilinx/xilinx_dffopt.cc index 13a0b9b83..ac9b57fe1 100644 --- a/techlibs/xilinx/xilinx_dffopt.cc +++ b/techlibs/xilinx/xilinx_dffopt.cc @@ -146,12 +146,12 @@ struct XilinxDffOptPass : public Pass { if (cell->get_bool_attribute(ID::keep)) continue; if (cell->type == ID(INV)) { - SigBit sigout = sigmap(cell->getPort(ID(O))); - SigBit sigin = sigmap(cell->getPort(ID(I))); + SigBit sigout = sigmap(cell->getPort(ID::O)); + SigBit sigin = sigmap(cell->getPort(ID::I)); bit_to_lut[sigout] = make_pair(LutData(Const(1, 2), {sigin}), cell); } else if (cell->type.in(ID(LUT1), ID(LUT2), ID(LUT3), ID(LUT4), ID(LUT5), ID(LUT6))) { - SigBit sigout = sigmap(cell->getPort(ID(O))); - const Const &init = cell->getParam(ID(INIT)); + SigBit sigout = sigmap(cell->getPort(ID::O)); + const Const &init = cell->getParam(ID::INIT); std::vector<SigBit> sigin; sigin.push_back(sigmap(cell->getPort(ID(I0)))); if (cell->type == ID(LUT1)) @@ -199,7 +199,7 @@ lut_sigin_done: continue; // Don't bother if D has more than one use. - SigBit sig_D = sigmap(cell->getPort(ID(D))); + SigBit sig_D = sigmap(cell->getPort(ID::D)); if (bit_uses[sig_D] > 2) continue; @@ -223,7 +223,7 @@ lut_sigin_done: bool worthy_post_r = false; // First, unmap CE. - SigBit sig_Q = sigmap(cell->getPort(ID(Q))); + SigBit sig_Q = sigmap(cell->getPort(ID::Q)); SigBit sig_CE = sigmap(cell->getPort(ID(CE))); LutData lut_ce = LutData(Const(2, 2), {sig_CE}); auto it_CE = bit_to_lut.find(sig_CE); @@ -247,7 +247,7 @@ lut_sigin_done: // Second, unmap S, if any. lut_d_post_s = lut_d_post_ce; if (has_s) { - SigBit sig_S = sigmap(cell->getPort(ID(S))); + SigBit sig_S = sigmap(cell->getPort(ID::S)); LutData lut_s = LutData(Const(2, 2), {sig_S}); bool inv_s = cell->hasParam(ID(IS_S_INVERTED)) && cell->getParam(ID(IS_S_INVERTED)).as_bool(); auto it_S = bit_to_lut.find(sig_S); @@ -269,7 +269,7 @@ lut_sigin_done: // Third, unmap R, if any. lut_d_post_r = lut_d_post_s; if (has_r) { - SigBit sig_R = sigmap(cell->getPort(ID(R))); + SigBit sig_R = sigmap(cell->getPort(ID::R)); LutData lut_r = LutData(Const(2, 2), {sig_R}); bool inv_r = cell->hasParam(ID(IS_R_INVERTED)) && cell->getParam(ID(IS_R_INVERTED)).as_bool(); auto it_R = bit_to_lut.find(sig_R); @@ -307,11 +307,11 @@ unmap: // Okay, we're doing it. Unmap ports. if (worthy_post_r) { cell->unsetParam(ID(IS_R_INVERTED)); - cell->setPort(ID(R), Const(0, 1)); + cell->setPort(ID::R, Const(0, 1)); } if (has_s && (worthy_post_r || worthy_post_s)) { cell->unsetParam(ID(IS_S_INVERTED)); - cell->setPort(ID(S), Const(0, 1)); + cell->setPort(ID::S, Const(0, 1)); } cell->setPort(ID(CE), Const(1, 1)); cell->unsetParam(ID(IS_D_INVERTED)); @@ -342,9 +342,9 @@ unmap: } lut_cell->attributes = cell_d->attributes; Wire *lut_out = module->addWire(NEW_ID); - lut_cell->setParam(ID(INIT), final_lut.first); - cell->setPort(ID(D), lut_out); - lut_cell->setPort(ID(O), lut_out); + lut_cell->setParam(ID::INIT, final_lut.first); + cell->setPort(ID::D, lut_out); + lut_cell->setPort(ID::O, lut_out); lut_cell->setPort(ID(I0), final_lut.second[0]); if (GetSize(final_lut.second) >= 2) lut_cell->setPort(ID(I1), final_lut.second[1]); |