aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs
diff options
context:
space:
mode:
Diffstat (limited to 'techlibs')
-rw-r--r--techlibs/achronix/synth_achronix.cc1
-rw-r--r--techlibs/anlogic/anlogic_eqn.cc24
-rw-r--r--techlibs/anlogic/anlogic_fixcarry.cc38
-rw-r--r--techlibs/anlogic/synth_anlogic.cc1
-rw-r--r--techlibs/common/Makefile.inc1
-rw-r--r--techlibs/common/cmp2lcu.v116
-rw-r--r--techlibs/common/cmp2lut.v8
-rw-r--r--techlibs/common/gen_fine_ffs.py238
-rw-r--r--techlibs/common/simcells.v86
-rw-r--r--techlibs/common/simlib.v2
-rw-r--r--techlibs/common/synth.cc6
-rw-r--r--techlibs/coolrunner2/coolrunner2_fixup.cc166
-rw-r--r--techlibs/coolrunner2/coolrunner2_sop.cc112
-rw-r--r--techlibs/ecp5/brams.txt62
-rw-r--r--techlibs/ecp5/ecp5_ffinit.cc44
-rw-r--r--techlibs/ecp5/ecp5_gsr.cc4
-rw-r--r--techlibs/ecp5/lutrams.txt9
-rw-r--r--techlibs/ecp5/synth_ecp5.cc5
-rw-r--r--techlibs/efinix/efinix_fixcarry.cc38
-rw-r--r--techlibs/efinix/efinix_gbuf.cc20
-rw-r--r--techlibs/efinix/synth_efinix.cc1
-rw-r--r--techlibs/gowin/determine_init.cc10
-rw-r--r--techlibs/gowin/synth_gowin.cc1
-rw-r--r--techlibs/greenpak4/greenpak4_dffinv.cc76
-rw-r--r--techlibs/ice40/brams.txt60
-rw-r--r--techlibs/ice40/ice40_braminit.cc14
-rw-r--r--techlibs/ice40/ice40_ffinit.cc32
-rw-r--r--techlibs/ice40/ice40_ffssr.cc34
-rw-r--r--techlibs/ice40/ice40_opt.cc94
-rw-r--r--techlibs/ice40/synth_ice40.cc13
-rw-r--r--techlibs/intel/Makefile.inc1
-rw-r--r--techlibs/intel/synth_intel.cc1
-rw-r--r--techlibs/intel_alm/Makefile.inc23
-rw-r--r--techlibs/intel_alm/common/alm_map.v56
-rw-r--r--techlibs/intel_alm/common/alm_sim.v482
-rw-r--r--techlibs/intel_alm/common/arith_alm_map.v64
-rw-r--r--techlibs/intel_alm/common/bram_m10k.txt33
-rw-r--r--techlibs/intel_alm/common/bram_m10k_map.v31
-rw-r--r--techlibs/intel_alm/common/bram_m20k.txt33
-rw-r--r--techlibs/intel_alm/common/bram_m20k_map.v31
-rw-r--r--techlibs/intel_alm/common/dff_map.v124
-rw-r--r--techlibs/intel_alm/common/dff_sim.v48
-rw-r--r--techlibs/intel_alm/common/lutram_mlab.txt20
-rw-r--r--techlibs/intel_alm/common/lutram_mlab_map.v29
-rw-r--r--techlibs/intel_alm/common/megafunction_bb.v108
-rw-r--r--techlibs/intel_alm/common/quartus_rename.v19
-rw-r--r--techlibs/intel_alm/cyclone10gx/quartus_rename.v54
-rw-r--r--techlibs/intel_alm/cyclonev/quartus_rename.v54
-rw-r--r--techlibs/intel_alm/synth_intel_alm.cc241
-rw-r--r--techlibs/sf2/sf2_iobs.cc42
-rw-r--r--techlibs/sf2/synth_sf2.cc1
-rw-r--r--techlibs/xilinx/synth_xilinx.cc6
-rw-r--r--techlibs/xilinx/xilinx_dffopt.cc26
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]);