diff --git a/himbaechel/uarch/gatemate/bitstream.cc b/himbaechel/uarch/gatemate/bitstream.cc index 813a69ae..5ce638be 100644 --- a/himbaechel/uarch/gatemate/bitstream.cc +++ b/himbaechel/uarch/gatemate/bitstream.cc @@ -87,6 +87,30 @@ struct BitstreamBackend return invert; } + bool need_switching(CellInfo *cell, IdString port) + { + PortRef sink; + sink.cell = cell; + sink.port = port; + + NetInfo *net_info = cell->getPort(port); + if (!net_info) + return false; + + WireId dst_wire = ctx->getNetinfoSinkWire(net_info, sink, 0); + + WireId cursor = dst_wire; + auto it = net_info->wires.find(cursor); + + PipId pip = it->second.pip; + const auto &extra_data = *uarch->pip_extra_data(pip); + if (extra_data.type == PipExtra::PIP_EXTRA_MUX && (extra_data.flags & MUX_PERMUTATION)) { + if (extra_data.value) + return true; + } + return false; + } + void update_cpe_lt(CellInfo *cell, IdString port, IdString init, dict ¶ms, bool even) { unsigned init_val = int_or_default(params, init); @@ -317,6 +341,14 @@ struct BitstreamBackend case id_CPE_RAMIO.index: { // Update configuration bits based on signal inversion dict params = cell.second->params; + auto update_param = [&](IdString name) { + int x = int_or_default(params, name, 0); + // when inputs exchange theier places in LUT2 + // function changes so bit 1 and bit 2 exchange values + int y = x ^ (( ( (x >> 1) ^ (x >> 2) ) & 1 ) << 1) + ^ (( ( (x >> 1) ^ (x >> 2) ) & 1 ) << 2); + params[name] = Property(y ,4); + }; Loc l = ctx->getBelLocation(cell.second->bel); params.erase(id_L2T4_UPPER); params.erase(id_MULT_INVERT); @@ -324,6 +356,13 @@ struct BitstreamBackend int c_i2 = int_or_default(params, id_C_I2, 0); int c_i3 = int_or_default(params, id_C_I3, 0); int c_i4 = int_or_default(params, id_C_I4, 0); + + if (cell.second->type.in(id_CPE_BRIDGE)) { + int in = int_or_default(params, id_C_SN, 0); + if (need_switching(cell.second.get(), ctx->idf("IN%d", in+1))) + params[id_C_SN] = Property(in ^ 1,3); + } + if (cell.second->type.in(id_CPE_L2T4, id_CPE_LT_L, id_CPE_LT_U)) { if (l.z == CPE_LT_U_Z) { update_cpe_lt(cell.second.get(), id_IN1, id_INIT_L00, params, true); @@ -337,6 +376,12 @@ struct BitstreamBackend update_cpe_lt(cell.second.get(), id_IN3, id_INIT_L01, params, true); update_cpe_lt(cell.second.get(), c_i4 ? id_PINX : id_IN4, id_INIT_L01, params, false); } + if (need_switching(cell.second.get(), id_IN1) || need_switching(cell.second.get(), id_IN2)) { + update_param(id_INIT_L00); + } + if (need_switching(cell.second.get(), id_IN3) || need_switching(cell.second.get(), id_IN4)) { + update_param(id_INIT_L01); + } } if (l.z == CPE_LT_FULL_Z) { if (!cell.second->type.in(id_CPE_MULT)) { @@ -359,6 +404,18 @@ struct BitstreamBackend update_cpe_lt(cell.second.get(), id_IN7, id_INIT_L03, params, true); update_cpe_lt(cell.second.get(), c_i4 ? id_PINX : id_IN8, id_INIT_L03, params, false); } + if (need_switching(cell.second.get(), id_IN1) || need_switching(cell.second.get(), id_IN2)) { + update_param(id_INIT_L00); + } + if (need_switching(cell.second.get(), id_IN3) || need_switching(cell.second.get(), id_IN4)) { + update_param(id_INIT_L01); + } + if (need_switching(cell.second.get(), id_IN5) || need_switching(cell.second.get(), id_IN6)) { + update_param(id_INIT_L02); + } + if (need_switching(cell.second.get(), id_IN7) || need_switching(cell.second.get(), id_IN8)) { + update_param(id_INIT_L03); + } } } diff --git a/himbaechel/uarch/gatemate/extra_data.h b/himbaechel/uarch/gatemate/extra_data.h index 96e8cc5b..636b45a5 100644 --- a/himbaechel/uarch/gatemate/extra_data.h +++ b/himbaechel/uarch/gatemate/extra_data.h @@ -85,6 +85,7 @@ enum MuxFlags MUX_VISIBLE = 2, MUX_CONFIG = 4, MUX_ROUTING = 8, + MUX_PERMUTATION = 16, }; enum PipExtra diff --git a/himbaechel/uarch/gatemate/gen/arch_gen.py b/himbaechel/uarch/gatemate/gen/arch_gen.py index 5970a0b6..7121e374 100644 --- a/himbaechel/uarch/gatemate/gen/arch_gen.py +++ b/himbaechel/uarch/gatemate/gen/arch_gen.py @@ -31,6 +31,7 @@ MUX_INVERT = 1 MUX_VISIBLE = 2 MUX_CONFIG = 4 MUX_ROUTING = 8 +MUX_PERMUTATION = 16 parser = argparse.ArgumentParser() parser.add_argument("--lib", help="Project Peppercorn python database script path", type=str, required=True) @@ -310,6 +311,8 @@ def main(): plane = int(mux.name[10:12]) if mux.name == "CPE.C_SN": mux_flags |= MUX_ROUTING + if mux.name.startswith("CPE.PERM"): + mux_flags |= MUX_PERMUTATION pp.extra_data = PipExtraData(PIP_EXTRA_MUX, ch.strs.id(mux.name), mux.bits, mux.value, mux_flags, plane) if type_name in new_wires: for wire in sorted(new_wires[type_name]): diff --git a/himbaechel/uarch/gatemate/pack.cc b/himbaechel/uarch/gatemate/pack.cc index f7c61375..4e824f9c 100644 --- a/himbaechel/uarch/gatemate/pack.cc +++ b/himbaechel/uarch/gatemate/pack.cc @@ -309,6 +309,16 @@ void GateMatePacker::repack_cpe() if (!cell.second->params.count(id_INIT_L20)) cell.second->params[id_INIT_L20] = Property(LUT_D1, 4); } + if (cell.second->getPort(id_IN1) && cell.second->getPort(id_IN2)) { + if (cell.second->getPort(id_IN1) == cell.second->getPort(id_IN2)) { + log_error("Used same signal for IN1 and IN2 in %s\n", cell.second->name.c_str(ctx)); + } + } + if (cell.second->getPort(id_IN3) && cell.second->getPort(id_IN4)) { + if (cell.second->getPort(id_IN3) == cell.second->getPort(id_IN4)) { + log_error("Used same signal for IN3 and IN4 in %s\n", cell.second->name.c_str(ctx)); + } + } cell.second->params[id_L2T4_UPPER] = Property((l.z == CPE_LT_U_Z) ? 1 : 0, 1); } else if (cell.second->type.in(id_CPE_LT_L)) { BelId bel = cell.second->bel; @@ -318,6 +328,16 @@ void GateMatePacker::repack_cpe() loc.z = CPE_LT_FULL_Z; ctx->unbindBel(bel); ctx->bindBel(ctx->getBelByLocation(loc), cell.second.get(), strength); + if (cell.second->getPort(id_IN1) && cell.second->getPort(id_IN2)) { + if (cell.second->getPort(id_IN1) == cell.second->getPort(id_IN2)) { + log_error("Used same signal for IN1 and IN2 in %s\n", cell.second->name.c_str(ctx)); + } + } + if (cell.second->getPort(id_IN3) && cell.second->getPort(id_IN4)) { + if (cell.second->getPort(id_IN3) == cell.second->getPort(id_IN4)) { + log_error("Used same signal for IN3 and IN4 in %s\n", cell.second->name.c_str(ctx)); + } + } cell.second->renamePort(id_IN1, id_IN5); cell.second->renamePort(id_IN2, id_IN6); cell.second->renamePort(id_IN3, id_IN7); @@ -374,6 +394,17 @@ void GateMatePacker::repack_cpe() upper->movePortTo(id_IN4, cell.second.get(), id_IN4); upper->movePortTo(id_OUT, cell.second.get(), id_OUT2); upper->movePortTo(id_CPOUT, cell.second.get(), id_CPOUT2); + if (cell.second->getPort(id_IN1) && cell.second->getPort(id_IN2)) { + if (cell.second->getPort(id_IN1) == cell.second->getPort(id_IN2)) { + log_error("Used same signal for IN1 and IN2 in %s\n", cell.second->name.c_str(ctx)); + } + } + if (cell.second->getPort(id_IN3) && cell.second->getPort(id_IN4)) { + if (cell.second->getPort(id_IN3) == cell.second->getPort(id_IN4)) { + log_error("Used same signal for IN3 and IN4 in %s\n", cell.second->name.c_str(ctx)); + } + } + } // Mark for deletion