Compare commits

...

4 Commits

Author SHA1 Message Date
Lofty
04be4bb082 hercules: global buffers 2022-09-22 23:26:35 +01:00
Lofty
a50d91e68d rbufx6 clock buffer 2022-09-22 23:26:35 +01:00
Lofty
5e86806b73 rbufx6 clock buffer 2022-09-19 02:55:29 +01:00
Lofty
1b16453d26 hercules: Viaduct arch for the HME-M7 2022-09-15 16:33:52 +01:00
3 changed files with 817 additions and 1 deletions

View File

@ -1,4 +1,4 @@
set(VIADUCT_UARCHES "example" "okami")
set(VIADUCT_UARCHES "example" "okami" "hercules")
foreach(uarch ${VIADUCT_UARCHES})
aux_source_directory(${family}/viaduct/${uarch} UARCH_FILES)
foreach(target ${family_targets})

View File

@ -0,0 +1,88 @@
X(PIP)
X(C_OUT)
X(DUMMY)
X(DX_FB)
X(DX)
X(DX40)
X(DY)
X(BYP)
X(TN)
X(TE)
X(TS)
X(TW)
X(MN)
X(ME)
X(MS)
X(MW)
X(ON)
X(OE)
X(OS)
X(OW)
X(XYN)
X(XYE)
X(XYS)
X(XYW)
X(XYEN)
X(XYSE)
X(XYWS)
X(XYNW)
X(XYNE)
X(XYES)
X(XYSW)
X(XYWN)
X(CCLK)
X(CLK_XBAR)
X(IXIX)
X(M7S_DGPIO)
X(pad)
X(od_d)
X(id_q)
X(oen)
X(config_data)
X(PAD)
X(INBUF)
X(OUTBUF)
X(LUT4)
X(f0)
X(f1)
X(f2)
X(f3)
X(dx)
X(LUT4C)
X(ca)
X(ci)
X(co)
X(s)
X(REG)
X(REGS)
X(a_sr)
X(di)
X(down_i)
X(mclk_b)
X(sclk)
X(shift)
X(up_i)
X(down_o)
X(qs)
X(qx)
X(up_o)
X(mux_dx4)
X(in0)
X(in1)
X(sel)
X(out)
X(mux_sc)
X(mux_dy)
X(CLK_MUX)
X(EN_MUX)
X(CLK_GATE_MUX)

View File

@ -0,0 +1,728 @@
#include "log.h"
#include "nextpnr.h"
#include "util.h"
#include "viaduct_api.h"
#include "viaduct_helpers.h"
#define GEN_INIT_CONSTIDS
#define VIADUCT_CONSTIDS "viaduct/hercules/constids.inc"
#include "viaduct_constids.h"
NEXTPNR_NAMESPACE_BEGIN
namespace {
struct LpInfo {
std::array<WireId, 5> byp;
WireId c_in;
std::array<WireId, 2> down_i;
WireId dx_fb;
std::array<WireId, 3> f2;
std::array<WireId, 3> f1;
std::array<WireId, 3> f0;
WireId fy;
std::array<WireId, 2> up_i;
WireId c_out;
// down_o is the same as qx;
std::array<WireId, 2> dx;
WireId dx40;
WireId dy;
// fx is the same as dx[1]
std::array<WireId, 2> qx;
// up_o is the same as qx;
};
struct LbufInfo {
WireId a_sr;
WireId mclk_b;
WireId sclk;
std::array<WireId, 2> sh;
};
struct LeInfo {
LbufInfo lbuf;
std::array<LpInfo, 4> lp;
};
struct PlbInfo {
LeInfo le;
std::array<WireId, 6> tn0_o;
std::array<WireId, 6> te0_o;
std::array<WireId, 6> ts0_o;
std::array<WireId, 6> tw0_o;
std::array<WireId, 4> mn0_o;
std::array<WireId, 4> me0_o;
std::array<WireId, 4> ms0_o;
std::array<WireId, 4> mw0_o;
std::array<WireId, 9> on0_o;
std::array<WireId, 7> oe0_o;
std::array<WireId, 9> os0_o;
std::array<WireId, 7> ow0_o;
std::array<WireId, 3> n_xy_o;
WireId ne_xy_o;
std::array<WireId, 2> en_xy_o;
std::array<WireId, 3> e_xy_o;
WireId es_xy_o;
std::array<WireId, 2> se_xy_o;
std::array<WireId, 3> s_xy_o;
WireId sw_xy_o;
std::array<WireId, 2> ws_xy_o;
std::array<WireId, 3> w_xy_o;
WireId wn_xy_o;
std::array<WireId, 2> nw_xy_o;
std::array<WireId, 6> cclk;
std::array<WireId, 4> clk_xbar;
};
struct GbufInfo {
std::array<WireId, 4> clkpad_n;
std::array<WireId, 4> clkpad_s;
std::array<WireId, 8> fabric_gclk;
std::array<WireId, 4> pclk_c1r1;
std::array<WireId, 4> pclk_c1r2;
std::array<WireId, 4> pclk_c2r1;
std::array<WireId, 4> pclk_c2r2;
};
struct RbufInfo {
std::array<WireId, 16> gclk;
std::array<WireId, 2> fabric_rclk;
};
struct Hercules : ViaductAPI {
void init(Context *const ctx) override {
init_uarch_constids(ctx); // Set up the string-interning pool.
ViaductAPI::init(ctx);
h.init(ctx);
log_info("Setting up FPGA...\n");
create_bels();
log_info("Setting up FPGA...done\n");
}
void pack() override {
// Trim nextpnr IOBs - assume IO buffer insertion has been done in synthesis
const pool<CellTypePort> top_ports{
CellTypePort(id_M7S_DGPIO, id_pad),
};
h.remove_nextpnr_iobs(top_ports);
// Replace constants with LUTs
const dict<IdString, Property> vcc_params = {{id_config_data, Property(0xFFFF, 16)}};
const dict<IdString, Property> gnd_params = {{id_config_data, Property(0x0000, 16)}};
h.replace_constants(CellTypePort(id_LUT4, id_f3), CellTypePort(id_LUT4, id_f3), vcc_params, gnd_params);
rename_regs();
}
bool isBelLocationValid(BelId bel) const override {
const Loc loc = ctx->getBelLocation(bel);
const bool at_x_edge = (loc.x == 0) || (loc.x == COLUMNS - 1);
const bool at_y_edge = (loc.y == 0) || (loc.y == ROWS - 1);
if (at_y_edge) {
// TODO: I/O buffer validation.
return true;
} else if (!at_x_edge && !at_y_edge) {
// TODO: LP validation.
return lp_is_valid(loc.x, loc.y, loc.z / LP_BELS);
}
return true;
}
private:
void rename_regs() {
for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second.get();
if (ci->type != id_REG)
continue;
ci->type = id_REGS;
}
}
BelId addBel(const int x, const int y, const int z, const IdString id) {
return ctx->addBel(h.xy_id(x, y, IdStringList::concat(id, ctx->idf("%d", z))), id, Loc(x, y, z), /* gb = */ false, /* hidden = */ false);
}
WireId addWire(const int x, const int y, const IdStringList name, const IdString type) {
return ctx->addWire(h.xy_id(x, y, name), type, x, y);
}
WireId addWireAsBelInput(const int x, const int y, const IdString id, const BelId bel) {
WireId wire = ctx->addWire(IdStringList::concat(ctx->getBelName(bel), id), id, x, y);
ctx->addBelInput(bel, id, wire);
return wire;
}
WireId addWireAsBelOutput(const int x, const int y, const IdString id, const BelId bel) {
WireId wire = ctx->addWire(IdStringList::concat(ctx->getBelName(bel), id), id, x, y);
ctx->addBelOutput(bel, id, wire);
return wire;
}
void add_cfgmux(const Loc loc, const WireId dst, const WireId src) {
NPNR_ASSERT(src != WireId());
NPNR_ASSERT(dst != WireId());
IdStringList name = IdStringList::concat(ctx->getWireName(dst), ctx->getWireName(src));
ctx->addPip(name, id_PIP, src, dst, 0.05, loc);
}
template<typename... Rest>
void add_cfgmux(const Loc loc, const WireId dst, const WireId src, Rest... rest) {
NPNR_ASSERT(src != WireId());
NPNR_ASSERT(dst != WireId());
IdStringList name = IdStringList::concat(ctx->getWireName(dst), ctx->getWireName(src));
ctx->addPip(name, id_PIP, src, dst, 0.05, loc);
add_cfgmux(loc, dst, rest...);
}
void create_iopad(const int x, const int y) {
// Is there another IO pad combined?
// note to self: xbar_tile_[ew]cap_io
for (int z = 0; z < 4; z++) {
const BelId bel = addBel(x, y, z, id_M7S_DGPIO);
if (x == 0) {
ctx->addBelInput(bel, id_od_d, plbs[x + 1][y].tw0_o[z]);
ctx->addBelInput(bel, id_oen, plbs[x + 1][y].mw0_o[3]);
} else {
ctx->addBelInput(bel, id_od_d, plbs[x - 1][y].te0_o[z]);
ctx->addBelInput(bel, id_oen, plbs[x - 1][y].me0_o[3]);
}
plbs[x][y].te0_o[z] = plbs[x][y].tw0_o[z] = addWireAsBelOutput(x, y, id_id_q, bel);
const WireId pad = addWire(x, y, IdStringList::concat(ctx->getBelName(bel), id_pad), id_pad);
ctx->addBelInout(bel, id_pad, pad);
}
}
void create_logic_parcel(const int x, const int y, const int lp_idx, LeInfo& le) {
LpInfo& lp = le.lp[lp_idx];
const BelId lut0 = addBel(x, y, LP_BELS*lp_idx + 0, id_LUT4);
ctx->addBelInput(lut0, id_f0, lp.f0[0]);
ctx->addBelInput(lut0, id_f1, lp.f1[0]);
const WireId l0_f2 = addWireAsBelInput(x, y, id_f2, lut0);
const WireId l0_f3 = addWireAsBelInput(x, y, id_f3, lut0);
ctx->addBelOutput(lut0, id_dx, lp.dx[0]);
const BelId lut40 = addBel(x, y, LP_BELS*lp_idx + 1, id_LUT4C);
const WireId l40_f0 = addWireAsBelInput(x, y, id_f0, lut40);
const WireId l40_f1 = addWireAsBelInput(x, y, id_f1, lut40);
const WireId l40_f2 = addWireAsBelInput(x, y, id_f2, lut40);
const WireId l40_f3 = addWireAsBelInput(x, y, id_f3, lut40);
const WireId l40_ca = addWireAsBelInput(x, y, id_ca, lut40);
ctx->addBelInput(lut40, id_ci, lp.c_in);
ctx->addBelOutput(lut40, id_co, lp.c_out);
ctx->addBelOutput(lut40, id_dx, lp.dx40);
const WireId l40_s = addWireAsBelOutput(x, y, id_s, lut40);
const BelId lut41 = addBel(x, y, LP_BELS*lp_idx + 2, id_LUT4);
ctx->addBelInput(lut41, id_f0, lp.f0[2]);
ctx->addBelInput(lut41, id_f1, lp.f1[2]);
ctx->addBelInput(lut41, id_f2, lp.f2[2]);
const WireId l41_f3 = addWireAsBelInput(x, y, id_f3, lut41);
const WireId l41_dx = addWireAsBelOutput(x, y, id_dx, lut41);
const BelId reg0 = addBel(x, y, LP_BELS*lp_idx + 3, id_REGS);
ctx->addBelInput(reg0, id_a_sr, le.lbuf.a_sr);
const WireId r0_di = addWireAsBelInput(x, y, id_di, reg0);
ctx->addBelInput(reg0, id_down_i, lp.down_i[0]);
ctx->addBelInput(reg0, id_mclk_b, le.lbuf.mclk_b);
ctx->addBelInput(reg0, id_sclk, le.lbuf.sclk);
ctx->addBelInput(reg0, id_shift, le.lbuf.sh[0]);
ctx->addBelInput(reg0, id_up_i, lp.up_i[0]);
ctx->addBelOutput(reg0, id_qx, lp.qx[0]);
const BelId reg1 = addBel(x, y, LP_BELS*lp_idx + 4, id_REGS);
ctx->addBelInput(reg1, id_a_sr, le.lbuf.a_sr);
const WireId r1_di = addWireAsBelInput(x, y, id_di, reg1);
ctx->addBelInput(reg1, id_down_i, lp.down_i[1]);
ctx->addBelInput(reg1, id_mclk_b, le.lbuf.mclk_b);
ctx->addBelInput(reg1, id_sclk, le.lbuf.sclk);
ctx->addBelInput(reg1, id_shift, le.lbuf.sh[1]);
ctx->addBelInput(reg1, id_up_i, lp.up_i[1]);
ctx->addBelOutput(reg1, id_qx, lp.qx[1]);
const BelId mux_dx4_0 = addBel(x, y, LP_BELS*lp_idx + 5, id_mux_dx4);
ctx->addBelInput(mux_dx4_0, id_in0, lp.dx40);
ctx->addBelInput(mux_dx4_0, id_in1, l41_dx);
ctx->addBelInput(mux_dx4_0, id_sel, lp.byp[2]);
ctx->addBelOutput(mux_dx4_0, id_out, lp.dx[1]);
const BelId mux_dx4_1 = addBel(x, y, LP_BELS*lp_idx + 6, id_mux_dx4);
ctx->addBelInput(mux_dx4_1, id_in0, l41_dx);
ctx->addBelInput(mux_dx4_1, id_in1, lp.dx40);
ctx->addBelInput(mux_dx4_1, id_sel, lp.byp[2]);
const WireId dx41_out = addWireAsBelOutput(x, y, id_out, mux_dx4_1);
add_cfgmux(Loc(x, y, 0), l0_f2, lp.f2[0], lp.qx[0]);
add_cfgmux(Loc(x, y, 0), l0_f3, lp.byp[0], lp.dx_fb);
add_cfgmux(Loc(x, y, 0), l40_f0, lp.f0[1], lp.dx[1]);
add_cfgmux(Loc(x, y, 0), l40_f1, lp.f1[1], l41_dx);
add_cfgmux(Loc(x, y, 0), l40_f2, lp.f2[1], lp.qx[1], lp.fy);
add_cfgmux(Loc(x, y, 0), l40_f3, lp.byp[1], lp.f2[2]);
add_cfgmux(Loc(x, y, 0), l40_ca, lp.byp[3], l40_f2, lp.dx[0]); // Technically input 0 should be GND, and this should go through an inverter.
WireId mux_sc = addWire(x, y, IdStringList::concat(ctx->getBelName(lut40), id_mux_sc), id_mux_sc);
add_cfgmux(Loc(x, y, 0), mux_sc, lp.c_out, l40_s);
add_cfgmux(Loc(x, y, 0), lp.dy, dx41_out, mux_sc);
add_cfgmux(Loc(x, y, 0), l41_f3, lp.byp[2], lp.f2[1], lp.qx[1]);
add_cfgmux(Loc(x, y, 0), r0_di, l40_s, lp.byp[3], lp.dx[0], lp.dx[1]);
add_cfgmux(Loc(x, y, 0), r1_di, l40_s, lp.byp[4], lp.dx[0], dx41_out);
add_cfgmux(Loc(x, y, 0), lp.dx[1], lp.dx40, l41_dx);
add_cfgmux(Loc(x, y, 0), dx41_out, l41_dx, lp.dx40);
}
void create_logic_element(const int x, const int y, LeInfo& info) {
// Create an unconnected wire for the initial carry-in if necessary.
if (y > 1)
info.lp[0].c_in = plbs[x][y-1].le.lp[3].c_out;
else
info.lp[0].c_in = addWire(x, y, IdStringList::concat(id_DUMMY, id_C_OUT), id_C_OUT);
// Same for dx_fb
if (y > 1)
info.lp[0].dx_fb = plbs[x][y-1].le.lp[3].dx[1];
else
info.lp[0].dx_fb = addWire(x, y, IdStringList::concat(id_DUMMY, id_DX_FB), id_DX_FB);
// Setup LBUF wires.
info.lbuf.a_sr = addWire(x, y, IdStringList(id_a_sr), id_a_sr);
info.lbuf.mclk_b = addWire(x, y, IdStringList(id_mclk_b), id_mclk_b);
info.lbuf.sclk = addWire(x, y, IdStringList(id_sclk), id_sclk);
info.lbuf.sh[0] = addWire(x, y, IdStringList::concat(id_shift, ctx->idf("0")), id_shift);
info.lbuf.sh[1] = addWire(x, y, IdStringList::concat(id_shift, ctx->idf("1")), id_shift);
/* lbuf bel I guess? */
const WireId lbuf_en{};
add_cfgmux(Loc(x, y, 0), info.lbuf.a_sr, plbs[x][y].cclk[0], plbs[x][y].cclk[1], plbs[x][y].cclk[2], plbs[x][y].cclk[3], plbs[x][y].cclk[4], plbs[x][y].cclk[5] /*, rc[1]? */);
add_cfgmux(Loc(x, y, 0), info.lbuf.mclk_b, plbs[x][y].cclk[0], plbs[x][y].cclk[1], plbs[x][y].cclk[2], plbs[x][y].cclk[3], plbs[x][y].cclk[4], plbs[x][y].cclk[5]);
//add_cfgmux(Loc(x, y, 0), lbuf_en, plbs[x][y].cclk[0], plbs[x][y].cclk[1], plbs[x][y].cclk[2], plbs[x][y].cclk[3], plbs[x][y].cclk[4], plbs[x][y].cclk[5] /*, rc[0]? */);
// Setup LP wires.
for (int lp_idx = 0; lp_idx < 4; lp_idx++) {
IdString lp_id = ctx->idf("LP%d", lp_idx);
LpInfo& lp = info.lp[lp_idx];
// LP inputs.
for (int byp = 0; byp < 5; byp++)
lp.byp[byp] = addWire(x, y, IdStringList::concat(lp_id, ctx->idf("BYP[%d]", byp)), id_BYP);
for (int fx = 0; fx < 3; fx++) {
lp.f0[fx] = addWire(x, y, IdStringList::concat(lp_id, ctx->idf("F0[%d]", fx)), id_f0);
lp.f1[fx] = addWire(x, y, IdStringList::concat(lp_id, ctx->idf("F1[%d]", fx)), id_f1);
lp.f2[fx] = addWire(x, y, IdStringList::concat(lp_id, ctx->idf("F2[%d]", fx)), id_f2);
}
if (x > 1)
lp.fy = plbs[x-1][y].le.lp[lp_idx].dy;
else
lp.fy = addWire(x, y, IdStringList::concat(lp_id, id_DUMMY), id_DY);
// LP outputs.
info.lp[lp_idx].c_out = addWire(x, y, IdStringList::concat(lp_id, id_C_OUT), id_C_OUT);
for (int dx = 0; dx < 2; dx++) {
lp.dx[dx] = addWire(x, y, IdStringList::concat(lp_id, ctx->idf("DX[%d]", dx)), id_dx);
lp.qx[dx] = addWire(x, y, IdStringList::concat(lp_id, ctx->idf("QX[%d]", dx)), id_qx);
}
info.lp[lp_idx].dx40 = addWire(x, y, IdStringList::concat(lp_id, id_DX40), id_DX40);
info.lp[lp_idx].dy = addWire(x, y, IdStringList::concat(lp_id, id_DY), id_DY);
}
for (int lp_idx = 0; lp_idx < 4; lp_idx++) {
if (lp_idx != 0) {
info.lp[lp_idx].c_in = info.lp[lp_idx-1].c_out;
info.lp[lp_idx].down_i[0] = info.lp[lp_idx-1].qx[0];
info.lp[lp_idx].down_i[1] = info.lp[lp_idx-1].qx[1];
info.lp[lp_idx].dx_fb = info.lp[lp_idx-1].dx[1];
}
if (lp_idx != 3) {
info.lp[lp_idx].up_i[0] = info.lp[lp_idx+1].qx[0];
info.lp[lp_idx].up_i[1] = info.lp[lp_idx+1].qx[1];
}
create_logic_parcel(x, y, lp_idx, info);
}
}
void create_input_crossbars(const int x_coord, const int y_coord, PlbInfo& plb)
{
const auto& lp = plb.le.lp;
const WireId i[4][4][16] = {
{
{ plb.te0_o[0], plb.oe0_o[0], get(x_coord+2, y_coord).te0_o[0], get(x_coord+1, y_coord).e_xy_o[0], get(x_coord+1, y_coord).te0_o[0], get(x_coord+4, y_coord).oe0_o[0], get(x_coord-1, y_coord).w_xy_o[1], plb.e_xy_o[0], get(x_coord+2, y_coord).te0_o[1], plb.te0_o[1], plb.oe0_o[1], plb.me0_o[0], get(x_coord+1, y_coord).ne_xy_o, get(x_coord+1, y_coord).te0_o[1], get(x_coord+4, y_coord).oe0_o[1], get(x_coord+1, y_coord).me0_o[0], },
{ plb.ts0_o[0], plb.os0_o[0], get(x_coord+1, y_coord+1).ne_xy_o, lp[3].byp[2], get(x_coord, y_coord+1).tn0_o[0], get(x_coord, y_coord+4).on0_o[1], get(x_coord, y_coord+2).tn0_o[0], get(x_coord, y_coord+1).tn0_o[1], lp[2].byp[2], get(x_coord, y_coord+1).n_xy_o[0], plb.on0_o[0], plb.mn0_o[0], get(x_coord-1, y_coord).ws_xy_o[0], plb.s_xy_o[0], get(x_coord, y_coord-4).os0_o[1], get(x_coord, y_coord-1).ms0_o[0], },
{ get(x_coord, y_coord+1).mn0_o[0], get(x_coord, y_coord+4).on0_o[0], get(x_coord-1, y_coord).nw_xy_o[0], lp[2].byp[0], plb.ms0_o[0], plb.os0_o[1], get(x_coord-1, y_coord+1).nw_xy_o[0], lp[1].byp[2], get(x_coord+1, y_coord).es_xy_o, get(x_coord, y_coord-2).ts0_o[0], get(x_coord, y_coord-4).os0_o[0], get(x_coord, y_coord-1).ts0_o[0], get(x_coord, y_coord+2).tn0_o[1], plb.tn0_o[1], plb.on0_o[1], plb.tn0_o[0], },
{ get(x_coord-1, y_coord).mw0_o[0], get(x_coord-4, y_coord).ow0_o[0], lp[0].dy, lp[0].dx[0], plb.mw0_o[0], plb.ow0_o[0], lp[0].qx[0], lp[2].qx[0], lp[2].dx[0], get(x_coord+1, y_coord+1).en_xy_o[0], get(x_coord-4, y_coord).ow0_o[1], get(x_coord-1, y_coord).tw0_o[0], lp[0].byp[1], get(x_coord-2, y_coord).tw0_o[0], plb.ow0_o[1], plb.tw0_o[0], },
},
{
{ plb.te0_o[2], plb.oe0_o[2], get(x_coord+2, y_coord).te0_o[2], get(x_coord+1, y_coord).e_xy_o[1], get(x_coord+1, y_coord).te0_o[2], get(x_coord+4, y_coord).oe0_o[2], get(x_coord-1, y_coord+1).wn_xy_o, lp[0].byp[2], lp[2].byp[3], get(x_coord+1, y_coord+1).en_xy_o[1], plb.oe0_o[3], plb.me0_o[1], lp[2].dx[1], get(x_coord-1, y_coord+1).nw_xy_o[1], get(x_coord+4, y_coord).oe0_o[3], get(x_coord+1, y_coord).me0_o[1], },
{ plb.ts0_o[1], plb.os0_o[2], plb.ts0_o[2], get(x_coord, y_coord-2).ts0_o[2], get(x_coord, y_coord+1).tn0_o[2], get(x_coord, y_coord+4).on0_o[3], get(x_coord, y_coord+2).tn0_o[2], lp[1].dy, lp[2].byp[1], plb.s_xy_o[1], plb.on0_o[2], plb.mn0_o[1], get(x_coord-1, y_coord).ws_xy_o[1], get(x_coord, y_coord+1).n_xy_o[1], get(x_coord, y_coord-4).os0_o[3], get(x_coord, y_coord-1).ms0_o[1], },
{ get(x_coord, y_coord+1).mn0_o[1], get(x_coord, y_coord+4).on0_o[2], plb.n_xy_o[0], lp[0].dx[1], plb.ms0_o[1], plb.os0_o[3], lp[0].byp[4], get(x_coord, y_coord-1).s_xy_o[0], get(x_coord, y_coord-1).ts0_o[2], get(x_coord, y_coord-2).ts0_o[1], get(x_coord, y_coord-4).os0_o[2], get(x_coord, y_coord-1).ts0_o[1], lp[0].qx[1], lp[2].qx[1], plb.on0_o[3], plb.tn0_o[2], },
{ get(x_coord-1, y_coord).mw0_o[1], get(x_coord-4, y_coord).ow0_o[2], get(x_coord-1, y_coord).tw0_o[2], lp[3].byp[3], plb.mw0_o[1], plb.ow0_o[2], plb.tw0_o[2], get(x_coord-2, y_coord).tw0_o[2], get(x_coord-1, y_coord).nw_xy_o[1], plb.w_xy_o[0], get(x_coord-4, y_coord).ow0_o[3], get(x_coord-1, y_coord).tw0_o[1], get(x_coord-1, y_coord).w_xy_o[0], get(x_coord-2, y_coord).tw0_o[1], plb.ow0_o[3], plb.tw0_o[1], },
},
{
{ plb.te0_o[3], plb.oe0_o[4], get(x_coord+2, y_coord).te0_o[3], get(x_coord+1, y_coord).e_xy_o[2], get(x_coord+1, y_coord).te0_o[3], get(x_coord+4, y_coord).oe0_o[4], get(x_coord+1, y_coord).se_xy_o[0], plb.e_xy_o[2], get(x_coord+2, y_coord).te0_o[4], plb.te0_o[4], plb.oe0_o[5], plb.me0_o[2], lp[3].dx[0], get(x_coord+1, y_coord).te0_o[4], get(x_coord+4, y_coord).oe0_o[5], get(x_coord+1, y_coord).me0_o[2], },
{ plb.ts0_o[3], plb.os0_o[4], lp[1].qx[0], lp[3].qx[0], get(x_coord, y_coord+1).tn0_o[3], get(x_coord, y_coord+4).on0_o[5], get(x_coord, y_coord+2).tn0_o[3], get(x_coord, y_coord+1).tn0_o[4], lp[2].byp[4], get(x_coord, y_coord+1).n_xy_o[2], plb.on0_o[4], plb.mn0_o[2], lp[1].byp[3], plb.s_xy_o[2], get(x_coord, y_coord-4).os0_o[5], get(x_coord, y_coord-1).ms0_o[2], },
{ get(x_coord, y_coord+1).mn0_o[2], get(x_coord, y_coord+4).on0_o[4], get(x_coord+1, y_coord).en_xy_o[0], get(x_coord, y_coord-1).s_xy_o[1], plb.ms0_o[2], plb.os0_o[5], plb.n_xy_o[1], lp[1].dx[0], lp[2].dy, get(x_coord, y_coord-2).ts0_o[3], get(x_coord, y_coord-4).os0_o[4], get(x_coord, y_coord-1).ts0_o[3], get(x_coord, y_coord+2).tn0_o[4], plb.tn0_o[4], plb.on0_o[5], plb.tn0_o[3], },
{ get(x_coord-1, y_coord).mw0_o[2], get(x_coord-4, y_coord).ow0_o[4], get(x_coord+1, y_coord-1).es_xy_o, get(x_coord+1, y_coord-1).se_xy_o[0], plb.mw0_o[2], plb.ow0_o[4], get(x_coord-1, y_coord-1).ws_xy_o[0], lp[1].byp[0], lp[3].byp[4], plb.w_xy_o[1], get(x_coord-4, y_coord).ow0_o[5], get(x_coord-1, y_coord).tw0_o[3], lp[0].byp[3], get(x_coord-2, y_coord).tw0_o[3], plb.ow0_o[5], plb.tw0_o[3], },
},
{
{ plb.te0_o[5], plb.oe0_o[6], get(x_coord+2, y_coord).te0_o[5], get(x_coord+1, y_coord-1).se_xy_o[1], get(x_coord+1, y_coord).te0_o[5], get(x_coord+4, y_coord).oe0_o[6], lp[1].byp[4], get(x_coord+1, y_coord).se_xy_o[1], lp[1].qx[1], lp[3].qx[1], plb.on0_o[8], plb.me0_o[3], plb.e_xy_o[1], lp[3].dy, get(x_coord, y_coord+4).on0_o[8], get(x_coord+1, y_coord).me0_o[3], },
{ plb.ts0_o[4], plb.os0_o[6], plb.ts0_o[5], get(x_coord, y_coord-2).ts0_o[5], get(x_coord, y_coord+1).tn0_o[5], get(x_coord, y_coord+4).on0_o[7], get(x_coord, y_coord+2).tn0_o[5], lp[0].byp[0], lp[3].byp[0], get(x_coord+1, y_coord).en_xy_o[1], plb.on0_o[6], plb.mn0_o[3], get(x_coord-1, y_coord-1).sw_xy_o, lp[1].byp[1], get(x_coord, y_coord-4).os0_o[7], get(x_coord, y_coord-1).ms0_o[3], },
{ get(x_coord, y_coord+1).mn0_o[3], get(x_coord, y_coord+4).on0_o[6], plb.n_xy_o[2], lp[1].dx[1], plb.ms0_o[3], plb.os0_o[7], get(x_coord-1, y_coord-1).ws_xy_o[1], get(x_coord, y_coord-1).s_xy_o[2], get(x_coord, y_coord-1).ts0_o[5], get(x_coord, y_coord-2).ts0_o[4], get(x_coord, y_coord-4).os0_o[6], get(x_coord, y_coord-1).ts0_o[4], lp[3].dx[1], get(x_coord-1, y_coord).wn_xy_o, plb.on0_o[7], plb.tn0_o[5], },
{ get(x_coord-1, y_coord).mw0_o[3], get(x_coord-4, y_coord).ow0_o[6], get(x_coord-1, y_coord).tw0_o[5], lp[3].byp[1], plb.mw0_o[3], plb.ow0_o[6], plb.tw0_o[5], get(x_coord-2, y_coord).tw0_o[5], get(x_coord-1, y_coord).sw_xy_o, plb.w_xy_o[2], get(x_coord, y_coord-4).os0_o[8], get(x_coord-1, y_coord).tw0_o[4], get(x_coord-1, y_coord).w_xy_o[2], get(x_coord-2, y_coord).tw0_o[4], plb.os0_o[8], plb.tw0_o[4], },
},
};
const WireId z[4][4][8] = {
{
{ plb.on0_o[0], plb.on0_o[1], lp[3].f2[0], lp[1].f0[2], lp[0].byp[0], plb.tn0_o[1], lp[0].f2[2], lp[0].f0[0], },
{ plb.mn0_o[0], plb.tn0_o[0], lp[3].byp[1], plb.te0_o[1], plb.mw0_o[0], plb.te0_o[0], plb.ow0_o[1], plb.oe0_o[1], },
{ lp[2].f0[2], lp[2].byp[2], plb.ts0_o[0], plb.ms0_o[0], plb.ow0_o[0], plb.oe0_o[0], plb.tw0_o[0], plb.me0_o[0], },
{ lp[3].f1[1], lp[2].f1[0], plb.os0_o[0], plb.os0_o[1], lp[2].f2[1], lp[0].f1[1], lp[0].byp[4], lp[1].byp[3], },
},
{
{ plb.on0_o[2], plb.on0_o[3], lp[2].f1[2], lp[2].f0[0], lp[3].byp[2], lp[3].f0[0], lp[1].f2[0], lp[0].f0[1], },
{ plb.mn0_o[1], plb.tn0_o[2], plb.ts0_o[2], lp[2].byp[3], plb.mw0_o[1], plb.te0_o[2], plb.ow0_o[3], plb.oe0_o[3], },
{ plb.tw0_o[2], lp[0].byp[1], plb.ts0_o[1], plb.ms0_o[1], plb.ow0_o[2], plb.oe0_o[2], plb.tw0_o[1], plb.me0_o[1], },
{ lp[3].f2[1], lp[2].f1[1], plb.os0_o[2], plb.os0_o[3], lp[1].f2[1], lp[0].f1[2], lp[1].byp[0], lp[1].byp[4], },
},
{
{ plb.on0_o[4], plb.on0_o[5], lp[2].f2[2], lp[2].f0[1], lp[2].byp[4], plb.tn0_o[4], lp[0].f2[0], lp[0].f0[2], },
{ plb.mn0_o[2], plb.tn0_o[3], lp[3].f0[1], plb.te0_o[4], plb.mw0_o[2], plb.te0_o[3], plb.ow0_o[5], plb.oe0_o[5], },
{ lp[3].byp[3], lp[0].byp[2], plb.ts0_o[3], plb.ms0_o[2], plb.ow0_o[4], plb.oe0_o[4], plb.tw0_o[3], plb.me0_o[2], },
{ lp[3].f1[2], lp[1].f1[1], plb.os0_o[4], plb.os0_o[5], lp[1].f2[2], lp[1].f1[0], lp[1].byp[1], lp[2].byp[0], },
},
{
{ plb.on0_o[6], plb.on0_o[7], lp[3].f1[0], lp[1].f0[1], lp[3].byp[0], lp[0].byp[3], lp[0].f2[1], lp[1].f0[0], },
{ plb.mn0_o[3], plb.tn0_o[5], plb.ts0_o[5], lp[3].f0[2], plb.mw0_o[3], plb.te0_o[5], plb.on0_o[8], plb.os0_o[8], },
{ plb.tw0_o[5], lp[3].byp[4], plb.ts0_o[4], plb.ms0_o[3], plb.ow0_o[6], plb.oe0_o[6], plb.tw0_o[4], plb.me0_o[3], },
{ lp[3].f2[2], lp[1].f1[2], plb.os0_o[6], plb.os0_o[7], lp[2].f2[0], lp[0].f1[0], lp[1].byp[2], lp[2].byp[1], },
},
};
const int swizzle[8] = {0, 1, 4, 5, 2, 3, 6, 7};
// Far, får får får? Nej, får får inte får, får får lamm.
for (int ixbar = 0; ixbar < 4; ixbar++) {
WireId x[4][8][4];
for (int a = 0; a < 4; a++)
for (int b = 0; b < 8; b++)
for (int c = 0; c < 4; c++) {
IdString ixbar_id = ctx->idf("IXBAR%d", ixbar);
IdStringList a_id = IdStringList::concat(ixbar_id, ctx->idf("IX%d", a));
IdStringList b_id = IdStringList::concat(a_id, ctx->idf("IX%d", b));
IdStringList id = IdStringList::concat(b_id, ctx->idf("SC_MUX_%d", c));
x[a][b][c] = addWire(x_coord, y_coord, id, id_IXIX);
}
// stage 1: the "ixix": select 32 groups of 4 signals from the i inputs.
for (int ixN = 0; ixN < 4; ixN++)
for (int ixM = 0; ixM < 8; ixM++)
for (int SC_mux_C = 0; SC_mux_C < 4; SC_mux_C++)
for (int a = 0; a < 4; a++)
add_cfgmux(Loc(x_coord, y_coord, 32*ixN+4*ixM+SC_mux_C), x[ixN][ixM][SC_mux_C], i[ixbar][a][ixN*4+SC_mux_C]);
// some ixixes can select from the clocks, as well.
if (ixbar < 2) {
for (int ixB = 6; ixB < 8; ixB++) {
add_cfgmux(Loc(x_coord, y_coord, 0), x[ixbar][ixB][0], plb.clk_xbar[2*ixbar+0]);
add_cfgmux(Loc(x_coord, y_coord, 0), x[ixbar][ixB][3], plb.clk_xbar[2*ixbar+1]);
}
}
// stage 2: the "xzzx": select 16 signals from 4 groups of 4 signals from the ixix.
for (int xzN = 0; xzN < 8; xzN++) {
for (int zxM = 0; zxM < 4; zxM++)
for (const auto x : x)
for (const auto x : x[swizzle[xzN]])
add_cfgmux(Loc(x_coord, y_coord, 4*xzN+zxM), z[ixbar][zxM][xzN], x);
}
}
}
void create_output_crossbar(const int x, const int y, PlbInfo& plb)
{
const WireId xy[24] = {
plb.s_xy_o[0],
plb.ws_xy_o[0],
plb.e_xy_o[0],
plb.es_xy_o,
plb.w_xy_o[0],
plb.se_xy_o[0],
plb.s_xy_o[1],
plb.ws_xy_o[1],
plb.n_xy_o[0],
plb.sw_xy_o,
plb.s_xy_o[2],
plb.se_xy_o[1],
plb.w_xy_o[1],
plb.nw_xy_o[0],
plb.e_xy_o[2],
plb.ne_xy_o,
plb.n_xy_o[1],
plb.en_xy_o[0],
plb.e_xy_o[1],
plb.nw_xy_o[1],
plb.w_xy_o[2],
plb.wn_xy_o,
plb.n_xy_o[2],
plb.en_xy_o[1],
};
for (int n = 0; n < 24; n++)
add_cfgmux(Loc(x, y, n), xy[n],
plb.le.lp[0].dx[0],
plb.le.lp[0].qx[0],
plb.le.lp[0].dx[1],
plb.le.lp[0].qx[1],
plb.le.lp[0].dy,
plb.le.lp[1].dx[0],
plb.le.lp[1].qx[0],
plb.le.lp[1].dx[1],
plb.le.lp[1].qx[1],
plb.le.lp[1].dy,
plb.le.lp[2].dx[0],
plb.le.lp[2].qx[0],
plb.le.lp[2].dx[1],
plb.le.lp[2].qx[1],
plb.le.lp[2].dy,
plb.le.lp[3].dx[0],
plb.le.lp[3].qx[0],
plb.le.lp[3].dx[1],
plb.le.lp[3].qx[1],
plb.le.lp[3].dy,
plb.le.lp[3].byp[4],
plb.le.lp[2].byp[4],
plb.le.lp[1].byp[4],
plb.le.lp[0].byp[4]
);
}
void create_programmable_logic_block(const int x, const int y) {
create_logic_element(x, y, plbs[x][y].le);
create_input_crossbars(x, y, plbs[x][y]);
create_output_crossbar(x, y, plbs[x][y]);
}
void create_gbuf(const int x, const int y, const int n, const WireId clk0, const WireId clk1, const WireId clk2, const WireId clk3, const WireId clk4, const WireId clk5, const WireId en0, const WireId en1) {
WireId clk_mux = addWire(x, y, h.xy_id(x, y, ctx->idf("GBUF%d", n)), id_CLK_MUX);
add_cfgmux(Loc(x, y, n), clk_mux, clk0, clk1, clk2, clk3, clk4, clk5);
WireId en_mux = addWire(x, y, h.xy_id(x, y, ctx->idf("GBUF%d", n)), id_EN_MUX);
add_cfgmux(Loc(x, y, n), en_mux, en0, en1);
// TODO: clock gating bel?
WireId clk_en_mux = clk_mux;
rbufs[x][y].gclk[n] = clk_en_mux;
}
void create_gbufx16(const int x, const int y) {
GbufInfo& gbuf = gbufs[x][y];
create_gbuf(x, y, 0, gbuf.pclk_c1r1[0], gbuf.pclk_c2r1[0], gbuf.pclk_c1r2[0], gbuf.pclk_c2r2[0], gbuf.clkpad_s[0], gbuf.fabric_gclk[0], gbuf.fabric_gclk[3], gbuf.fabric_gclk[4]);
create_gbuf(x, y, 1, gbuf.pclk_c1r1[1], gbuf.pclk_c2r1[1], gbuf.pclk_c1r2[1], gbuf.pclk_c2r2[1], gbuf.clkpad_s[1], gbuf.fabric_gclk[1], gbuf.fabric_gclk[3], gbuf.fabric_gclk[4]);
create_gbuf(x, y, 2, gbuf.pclk_c1r1[2], gbuf.pclk_c2r1[2], gbuf.pclk_c1r2[2], gbuf.pclk_c2r2[2], gbuf.clkpad_s[2], gbuf.fabric_gclk[2], gbuf.fabric_gclk[4], gbuf.fabric_gclk[5]);
create_gbuf(x, y, 3, gbuf.pclk_c1r1[3], gbuf.pclk_c2r1[3], gbuf.pclk_c1r2[3], gbuf.pclk_c2r2[3], gbuf.clkpad_s[3], gbuf.fabric_gclk[3], gbuf.fabric_gclk[4], gbuf.fabric_gclk[5]);
create_gbuf(x, y, 4, gbuf.pclk_c1r1[0], gbuf.pclk_c2r1[0], gbuf.pclk_c1r2[0], gbuf.pclk_c2r2[0], gbuf.clkpad_s[0], gbuf.fabric_gclk[2], gbuf.fabric_gclk[5], gbuf.fabric_gclk[6]);
create_gbuf(x, y, 5, gbuf.pclk_c1r1[1], gbuf.pclk_c2r1[1], gbuf.pclk_c1r2[1], gbuf.pclk_c2r2[1], gbuf.clkpad_s[1], gbuf.fabric_gclk[3], gbuf.fabric_gclk[5], gbuf.fabric_gclk[6]);
create_gbuf(x, y, 6, gbuf.pclk_c1r1[2], gbuf.pclk_c2r1[2], gbuf.pclk_c1r2[2], gbuf.pclk_c2r2[2], gbuf.clkpad_s[2], gbuf.fabric_gclk[4], gbuf.fabric_gclk[6], gbuf.fabric_gclk[7]);
create_gbuf(x, y, 7, gbuf.pclk_c1r1[3], gbuf.pclk_c2r1[3], gbuf.pclk_c1r2[3], gbuf.pclk_c2r2[3], gbuf.clkpad_s[3], gbuf.fabric_gclk[5], gbuf.fabric_gclk[6], gbuf.fabric_gclk[7]);
create_gbuf(x, y, 8, gbuf.pclk_c1r1[0], gbuf.pclk_c2r1[0], gbuf.pclk_c1r2[0], gbuf.pclk_c2r2[0], gbuf.clkpad_n[0], gbuf.fabric_gclk[4], gbuf.fabric_gclk[7], gbuf.fabric_gclk[0]);
create_gbuf(x, y, 9, gbuf.pclk_c1r1[1], gbuf.pclk_c2r1[1], gbuf.pclk_c1r2[1], gbuf.pclk_c2r2[1], gbuf.clkpad_n[1], gbuf.fabric_gclk[5], gbuf.fabric_gclk[7], gbuf.fabric_gclk[0]);
create_gbuf(x, y, 10, gbuf.pclk_c1r1[2], gbuf.pclk_c2r1[2], gbuf.pclk_c1r2[2], gbuf.pclk_c2r2[2], gbuf.clkpad_n[2], gbuf.fabric_gclk[6], gbuf.fabric_gclk[0], gbuf.fabric_gclk[1]);
create_gbuf(x, y, 11, gbuf.pclk_c1r1[3], gbuf.pclk_c2r1[3], gbuf.pclk_c1r2[3], gbuf.pclk_c2r2[3], gbuf.clkpad_n[3], gbuf.fabric_gclk[7], gbuf.fabric_gclk[0], gbuf.fabric_gclk[1]);
create_gbuf(x, y, 12, gbuf.pclk_c1r1[0], gbuf.pclk_c2r1[0], gbuf.pclk_c1r2[0], gbuf.pclk_c2r2[0], gbuf.clkpad_n[0], gbuf.fabric_gclk[6], gbuf.fabric_gclk[1], gbuf.fabric_gclk[2]);
create_gbuf(x, y, 13, gbuf.pclk_c1r1[1], gbuf.pclk_c2r1[1], gbuf.pclk_c1r2[1], gbuf.pclk_c2r2[1], gbuf.clkpad_n[1], gbuf.fabric_gclk[7], gbuf.fabric_gclk[1], gbuf.fabric_gclk[2]);
create_gbuf(x, y, 14, gbuf.pclk_c1r1[2], gbuf.pclk_c2r1[2], gbuf.pclk_c1r2[2], gbuf.pclk_c2r2[2], gbuf.clkpad_n[2], gbuf.fabric_gclk[0], gbuf.fabric_gclk[2], gbuf.fabric_gclk[3]);
create_gbuf(x, y, 15, gbuf.pclk_c1r1[3], gbuf.pclk_c2r1[3], gbuf.pclk_c1r2[3], gbuf.pclk_c2r2[3], gbuf.clkpad_n[3], gbuf.fabric_gclk[1], gbuf.fabric_gclk[2], gbuf.fabric_gclk[3]);
}
void create_rbuf(const int x, const int y, const int n, const WireId clk0, const WireId clk1, const WireId clk2, const WireId clk3, const WireId en0, const WireId en1) {
WireId clk_mux = addWire(x, y, h.xy_id(x, y, ctx->idf("RBUF%d", n)), id_CLK_MUX);
add_cfgmux(Loc(x, y, n), clk_mux, clk0, clk1, clk2, clk3);
WireId en_mux = addWire(x, y, h.xy_id(x, y, ctx->idf("RBUF%d", n)), id_EN_MUX);
add_cfgmux(Loc(x, y, n), en_mux, en0, en1);
// TODO: clock gating bel?
WireId clk_en_mux = clk_mux;
// TODO: investigate rbufx6.rclk_[td]_xbar_[12]
for (int x_offset = 0; x_offset < 8; x_offset++)
for (int y_offset = 0; y_offset < 2; y_offset++)
get(x + x_offset, y + y_offset).cclk[n] = clk_en_mux;
}
void create_rbufx6(const int x, const int y) {
RbufInfo& rbuf = rbufs[x][y];
if (x < (COLUMNS / 2)) {
}
create_rbuf(x, y, 0, rbuf.gclk[0], rbuf.gclk[6], rbuf.gclk[10], rbuf.gclk[12], rbuf.gclk[4], rbuf.fabric_rclk[0]);
create_rbuf(x, y, 1, rbuf.gclk[1], rbuf.gclk[7], rbuf.gclk[11], rbuf.gclk[13], rbuf.gclk[5], rbuf.fabric_rclk[1]);
create_rbuf(x, y, 2, rbuf.gclk[2], rbuf.gclk[8], rbuf.gclk[12], rbuf.gclk[14], rbuf.gclk[0], rbuf.gclk[6]);
create_rbuf(x, y, 3, rbuf.gclk[3], rbuf.gclk[9], rbuf.gclk[13], rbuf.gclk[15], rbuf.gclk[1], rbuf.gclk[7]);
create_rbuf(x, y, 4, rbuf.gclk[4], rbuf.gclk[10], rbuf.gclk[14], rbuf.fabric_rclk[0], rbuf.gclk[2], rbuf.gclk[8]);
create_rbuf(x, y, 5, rbuf.gclk[5], rbuf.gclk[11], rbuf.gclk[15], rbuf.fabric_rclk[1], rbuf.gclk[3], rbuf.gclk[9]);
}
void create_bels() {
for (int x = 0; x < COLUMNS; x++) {
for (int y = 0; y < ROWS; y++) {
plbs[x][y] = setup_plb(x, y);
if ((x - 1) % 8 == 0 && (y - 1) % 2 == 0)
create_rbufx6(x, y);
}
}
for (int x = 1; x < COLUMNS - 1; x++) {
for (int y = 0; y < ROWS; y++) {
const bool at_y_edge = (y == 0) || (y == ROWS - 1);
if (at_y_edge) {
create_iopad(x, y);
}
}
}
for (int x = 0; x < COLUMNS; x++) {
const bool at_x_edge = (x == 0) || (x == COLUMNS - 1);
for (int y = 0; y < ROWS; y++) {
const bool at_y_edge = (y == 0) || (y == ROWS - 1);
if (!at_x_edge && !at_y_edge) {
create_programmable_logic_block(x, y);
}
}
}
}
PlbInfo setup_plb(const int x, const int y) {
PlbInfo plb{};
for (int triple = 0; triple < 6; triple++) {
IdString id = ctx->idf("%d", triple);
plb.tn0_o[triple] = addWire(x, y, IdStringList::concat(id_TN, id), id_TN);
plb.te0_o[triple] = addWire(x, y, IdStringList::concat(id_TE, id), id_TE);
plb.ts0_o[triple] = addWire(x, y, IdStringList::concat(id_TS, id), id_TS);
plb.tw0_o[triple] = addWire(x, y, IdStringList::concat(id_TW, id), id_TW);
}
for (int mono = 0; mono < 4; mono++) {
IdString id = ctx->idf("%d", mono);
plb.mn0_o[mono] = addWire(x, y, IdStringList::concat(id_MN, id), id_MN);
plb.me0_o[mono] = addWire(x, y, IdStringList::concat(id_ME, id), id_ME);
plb.ms0_o[mono] = addWire(x, y, IdStringList::concat(id_MS, id), id_MS);
plb.mw0_o[mono] = addWire(x, y, IdStringList::concat(id_MW, id), id_MW);
plb.clk_xbar[mono] = addWire(x, y, IdStringList::concat(id_CLK_XBAR, id), id_CLK_XBAR);
}
for (int octal = 0; octal < 9; octal++) {
IdString id = ctx->idf("%d", octal);
plb.on0_o[octal] = addWire(x, y, IdStringList::concat(id_ON, id), id_ON);
plb.os0_o[octal] = addWire(x, y, IdStringList::concat(id_OS, id), id_OS);
if (octal < 7) {
plb.oe0_o[octal] = addWire(x, y, IdStringList::concat(id_OE, id), id_OE);
plb.ow0_o[octal] = addWire(x, y, IdStringList::concat(id_OW, id), id_OW);
}
}
for (int xy = 0; xy < 3; xy++) {
IdString id = ctx->idf("%d", xy);
plb.n_xy_o[xy] = addWire(x, y, IdStringList::concat(id_XYN, id), id_XYN);
plb.e_xy_o[xy] = addWire(x, y, IdStringList::concat(id_XYE, id), id_XYE);
plb.s_xy_o[xy] = addWire(x, y, IdStringList::concat(id_XYS, id), id_XYS);
plb.w_xy_o[xy] = addWire(x, y, IdStringList::concat(id_XYW, id), id_XYW);
}
for (int xy = 0; xy < 2; xy++) {
IdString id = ctx->idf("%d", xy);
plb.en_xy_o[xy] = addWire(x, y, IdStringList::concat(id_XYEN, id), id_XYEN);
plb.se_xy_o[xy] = addWire(x, y, IdStringList::concat(id_XYSE, id), id_XYSE);
plb.ws_xy_o[xy] = addWire(x, y, IdStringList::concat(id_XYWS, id), id_XYWS);
plb.nw_xy_o[xy] = addWire(x, y, IdStringList::concat(id_XYNW, id), id_XYNW);
}
IdString id = ctx->id("0");
plb.ne_xy_o = addWire(x, y, IdStringList::concat(id_XYNE, id), id_XYNE);
plb.es_xy_o = addWire(x, y, IdStringList::concat(id_XYES, id), id_XYES);
plb.sw_xy_o = addWire(x, y, IdStringList::concat(id_XYSW, id), id_XYSW);
plb.wn_xy_o = addWire(x, y, IdStringList::concat(id_XYWN, id), id_XYWN);
return plb;
}
PlbInfo& get(int x, int y) {
if (x < 0)
x = -x;
if (x >= COLUMNS)
x = COLUMNS - (x - COLUMNS);
if (y < 0)
y = -y;
if (y >= ROWS)
y = ROWS - (y - ROWS);
return plbs[x][y];
}
bool lp_is_valid(int x, int y, int lp_idx) const {
const CellInfo *lut0 = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, LP_BELS*lp_idx + 0)));
const CellInfo *lut40 = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, LP_BELS*lp_idx + 1)));
const CellInfo *lut41 = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, LP_BELS*lp_idx + 2)));
const CellInfo *reg0 = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, LP_BELS*lp_idx + 3)));
const CellInfo *reg1 = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, LP_BELS*lp_idx + 4)));
const CellInfo *mux_dx4_0 = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, LP_BELS*lp_idx + 5)));
const CellInfo *mux_dx4_1 = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(x, y, LP_BELS*lp_idx + 6)));
// TODO: mux_dx4
if (!lut0 && !lut40 && !lut41) {
// assume routing via byp[34]
return true;
}
/*if (reg0) {
if ()
}*/
// common signals for reg0/reg1
if (reg0 && reg1) {
if (reg0->getPort(id_a_sr) != reg1->getPort(id_a_sr))
return false;
if (reg0->getPort(id_mclk_b) != reg1->getPort(id_mclk_b))
return false;
if (reg0->getPort(id_sclk) != reg1->getPort(id_sclk))
return false;
}
return true;
}
private:
ViaductHelpers h;
static const int COLUMNS = 28;
static const int ROWS = 50;
static const int LP_BELS = 7;
std::array<std::array<PlbInfo, ROWS>, COLUMNS> plbs;
std::array<std::array<RbufInfo, ROWS>, COLUMNS> rbufs;
std::array<GbufInfo, 2> gbufs;
};
struct HerculesArch : ViaductArch {
HerculesArch() : ViaductArch("hercules") {}
std::unique_ptr<ViaductAPI> create(const dict<std::string, std::string> &args) {
return std::make_unique<Hercules>();
}
} hercules;
} // namespace
NEXTPNR_NAMESPACE_END