aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fpga_interchange/arch.cc187
-rw-r--r--fpga_interchange/arch.h4
-rw-r--r--fpga_interchange/archdefs.h1
-rw-r--r--fpga_interchange/examples/template.mk18
-rw-r--r--fpga_interchange/examples/wire/wire.xdc3
-rw-r--r--fpga_interchange/fpga_interchange.cpp13
6 files changed, 218 insertions, 8 deletions
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc
index 0955c376..966d74f3 100644
--- a/fpga_interchange/arch.cc
+++ b/fpga_interchange/arch.cc
@@ -606,6 +606,7 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
bool Arch::pack()
{
+ merge_constant_nets();
pack_ports();
return true;
}
@@ -754,7 +755,7 @@ const std::vector<std::string> Arch::availablePlacers = {"sa",
const std::string Arch::defaultRouter = "router2";
const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};
-void Arch::map_cell_pins(CellInfo *cell, int32_t mapping) const
+void Arch::map_cell_pins(CellInfo *cell, int32_t mapping)
{
cell->cell_mapping = mapping;
cell->cell_bel_pins.clear();
@@ -766,11 +767,32 @@ void Arch::map_cell_pins(CellInfo *cell, int32_t mapping) const
IdString bel_pin(pin_map.bel_pin);
if (cell_pin.str(this) == "GND") {
- // FIXME: Tie this pin to the GND net
+ PortInfo port_info;
+ port_info.name = bel_pin;
+ port_info.type = PORT_IN;
+ port_info.net = nullptr;
+
+ auto result = cell->ports.emplace(bel_pin, port_info);
+ NPNR_ASSERT(result.second);
+
+ cell->cell_bel_pins[bel_pin].push_back(bel_pin);
+
+ connectPort(IdString(chip_info->constants->gnd_net_name), cell->name, bel_pin);
continue;
}
+
if (cell_pin.str(this) == "VCC") {
- // FIXME: Tie this pin to the VCC net
+ PortInfo port_info;
+ port_info.name = bel_pin;
+ port_info.type = PORT_IN;
+ port_info.net = nullptr;
+
+ auto result = cell->ports.emplace(bel_pin, port_info);
+ NPNR_ASSERT(result.second);
+
+ cell->cell_bel_pins[bel_pin].push_back(bel_pin);
+
+ connectPort(IdString(chip_info->constants->vcc_net_name), cell->name, bel_pin);
continue;
}
@@ -795,11 +817,30 @@ void Arch::map_cell_pins(CellInfo *cell, int32_t mapping) const
IdString bel_pin(pin_map.bel_pin);
if (cell_pin.str(this) == "GND") {
- // FIXME: Tie this pin to the GND net
+ PortInfo port_info;
+ port_info.name = bel_pin;
+ port_info.type = PORT_IN;
+
+ auto result = cell->ports.emplace(bel_pin, port_info);
+ NPNR_ASSERT(result.second);
+
+ cell->cell_bel_pins[bel_pin].push_back(bel_pin);
+
+ connectPort(IdString(chip_info->constants->gnd_net_name), cell->name, bel_pin);
continue;
}
+
if (cell_pin.str(this) == "VCC") {
- // FIXME: Tie this pin to the VCC net
+ PortInfo port_info;
+ port_info.name = bel_pin;
+ port_info.type = PORT_IN;
+
+ auto result = cell->ports.emplace(bel_pin, port_info);
+ NPNR_ASSERT(result.second);
+
+ cell->cell_bel_pins[bel_pin].push_back(bel_pin);
+
+ connectPort(IdString(chip_info->constants->vcc_net_name), cell->name, bel_pin);
continue;
}
@@ -858,6 +899,142 @@ size_t Arch::get_cell_type_index(IdString cell_type) const
return cell_offset;
}
+void Arch::merge_constant_nets() {
+ NetInfo* gnd_net = nullptr;
+ NetInfo* vcc_net = nullptr;
+
+ bool need_gnd_source = false;
+ bool need_vcc_source = false;
+
+ IdString gnd_net_name(chip_info->constants->gnd_net_name);
+ IdString gnd_cell_type(chip_info->constants->gnd_cell_name);
+ IdString gnd_cell_port(chip_info->constants->gnd_cell_port);
+
+ auto gnd_iter = nets.find(gnd_net_name);
+ if(gnd_iter != nets.end()) {
+ NPNR_ASSERT(gnd_iter->second->driver.cell != nullptr);
+ NPNR_ASSERT(gnd_iter->second->driver.cell->type == gnd_cell_type);
+ NPNR_ASSERT(gnd_iter->second->driver.port == gnd_cell_port);
+
+ gnd_net = gnd_iter->second.get();
+ } else {
+ gnd_net = createNet(gnd_net_name);
+ need_gnd_source = true;
+ }
+
+ IdString vcc_net_name(chip_info->constants->vcc_net_name);
+ IdString vcc_cell_type(chip_info->constants->vcc_cell_name);
+ IdString vcc_cell_port(chip_info->constants->vcc_cell_port);
+
+ auto vcc_iter = nets.find(vcc_net_name);
+ if(vcc_iter != nets.end()) {
+ NPNR_ASSERT(vcc_iter->second->driver.cell != nullptr);
+ NPNR_ASSERT(vcc_iter->second->driver.cell->type == vcc_cell_type);
+ NPNR_ASSERT(vcc_iter->second->driver.port == vcc_cell_port);
+
+ vcc_net = vcc_iter->second.get();
+ } else {
+ vcc_net = createNet(vcc_net_name);
+ need_vcc_source = true;
+ }
+
+ std::vector<IdString> other_gnd_nets;
+ std::vector<IdString> other_vcc_nets;
+
+ for(auto & net_pair : nets) {
+ if(net_pair.first == gnd_net_name) {
+ NPNR_ASSERT(net_pair.second.get() == gnd_net);
+ continue;
+ }
+
+ if(net_pair.first == vcc_net_name) {
+ NPNR_ASSERT(net_pair.second.get() == vcc_net);
+ continue;
+ }
+
+ NetInfo *net = net_pair.second.get();
+ if(net->driver.cell == nullptr) {
+ continue;
+ }
+
+ if(net->driver.cell->type == gnd_cell_type) {
+ NPNR_ASSERT(net->driver.port == gnd_cell_port);
+
+ other_gnd_nets.push_back(net_pair.first);
+
+ if(need_gnd_source) {
+ IdString driver_cell = net->driver.cell->name;
+ disconnectPort(driver_cell, gnd_cell_port);
+ connectPort(gnd_net_name, driver_cell, gnd_cell_port);
+ need_gnd_source = false;
+ }
+
+ NPNR_ASSERT(net->driver.port == gnd_cell_port);
+ std::vector<PortRef> users_copy = net->users;
+ for(const PortRef & port_ref : users_copy) {
+ IdString cell = port_ref.cell->name;
+ disconnectPort(cell, port_ref.port);
+ connectPort(gnd_net_name, cell, port_ref.port);
+ }
+ }
+
+ if(net->driver.cell->type == vcc_cell_type) {
+ NPNR_ASSERT(net->driver.port == vcc_cell_port);
+
+ other_vcc_nets.push_back(net_pair.first);
+
+ if(need_vcc_source) {
+ IdString driver_cell = net->driver.cell->name;
+ disconnectPort(driver_cell, vcc_cell_port);
+ connectPort(vcc_net_name, driver_cell, vcc_cell_port);
+ need_vcc_source = false;
+ }
+
+ NPNR_ASSERT(net->driver.port == vcc_cell_port);
+ std::vector<PortRef> users_copy = net->users;
+ for(const PortRef & port_ref : users_copy) {
+ IdString cell = port_ref.cell->name;
+ disconnectPort(cell, port_ref.port);
+ connectPort(vcc_net_name, cell, port_ref.port);
+ }
+ }
+ }
+
+ for(IdString other_gnd_net : other_gnd_nets) {
+ NetInfo * net = getNetByAlias(other_gnd_net);
+ NPNR_ASSERT(net->users.empty());
+ }
+
+ for(IdString other_vcc_net : other_vcc_nets) {
+ NetInfo * net = getNetByAlias(other_vcc_net);
+ NPNR_ASSERT(net->users.empty());
+ }
+
+ for(IdString other_gnd_net : other_gnd_nets) {
+ NPNR_ASSERT(nets.erase(other_gnd_net));
+ gnd_net->aliases.push_back(other_gnd_net);
+ net_aliases[other_gnd_net] = gnd_net_name;
+ }
+
+ for(IdString other_vcc_net : other_vcc_nets) {
+ NPNR_ASSERT(nets.erase(other_vcc_net));
+ vcc_net->aliases.push_back(other_vcc_net);
+ net_aliases[other_vcc_net] = vcc_net_name;
+ }
+
+ if(need_gnd_source) {
+ CellInfo * gnd_cell = createCell(gnd_cell_type, gnd_cell_type);
+ gnd_cell->addOutput(gnd_cell_port);
+ connectPort(gnd_net_name, gnd_cell_type, gnd_cell_port);
+ }
+
+ if(need_vcc_source) {
+ CellInfo * vcc_cell = createCell(vcc_cell_type, vcc_cell_type);
+ vcc_cell->addOutput(vcc_cell_port);
+ connectPort(vcc_net_name, vcc_cell_type, vcc_cell_port);
+ }
+}
+
// 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 780382ec..c713ddb9 100644
--- a/fpga_interchange/arch.h
+++ b/fpga_interchange/arch.h
@@ -871,7 +871,7 @@ struct Arch : ArchAPI<ArchRanges>
uint32_t getBelChecksum(BelId bel) const override { return bel.index; }
- void map_cell_pins(CellInfo *cell, int32_t mapping) const;
+ void map_cell_pins(CellInfo *cell, int32_t mapping);
void map_port_pins(BelId bel, CellInfo *cell) const;
TileStatus &get_tile_status(int32_t tile)
@@ -1716,6 +1716,8 @@ struct Arch : ArchAPI<ArchRanges>
return is_bel_synthetic(bel);
}
}
+
+ void merge_constant_nets();
};
NEXTPNR_NAMESPACE_END
diff --git a/fpga_interchange/archdefs.h b/fpga_interchange/archdefs.h
index 75af6974..33d999bb 100644
--- a/fpga_interchange/archdefs.h
+++ b/fpga_interchange/archdefs.h
@@ -106,6 +106,7 @@ struct ArchCellInfo
int32_t cell_mapping;
std::unordered_map<IdString, std::vector<IdString>> cell_bel_pins;
+ std::unordered_set<IdString> const_ports;
};
NEXTPNR_NAMESPACE_END
diff --git a/fpga_interchange/examples/template.mk b/fpga_interchange/examples/template.mk
index d12a4e11..c795544e 100644
--- a/fpga_interchange/examples/template.mk
+++ b/fpga_interchange/examples/template.mk
@@ -55,6 +55,15 @@ verbose: build/$(DESIGN).netlist
--package $(PACKAGE) \
--verbose
+verbose2: build/$(DESIGN).netlist
+ $(NEXTPNR_BIN) \
+ --chipdb $(BBA_PATH) \
+ --xdc $(DESIGN).xdc \
+ --netlist build/$(DESIGN).netlist \
+ --phys build/$(DESIGN).phys \
+ --package $(PACKAGE) \
+ --debug
+
debug: build/$(DESIGN).netlist
gdb --args $(NEXTPNR_BIN) \
--chipdb $(BBA_PATH) \
@@ -63,6 +72,15 @@ debug: build/$(DESIGN).netlist
--phys build/$(DESIGN).phys \
--package $(PACKAGE)
+debug_verbose: build/$(DESIGN).netlist
+ gdb --args $(NEXTPNR_BIN) \
+ --chipdb $(BBA_PATH) \
+ --xdc $(DESIGN).xdc \
+ --netlist build/$(DESIGN).netlist \
+ --phys build/$(DESIGN).phys \
+ --package $(PACKAGE) \
+ --verbose
+
build/$(DESIGN).dcp: build/$(DESIGN).netlist build/$(DESIGN).phys $(DESIGN).xdc
RAPIDWRIGHT_PATH=$(RAPIDWRIGHT_PATH) \
$(RAPIDWRIGHT_PATH)/scripts/invoke_rapidwright.sh \
diff --git a/fpga_interchange/examples/wire/wire.xdc b/fpga_interchange/examples/wire/wire.xdc
index e1fce5f0..c923f0fc 100644
--- a/fpga_interchange/examples/wire/wire.xdc
+++ b/fpga_interchange/examples/wire/wire.xdc
@@ -1,2 +1,5 @@
set_property PACKAGE_PIN N16 [get_ports i]
set_property PACKAGE_PIN N15 [get_ports o]
+
+set_property IOSTANDARD LVCMOS33 [get_ports i]
+set_property IOSTANDARD LVCMOS33 [get_ports o]
diff --git a/fpga_interchange/fpga_interchange.cpp b/fpga_interchange/fpga_interchange.cpp
index fd57e09c..027513c8 100644
--- a/fpga_interchange/fpga_interchange.cpp
+++ b/fpga_interchange/fpga_interchange.cpp
@@ -269,8 +269,10 @@ static void find_non_synthetic_edges(const Context * ctx, WireId root_wire,
auto downhill_iter = pip_downhill.find(wire);
if(downhill_iter == pip_downhill.end()) {
- log_warning("Wire %s never entered the real fabric?\n",
- ctx->nameOfWire(wire));
+ if(root_wire != wire) {
+ log_warning("Wire %s never entered the real fabric?\n",
+ ctx->nameOfWire(wire));
+ }
continue;
}
@@ -365,6 +367,9 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str
// Don't emit pin map for ports.
size_t pin_count = 0;
for(const auto & pin : cell.cell_bel_pins) {
+ if(cell.const_ports.count(pin.first)) {
+ continue;
+ }
pin_count += pin.second.size();
}
@@ -372,6 +377,10 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str
auto pin_iter = pins.begin();
for(const auto & cell_to_bel_pins : cell.cell_bel_pins) {
+ if(cell.const_ports.count(cell_to_bel_pins.first)) {
+ continue;
+ }
+
std::string cell_pin = cell_to_bel_pins.first.str(ctx);
size_t cell_pin_index = strings.get_index(cell_pin);