diff --git a/.github/workflows/interchange_ci.yml b/.github/workflows/interchange_ci.yml index 31036465..e8f1c153 100644 --- a/.github/workflows/interchange_ci.yml +++ b/.github/workflows/interchange_ci.yml @@ -108,7 +108,7 @@ jobs: env: RAPIDWRIGHT_PATH: ${{ github.workspace }}/RapidWright PYTHON_INTERCHANGE_PATH: ${{ github.workspace }}/python-fpga-interchange - PYTHON_INTERCHANGE_TAG: v0.0.9 + PYTHON_INTERCHANGE_TAG: v0.0.10 PRJOXIDE_REVISION: a85135648c3ef2f7b3fd53ae2187ef6460e34b16 DEVICE: ${{ matrix.device }} run: | diff --git a/3rdparty/fpga-interchange-schema b/3rdparty/fpga-interchange-schema index 8ec5b173..5208d794 160000 --- a/3rdparty/fpga-interchange-schema +++ b/3rdparty/fpga-interchange-schema @@ -1 +1 @@ -Subproject commit 8ec5b1739d7b91b84df3e92ccc70c7a7ee644089 +Subproject commit 5208d794d318e9151b93120d7e5ba75d8aef45e7 diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc index c1446245..441c2e1f 100644 --- a/fpga_interchange/arch.cc +++ b/fpga_interchange/arch.cc @@ -727,6 +727,7 @@ bool Arch::pack() decode_lut_cells(); merge_constant_nets(); pack_ports(); + pack_default_conns(); return true; } @@ -1984,6 +1985,58 @@ DelayQuad Arch::getPipDelay(PipId pip) const return DelayQuad(100 * (1 + pip_data.pseudo_cell_wires.size())); } +const DefaultCellConnsPOD *Arch::get_default_conns(IdString cell_type) const +{ + for (const auto &conn : chip_info->constants->default_conns) { + if (IdString(conn.cell_type) == cell_type) + return &conn; + } + return nullptr; +} + +void Arch::pack_default_conns() +{ + IdString vcc_net_name(chip_info->constants->vcc_net_name); + IdString gnd_net_name(chip_info->constants->gnd_net_name); + Context *ctx = getCtx(); + + std::vector dead_nets; + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + const DefaultCellConnsPOD *conns = get_default_conns(ci->type); + if (conns == nullptr) + continue; + for (const auto &pin : conns->pins) { + IdString pin_name(pin.pin_name); + // pin missing, create it + if (!ci->ports.count(pin_name)) + ci->addInput(pin_name); + const NetInfo *net = ci->ports.at(pin_name).net; + if (net != nullptr) { + // pin is connected, and driven, nothing to do + if (net->driver.cell != nullptr) + continue; + // pin is connected but undriven, disconnect the existing net + ctx->disconnectPort(ci->name, pin_name); + // remove net if it has no remaining users + if (net->users.empty()) + dead_nets.push_back(net->name); + } + if (pin.value == PIN_VALUE_GND) + ctx->connectPort(gnd_net_name, ci->name, pin_name); + else if (pin.value == PIN_VALUE_VCC) + ctx->connectPort(vcc_net_name, ci->name, pin_name); + else + NPNR_ASSERT(pin.value == PIN_VALUE_FLOAT); + } + } + + // Remove any left-behind nets with no users and no drivers + for (auto net : dead_nets) + ctx->nets.erase(net); +} + // Instance constraint templates. template void Arch::ArchConstraints::bindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange); template void Arch::ArchConstraints::unbindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange); diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h index 9b369c92..da620699 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -1100,6 +1100,9 @@ struct Arch : ArchAPI void unmask_bel_pins(); void explain_bel_status(BelId bel) const; + + const DefaultCellConnsPOD *get_default_conns(IdString cell_type) const; + void pack_default_conns(); }; NEXTPNR_NAMESPACE_END diff --git a/fpga_interchange/chipdb.h b/fpga_interchange/chipdb.h index 6c7b8c83..b66640e3 100644 --- a/fpga_interchange/chipdb.h +++ b/fpga_interchange/chipdb.h @@ -34,7 +34,7 @@ NEXTPNR_NAMESPACE_BEGIN * kExpectedChipInfoVersion */ -static constexpr int32_t kExpectedChipInfoVersion = 6; +static constexpr int32_t kExpectedChipInfoVersion = 7; // Flattened site indexing. // @@ -255,6 +255,26 @@ NPNR_PACKED_STRUCT(struct PackagePOD { RelSlice pins; }); +enum CellPinValue +{ + // leave floating + PIN_VALUE_FLOAT = 0, + // connect to ground + PIN_VALUE_GND = 1, + // connect to vcc + PIN_VALUE_VCC = 2, +}; + +NPNR_PACKED_STRUCT(struct DefaultCellConnPOD { + int32_t pin_name; // constid + int32_t value; // CellPinValue +}); + +NPNR_PACKED_STRUCT(struct DefaultCellConnsPOD { + int32_t cell_type; // constid + RelSlice pins; +}); + NPNR_PACKED_STRUCT(struct ConstantsPOD { // Cell type and port for the GND and VCC global source. int32_t gnd_cell_name; // constid @@ -280,6 +300,9 @@ NPNR_PACKED_STRUCT(struct ConstantsPOD { // If a choice is available, which constant net should be used? // Can be ''/0 if either constant net are equivilent. int32_t best_constant_net; // constid + + // Default cell pin connections + RelSlice default_conns; }); NPNR_PACKED_STRUCT(struct ChipInfoPOD { diff --git a/fpga_interchange/fpga_interchange.cpp b/fpga_interchange/fpga_interchange.cpp index 52d49fa2..60331382 100644 --- a/fpga_interchange/fpga_interchange.cpp +++ b/fpga_interchange/fpga_interchange.cpp @@ -1065,12 +1065,6 @@ ModuleReader::ModuleReader(const LogicalNetlistImpl *root, if(iter == net_indicies.end()) { PortKey port_key = port_connections.first; auto port = ports[port_key.port_idx]; - if(port_key.inst_idx != -1 && port.getDir() != LogicalNetlist::Netlist::Direction::OUTPUT) { - log_error("Cell instance %s port %s is disconnected!\n", - root->strings.at(root->root.getInstList()[port_key.inst_idx].getName()).c_str(), - root->strings.at(ports[port_key.port_idx].getName()).c_str() - ); - } disconnected_nets[net_idx] = stringf("%s.%d", root->strings.at(port.getName()).c_str(), i); } }