nexus: Add constant/inversion packing
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
1bb509897c
commit
da1e3c8612
@ -785,17 +785,19 @@ enum CellPinStyle
|
|||||||
|
|
||||||
PINBIT_GATED = 0x1000, // pin must be enabled in bitstream if used
|
PINBIT_GATED = 0x1000, // pin must be enabled in bitstream if used
|
||||||
PINBIT_1 = 0x2000, // pin has an explicit bit that must be set if tied to 1
|
PINBIT_1 = 0x2000, // pin has an explicit bit that must be set if tied to 1
|
||||||
|
PINBIT_CIBMUX = 0x4000, // pin's CIBMUX must be floating for pin to be 1
|
||||||
|
|
||||||
PINSTYLE_NONE = 0x0000, // default
|
PINSTYLE_NONE = 0x0000, // default
|
||||||
PINSTYLE_CIB = 0x0012, // 'CIB' signal, floats high but explicitly zeroed if not used
|
PINSTYLE_CIB = 0x4012, // 'CIB' signal, floats high but explicitly zeroed if not used
|
||||||
PINSTYLE_CLK = 0x0107, // CLK type signal, invertible and defaults to disconnected
|
PINSTYLE_CLK = 0x0107, // CLK type signal, invertible and defaults to disconnected
|
||||||
PINSTYLE_CE = 0x0027, // CE type signal, invertible and defaults to enabled
|
PINSTYLE_CE = 0x0027, // CE type signal, invertible and defaults to enabled
|
||||||
PINSTYLE_LSR = 0x0017, // LSR type signal, invertible and defaults to not reset
|
PINSTYLE_LSR = 0x0017, // LSR type signal, invertible and defaults to not reset
|
||||||
PINSTYLE_DEDI = 0x0000, // dedicated signals, leave alone
|
PINSTYLE_DEDI = 0x0000, // dedicated signals, leave alone
|
||||||
PINSTYLE_PU = 0x0022, // signals that float high and default high
|
PINSTYLE_PU = 0x4022, // signals that float high and default high
|
||||||
|
PINSTYLE_T = 0x4027, // PIO 'T' signal
|
||||||
|
|
||||||
PINSTYLE_INV_PD = 0x0017, // invertible, pull down by default
|
PINSTYLE_INV_PD = 0x0017, // invertible, pull down by default
|
||||||
PINSTYLE_INV_PU = 0x0027, // invertible, pull up by default
|
PINSTYLE_INV_PU = 0x4027, // invertible, pull up by default
|
||||||
|
|
||||||
PINSTYLE_IOL_CE = 0x2027, // CE type signal, with explicit 'const-1' config bit
|
PINSTYLE_IOL_CE = 0x2027, // CE type signal, with explicit 'const-1' config bit
|
||||||
PINSTYLE_GATE = 0x1011, // gated signal that defaults to 0
|
PINSTYLE_GATE = 0x1011, // gated signal that defaults to 0
|
||||||
|
@ -170,7 +170,7 @@ struct NexusFasmWriter
|
|||||||
std::string tile = tile_name(pip.tile, tile_by_type_and_loc(pip.tile, pd.tile_type));
|
std::string tile = tile_name(pip.tile, tile_by_type_and_loc(pip.tile, pd.tile_type));
|
||||||
std::string source_wire = escape_name(ctx->pip_src_wire_name(pip).str(ctx));
|
std::string source_wire = escape_name(ctx->pip_src_wire_name(pip).str(ctx));
|
||||||
std::string dest_wire = escape_name(ctx->pip_dst_wire_name(pip).str(ctx));
|
std::string dest_wire = escape_name(ctx->pip_dst_wire_name(pip).str(ctx));
|
||||||
write_bit(stringf("%s.PIP.%s.%s", tile.c_str(), dest_wire.c_str(), source_wire.c_str()));
|
out << stringf("%s.PIP.%s.%s", tile.c_str(), dest_wire.c_str(), source_wire.c_str()) << std::endl;
|
||||||
}
|
}
|
||||||
// Write out all the pips corresponding to a net
|
// Write out all the pips corresponding to a net
|
||||||
void write_net(const NetInfo *net)
|
void write_net(const NetInfo *net)
|
||||||
@ -184,6 +184,25 @@ struct NexusFasmWriter
|
|||||||
write_pip(p);
|
write_pip(p);
|
||||||
blank();
|
blank();
|
||||||
}
|
}
|
||||||
|
// Find the CIBMUX output for a signal
|
||||||
|
WireId find_cibmux(const CellInfo *cell, IdString pin)
|
||||||
|
{
|
||||||
|
WireId cursor = ctx->getBelPinWire(cell->bel, pin);
|
||||||
|
if (cursor == WireId())
|
||||||
|
return WireId();
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
std::string cursor_name = IdString(ctx->wire_data(cursor).name).str(ctx);
|
||||||
|
if (cursor_name.find("JCIBMUXOUT") == 0) {
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
for (PipId pip : ctx->getPipsUphill(cursor))
|
||||||
|
if (ctx->checkPipAvail(pip)) {
|
||||||
|
cursor = ctx->getPipSrcWire(pip);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return WireId();
|
||||||
|
}
|
||||||
// Write out the mux config for a cell
|
// Write out the mux config for a cell
|
||||||
void write_cell_muxes(const CellInfo *cell)
|
void write_cell_muxes(const CellInfo *cell)
|
||||||
{
|
{
|
||||||
@ -206,8 +225,26 @@ struct NexusFasmWriter
|
|||||||
// Pins that must be explictly set to 1 rather than just left floating
|
// Pins that must be explictly set to 1 rather than just left floating
|
||||||
if ((pin_style & PINBIT_1) && (pin_mux == PINMUX_1))
|
if ((pin_style & PINBIT_1) && (pin_mux == PINMUX_1))
|
||||||
write_bit(stringf("%sMUX.1", ctx->nameOf(port.first)));
|
write_bit(stringf("%sMUX.1", ctx->nameOf(port.first)));
|
||||||
|
// Handle CIB muxes - these must be set such that floating pins really are floating to VCC and not connected
|
||||||
|
// to another CIB signal
|
||||||
|
if ((pin_style & PINBIT_CIBMUX) && port.second.net == nullptr) {
|
||||||
|
WireId cibmuxout = find_cibmux(cell, port.first);
|
||||||
|
if (cibmuxout != WireId()) {
|
||||||
|
write_comment(stringf("CIBMUX for unused pin %s", ctx->nameOf(port.first)));
|
||||||
|
bool found = false;
|
||||||
|
for (PipId pip : ctx->getPipsUphill(cibmuxout)) {
|
||||||
|
if (ctx->checkPipAvail(pip) && ctx->checkWireAvail(ctx->getPipSrcWire(pip))) {
|
||||||
|
write_pip(pip);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NPNR_ASSERT(found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Write config for an OXIDE_COMB cell
|
// Write config for an OXIDE_COMB cell
|
||||||
void write_comb(const CellInfo *cell)
|
void write_comb(const CellInfo *cell)
|
||||||
{
|
{
|
||||||
@ -244,10 +281,7 @@ struct NexusFasmWriter
|
|||||||
pop();
|
pop();
|
||||||
write_enum(cell, "REGDDR");
|
write_enum(cell, "REGDDR");
|
||||||
write_enum(cell, "SRMODE");
|
write_enum(cell, "SRMODE");
|
||||||
write_enum(cell, "CLKMUX");
|
write_cell_muxes(cell);
|
||||||
write_enum(cell, "CEMUX");
|
|
||||||
write_enum(cell, "LSRMUX");
|
|
||||||
write_enum(cell, "GSR");
|
|
||||||
pop(2);
|
pop(2);
|
||||||
}
|
}
|
||||||
// Write config for an SEIO33_CORE cell
|
// Write config for an SEIO33_CORE cell
|
||||||
@ -267,6 +301,7 @@ struct NexusFasmWriter
|
|||||||
const char *iodir = is_input ? "INPUT" : (is_output ? "OUTPUT" : "BIDIR");
|
const char *iodir = is_input ? "INPUT" : (is_output ? "OUTPUT" : "BIDIR");
|
||||||
write_bit(stringf("BASE_TYPE.%s_%s", iodir, str_or_default(cell->attrs, id_IO_TYPE, "LVCMOS33").c_str()));
|
write_bit(stringf("BASE_TYPE.%s_%s", iodir, str_or_default(cell->attrs, id_IO_TYPE, "LVCMOS33").c_str()));
|
||||||
write_ioattr(cell, "PULLMODE", "NONE");
|
write_ioattr(cell, "PULLMODE", "NONE");
|
||||||
|
write_cell_muxes(cell);
|
||||||
pop(2);
|
pop(2);
|
||||||
}
|
}
|
||||||
// Write config for an SEIO18_CORE cell
|
// Write config for an SEIO18_CORE cell
|
||||||
@ -287,6 +322,7 @@ struct NexusFasmWriter
|
|||||||
const char *iodir = is_input ? "INPUT" : (is_output ? "OUTPUT" : "BIDIR");
|
const char *iodir = is_input ? "INPUT" : (is_output ? "OUTPUT" : "BIDIR");
|
||||||
write_bit(stringf("BASE_TYPE.%s_%s", iodir, str_or_default(cell->attrs, id_IO_TYPE, "LVCMOS18H").c_str()));
|
write_bit(stringf("BASE_TYPE.%s_%s", iodir, str_or_default(cell->attrs, id_IO_TYPE, "LVCMOS18H").c_str()));
|
||||||
write_ioattr(cell, "PULLMODE", "NONE");
|
write_ioattr(cell, "PULLMODE", "NONE");
|
||||||
|
write_cell_muxes(cell);
|
||||||
pop(3);
|
pop(3);
|
||||||
}
|
}
|
||||||
// Write config for an OSC_CORE cell
|
// Write config for an OSC_CORE cell
|
||||||
@ -302,6 +338,7 @@ struct NexusFasmWriter
|
|||||||
write_enum(cell, "LF_OUTPUT_EN");
|
write_enum(cell, "LF_OUTPUT_EN");
|
||||||
write_enum(cell, "DEBUG_N", "DISABLED");
|
write_enum(cell, "DEBUG_N", "DISABLED");
|
||||||
write_int_vector(stringf("HF_CLK_DIV[7:0]"), ctx->parse_lattice_param(cell, id_HF_CLK_DIV, 8, 0).intval, 8);
|
write_int_vector(stringf("HF_CLK_DIV[7:0]"), ctx->parse_lattice_param(cell, id_HF_CLK_DIV, 8, 0).intval, 8);
|
||||||
|
write_cell_muxes(cell);
|
||||||
pop(2);
|
pop(2);
|
||||||
}
|
}
|
||||||
// Write out FASM for the whole design
|
// Write out FASM for the whole design
|
||||||
|
@ -321,7 +321,12 @@ struct NexusPacker
|
|||||||
{
|
{
|
||||||
NetInfo *net = get_net_or_empty(cell, port);
|
NetInfo *net = get_net_or_empty(cell, port);
|
||||||
if (net == nullptr || net->driver.cell == nullptr) {
|
if (net == nullptr || net->driver.cell == nullptr) {
|
||||||
// Pin is disconnected, return its default value
|
// Pin is disconnected
|
||||||
|
// If a mux value exists already, honour it
|
||||||
|
CellPinMux exist_mux = ctx->get_cell_pinmux(cell, port);
|
||||||
|
if (exist_mux != PINMUX_SIG)
|
||||||
|
return exist_mux;
|
||||||
|
// Otherwise, look up the default value and use that
|
||||||
CellPinStyle pin_style = ctx->get_cell_pin_style(cell, port);
|
CellPinStyle pin_style = ctx->get_cell_pin_style(cell, port);
|
||||||
if ((pin_style & PINDEF_MASK) == PINDEF_0)
|
if ((pin_style & PINDEF_MASK) == PINDEF_0)
|
||||||
return PINMUX_0;
|
return PINMUX_0;
|
||||||
@ -434,7 +439,7 @@ struct NexusPacker
|
|||||||
|
|
||||||
if (req_mux == PINMUX_INV) {
|
if (req_mux == PINMUX_INV) {
|
||||||
// Pin is inverted. If there is a hard inverter; then use it
|
// Pin is inverted. If there is a hard inverter; then use it
|
||||||
if ((pin_style & PINOPT_MASK) == PINOPT_INV) {
|
if (pin_style & PINOPT_INV) {
|
||||||
uninvert_port(cell, port_name);
|
uninvert_port(cell, port_name);
|
||||||
ctx->set_cell_pinmux(cell, port_name, PINMUX_INV);
|
ctx->set_cell_pinmux(cell, port_name, PINMUX_INV);
|
||||||
}
|
}
|
||||||
@ -624,13 +629,30 @@ struct NexusPacker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pack_constants()
|
||||||
|
{
|
||||||
|
// Make sure we have high and low nets available
|
||||||
|
get_const_net(id_VHI);
|
||||||
|
get_const_net(id_VLO);
|
||||||
|
// Iterate through cells
|
||||||
|
for (auto cell : sorted(ctx->cells)) {
|
||||||
|
CellInfo *ci = cell.second;
|
||||||
|
// Skip certain cells at this point
|
||||||
|
if (ci->type != id_LUT4 && ci->type != id_INV && ci->type != id_VHI && ci->type != id_VLO)
|
||||||
|
process_inv_constants(cell.second);
|
||||||
|
}
|
||||||
|
// Remove superfluous inverters and constant drivers
|
||||||
|
trim_design();
|
||||||
|
}
|
||||||
|
|
||||||
explicit NexusPacker(Context *ctx) : ctx(ctx) {}
|
explicit NexusPacker(Context *ctx) : ctx(ctx) {}
|
||||||
|
|
||||||
void operator()()
|
void operator()()
|
||||||
{
|
{
|
||||||
pack_ffs();
|
|
||||||
pack_luts();
|
|
||||||
pack_io();
|
pack_io();
|
||||||
|
pack_ffs();
|
||||||
|
pack_constants();
|
||||||
|
pack_luts();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,15 +48,15 @@ static const std::unordered_map<IdString, Arch::CellPinsData> base_cell_pin_data
|
|||||||
}},
|
}},
|
||||||
{id_SEIO18_CORE,
|
{id_SEIO18_CORE,
|
||||||
{
|
{
|
||||||
{id_T, PINSTYLE_CE},
|
{id_T, PINSTYLE_T},
|
||||||
{id_B, PINSTYLE_DEDI},
|
{id_B, PINSTYLE_DEDI},
|
||||||
{{}, PINSTYLE_INV_PU},
|
{{}, PINSTYLE_PU},
|
||||||
}},
|
}},
|
||||||
{id_SEIO33_CORE,
|
{id_SEIO33_CORE,
|
||||||
{
|
{
|
||||||
{id_T, PINSTYLE_CE},
|
{id_T, PINSTYLE_T},
|
||||||
{id_B, PINSTYLE_DEDI},
|
{id_B, PINSTYLE_DEDI},
|
||||||
{{}, PINSTYLE_INV_PU},
|
{{}, PINSTYLE_PU},
|
||||||
}},
|
}},
|
||||||
{id_OXIDE_EBR, {{id_CLKA, PINSTYLE_CLK}, {id_CLKB, PINSTYLE_CLK}, {id_CEA, PINSTYLE_CE},
|
{id_OXIDE_EBR, {{id_CLKA, PINSTYLE_CLK}, {id_CLKB, PINSTYLE_CLK}, {id_CEA, PINSTYLE_CE},
|
||||||
{id_CEB, PINSTYLE_CE}, {id_CSA0, PINSTYLE_PU}, {id_CSA1, PINSTYLE_PU},
|
{id_CEB, PINSTYLE_CE}, {id_CSA0, PINSTYLE_PU}, {id_CSA1, PINSTYLE_PU},
|
||||||
|
Loading…
Reference in New Issue
Block a user