diff --git a/himbaechel/uarch/gatemate/pack.h b/himbaechel/uarch/gatemate/pack.h index 1d8a9bce..4b45dfcd 100644 --- a/himbaechel/uarch/gatemate/pack.h +++ b/himbaechel/uarch/gatemate/pack.h @@ -24,6 +24,26 @@ NEXTPNR_NAMESPACE_BEGIN +enum CPELut +{ + LUT_ZERO = 0b0000, + LUT_NOR = 0b0001, + LUT_AND_INV_D1 = 0b0010, + LUT_INV_D1 = 0b0011, + LUT_AND_INV_D0 = 0b0100, + LUT_INV_D0 = 0b0101, + LUT_XOR = 0b0110, + LUT_NAND = 0b0111, + LUT_AND = 0b1000, + LUT_XNOR = 0b1001, + LUT_D0 = 0b1010, + LUT_NAND_INV_D0 = 0b1011, + LUT_D1 = 0b1100, + LUT_NAND_INV_D1 = 0b1101, + LUT_OR = 0b1110, + LUT_ONE = 0b1111 +}; + struct GateMatePacker { GateMatePacker(Context *ctx, GateMateImpl *uarch) : ctx(ctx), uarch(uarch) { h.init(ctx); }; diff --git a/himbaechel/uarch/gatemate/pack_mult.cc b/himbaechel/uarch/gatemate/pack_mult.cc index 435ae416..72069a26 100644 --- a/himbaechel/uarch/gatemate/pack_mult.cc +++ b/himbaechel/uarch/gatemate/pack_mult.cc @@ -23,6 +23,7 @@ #include "nextpnr_types.h" #include "pack.h" #include "property.h" +#include "uarch/gatemate/extra_data.h" #include "util.h" #define HIMBAECHEL_CONSTIDS "uarch/gatemate/constids.inc" @@ -30,25 +31,32 @@ NEXTPNR_NAMESPACE_BEGIN -// Propagate A0 through OUT1 and A1 through OUT2 -// -// TODO: do we need this cell? +// Propagate A0 through OUT1 and A1 through OUT2; zero COUTX and POUTX. struct APassThroughCell { APassThroughCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper} { lower->cluster = name; lower->constr_abs_z = false; - lower->params[id_INIT_L00] = Property(0b0101, 4); // IN1 - lower->params[id_INIT_L01] = Property(0b0000, 4); // 0 (unused) - lower->params[id_INIT_L10] = Property(0b0101, 4); // L00 -> OUT2 + lower->params[id_INIT_L00] = Property(LUT_D0, 4); // IN1 + lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused) + lower->params[id_INIT_L10] = Property(LUT_D0, 4); // L00 -> COMB2OUT upper->cluster = name; upper->constr_abs_z = false; - upper->params[id_INIT_L02] = Property(0b0101, 4); // IN5 - upper->params[id_INIT_L03] = Property(0b0000, 4); // 0 (unused) - upper->params[id_INIT_L11] = Property(0b0101, 4); // L02 - upper->params[id_INIT_L20] = Property(0b0101, 4); // L11 -> OUT1 + upper->params[id_INIT_L02] = Property(LUT_D0, 4); // IN5 + upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused) + upper->params[id_INIT_L11] = Property(LUT_D0, 4); // L02 + upper->params[id_INIT_L20] = Property(LUT_D1, 4); // L11 -> COMB1OUT + upper->params[id_INIT_L30] = Property(LUT_ONE, 4); // zero -> COMP_OUT (L30 is inverted) + + upper->params[id_C_SEL_C] = Property(1, 1); // COMP_OUT -> CX_VAL + upper->params[id_C_SEL_P] = Property(1, 1); // COMP_OUT -> PX_VAL + upper->params[id_C_CX_I] = Property(1, 1); // CX_VAL -> COUTX + upper->params[id_C_PX_I] = Property(1, 1); // PX_VAL -> POUTX + + upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1 + upper->params[id_C_O2] = Property(0b11, 2); // COMB2OUT -> OUT2 } PortRef a0() const { return PortRef{upper, id_IN1}; } @@ -68,22 +76,22 @@ struct BPassThroughCell { lower->cluster = name; lower->constr_abs_z = false; - lower->params[id_INIT_L00] = Property(0b0101, 4); // IN1 - lower->params[id_INIT_L01] = Property(0b0000, 4); // 0 (unused) - lower->params[id_INIT_L10] = Property(0b0101, 4); // L00 -> OUT2 + lower->params[id_INIT_L00] = Property(LUT_D0, 4); // IN1 + lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused) + lower->params[id_INIT_L10] = Property(LUT_D0, 4); // L00 -> COMB2OUT upper->cluster = name; upper->constr_abs_z = false; - upper->params[id_INIT_L02] = Property(0b0101, 4); // IN5 - upper->params[id_INIT_L03] = Property(0b0000, 4); // 0 (unused) - upper->params[id_INIT_L11] = Property(0b0101, 4); // L02 - upper->params[id_INIT_L20] = Property(0b0101, 4); // L11 -> OUT1 + upper->params[id_INIT_L02] = Property(LUT_D0, 4); // IN5 + upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused) + upper->params[id_INIT_L11] = Property(LUT_D0, 4); // L02 + upper->params[id_INIT_L20] = Property(LUT_D1, 4); // L11 -> COMB1OUT - upper->params[id_C_SEL_C] = Property(0, 1); // OUT2 -> CY1_VAL - upper->params[id_C_SEL_P] = Property(0, 1); // OUT1 -> PY_VAL - upper->params[id_C_SELY1] = Property(0, 1); // OUT1 -> PY1_VAL; OUT2 -> CY1_VAL upper->params[id_C_CY1_I] = Property(1, 1); // CY1_VAL -> COUTY1 upper->params[id_C_PY1_I] = Property(1, 1); // PY1_VAL -> POUTY1 + + upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1 + upper->params[id_C_O2] = Property(0b11, 2); // COMB2OUT -> OUT2 } PortRef b0() const { return PortRef{upper, id_IN1}; } @@ -93,6 +101,125 @@ struct BPassThroughCell CellInfo *lower; }; +// TODO: Micko points out this is an L2T4 CPE_HALF +struct CarryGenCell +{ + CarryGenCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper} + { + // TODO: simplify AND with zero/OR with zero into something more sensical. + + lower->cluster = name; + lower->constr_abs_z = false; + lower->params[id_INIT_L00] = Property(LUT_ZERO, 4); // (unused) + lower->params[id_INIT_L01] = Property(LUT_D1, 4); // CINX + lower->params[id_INIT_L10] = Property(is_even_x ? LUT_AND : LUT_OR, 4); + + upper->cluster = name; + upper->constr_abs_z = false; + upper->params[id_INIT_L02] = Property(LUT_D1, 4); // PINY1 + upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused) + upper->params[id_INIT_L11] = Property(is_even_x ? LUT_AND : LUT_OR, 4); + upper->params[id_INIT_L20] = Property(is_even_x ? LUT_AND : LUT_OR, 4); + upper->params[id_INIT_L30] = Property(LUT_INV_D0, 4); // OUT1 -> COMP_OUT + + upper->params[id_C_I2] = Property(1, 1); // CINX for L01 + upper->params[id_C_I3] = Property(1, 1); // PINY1 for L02 + upper->params[id_C_FUNCTION] = Property(C_EN_CIN, 3); + upper->params[id_C_PY1_I] = Property(0, 1); // PINY1 -> POUTY1 + upper->params[id_C_CY1_I] = Property(0, 1); // CINY1 -> COUTY1 + upper->params[id_C_CY2_I] = Property(1, 1); // CY2_VAL -> COUTY2 + upper->params[id_C_SEL_C] = Property(1, 1); // COMP_OUT -> CY2_VAL + upper->params[id_C_SELY2] = Property(0, 1); // COMP_OUT -> CY2_VAL + + upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1 + } + + CellInfo *upper; + CellInfo *lower; +}; + +// This prepares B bits for multiplication. +struct MultfabCell +{ + MultfabCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper} + { + // TODO: perhaps C_I[1234] could be pips? + + lower->cluster = name; + lower->constr_abs_z = false; + lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1 + lower->params[id_INIT_L01] = Property(is_even_x ? LUT_ZERO : LUT_D1, 4); // CINX + lower->params[id_INIT_L10] = Property(LUT_XOR, 4); // XOR + + upper->cluster = name; + upper->constr_abs_z = false; + upper->params[id_INIT_L02] = Property(LUT_D1, 4); // PINY1 + upper->params[id_INIT_L03] = Property(LUT_ZERO, 4); // (unused) + upper->params[id_INIT_L11] = Property(LUT_D0, 4); // L02 + upper->params[id_INIT_L20] = Property(is_even_x ? LUT_AND_INV_D0 : LUT_OR, 4); // L10 AND L11 -> OUT1 + upper->params[id_INIT_L30] = Property(LUT_INV_D1, 4); // L10 -> COMP_OUT + + upper->params[id_C_I1] = Property(1, 1); // PINY1 for L00 + upper->params[id_C_I2] = Property(1, 1); // CINX for L01 + upper->params[id_C_I3] = Property(1, 1); // PINY1 for L02 + upper->params[id_C_FUNCTION] = Property(C_ADDCIN, 3); + upper->params[id_C_SELX] = Property(1, 1); // inverted CINY2 -> CX_VAL + upper->params[id_C_SEL_C] = Property(1, 1); // inverted CINY2 -> CX_VAL; COMP_OUT -> CY1_VAL + upper->params[id_C_Y12] = Property(1, 1); // inverted CINY2 -> CX_VAL + upper->params[id_C_CX_I] = Property(1, 1); // CX_VAL -> COUTX + upper->params[id_C_CY1_I] = Property(1, 1); // CY1_VAL -> COUTY1 + upper->params[id_C_PY1_I] = Property(1, 1); // PY1_VAL -> POUTY1 + upper->params[id_C_SEL_P] = Property(0, 1); // OUT1 -> PY1_VAL + upper->params[id_C_SELY1] = Property(0, 1); // COMP_OUT -> CY1_VAL; OUT1 -> PY1_VAL + + upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1 + } + + CellInfo *upper; + CellInfo *lower; +}; + +// CITE: CPE_ges_f-routing-1.pdf +// TODO: +struct FRoutingCell +{ + FRoutingCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper} + { + // TODO: simplify AND with zero/OR with zero into something more sensical. + + lower->cluster = name; + lower->constr_abs_z = false; + lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1 + lower->params[id_INIT_L01] = Property(LUT_ONE, 4); // (unused) + lower->params[id_INIT_L10] = Property(LUT_AND, 4); + + upper->cluster = name; + upper->constr_abs_z = false; + upper->params[id_INIT_L02] = Property(LUT_ZERO, 4); // (unused) + upper->params[id_INIT_L03] = Property(LUT_ONE, 4); // (unused) + upper->params[id_INIT_L11] = Property(LUT_AND, 4); + upper->params[id_INIT_L20] = Property(LUT_D1, 4); + upper->params[id_INIT_L30] = Property(is_even_x ? LUT_ONE : LUT_INV_D1, 4); // OUT1 -> COMP_OUT + + upper->params[id_C_I1] = Property(1, 1); // PINY1 for L00 + upper->params[id_C_FUNCTION] = Property(C_ADDCIN, 3); + upper->params[id_C_SELX] = Property(1, 1); + upper->params[id_C_SEL_C] = Property(1, 1); + upper->params[id_C_Y12] = Property(1, 1); + upper->params[id_C_CX_I] = Property(1, 1); + upper->params[id_C_CY1_I] = Property(is_even_x, 1); + upper->params[id_C_CY2_I] = Property(1, 1); + upper->params[id_C_PY1_I] = Property(1, 1); + upper->params[id_C_PY2_I] = Property(1, 1); + + upper->params[id_C_O1] = Property(0b11, 2); // COMB1OUT -> OUT1 + upper->params[id_C_O2] = Property(0b11, 2); // COMB2OUT -> OUT2 + } + + CellInfo *upper; + CellInfo *lower; +}; + // Multiply two bits of A with two bits of B. // // CITE: CPE_MULT.pdf @@ -102,132 +229,113 @@ struct MultCell { lower->cluster = name; lower->constr_abs_z = false; - lower->params[id_INIT_L00] = Property(0b1000, 4); // AND - lower->params[id_INIT_L01] = Property(0b1100, 4); // CINX - lower->params[id_INIT_L10] = Property(0b0110, 4); // XOR + lower->params[id_INIT_L00] = Property(LUT_AND, 4); + lower->params[id_INIT_L01] = Property(LUT_D1, 4); // CINX + lower->params[id_INIT_L10] = Property(LUT_XOR, 4); upper->cluster = name; upper->constr_abs_z = false; - upper->params[id_INIT_L02] = Property(0b1000, 4); // AND - upper->params[id_INIT_L03] = Property(0b1100, 4); // PINX - upper->params[id_INIT_L11] = Property(0b0110, 4); // XOR - upper->params[id_INIT_L20] = Property(0b1100, 4); // L11 + upper->params[id_INIT_L02] = Property(LUT_AND, 4); + upper->params[id_INIT_L03] = Property(LUT_D1, 4); // PINX + upper->params[id_INIT_L11] = Property(LUT_XOR, 4); + upper->params[id_INIT_L20] = Property(LUT_D1, 4); // L11 - upper->params[id_C_FUNCTION] = Property(C_MULT, 3); upper->params[id_C_I1] = Property(1, 1); // PINY1 for L00 upper->params[id_C_I2] = Property(1, 1); // CINX for L01 upper->params[id_C_I3] = Property(1, 1); // PINY1 for L02 upper->params[id_C_I4] = Property(1, 1); // PINX for L03 - } - - CellInfo *upper; - CellInfo *lower; -}; - -// This seems to prepare B bits for multiplication. -// -// CITE: CPE_MULTFab.pdf -struct MultfabCell -{ - MultfabCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper} - { - lower->cluster = name; - lower->constr_abs_z = false; - lower->params[id_INIT_L00] = Property(0b1100, 4); // PINY1 - lower->params[id_INIT_L01] = Property(0b1100, 4); // CINX - lower->params[id_INIT_L10] = Property(0b0110, 4); // XOR - - upper->cluster = name; - upper->constr_abs_z = false; - upper->params[id_INIT_L02] = Property(0b1100, 4); // PINY1 - upper->params[id_INIT_L03] = Property(0b0000, 4); // 0 (unused) - upper->params[id_INIT_L11] = Property(0b0101, 4); // L02 - if (is_even_x) { - // TODO: the diagrams suggest that AND has L10 inverted? need to check. - upper->params[id_INIT_L20] = Property(0b1000, 4); // L10 AND L11 -> OUT1 - } else { - upper->params[id_INIT_L20] = Property(0b1110, 4); // L10 OR L11 -> OUT1 - } - upper->params[id_INIT_L30] = Property(0b1100, 4); // L10 -> COMP_OUT - upper->params[id_C_FUNCTION] = Property(C_MULT, 3); - upper->params[id_C_I1] = Property(1, 1); // PINY1 for L00 - upper->params[id_C_I2] = Property(1, 1); // CINX for L01 - upper->params[id_C_I3] = Property(1, 1); // PINY1 for L02 - upper->params[id_C_CX_I] = Property(1, 1); // CX_VAL -> COUTX - upper->params[id_C_CY1_I] = Property(1, 1); // CY1_VAL -> COUTY1 - upper->params[id_C_PY1_I] = Property(1, 1); // PY1_VAL -> POUTY1 - upper->params[id_C_SELX] = Property(1, 1); // inverted CINY2 -> CX_VAL - upper->params[id_C_SELY1] = Property(0, 1); // COMP_OUT -> CY1_VAL; OUT1 -> PY1_VAL - upper->params[id_C_Y12] = Property(1, 1); // inverted CINY2 -> CX_VAL - upper->params[id_C_SEL_C] = Property(1, 1); // inverted CINY2 -> CX_VAL; COMP_OUT -> CY1_VAL - upper->params[id_C_SEL_P] = Property(0, 1); // OUT1 -> PY1_VAL + + upper->params[id_C_O1] = Property(0b10, 2); // CP_OUT1 -> OUT1 + upper->params[id_C_O2] = Property(0b10, 2); // CP_OUT2 -> OUT2 } + PortRef a0() const { return PortRef{upper, id_IN4}; } + PortRef a1() const { return PortRef{upper, id_IN1}; } + PortRef a2() const { return PortRef{lower, id_IN1}; } + CellInfo *upper; CellInfo *lower; }; -// CITE: CPE_ges_carry-gen.pdf -struct CarryGenCell +struct MultMsbCell { - CarryGenCell(CellInfo *lower, CellInfo *upper, IdString name, bool is_even_x) : lower{lower}, upper{upper} + MultMsbCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper} { lower->cluster = name; lower->constr_abs_z = false; - lower->params[id_INIT_L00] = Property(0b0000, 4); // 0 (unused) - lower->params[id_INIT_L01] = Property(0b1100, 4); // CINX - lower->params[id_INIT_L10] = Property(0b1100, 4); // L01 -> OUT2 + lower->params[id_INIT_L00] = Property(LUT_AND, 4); + lower->params[id_INIT_L01] = Property(LUT_D1, 4); // CINX + lower->params[id_INIT_L10] = Property(LUT_XOR, 4); upper->cluster = name; upper->constr_abs_z = false; - upper->params[id_INIT_L02] = Property(0b1100, 4); // PINY1 - upper->params[id_INIT_L03] = Property(0b0000, 4); // 0 (unused) - if (is_even_x) { - upper->params[id_INIT_L11] = Property(0b1000, 4); // AND - upper->params[id_INIT_L20] = Property(0b1000, 4); // AND - } else { - upper->params[id_INIT_L11] = Property(0b1110, 4); // OR - upper->params[id_INIT_L20] = Property(0b1110, 4); // OR - } - upper->params[id_INIT_L30] = Property(0b0101, 4); // OUT1 -> COMP_OUT + upper->params[id_INIT_L02] = Property(LUT_AND, 4); + upper->params[id_INIT_L03] = Property(LUT_D1, 4); // PINX + upper->params[id_INIT_L11] = Property(LUT_XOR, 4); + upper->params[id_INIT_L20] = Property(LUT_D1, 4); // L11 + upper->params[id_C_I1] = Property(1, 1); // PINY1 for L00 upper->params[id_C_I2] = Property(1, 1); // CINX for L01 upper->params[id_C_I3] = Property(1, 1); // PINY1 for L02 - // TODO: how do I get B1 through CIN?? - upper->params[id_C_PY1_I] = Property(0, 1); // PINY1 -> POUTY1 - upper->params[id_C_CY1_I] = Property(0, 1); // CINY1 -> COUTY1 - upper->params[id_C_CY2_I] = Property(1, 1); // CY2_VAL -> COUTY2 - upper->params[id_C_SEL_C] = Property(1, 1); // COMP_OUT -> CY2_VAL - upper->params[id_C_SELY2] = Property(0, 1); // COMP_OUT -> CY2_VAL + upper->params[id_C_I4] = Property(1, 1); // PINX for L03 + upper->params[id_C_FUNCTION] = Property(C_MULT, 3); + upper->params[id_C_PY1_I] = Property(1, 1); + upper->params[id_C_C_P] = Property(1, 1); + + upper->params[id_C_O1] = Property(0b10, 2); // CP_OUT1 -> OUT1 } CellInfo *upper; CellInfo *lower; }; -// CITE: CPE_ges_f-routing-1.pdf -// TODO: -struct FRoutingCell -{ - CellInfo *upper; - CellInfo *lower; -}; - // CITE: CPE_ges_MSB-routing.pdf struct MsbRoutingCell { + MsbRoutingCell(CellInfo *lower, CellInfo *upper, IdString name) : lower{lower}, upper{upper} + { + lower->cluster = name; + lower->constr_abs_z = false; + lower->params[id_INIT_L00] = Property(LUT_D1, 4); // PINY1 + lower->params[id_INIT_L01] = Property(LUT_ZERO, 4); // (unused) + lower->params[id_INIT_L10] = Property(LUT_OR, 4); + + upper->cluster = name; + upper->constr_abs_z = false; + upper->params[id_INIT_L02] = Property(LUT_ONE, 4); + upper->params[id_INIT_L03] = Property(LUT_ONE, 4); + upper->params[id_INIT_L11] = Property(LUT_ZERO, 4); + upper->params[id_INIT_L20] = Property(LUT_D1, 4); // L11 + upper->params[id_INIT_L30] = Property(LUT_ONE, 4); + + upper->params[id_C_I1] = Property(1, 1); // PINY1 for L00 + upper->params[id_C_FUNCTION] = Property(C_MULT, 3); + upper->params[id_C_SELX] = Property(1, 1); + upper->params[id_C_SEL_P] = Property(1, 1); + upper->params[id_C_CX_I] = Property(1, 1); + upper->params[id_C_PX_I] = Property(1, 1); + upper->params[id_C_PY1_I] = Property(1, 1); + upper->params[id_C_PY2_I] = Property(1, 1); + + upper->params[id_C_O2] = Property(0b10, 2); // CP_OUT2 -> OUT2 + } + CellInfo *upper; CellInfo *lower; }; struct MultiplierColumn { - MsbRoutingCell msb_route; - std::vector mults; + // the variables are in bottom-up physical order as a mnemonic. + + BPassThroughCell b_passthru; + CarryGenCell carry; MultfabCell multfab; FRoutingCell f_route; - BPassThroughCell b_passthru; + std::vector mults; + MultMsbCell multmsb; + MsbRoutingCell msb_route; }; // A GateMate multiplier is made up of columns of 2x2 multipliers. @@ -239,6 +347,9 @@ struct Multiplier void GateMatePacker::pack_mult() { + // note to self: use constr_children for recursive constraints + // fpga_generic.pas in p_r might have useful info + auto create_mult_cell = [&](IdString name) { // instantiate a full CPE by creating two halves. auto *lower = create_cell_ptr(id_CPE_HALF_L, ctx->idf("%s$lower", name.c_str(ctx)));