Use TRELLIS primitives
This commit is contained in:
parent
ad5f6fccaa
commit
0ce72e1a31
@ -368,7 +368,7 @@ bool Arch::place()
|
||||
return retVal;
|
||||
} else if (placer == "heap") {
|
||||
PlacerHeapCfg cfg(getCtx());
|
||||
cfg.ioBufTypes.insert(id_FACADE_IO);
|
||||
cfg.ioBufTypes.insert(id_TRELLIS_IO);
|
||||
bool retVal = placer_heap(getCtx(), cfg);
|
||||
getCtx()->settings[id_place] = 1;
|
||||
archInfoToAttributes();
|
||||
|
@ -225,7 +225,7 @@ void write_bitstream(Context *ctx, std::string text_config_file)
|
||||
continue;
|
||||
}
|
||||
BelId bel = ci->bel;
|
||||
if (ci->type == id_FACADE_SLICE) {
|
||||
if (ci->type == id_TRELLIS_SLICE) {
|
||||
std::string tname = ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, "PLC");
|
||||
std::string slice = ctx->tile_info(bel)->bel_data[bel.index].name.get();
|
||||
|
||||
@ -253,7 +253,7 @@ void write_bitstream(Context *ctx, std::string text_config_file)
|
||||
cc.tiles[tname].add_enum(slice + ".REG1.SD", intstr_or_default(ci->params, id_REG1_SD, "0"));
|
||||
cc.tiles[tname].add_enum(slice + ".REG0.REGSET", str_or_default(ci->params, id_REG0_REGSET, "RESET"));
|
||||
cc.tiles[tname].add_enum(slice + ".REG1.REGSET", str_or_default(ci->params, id_REG1_REGSET, "RESET"));
|
||||
} else if (ci->type == id_FACADE_IO) {
|
||||
} else if (ci->type == id_TRELLIS_IO) {
|
||||
std::string pio = ctx->tile_info(bel)->bel_data[bel.index].name.get();
|
||||
std::string iotype = str_or_default(ci->attrs, id_IO_TYPE, "LVCMOS33");
|
||||
std::string dir = str_or_default(ci->params, id_DIR, "INPUT");
|
||||
|
@ -32,7 +32,7 @@ std::unique_ptr<CellInfo> create_machxo2_cell(Context *ctx, IdString type, std::
|
||||
name.empty() ? ctx->id("$nextpnr_" + type.str(ctx) + "_" + std::to_string(auto_idx++)) : ctx->id(name);
|
||||
auto new_cell = std::make_unique<CellInfo>(ctx, name_id, type);
|
||||
|
||||
if (type == id_FACADE_SLICE) {
|
||||
if (type == id_TRELLIS_SLICE) {
|
||||
new_cell->params[id_MODE] = std::string("LOGIC");
|
||||
new_cell->params[id_GSR] = std::string("ENABLED");
|
||||
new_cell->params[id_SRMODE] = std::string("LSR_OVER_CE");
|
||||
@ -101,11 +101,11 @@ std::unique_ptr<CellInfo> create_machxo2_cell(Context *ctx, IdString type, std::
|
||||
new_cell->addOutput(id_WADO1);
|
||||
new_cell->addOutput(id_WADO2);
|
||||
new_cell->addOutput(id_WADO3);
|
||||
} else if (type == id_FACADE_IO) {
|
||||
} else if (type == id_TRELLIS_IO) {
|
||||
new_cell->params[id_DIR] = std::string("INPUT");
|
||||
new_cell->attrs[id_IO_TYPE] = std::string("LVCMOS33");
|
||||
|
||||
new_cell->addInout(id_PAD);
|
||||
new_cell->addInout(id_B);
|
||||
new_cell->addInput(id_I);
|
||||
new_cell->addInput(id_EN);
|
||||
new_cell->addOutput(id_O);
|
||||
|
@ -26,7 +26,7 @@
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
// When packing DFFs, we need context of how it's connected to a LUT to
|
||||
// properly map DFF ports to FACADE_SLICEs; DI0 input muxes F0 and OFX0,
|
||||
// properly map DFF ports to TRELLIS_SLICEs; DI0 input muxes F0 and OFX0,
|
||||
// and a DFF inside a slice can use either DI0 or M0 as an input.
|
||||
enum class LutType
|
||||
{
|
||||
@ -43,9 +43,9 @@ std::unique_ptr<CellInfo> create_machxo2_cell(Context *ctx, IdString type, std::
|
||||
inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_LUT4; }
|
||||
|
||||
// Return true if a cell is a flipflop
|
||||
inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_FACADE_FF; }
|
||||
inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_TRELLIS_FF; }
|
||||
|
||||
inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_FACADE_SLICE; }
|
||||
inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_TRELLIS_SLICE; }
|
||||
|
||||
// Convert a LUT primitive to (part of) an GENERIC_SLICE, swapping ports
|
||||
// as needed. Set no_dff if a DFF is not being used, so that the output
|
||||
|
@ -1,4 +1,4 @@
|
||||
X(FACADE_SLICE)
|
||||
X(TRELLIS_SLICE)
|
||||
X(A0)
|
||||
X(B0)
|
||||
X(C0)
|
||||
@ -60,15 +60,14 @@ X(CCU2_INJECT1_1)
|
||||
X(WREMUX)
|
||||
|
||||
|
||||
X(FACADE_FF)
|
||||
X(TRELLIS_FF)
|
||||
X(DI)
|
||||
X(Q)
|
||||
|
||||
X(REGSET)
|
||||
|
||||
|
||||
X(FACADE_IO)
|
||||
X(PAD)
|
||||
X(TRELLIS_IO)
|
||||
X(I)
|
||||
X(EN)
|
||||
X(O)
|
||||
|
@ -469,11 +469,11 @@ def main():
|
||||
constids[line[1]] = idx
|
||||
const_id_count += 1
|
||||
|
||||
constids["SLICE"] = constids["FACADE_SLICE"]
|
||||
constids["PIO"] = constids["FACADE_IO"]
|
||||
constids["SLICE"] = constids["TRELLIS_SLICE"]
|
||||
constids["PIO"] = constids["TRELLIS_IO"]
|
||||
|
||||
chip = pytrellis.Chip(dev_names[args.device])
|
||||
rg = pytrellis.make_optimized_chipdb(chip)
|
||||
rg = pytrellis.make_optimized_chipdb(chip, split_slice_mode=False)
|
||||
max_row = chip.get_max_row()
|
||||
max_col = chip.get_max_col()
|
||||
process_pio_db(rg, args.device)
|
||||
|
@ -43,19 +43,19 @@ void gfxTileBel(std::vector<GraphicElement> &g, int x, int y, int z, int w, int
|
||||
GraphicElement el;
|
||||
el.type = GraphicElement::TYPE_BOX;
|
||||
el.style = style;
|
||||
if (bel_type == id_FACADE_SLICE) {
|
||||
if (bel_type == id_TRELLIS_SLICE) {
|
||||
el.x1 = x + slice_x1;
|
||||
el.x2 = x + slice_x2_comb;
|
||||
el.y1 = y + slice_y1 + z * slice_pitch;
|
||||
el.y2 = y + slice_y2 + z * slice_pitch;
|
||||
g.push_back(el);
|
||||
/* } else if (bel_type == id_FACADE_FF) {
|
||||
/* } else if (bel_type == id_TRELLIS_FF) {
|
||||
el.x1 = x + slice_x1_ff;
|
||||
el.x2 = x + slice_x2;
|
||||
el.y1 = y + slice_y1 + z * slice_pitch;
|
||||
el.y2 = y + slice_y2 + z * slice_pitch;
|
||||
g.push_back(el);*/
|
||||
} else if (bel_type.in(id_FACADE_IO)) {
|
||||
} else if (bel_type.in(id_TRELLIS_IO)) {
|
||||
bool top_bottom = (y == 0 || y == (h - 1));
|
||||
if (top_bottom) {
|
||||
el.x1 = x + io_cell_h_x1 + (z + 2) * io_cell_gap;
|
||||
|
@ -39,7 +39,7 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
if (ctx->verbose)
|
||||
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
|
||||
if (is_lut(ctx, ci)) {
|
||||
std::unique_ptr<CellInfo> packed = create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC");
|
||||
std::unique_ptr<CellInfo> packed = create_machxo2_cell(ctx, id_TRELLIS_SLICE, ci->name.str(ctx) + "_LC");
|
||||
for (auto &attr : ci->attrs)
|
||||
packed->attrs[attr.first] = attr.second;
|
||||
|
||||
@ -100,7 +100,7 @@ static void pack_remaining_ffs(Context *ctx)
|
||||
if (ctx->verbose)
|
||||
log_info("cell '%s' of type '%s remains unpacked'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
|
||||
|
||||
std::unique_ptr<CellInfo> packed = create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC");
|
||||
std::unique_ptr<CellInfo> packed = create_machxo2_cell(ctx, id_TRELLIS_SLICE, ci->name.str(ctx) + "_LC");
|
||||
for (auto &attr : ci->attrs)
|
||||
packed->attrs[attr.first] = attr.second;
|
||||
|
||||
@ -141,10 +141,10 @@ static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, boo
|
||||
if (ctx->verbose)
|
||||
log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx));
|
||||
|
||||
if (uc->type == id_FACADE_FF && user.port == id_DI) {
|
||||
log_info("FACADE_FF %s is driven by a constant\n", uc->name.c_str(ctx));
|
||||
if (uc->type == id_TRELLIS_FF && user.port == id_DI) {
|
||||
log_info("TRELLIS_FF %s is driven by a constant\n", uc->name.c_str(ctx));
|
||||
|
||||
std::unique_ptr<CellInfo> lc = create_machxo2_cell(ctx, id_FACADE_SLICE, uc->name.str(ctx) + "_CONST");
|
||||
std::unique_ptr<CellInfo> lc = create_machxo2_cell(ctx, id_TRELLIS_SLICE, uc->name.str(ctx) + "_CONST");
|
||||
for (auto &attr : uc->attrs)
|
||||
lc->attrs[attr.first] = attr.second;
|
||||
|
||||
@ -179,7 +179,7 @@ static void pack_constants(Context *ctx)
|
||||
{
|
||||
log_info("Packing constants..\n");
|
||||
|
||||
std::unique_ptr<CellInfo> const_cell = create_machxo2_cell(ctx, id_FACADE_SLICE, "$PACKER_CONST");
|
||||
std::unique_ptr<CellInfo> const_cell = create_machxo2_cell(ctx, id_TRELLIS_SLICE, "$PACKER_CONST");
|
||||
const_cell->params[id_LUT0_INITVAL] = Property(0, 16);
|
||||
const_cell->params[id_LUT1_INITVAL] = Property(0xFFFF, 16);
|
||||
|
||||
@ -224,9 +224,9 @@ static bool is_nextpnr_iob(Context *ctx, CellInfo *cell)
|
||||
cell->type == ctx->id("$nextpnr_iobuf");
|
||||
}
|
||||
|
||||
static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cell->type == id_FACADE_IO; }
|
||||
static bool is_trellis_iob(const Context *ctx, const CellInfo *cell) { return cell->type == id_TRELLIS_IO; }
|
||||
|
||||
static bool nextpnr_iob_connects_only_facade_iob(Context *ctx, CellInfo *iob, NetInfo *&top)
|
||||
static bool nextpnr_iob_connects_only_trellis_iob(Context *ctx, CellInfo *iob, NetInfo *&top)
|
||||
{
|
||||
NPNR_ASSERT(is_nextpnr_iob(ctx, iob));
|
||||
|
||||
@ -234,18 +234,18 @@ static bool nextpnr_iob_connects_only_facade_iob(Context *ctx, CellInfo *iob, Ne
|
||||
NetInfo *o = iob->ports.at(id_O).net;
|
||||
top = o;
|
||||
|
||||
CellInfo *fio = net_only_drives(ctx, o, is_facade_iob, id_PAD, true);
|
||||
CellInfo *fio = net_only_drives(ctx, o, is_trellis_iob, id_B, true);
|
||||
return fio != nullptr;
|
||||
} else if (iob->type == ctx->id("$nextpnr_obuf")) {
|
||||
NetInfo *i = iob->ports.at(id_I).net;
|
||||
top = i;
|
||||
|
||||
// If connected to a FACADE_IO PAD, the net attached to an I port of an
|
||||
// If connected to a TRELLIS_IO PAD, the net attached to an I port of an
|
||||
// $nextpnr_obuf will not have a driver, only users; an inout port
|
||||
// like PAD cannot be a driver in nextpnr. So net_driven_by won't
|
||||
// return anything. We exclude the IOB as one of the two users because
|
||||
// we already know that the net drives the $nextpnr_obuf.
|
||||
CellInfo *fio = net_only_drives(ctx, i, is_facade_iob, id_PAD, true, iob);
|
||||
CellInfo *fio = net_only_drives(ctx, i, is_trellis_iob, id_B, true, iob);
|
||||
return fio != nullptr;
|
||||
} else if (iob->type == ctx->id("$nextpnr_iobuf")) {
|
||||
NetInfo *o = iob->ports.at(id_O).net;
|
||||
@ -254,10 +254,10 @@ static bool nextpnr_iob_connects_only_facade_iob(Context *ctx, CellInfo *iob, Ne
|
||||
// When split_io is enabled in a frontend (it is for JSON), the I and O
|
||||
// ports of a $nextpnr_iobuf are split; the I port connects to the
|
||||
// driver of the original net before IOB insertion, and the O port
|
||||
// connects everything else. Because FACADE_IO PADs cannot be a driver
|
||||
// connects everything else. Because TRELLIS_IO PADs cannot be a driver
|
||||
// in nextpnr, the we can safely ignore the I port of an $nextpnr_iobuf
|
||||
// for any JSON input we're interested in accepting.
|
||||
CellInfo *fio_o = net_only_drives(ctx, o, is_facade_iob, id_PAD, true);
|
||||
CellInfo *fio_o = net_only_drives(ctx, o, is_trellis_iob, id_B, true);
|
||||
return fio_o != nullptr;
|
||||
}
|
||||
|
||||
@ -266,7 +266,7 @@ static bool nextpnr_iob_connects_only_facade_iob(Context *ctx, CellInfo *iob, Ne
|
||||
}
|
||||
|
||||
// Pack IO buffers- Right now, all this does is remove $nextpnr_[io]buf cells.
|
||||
// User is expected to manually instantiate FACADE_IO with BEL/IO_TYPE
|
||||
// User is expected to manually instantiate TRELLIS_IO with BEL/IO_TYPE
|
||||
// attributes.
|
||||
static void pack_io(Context *ctx)
|
||||
{
|
||||
@ -279,8 +279,8 @@ static void pack_io(Context *ctx)
|
||||
if (is_nextpnr_iob(ctx, ci)) {
|
||||
NetInfo *top;
|
||||
|
||||
if (!nextpnr_iob_connects_only_facade_iob(ctx, ci, top))
|
||||
log_error("Top level net '%s' is not connected to a FACADE_IO PAD port.\n", top->name.c_str(ctx));
|
||||
if (!nextpnr_iob_connects_only_trellis_iob(ctx, ci, top))
|
||||
log_error("Top level net '%s' is not connected to a TRELLIS_IO PAD port.\n", top->name.c_str(ctx));
|
||||
|
||||
if (ctx->verbose)
|
||||
log_info("Removing top-level IOBUF '%s' of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
|
||||
@ -288,11 +288,11 @@ static void pack_io(Context *ctx)
|
||||
for (auto &p : ci->ports)
|
||||
ci->disconnectPort(p.first);
|
||||
packed_cells.insert(ci->name);
|
||||
} else if (is_facade_iob(ctx, ci)) {
|
||||
// If FACADE_IO has LOC attribute, convert the LOC (pin) to a BEL
|
||||
// attribute and place FACADE_IO at resulting BEL location. A BEL
|
||||
// attribute already on a FACADE_IO is an error. Attributes on
|
||||
// the pin attached to the PAD of FACADE_IO are ignored by this
|
||||
} else if (is_trellis_iob(ctx, ci)) {
|
||||
// If TRELLIS_IO has LOC attribute, convert the LOC (pin) to a BEL
|
||||
// attribute and place TRELLIS_IO at resulting BEL location. A BEL
|
||||
// attribute already on a TRELLIS_IO is an error. Attributes on
|
||||
// the pin attached to the PAD of TRELLIS_IO are ignored by this
|
||||
// packing phase.
|
||||
auto loc_attr_cell = ci->attrs.find(id_LOC);
|
||||
auto bel_attr_cell = ci->attrs.find(id_BEL);
|
||||
|
Loading…
Reference in New Issue
Block a user