From 510969ab9704865f87c7c0bd09e0185b729feffc Mon Sep 17 00:00:00 2001 From: gatecat Date: Thu, 11 Feb 2021 11:10:32 +0000 Subject: Create machxo2 backend (renamed from generic). Signed-off-by: William D. Jones --- machxo2/arch.cc | 730 ++++++++++++++++++++++++++++++++++++++ machxo2/arch.h | 302 ++++++++++++++++ machxo2/arch_pybindings.cc | 241 +++++++++++++ machxo2/arch_pybindings.h | 31 ++ machxo2/archdefs.h | 72 ++++ machxo2/cells.cc | 147 ++++++++ machxo2/cells.h | 55 +++ machxo2/examples/.gitignore | 6 + machxo2/examples/README.md | 15 + machxo2/examples/__init__.py | 0 machxo2/examples/bitstream.py | 17 + machxo2/examples/blinky.v | 12 + machxo2/examples/blinky_tb.v | 38 ++ machxo2/examples/simple.py | 77 ++++ machxo2/examples/simple.sh | 5 + machxo2/examples/simple_config.py | 15 + machxo2/examples/simple_timing.py | 13 + machxo2/examples/simtest.sh | 7 + machxo2/examples/write_fasm.py | 51 +++ machxo2/family.cmake | 0 machxo2/main.cc | 75 ++++ machxo2/pack.cc | 288 +++++++++++++++ machxo2/synth/cells_map.v | 12 + machxo2/synth/prims.v | 67 ++++ machxo2/synth/synth_machxo2.tcl | 24 ++ 25 files changed, 2300 insertions(+) create mode 100644 machxo2/arch.cc create mode 100644 machxo2/arch.h create mode 100644 machxo2/arch_pybindings.cc create mode 100644 machxo2/arch_pybindings.h create mode 100644 machxo2/archdefs.h create mode 100644 machxo2/cells.cc create mode 100644 machxo2/cells.h create mode 100644 machxo2/examples/.gitignore create mode 100644 machxo2/examples/README.md create mode 100644 machxo2/examples/__init__.py create mode 100644 machxo2/examples/bitstream.py create mode 100644 machxo2/examples/blinky.v create mode 100644 machxo2/examples/blinky_tb.v create mode 100644 machxo2/examples/simple.py create mode 100644 machxo2/examples/simple.sh create mode 100644 machxo2/examples/simple_config.py create mode 100644 machxo2/examples/simple_timing.py create mode 100644 machxo2/examples/simtest.sh create mode 100644 machxo2/examples/write_fasm.py create mode 100644 machxo2/family.cmake create mode 100644 machxo2/main.cc create mode 100644 machxo2/pack.cc create mode 100644 machxo2/synth/cells_map.v create mode 100644 machxo2/synth/prims.v create mode 100644 machxo2/synth/synth_machxo2.tcl (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc new file mode 100644 index 00000000..6979673a --- /dev/null +++ b/machxo2/arch.cc @@ -0,0 +1,730 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include +#include "nextpnr.h" +#include "placer1.h" +#include "placer_heap.h" +#include "router1.h" +#include "router2.h" +#include "util.h" + +NEXTPNR_NAMESPACE_BEGIN + +WireInfo &Arch::wire_info(IdString wire) +{ + auto w = wires.find(wire); + if (w == wires.end()) + NPNR_ASSERT_FALSE_STR("no wire named " + wire.str(this)); + return w->second; +} + +PipInfo &Arch::pip_info(IdString pip) +{ + auto p = pips.find(pip); + if (p == pips.end()) + NPNR_ASSERT_FALSE_STR("no pip named " + pip.str(this)); + return p->second; +} + +BelInfo &Arch::bel_info(IdString bel) +{ + auto b = bels.find(bel); + if (b == bels.end()) + NPNR_ASSERT_FALSE_STR("no bel named " + bel.str(this)); + return b->second; +} + +void Arch::addWire(IdString name, IdString type, int x, int y) +{ + NPNR_ASSERT(wires.count(name) == 0); + WireInfo &wi = wires[name]; + wi.name = name; + wi.type = type; + wi.x = x; + wi.y = y; + + wire_ids.push_back(name); +} + +void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay, Loc loc) +{ + NPNR_ASSERT(pips.count(name) == 0); + PipInfo &pi = pips[name]; + pi.name = name; + pi.type = type; + pi.srcWire = srcWire; + pi.dstWire = dstWire; + pi.delay = delay; + pi.loc = loc; + + wire_info(srcWire).downhill.push_back(name); + wire_info(dstWire).uphill.push_back(name); + pip_ids.push_back(name); + + if (int(tilePipDimZ.size()) <= loc.x) + tilePipDimZ.resize(loc.x + 1); + + if (int(tilePipDimZ[loc.x].size()) <= loc.y) + tilePipDimZ[loc.x].resize(loc.y + 1); + + gridDimX = std::max(gridDimX, loc.x + 1); + gridDimY = std::max(gridDimY, loc.x + 1); + tilePipDimZ[loc.x][loc.y] = std::max(tilePipDimZ[loc.x][loc.y], loc.z + 1); +} + +void Arch::addAlias(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay) +{ + NPNR_ASSERT(pips.count(name) == 0); + PipInfo &pi = pips[name]; + pi.name = name; + pi.type = type; + pi.srcWire = srcWire; + pi.dstWire = dstWire; + pi.delay = delay; + + wire_info(srcWire).aliases.push_back(name); + pip_ids.push_back(name); +} + +void Arch::addBel(IdString name, IdString type, Loc loc, bool gb) +{ + NPNR_ASSERT(bels.count(name) == 0); + NPNR_ASSERT(bel_by_loc.count(loc) == 0); + BelInfo &bi = bels[name]; + bi.name = name; + bi.type = type; + bi.x = loc.x; + bi.y = loc.y; + bi.z = loc.z; + bi.gb = gb; + + bel_ids.push_back(name); + bel_by_loc[loc] = name; + + if (int(bels_by_tile.size()) <= loc.x) + bels_by_tile.resize(loc.x + 1); + + if (int(bels_by_tile[loc.x].size()) <= loc.y) + bels_by_tile[loc.x].resize(loc.y + 1); + + bels_by_tile[loc.x][loc.y].push_back(name); + + if (int(tileBelDimZ.size()) <= loc.x) + tileBelDimZ.resize(loc.x + 1); + + if (int(tileBelDimZ[loc.x].size()) <= loc.y) + tileBelDimZ[loc.x].resize(loc.y + 1); + + gridDimX = std::max(gridDimX, loc.x + 1); + gridDimY = std::max(gridDimY, loc.x + 1); + tileBelDimZ[loc.x][loc.y] = std::max(tileBelDimZ[loc.x][loc.y], loc.z + 1); +} + +void Arch::addBelInput(IdString bel, IdString name, IdString wire) +{ + NPNR_ASSERT(bel_info(bel).pins.count(name) == 0); + PinInfo &pi = bel_info(bel).pins[name]; + pi.name = name; + pi.wire = wire; + pi.type = PORT_IN; + + wire_info(wire).downhill_bel_pins.push_back(BelPin{bel, name}); + wire_info(wire).bel_pins.push_back(BelPin{bel, name}); +} + +void Arch::addBelOutput(IdString bel, IdString name, IdString wire) +{ + NPNR_ASSERT(bel_info(bel).pins.count(name) == 0); + PinInfo &pi = bel_info(bel).pins[name]; + pi.name = name; + pi.wire = wire; + pi.type = PORT_OUT; + + wire_info(wire).uphill_bel_pin = BelPin{bel, name}; + wire_info(wire).bel_pins.push_back(BelPin{bel, name}); +} + +void Arch::addBelInout(IdString bel, IdString name, IdString wire) +{ + NPNR_ASSERT(bel_info(bel).pins.count(name) == 0); + PinInfo &pi = bel_info(bel).pins[name]; + pi.name = name; + pi.wire = wire; + pi.type = PORT_INOUT; + + wire_info(wire).downhill_bel_pins.push_back(BelPin{bel, name}); + wire_info(wire).bel_pins.push_back(BelPin{bel, name}); +} + +void Arch::addGroupBel(IdString group, IdString bel) { groups[group].bels.push_back(bel); } + +void Arch::addGroupWire(IdString group, IdString wire) { groups[group].wires.push_back(wire); } + +void Arch::addGroupPip(IdString group, IdString pip) { groups[group].pips.push_back(pip); } + +void Arch::addGroupGroup(IdString group, IdString grp) { groups[group].groups.push_back(grp); } + +void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic) +{ + decal_graphics[decal].push_back(graphic); + refreshUi(); +} + +void Arch::setWireDecal(WireId wire, DecalXY decalxy) +{ + wire_info(wire).decalxy = decalxy; + refreshUiWire(wire); +} + +void Arch::setPipDecal(PipId pip, DecalXY decalxy) +{ + pip_info(pip).decalxy = decalxy; + refreshUiPip(pip); +} + +void Arch::setBelDecal(BelId bel, DecalXY decalxy) +{ + bel_info(bel).decalxy = decalxy; + refreshUiBel(bel); +} + +void Arch::setGroupDecal(GroupId group, DecalXY decalxy) +{ + groups[group].decalxy = decalxy; + refreshUiGroup(group); +} + +void Arch::setWireAttr(IdString wire, IdString key, const std::string &value) { wire_info(wire).attrs[key] = value; } + +void Arch::setPipAttr(IdString pip, IdString key, const std::string &value) { pip_info(pip).attrs[key] = value; } + +void Arch::setBelAttr(IdString bel, IdString key, const std::string &value) { bel_info(bel).attrs[key] = value; } + +void Arch::setLutK(int K) { args.K = K; } + +void Arch::setDelayScaling(double scale, double offset) +{ + args.delayScale = scale; + args.delayOffset = offset; +} + +void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; } + +void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay) +{ + if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE) + cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT; + if (get_or_default(cellTiming[cell].portClasses, toPort, TMG_IGNORE) == TMG_IGNORE) + cellTiming[cell].portClasses[toPort] = TMG_COMB_OUTPUT; + cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = delay; +} + +void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold) +{ + TimingClockingInfo ci; + ci.clock_port = clock; + ci.edge = RISING_EDGE; + ci.setup = setup; + ci.hold = hold; + cellTiming[cell].clockingInfo[port].push_back(ci); + cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT; +} + +void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq) +{ + TimingClockingInfo ci; + ci.clock_port = clock; + ci.edge = RISING_EDGE; + ci.clockToQ = clktoq; + cellTiming[cell].clockingInfo[port].push_back(ci); + cellTiming[cell].portClasses[port] = TMG_REGISTER_OUTPUT; +} + +// --------------------------------------------------------------- + +Arch::Arch(ArchArgs args) : chipName("generic"), args(args) +{ + // Dummy for empty decals + decal_graphics[IdString()]; +} + +void IdString::initialize_arch(const BaseCtx *ctx) {} + +// --------------------------------------------------------------- + +BelId Arch::getBelByName(IdString name) const +{ + if (bels.count(name)) + return name; + return BelId(); +} + +IdString Arch::getBelName(BelId bel) const { return bel; } + +Loc Arch::getBelLocation(BelId bel) const +{ + auto &info = bels.at(bel); + return Loc(info.x, info.y, info.z); +} + +BelId Arch::getBelByLocation(Loc loc) const +{ + auto it = bel_by_loc.find(loc); + if (it != bel_by_loc.end()) + return it->second; + return BelId(); +} + +const std::vector &Arch::getBelsByTile(int x, int y) const { return bels_by_tile.at(x).at(y); } + +bool Arch::getBelGlobalBuf(BelId bel) const { return bels.at(bel).gb; } + +uint32_t Arch::getBelChecksum(BelId bel) const +{ + // FIXME + return 0; +} + +void Arch::bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) +{ + bels.at(bel).bound_cell = cell; + cell->bel = bel; + cell->belStrength = strength; + refreshUiBel(bel); +} + +void Arch::unbindBel(BelId bel) +{ + bels.at(bel).bound_cell->bel = BelId(); + bels.at(bel).bound_cell->belStrength = STRENGTH_NONE; + bels.at(bel).bound_cell = nullptr; + refreshUiBel(bel); +} + +bool Arch::checkBelAvail(BelId bel) const { return bels.at(bel).bound_cell == nullptr; } + +CellInfo *Arch::getBoundBelCell(BelId bel) const { return bels.at(bel).bound_cell; } + +CellInfo *Arch::getConflictingBelCell(BelId bel) const { return bels.at(bel).bound_cell; } + +const std::vector &Arch::getBels() const { return bel_ids; } + +IdString Arch::getBelType(BelId bel) const { return bels.at(bel).type; } + +const std::map &Arch::getBelAttrs(BelId bel) const { return bels.at(bel).attrs; } + +WireId Arch::getBelPinWire(BelId bel, IdString pin) const +{ + const auto &bdata = bels.at(bel); + if (!bdata.pins.count(pin)) + log_error("bel '%s' has no pin '%s'\n", bel.c_str(this), pin.c_str(this)); + return bdata.pins.at(pin).wire; +} + +PortType Arch::getBelPinType(BelId bel, IdString pin) const { return bels.at(bel).pins.at(pin).type; } + +std::vector Arch::getBelPins(BelId bel) const +{ + std::vector ret; + for (auto &it : bels.at(bel).pins) + ret.push_back(it.first); + return ret; +} + +// --------------------------------------------------------------- + +WireId Arch::getWireByName(IdString name) const +{ + if (wires.count(name)) + return name; + return WireId(); +} + +IdString Arch::getWireName(WireId wire) const { return wire; } + +IdString Arch::getWireType(WireId wire) const { return wires.at(wire).type; } + +const std::map &Arch::getWireAttrs(WireId wire) const { return wires.at(wire).attrs; } + +uint32_t Arch::getWireChecksum(WireId wire) const +{ + // FIXME + return 0; +} + +void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength) +{ + wires.at(wire).bound_net = net; + net->wires[wire].pip = PipId(); + net->wires[wire].strength = strength; + refreshUiWire(wire); +} + +void Arch::unbindWire(WireId wire) +{ + auto &net_wires = wires.at(wire).bound_net->wires; + + auto pip = net_wires.at(wire).pip; + if (pip != PipId()) { + pips.at(pip).bound_net = nullptr; + refreshUiPip(pip); + } + + net_wires.erase(wire); + wires.at(wire).bound_net = nullptr; + refreshUiWire(wire); +} + +bool Arch::checkWireAvail(WireId wire) const { return wires.at(wire).bound_net == nullptr; } + +NetInfo *Arch::getBoundWireNet(WireId wire) const { return wires.at(wire).bound_net; } + +NetInfo *Arch::getConflictingWireNet(WireId wire) const { return wires.at(wire).bound_net; } + +const std::vector &Arch::getWireBelPins(WireId wire) const { return wires.at(wire).bel_pins; } + +const std::vector &Arch::getWires() const { return wire_ids; } + +// --------------------------------------------------------------- + +PipId Arch::getPipByName(IdString name) const +{ + if (pips.count(name)) + return name; + return PipId(); +} + +IdString Arch::getPipName(PipId pip) const { return pip; } + +IdString Arch::getPipType(PipId pip) const { return pips.at(pip).type; } + +const std::map &Arch::getPipAttrs(PipId pip) const { return pips.at(pip).attrs; } + +uint32_t Arch::getPipChecksum(PipId wire) const +{ + // FIXME + return 0; +} + +void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength) +{ + WireId wire = pips.at(pip).dstWire; + pips.at(pip).bound_net = net; + wires.at(wire).bound_net = net; + net->wires[wire].pip = pip; + net->wires[wire].strength = strength; + refreshUiPip(pip); + refreshUiWire(wire); +} + +void Arch::unbindPip(PipId pip) +{ + WireId wire = pips.at(pip).dstWire; + wires.at(wire).bound_net->wires.erase(wire); + pips.at(pip).bound_net = nullptr; + wires.at(wire).bound_net = nullptr; + refreshUiPip(pip); + refreshUiWire(wire); +} + +bool Arch::checkPipAvail(PipId pip) const { return pips.at(pip).bound_net == nullptr; } + +NetInfo *Arch::getBoundPipNet(PipId pip) const { return pips.at(pip).bound_net; } + +NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; } + +WireId Arch::getConflictingPipWire(PipId pip) const { return pips.at(pip).bound_net ? pips.at(pip).dstWire : WireId(); } + +const std::vector &Arch::getPips() const { return pip_ids; } + +Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; } + +WireId Arch::getPipSrcWire(PipId pip) const { return pips.at(pip).srcWire; } + +WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; } + +DelayInfo Arch::getPipDelay(PipId pip) const { return pips.at(pip).delay; } + +const std::vector &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; } + +const std::vector &Arch::getPipsUphill(WireId wire) const { return wires.at(wire).uphill; } + +const std::vector &Arch::getWireAliases(WireId wire) const { return wires.at(wire).aliases; } + +// --------------------------------------------------------------- + +GroupId Arch::getGroupByName(IdString name) const { return name; } + +IdString Arch::getGroupName(GroupId group) const { return group; } + +std::vector Arch::getGroups() const +{ + std::vector ret; + for (auto &it : groups) + ret.push_back(it.first); + return ret; +} + +const std::vector &Arch::getGroupBels(GroupId group) const { return groups.at(group).bels; } + +const std::vector &Arch::getGroupWires(GroupId group) const { return groups.at(group).wires; } + +const std::vector &Arch::getGroupPips(GroupId group) const { return groups.at(group).pips; } + +const std::vector &Arch::getGroupGroups(GroupId group) const { return groups.at(group).groups; } + +// --------------------------------------------------------------- + +delay_t Arch::estimateDelay(WireId src, WireId dst) const +{ + const WireInfo &s = wires.at(src); + const WireInfo &d = wires.at(dst); + int dx = abs(s.x - d.x); + int dy = abs(s.y - d.y); + return (dx + dy) * args.delayScale + args.delayOffset; +} + +delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const +{ + const auto &driver = net_info->driver; + auto driver_loc = getBelLocation(driver.cell->bel); + auto sink_loc = getBelLocation(sink.cell->bel); + + int dx = abs(sink_loc.x - driver_loc.x); + int dy = abs(sink_loc.y - driver_loc.y); + return (dx + dy) * args.delayScale + args.delayOffset; +} + +bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; } + +ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const +{ + ArcBounds bb; + + int src_x = wires.at(src).x; + int src_y = wires.at(src).y; + int dst_x = wires.at(dst).x; + int dst_y = wires.at(dst).y; + + bb.x0 = src_x; + bb.y0 = src_y; + bb.x1 = src_x; + bb.y1 = src_y; + + auto extend = [&](int x, int y) { + bb.x0 = std::min(bb.x0, x); + bb.x1 = std::max(bb.x1, x); + bb.y0 = std::min(bb.y0, y); + bb.y1 = std::max(bb.y1, y); + }; + extend(dst_x, dst_y); + return bb; +} + +// --------------------------------------------------------------- + +bool Arch::place() +{ + std::string placer = str_or_default(settings, id("placer"), defaultPlacer); + if (placer == "heap") { + bool have_iobuf_or_constr = false; + for (auto cell : sorted(cells)) { + CellInfo *ci = cell.second; + if (ci->type == id("GENERIC_IOB") || ci->bel != BelId() || ci->attrs.count(id("BEL"))) { + have_iobuf_or_constr = true; + break; + } + } + bool retVal; + if (!have_iobuf_or_constr) { + log_warning("Unable to use HeAP due to a lack of IO buffers or constrained cells as anchors; reverting to " + "SA.\n"); + retVal = placer1(getCtx(), Placer1Cfg(getCtx())); + } else { + PlacerHeapCfg cfg(getCtx()); + cfg.ioBufTypes.insert(id("GENERIC_IOB")); + retVal = placer_heap(getCtx(), cfg); + } + getCtx()->settings[getCtx()->id("place")] = 1; + archInfoToAttributes(); + return retVal; + } else if (placer == "sa") { + bool retVal = placer1(getCtx(), Placer1Cfg(getCtx())); + getCtx()->settings[getCtx()->id("place")] = 1; + archInfoToAttributes(); + return retVal; + } else { + log_error("Generic architecture does not support placer '%s'\n", placer.c_str()); + } +} + +bool Arch::route() +{ + std::string router = str_or_default(settings, id("router"), defaultRouter); + bool result; + if (router == "router1") { + result = router1(getCtx(), Router1Cfg(getCtx())); + } else if (router == "router2") { + router2(getCtx(), Router2Cfg(getCtx())); + result = true; + } else { + log_error("iCE40 architecture does not support router '%s'\n", router.c_str()); + } + getCtx()->settings[getCtx()->id("route")] = 1; + archInfoToAttributes(); + return result; +} + +// --------------------------------------------------------------- + +const std::vector &Arch::getDecalGraphics(DecalId decal) const +{ + if (!decal_graphics.count(decal)) { + std::cerr << "No decal named " << decal.str(this) << std::endl; + log_error("No decal named %s!\n", decal.c_str(this)); + } + return decal_graphics.at(decal); +} + +DecalXY Arch::getBelDecal(BelId bel) const { return bels.at(bel).decalxy; } + +DecalXY Arch::getWireDecal(WireId wire) const { return wires.at(wire).decalxy; } + +DecalXY Arch::getPipDecal(PipId pip) const { return pips.at(pip).decalxy; } + +DecalXY Arch::getGroupDecal(GroupId group) const { return groups.at(group).decalxy; } + +// --------------------------------------------------------------- + +bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const +{ + if (!cellTiming.count(cell->name)) + return false; + const auto &tmg = cellTiming.at(cell->name); + auto fnd = tmg.combDelays.find(CellDelayKey{fromPort, toPort}); + if (fnd != tmg.combDelays.end()) { + delay = fnd->second; + return true; + } else { + return false; + } +} + +// Get the port class, also setting clockPort if applicable +TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const +{ + if (!cellTiming.count(cell->name)) + return TMG_IGNORE; + const auto &tmg = cellTiming.at(cell->name); + if (tmg.clockingInfo.count(port)) + clockInfoCount = int(tmg.clockingInfo.at(port).size()); + else + clockInfoCount = 0; + return get_or_default(tmg.portClasses, port, TMG_IGNORE); +} + +TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const +{ + NPNR_ASSERT(cellTiming.count(cell->name)); + const auto &tmg = cellTiming.at(cell->name); + NPNR_ASSERT(tmg.clockingInfo.count(port)); + return tmg.clockingInfo.at(port).at(index); +} + +bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const +{ + std::vector cells; + cells.push_back(cell); + Loc loc = getBelLocation(bel); + for (auto tbel : getBelsByTile(loc.x, loc.y)) { + if (tbel == bel) + continue; + CellInfo *bound = getBoundBelCell(tbel); + if (bound != nullptr) + cells.push_back(bound); + } + return cellsCompatible(cells.data(), int(cells.size())); +} + +bool Arch::isBelLocationValid(BelId bel) const +{ + std::vector cells; + Loc loc = getBelLocation(bel); + for (auto tbel : getBelsByTile(loc.x, loc.y)) { + CellInfo *bound = getBoundBelCell(tbel); + if (bound != nullptr) + cells.push_back(bound); + } + return cellsCompatible(cells.data(), int(cells.size())); +} + +#ifdef WITH_HEAP +const std::string Arch::defaultPlacer = "heap"; +#else +const std::string Arch::defaultPlacer = "sa"; +#endif + +const std::vector Arch::availablePlacers = {"sa", +#ifdef WITH_HEAP + "heap" +#endif +}; + +const std::string Arch::defaultRouter = "router1"; +const std::vector Arch::availableRouters = {"router1", "router2"}; + +void Arch::assignArchInfo() +{ + for (auto &cell : getCtx()->cells) { + CellInfo *ci = cell.second.get(); + if (ci->type == id("GENERIC_SLICE")) { + ci->is_slice = true; + ci->slice_clk = get_net_or_empty(ci, id("CLK")); + } else { + ci->is_slice = false; + } + ci->user_group = int_or_default(ci->attrs, id("PACK_GROUP"), -1); + } +} + +bool Arch::cellsCompatible(const CellInfo **cells, int count) const +{ + const NetInfo *clk = nullptr; + int group = -1; + for (int i = 0; i < count; i++) { + const CellInfo *ci = cells[i]; + if (ci->is_slice && ci->slice_clk != nullptr) { + if (clk == nullptr) + clk = ci->slice_clk; + else if (clk != ci->slice_clk) + return false; + } + if (ci->user_group != -1) { + if (group == -1) + group = ci->user_group; + else if (group != ci->user_group) + return false; + } + } + return true; +} + +NEXTPNR_NAMESPACE_END diff --git a/machxo2/arch.h b/machxo2/arch.h new file mode 100644 index 00000000..cbfb943d --- /dev/null +++ b/machxo2/arch.h @@ -0,0 +1,302 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef NEXTPNR_H +#error Include "arch.h" via "nextpnr.h" only. +#endif + +NEXTPNR_NAMESPACE_BEGIN + +struct ArchArgs +{ + // Number of LUT inputs + int K = 4; + // y = mx + c relationship between distance and delay for interconnect + // delay estimates + double delayScale = 0.1, delayOffset = 0; +}; + +struct WireInfo; + +struct PipInfo +{ + IdString name, type; + std::map attrs; + NetInfo *bound_net; + WireId srcWire, dstWire; + DelayInfo delay; + DecalXY decalxy; + Loc loc; +}; + +struct WireInfo +{ + IdString name, type; + std::map attrs; + NetInfo *bound_net; + std::vector downhill, uphill, aliases; + BelPin uphill_bel_pin; + std::vector downhill_bel_pins; + std::vector bel_pins; + DecalXY decalxy; + int x, y; +}; + +struct PinInfo +{ + IdString name; + WireId wire; + PortType type; +}; + +struct BelInfo +{ + IdString name, type; + std::map attrs; + CellInfo *bound_cell; + std::unordered_map pins; + DecalXY decalxy; + int x, y, z; + bool gb; +}; + +struct GroupInfo +{ + IdString name; + std::vector bels; + std::vector wires; + std::vector pips; + std::vector groups; + DecalXY decalxy; +}; + +struct CellDelayKey +{ + IdString from, to; + inline bool operator==(const CellDelayKey &other) const { return from == other.from && to == other.to; } +}; + +NEXTPNR_NAMESPACE_END +namespace std { +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX CellDelayKey &dk) const noexcept + { + std::size_t seed = std::hash()(dk.from); + seed ^= std::hash()(dk.to) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; +} // namespace std +NEXTPNR_NAMESPACE_BEGIN + +struct CellTiming +{ + std::unordered_map portClasses; + std::unordered_map combDelays; + std::unordered_map> clockingInfo; +}; + +struct Arch : BaseCtx +{ + std::string chipName; + + std::unordered_map wires; + std::unordered_map pips; + std::unordered_map bels; + std::unordered_map groups; + + // These functions include useful errors if not found + WireInfo &wire_info(IdString wire); + PipInfo &pip_info(IdString wire); + BelInfo &bel_info(IdString wire); + + std::vector bel_ids, wire_ids, pip_ids; + + std::unordered_map bel_by_loc; + std::vector>> bels_by_tile; + + std::unordered_map> decal_graphics; + + int gridDimX, gridDimY; + std::vector> tileBelDimZ; + std::vector> tilePipDimZ; + + std::unordered_map cellTiming; + + void addWire(IdString name, IdString type, int x, int y); + void addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay, Loc loc); + void addAlias(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay); + + void addBel(IdString name, IdString type, Loc loc, bool gb); + void addBelInput(IdString bel, IdString name, IdString wire); + void addBelOutput(IdString bel, IdString name, IdString wire); + void addBelInout(IdString bel, IdString name, IdString wire); + + void addGroupBel(IdString group, IdString bel); + void addGroupWire(IdString group, IdString wire); + void addGroupPip(IdString group, IdString pip); + void addGroupGroup(IdString group, IdString grp); + + void addDecalGraphic(DecalId decal, const GraphicElement &graphic); + void setWireDecal(WireId wire, DecalXY decalxy); + void setPipDecal(PipId pip, DecalXY decalxy); + void setBelDecal(BelId bel, DecalXY decalxy); + void setGroupDecal(GroupId group, DecalXY decalxy); + + void setWireAttr(IdString wire, IdString key, const std::string &value); + void setPipAttr(IdString pip, IdString key, const std::string &value); + void setBelAttr(IdString bel, IdString key, const std::string &value); + + void setLutK(int K); + void setDelayScaling(double scale, double offset); + + void addCellTimingClock(IdString cell, IdString port); + void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay); + void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold); + void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq); + + // --------------------------------------------------------------- + // Common Arch API. Every arch must provide the following methods. + + ArchArgs args; + Arch(ArchArgs args); + + std::string getChipName() const { return chipName; } + + IdString archId() const { return id("generic"); } + ArchArgs archArgs() const { return args; } + IdString archArgsToId(ArchArgs args) const { return id("none"); } + + int getGridDimX() const { return gridDimX; } + int getGridDimY() const { return gridDimY; } + int getTileBelDimZ(int x, int y) const { return tileBelDimZ[x][y]; } + int getTilePipDimZ(int x, int y) const { return tilePipDimZ[x][y]; } + + BelId getBelByName(IdString name) const; + IdString getBelName(BelId bel) const; + Loc getBelLocation(BelId bel) const; + BelId getBelByLocation(Loc loc) const; + const std::vector &getBelsByTile(int x, int y) const; + bool getBelGlobalBuf(BelId bel) const; + uint32_t getBelChecksum(BelId bel) const; + void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength); + void unbindBel(BelId bel); + bool checkBelAvail(BelId bel) const; + CellInfo *getBoundBelCell(BelId bel) const; + CellInfo *getConflictingBelCell(BelId bel) const; + const std::vector &getBels() const; + IdString getBelType(BelId bel) const; + const std::map &getBelAttrs(BelId bel) const; + WireId getBelPinWire(BelId bel, IdString pin) const; + PortType getBelPinType(BelId bel, IdString pin) const; + std::vector getBelPins(BelId bel) const; + + WireId getWireByName(IdString name) const; + IdString getWireName(WireId wire) const; + IdString getWireType(WireId wire) const; + const std::map &getWireAttrs(WireId wire) const; + uint32_t getWireChecksum(WireId wire) const; + void bindWire(WireId wire, NetInfo *net, PlaceStrength strength); + void unbindWire(WireId wire); + bool checkWireAvail(WireId wire) const; + NetInfo *getBoundWireNet(WireId wire) const; + WireId getConflictingWireWire(WireId wire) const { return wire; } + NetInfo *getConflictingWireNet(WireId wire) const; + DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); } + const std::vector &getWires() const; + const std::vector &getWireBelPins(WireId wire) const; + + PipId getPipByName(IdString name) const; + IdString getPipName(PipId pip) const; + IdString getPipType(PipId pip) const; + const std::map &getPipAttrs(PipId pip) const; + uint32_t getPipChecksum(PipId pip) const; + void bindPip(PipId pip, NetInfo *net, PlaceStrength strength); + void unbindPip(PipId pip); + bool checkPipAvail(PipId pip) const; + NetInfo *getBoundPipNet(PipId pip) const; + WireId getConflictingPipWire(PipId pip) const; + NetInfo *getConflictingPipNet(PipId pip) const; + const std::vector &getPips() const; + Loc getPipLocation(PipId pip) const; + WireId getPipSrcWire(PipId pip) const; + WireId getPipDstWire(PipId pip) const; + DelayInfo getPipDelay(PipId pip) const; + const std::vector &getPipsDownhill(WireId wire) const; + const std::vector &getPipsUphill(WireId wire) const; + const std::vector &getWireAliases(WireId wire) const; + + GroupId getGroupByName(IdString name) const; + IdString getGroupName(GroupId group) const; + std::vector getGroups() const; + const std::vector &getGroupBels(GroupId group) const; + const std::vector &getGroupWires(GroupId group) const; + const std::vector &getGroupPips(GroupId group) const; + const std::vector &getGroupGroups(GroupId group) const; + + delay_t estimateDelay(WireId src, WireId dst) const; + delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const; + delay_t getDelayEpsilon() const { return 0.001; } + delay_t getRipupDelayPenalty() const { return 0.015; } + float getDelayNS(delay_t v) const { return v; } + + DelayInfo getDelayFromNS(float ns) const + { + DelayInfo del; + del.delay = ns; + return del; + } + + uint32_t getDelayChecksum(delay_t v) const { return 0; } + bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const; + + ArcBounds getRouteBoundingBox(WireId src, WireId dst) const; + + bool pack(); + bool place(); + bool route(); + + const std::vector &getDecalGraphics(DecalId decal) const; + DecalXY getBelDecal(BelId bel) const; + DecalXY getWireDecal(WireId wire) const; + DecalXY getPipDecal(PipId pip) const; + DecalXY getGroupDecal(GroupId group) const; + + bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; + // Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port + TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const; + // Get the TimingClockingInfo of a port + TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const; + + bool isValidBelForCell(CellInfo *cell, BelId bel) const; + bool isBelLocationValid(BelId bel) const; + + static const std::string defaultPlacer; + static const std::vector availablePlacers; + static const std::string defaultRouter; + static const std::vector availableRouters; + + // --------------------------------------------------------------- + // Internal usage + void assignArchInfo(); + bool cellsCompatible(const CellInfo **cells, int count) const; +}; + +NEXTPNR_NAMESPACE_END diff --git a/machxo2/arch_pybindings.cc b/machxo2/arch_pybindings.cc new file mode 100644 index 00000000..2600cac0 --- /dev/null +++ b/machxo2/arch_pybindings.cc @@ -0,0 +1,241 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef NO_PYTHON + +#include "arch_pybindings.h" +#include "nextpnr.h" +#include "pybindings.h" +#include "pywrappers.h" + +NEXTPNR_NAMESPACE_BEGIN +namespace PythonConversion { +template <> struct string_converter +{ + const IdString &from_str(Context *ctx, std::string name) { NPNR_ASSERT_FALSE("unsupported"); } + + std::string to_str(Context *ctx, const IdString &id) { return id.str(ctx); } +}; +} // namespace PythonConversion + +void arch_wrap_python() +{ + using namespace PythonConversion; + + auto arch_cls = class_, boost::noncopyable>("Arch", init()); + + auto dxy_cls = class_>("DecalXY_", no_init); + readwrite_wrapper, + conv_from_str>::def_wrap(dxy_cls, "decal"); + readwrite_wrapper, pass_through>::def_wrap( + dxy_cls, "x"); + readwrite_wrapper, pass_through>::def_wrap( + dxy_cls, "y"); + + auto ctx_cls = class_, boost::noncopyable>("Context", no_init) + .def("checksum", &Context::checksum) + .def("pack", &Context::pack) + .def("place", &Context::place) + .def("route", &Context::route); + + class_("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); + + class_("DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay); + + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBelType"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "checkBelAvail"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBelChecksum"); + fn_wrapper_3a_v, + addr_and_unwrap, pass_through>::def_wrap(ctx_cls, "bindBel"); + fn_wrapper_1a_v>::def_wrap( + ctx_cls, "unbindBel"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBoundBelCell"); + fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); + fn_wrapper_0a &>>::def_wrap(ctx_cls, "getBels"); + + fn_wrapper_2a, + conv_from_str, conv_from_str>::def_wrap(ctx_cls, "getBelPinWire"); + fn_wrapper_1a &>, conv_from_str>::def_wrap(ctx_cls, + "getWireBelPins"); + + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getWireChecksum"); + fn_wrapper_3a_v, + addr_and_unwrap, pass_through>::def_wrap(ctx_cls, "bindWire"); + fn_wrapper_1a_v>::def_wrap( + ctx_cls, "unbindWire"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "checkWireAvail"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBoundWireNet"); + fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingWireNet"); + + fn_wrapper_0a &>>::def_wrap(ctx_cls, "getWires"); + + fn_wrapper_0a &>>::def_wrap(ctx_cls, "getPips"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getPipChecksum"); + fn_wrapper_3a_v, + addr_and_unwrap, pass_through>::def_wrap(ctx_cls, "bindPip"); + fn_wrapper_1a_v>::def_wrap( + ctx_cls, "unbindPip"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "checkPipAvail"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBoundPipNet"); + fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingPipNet"); + + fn_wrapper_1a &>, conv_from_str>::def_wrap(ctx_cls, + "getPipsDownhill"); + fn_wrapper_1a &>, conv_from_str>::def_wrap(ctx_cls, "getPipsUphill"); + fn_wrapper_1a &>, conv_from_str>::def_wrap(ctx_cls, "getWireAliases"); + + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getPipSrcWire"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getPipDstWire"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getPipDelay"); + + fn_wrapper_1a, + pass_through>::def_wrap(ctx_cls, "getDelayFromNS"); + + fn_wrapper_0a>::def_wrap( + ctx_cls, "getChipName"); + fn_wrapper_0a>::def_wrap(ctx_cls, + "archId"); + + fn_wrapper_3a, + conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "DecalXY"); + + typedef std::unordered_map> CellMap; + typedef std::unordered_map> NetMap; + typedef std::unordered_map HierarchyMap; + + readonly_wrapper>::def_wrap(ctx_cls, + "cells"); + readonly_wrapper>::def_wrap(ctx_cls, + "nets"); + + fn_wrapper_2a_v, + pass_through>::def_wrap(ctx_cls, "addClock"); + + // Generic arch construction API + fn_wrapper_4a_v, + conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "addWire", + (arg("name"), "type", "x", + "y")); + fn_wrapper_6a_v, + conv_from_str, conv_from_str, conv_from_str, pass_through, + pass_through>::def_wrap(ctx_cls, "addPip", + (arg("name"), "type", "srcWire", "dstWire", "delay", "loc")); + fn_wrapper_5a_v, + conv_from_str, conv_from_str, conv_from_str, + pass_through>::def_wrap(ctx_cls, "addAlias", + (arg("name"), "type", "srcWire", "dstWire", "delay")); + + fn_wrapper_4a_v, + conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "addBel", + (arg("name"), "type", + "loc", "gb")); + fn_wrapper_3a_v, + conv_from_str, conv_from_str>::def_wrap(ctx_cls, "addBelInput", + (arg("bel"), "name", "wire")); + fn_wrapper_3a_v, + conv_from_str, conv_from_str>::def_wrap(ctx_cls, "addBelOutput", + (arg("bel"), "name", "wire")); + fn_wrapper_3a_v, + conv_from_str, conv_from_str>::def_wrap(ctx_cls, "addBelInout", + (arg("bel"), "name", "wire")); + + fn_wrapper_2a_v, + conv_from_str>::def_wrap(ctx_cls, "addGroupBel", (arg("group"), "bel")); + fn_wrapper_2a_v, + conv_from_str>::def_wrap(ctx_cls, "addGroupWire", (arg("group"), "wire")); + fn_wrapper_2a_v, + conv_from_str>::def_wrap(ctx_cls, "addGroupPip", (arg("group"), "pip")); + fn_wrapper_2a_v, + conv_from_str>::def_wrap(ctx_cls, "addGroupGroup", (arg("group"), "grp")); + + fn_wrapper_2a_v, + pass_through>::def_wrap(ctx_cls, "addDecalGraphic", (arg("decal"), "graphic")); + fn_wrapper_2a_v, + unwrap_context>::def_wrap(ctx_cls, "setWireDecal", (arg("wire"), "decalxy")); + fn_wrapper_2a_v, + unwrap_context>::def_wrap(ctx_cls, "setPipDecal", (arg("pip"), "decalxy")); + fn_wrapper_2a_v, + unwrap_context>::def_wrap(ctx_cls, "setBelDecal", (arg("bel"), "decalxy")); + fn_wrapper_2a_v, + unwrap_context>::def_wrap(ctx_cls, "setGroupDecal", (arg("group"), "decalxy")); + + fn_wrapper_3a_v, + conv_from_str, pass_through>::def_wrap(ctx_cls, "setWireAttr", + (arg("wire"), "key", "value")); + fn_wrapper_3a_v, + conv_from_str, pass_through>::def_wrap(ctx_cls, "setBelAttr", + (arg("bel"), "key", "value")); + fn_wrapper_3a_v, + conv_from_str, pass_through>::def_wrap(ctx_cls, "setPipAttr", + (arg("pip"), "key", "value")); + + fn_wrapper_1a_v>::def_wrap( + ctx_cls, "setLutK", arg("K")); + fn_wrapper_2a_v, + pass_through>::def_wrap(ctx_cls, "setDelayScaling", (arg("scale"), "offset")); + + fn_wrapper_2a_v, conv_from_str>::def_wrap(ctx_cls, "addCellTimingClock", + (arg("cell"), "port")); + fn_wrapper_4a_v, conv_from_str, conv_from_str, + pass_through>::def_wrap(ctx_cls, "addCellTimingDelay", + (arg("cell"), "fromPort", "toPort", "delay")); + fn_wrapper_5a_v, conv_from_str, conv_from_str, pass_through, + pass_through>::def_wrap(ctx_cls, "addCellTimingSetupHold", + (arg("cell"), "port", "clock", "setup", "hold")); + fn_wrapper_4a_v, conv_from_str, conv_from_str, + pass_through>::def_wrap(ctx_cls, "addCellTimingClockToOut", + (arg("cell"), "port", "clock", "clktoq")); + + WRAP_MAP_UPTR(CellMap, "IdCellMap"); + WRAP_MAP_UPTR(NetMap, "IdNetMap"); + WRAP_MAP(HierarchyMap, wrap_context, "HierarchyMap"); + WRAP_VECTOR(const std::vector, conv_to_str); +} + +NEXTPNR_NAMESPACE_END + +#endif \ No newline at end of file diff --git a/machxo2/arch_pybindings.h b/machxo2/arch_pybindings.h new file mode 100644 index 00000000..f7f07529 --- /dev/null +++ b/machxo2/arch_pybindings.h @@ -0,0 +1,31 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ +#ifndef ARCH_PYBINDINGS_H +#define ARCH_PYBINDINGS_H +#ifndef NO_PYTHON + +#include "nextpnr.h" +#include "pybindings.h" + +NEXTPNR_NAMESPACE_BEGIN + +NEXTPNR_NAMESPACE_END +#endif +#endif diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h new file mode 100644 index 00000000..978c9c9b --- /dev/null +++ b/machxo2/archdefs.h @@ -0,0 +1,72 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef NEXTPNR_H +#error Include "archdefs.h" via "nextpnr.h" only. +#endif + +NEXTPNR_NAMESPACE_BEGIN + +typedef float delay_t; + +struct DelayInfo +{ + delay_t delay = 0; + + delay_t minRaiseDelay() const { return delay; } + delay_t maxRaiseDelay() const { return delay; } + + delay_t minFallDelay() const { return delay; } + delay_t maxFallDelay() const { return delay; } + + delay_t minDelay() const { return delay; } + delay_t maxDelay() const { return delay; } + + DelayInfo operator+(const DelayInfo &other) const + { + DelayInfo ret; + ret.delay = this->delay + other.delay; + return ret; + } +}; + +typedef IdString BelId; +typedef IdString WireId; +typedef IdString PipId; +typedef IdString GroupId; +typedef IdString DecalId; + +struct ArchNetInfo +{ +}; + +struct NetInfo; + +struct ArchCellInfo +{ + // Custom grouping set via "PACK_GROUP" attribute. All cells with the same group + // value may share a tile (-1 = don't care, default if not set) + int user_group; + // Is a slice type primitive + bool is_slice; + // Only packing rule for slice type primitives is a single clock per tile + const NetInfo *slice_clk; +}; + +NEXTPNR_NAMESPACE_END diff --git a/machxo2/cells.cc b/machxo2/cells.cc new file mode 100644 index 00000000..c4421f90 --- /dev/null +++ b/machxo2/cells.cc @@ -0,0 +1,147 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2019 David Shah + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "cells.h" +#include "design_utils.h" +#include "log.h" +#include "util.h" + +NEXTPNR_NAMESPACE_BEGIN + +void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir) +{ + IdString id = ctx->id(name); + NPNR_ASSERT(cell->ports.count(id) == 0); + cell->ports[id] = PortInfo{id, nullptr, dir}; +} + +std::unique_ptr create_generic_cell(Context *ctx, IdString type, std::string name) +{ + static int auto_idx = 0; + std::unique_ptr new_cell = std::unique_ptr(new CellInfo()); + if (name.empty()) { + new_cell->name = ctx->id("$nextpnr_" + type.str(ctx) + "_" + std::to_string(auto_idx++)); + } else { + new_cell->name = ctx->id(name); + } + new_cell->type = type; + if (type == ctx->id("GENERIC_SLICE")) { + new_cell->params[ctx->id("K")] = ctx->args.K; + new_cell->params[ctx->id("INIT")] = 0; + new_cell->params[ctx->id("FF_USED")] = 0; + + for (int i = 0; i < ctx->args.K; i++) + add_port(ctx, new_cell.get(), "I[" + std::to_string(i) + "]", PORT_IN); + + add_port(ctx, new_cell.get(), "CLK", PORT_IN); + + add_port(ctx, new_cell.get(), "F", PORT_OUT); + add_port(ctx, new_cell.get(), "Q", PORT_OUT); + } else if (type == ctx->id("GENERIC_IOB")) { + new_cell->params[ctx->id("INPUT_USED")] = 0; + new_cell->params[ctx->id("OUTPUT_USED")] = 0; + new_cell->params[ctx->id("ENABLE_USED")] = 0; + + add_port(ctx, new_cell.get(), "PAD", PORT_INOUT); + add_port(ctx, new_cell.get(), "I", PORT_IN); + add_port(ctx, new_cell.get(), "EN", PORT_IN); + add_port(ctx, new_cell.get(), "O", PORT_OUT); + } else { + log_error("unable to create generic cell of type %s", type.c_str(ctx)); + } + return new_cell; +} + +void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) +{ + lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")]; + + int lut_k = int_or_default(lut->params, ctx->id("K"), 4); + NPNR_ASSERT(lut_k <= ctx->args.K); + + for (int i = 0; i < lut_k; i++) { + IdString port = ctx->id("I[" + std::to_string(i) + "]"); + replace_port(lut, port, lc, port); + } + + if (no_dff) { + lc->params[ctx->id("FF_USED")] = 0; + replace_port(lut, ctx->id("Q"), lc, ctx->id("F")); + } +} + +void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) +{ + lc->params[ctx->id("FF_USED")] = 1; + replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK")); + + if (pass_thru_lut) { + // Fill LUT with alternating 10 + const int init_size = 1 << lc->params[ctx->id("K")].as_int64(); + std::string init; + init.reserve(init_size); + for (int i = 0; i < init_size; i += 2) + init.append("10"); + lc->params[ctx->id("INIT")] = Property::from_string(init); + + replace_port(dff, ctx->id("D"), lc, ctx->id("I[0]")); + } + + replace_port(dff, ctx->id("Q"), lc, ctx->id("Q")); +} + +void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set &todelete_cells) +{ + if (nxio->type == ctx->id("$nextpnr_ibuf")) { + iob->params[ctx->id("INPUT_USED")] = 1; + replace_port(nxio, ctx->id("O"), iob, ctx->id("O")); + } else if (nxio->type == ctx->id("$nextpnr_obuf")) { + iob->params[ctx->id("OUTPUT_USED")] = 1; + replace_port(nxio, ctx->id("I"), iob, ctx->id("I")); + } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { + // N.B. tristate will be dealt with below + iob->params[ctx->id("INPUT_USED")] = 1; + iob->params[ctx->id("OUTPUT_USED")] = 1; + replace_port(nxio, ctx->id("I"), iob, ctx->id("I")); + replace_port(nxio, ctx->id("O"), iob, ctx->id("O")); + } else { + NPNR_ASSERT(false); + } + NetInfo *donet = iob->ports.at(ctx->id("I")).net; + CellInfo *tbuf = net_driven_by( + ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); }, + ctx->id("Y")); + if (tbuf) { + iob->params[ctx->id("ENABLE_USED")] = 1; + replace_port(tbuf, ctx->id("A"), iob, ctx->id("I")); + replace_port(tbuf, ctx->id("E"), iob, ctx->id("EN")); + + if (donet->users.size() > 1) { + for (auto user : donet->users) + log_info(" remaining tristate user: %s.%s\n", user.cell->name.c_str(ctx), user.port.c_str(ctx)); + log_error("unsupported tristate IO pattern for IO buffer '%s', " + "instantiate GENERIC_IOB manually to ensure correct behaviour\n", + nxio->name.c_str(ctx)); + } + ctx->nets.erase(donet->name); + todelete_cells.insert(tbuf->name); + } +} + +NEXTPNR_NAMESPACE_END diff --git a/machxo2/cells.h b/machxo2/cells.h new file mode 100644 index 00000000..646d738d --- /dev/null +++ b/machxo2/cells.h @@ -0,0 +1,55 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2019 David Shah + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "nextpnr.h" + +#ifndef GENERIC_CELLS_H +#define GENERIC_CELLS_H + +NEXTPNR_NAMESPACE_BEGIN + +// Create a generic arch cell and return it +// Name will be automatically assigned if not specified +std::unique_ptr create_generic_cell(Context *ctx, IdString type, std::string name = ""); + +// Return true if a cell is a LUT +inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("LUT"); } + +// Return true if a cell is a flipflop +inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("DFF"); } + +inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("GENERIC_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 +// can be reconnected +void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = true); + +// Convert a DFF primitive to (part of) an GENERIC_SLICE, setting parameters +// and reconnecting signals as necessary. If pass_thru_lut is True, the LUT will +// be configured as pass through and D connected to I0, otherwise D will be +// ignored +void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false); + +// Convert a nextpnr IO buffer to a GENERIC_IOB +void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set &todelete_cells); + +NEXTPNR_NAMESPACE_END + +#endif diff --git a/machxo2/examples/.gitignore b/machxo2/examples/.gitignore new file mode 100644 index 00000000..ad2fba28 --- /dev/null +++ b/machxo2/examples/.gitignore @@ -0,0 +1,6 @@ +blinky.fasm +__pycache__ +*.pyc +pnrblinky.v +/blinky_simtest +*.vcd diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md new file mode 100644 index 00000000..e064d077 --- /dev/null +++ b/machxo2/examples/README.md @@ -0,0 +1,15 @@ +# MachXO2 Architecture Example + +This contains a simple example of the nextpnr machxo2 API. As time goes on, +python scripts required as boilerplate will be removed. + + - simple.py procedurally generates a simple FPGA architecture with IO at the edges, + logic slices in all other tiles, and interconnect only between adjacent tiles + + - simple_timing.py annotates cells with timing data (this is a separate script that must be run after packing) + + - write_fasm.py uses the nextpnr Python API to write a FASM file for a design + + - bitstream.py uses write_fasm.py to create a FASM ("FPGA assembly") file for the place-and-routed design + + - Run simple.sh to build an example design on the FPGA above diff --git a/machxo2/examples/__init__.py b/machxo2/examples/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/machxo2/examples/bitstream.py b/machxo2/examples/bitstream.py new file mode 100644 index 00000000..7f0b5c07 --- /dev/null +++ b/machxo2/examples/bitstream.py @@ -0,0 +1,17 @@ +from write_fasm import * +from simple_config import K + +# Need to tell FASM generator how to write parameters +# (celltype, parameter) -> ParameterConfig +param_map = { + ("GENERIC_SLICE", "K"): ParameterConfig(write=False), + ("GENERIC_SLICE", "INIT"): ParameterConfig(write=True, numeric=True, width=2**K), + ("GENERIC_SLICE", "FF_USED"): ParameterConfig(write=True, numeric=True, width=1), + + ("GENERIC_IOB", "INPUT_USED"): ParameterConfig(write=True, numeric=True, width=1), + ("GENERIC_IOB", "OUTPUT_USED"): ParameterConfig(write=True, numeric=True, width=1), + ("GENERIC_IOB", "ENABLE_USED"): ParameterConfig(write=True, numeric=True, width=1), +} + +with open("blinky.fasm", "w") as f: + write_fasm(ctx, param_map, f) diff --git a/machxo2/examples/blinky.v b/machxo2/examples/blinky.v new file mode 100644 index 00000000..42becb72 --- /dev/null +++ b/machxo2/examples/blinky.v @@ -0,0 +1,12 @@ +module top(input clk, rst, output reg [7:0] leds); + +reg [7:0] ctr; +always @(posedge clk) + if (rst) + ctr <= 8'h00; + else + ctr <= ctr + 1'b1; + +assign leds = ctr; + +endmodule diff --git a/machxo2/examples/blinky_tb.v b/machxo2/examples/blinky_tb.v new file mode 100644 index 00000000..f9925e6f --- /dev/null +++ b/machxo2/examples/blinky_tb.v @@ -0,0 +1,38 @@ +`timescale 1ns / 1ps +module blinky_tb; + +reg clk = 1'b0, rst = 1'b0; +reg [7:0] ctr_gold = 8'h00; +wire [7:0] ctr_gate; +top dut_i(.clk(clk), .rst(rst), .leds(ctr_gate)); + +task oneclk; + begin + clk = 1'b1; + #10; + clk = 1'b0; + #10; + end +endtask + +initial begin + $dumpfile("blinky_simtest.vcd"); + $dumpvars(0, blinky_tb); + #100; + rst = 1'b1; + repeat (5) oneclk; + #5 + rst = 1'b0; + #5 + repeat (500) begin + if (ctr_gold !== ctr_gate) begin + $display("mismatch gold=%b gate=%b", ctr_gold, ctr_gate); + $stop; + end + oneclk; + ctr_gold = ctr_gold + 1'b1; + end + $finish; +end + +endmodule diff --git a/machxo2/examples/simple.py b/machxo2/examples/simple.py new file mode 100644 index 00000000..9379b505 --- /dev/null +++ b/machxo2/examples/simple.py @@ -0,0 +1,77 @@ +from simple_config import * + +def is_io(x, y): + return x == 0 or x == X-1 or y == 0 or y == Y-1 + +for x in range(X): + for y in range(Y): + # Bel port wires + for z in range(N): + ctx.addWire(name="X%dY%dZ%d_CLK" % (x, y, z), type="BEL_CLK", x=x, y=y) + ctx.addWire(name="X%dY%dZ%d_Q" % (x, y, z), type="BEL_Q", x=x, y=y) + ctx.addWire(name="X%dY%dZ%d_F" % (x, y, z), type="BEL_F", x=x, y=y) + for i in range(K): + ctx.addWire(name="X%dY%dZ%d_I%d" % (x, y, z, i), type="BEL_I", x=x, y=y) + # Local wires + for l in range(Wl): + ctx.addWire(name="X%dY%d_LOCAL%d" % (x, y, l), type="LOCAL", x=x, y=y) + # Create bels + if is_io(x, y): + if x == y: + continue + for z in range(2): + ctx.addBel(name="X%dY%d_IO%d" % (x, y, z), type="GENERIC_IOB", loc=Loc(x, y, z), gb=False) + ctx.addBelInput(bel="X%dY%d_IO%d" % (x, y, z), name="I", wire="X%dY%dZ%d_I0" % (x, y, z)) + ctx.addBelInput(bel="X%dY%d_IO%d" % (x, y, z), name="EN", wire="X%dY%dZ%d_I1" % (x, y, z)) + ctx.addBelOutput(bel="X%dY%d_IO%d" % (x, y, z), name="O", wire="X%dY%dZ%d_Q" % (x, y, z)) + else: + for z in range(N): + ctx.addBel(name="X%dY%d_SLICE%d" % (x, y, z), type="GENERIC_SLICE", loc=Loc(x, y, z), gb=False) + ctx.addBelInput(bel="X%dY%d_SLICE%d" % (x, y, z), name="CLK", wire="X%dY%dZ%d_CLK" % (x, y, z)) + for k in range(K): + ctx.addBelInput(bel="X%dY%d_SLICE%d" % (x, y, z), name="I[%d]" % k, wire="X%dY%dZ%d_I%d" % (x, y, z, k)) + ctx.addBelOutput(bel="X%dY%d_SLICE%d" % (x, y, z), name="F", wire="X%dY%dZ%d_F" % (x, y, z)) + ctx.addBelOutput(bel="X%dY%d_SLICE%d" % (x, y, z), name="Q", wire="X%dY%dZ%d_Q" % (x, y, z)) + +for x in range(X): + for y in range(Y): + # Pips driving bel input wires + # Bel input wires are driven by every Si'th local with an offset + def create_input_pips(dst, offset, skip): + for i in range(offset % skip, Wl, skip): + src = "X%dY%d_LOCAL%d" % (x, y, i) + ctx.addPip(name="X%dY%d.%s.%s" % (x, y, src, dst), type="BEL_INPUT", + srcWire=src, dstWire=dst, delay=ctx.getDelayFromNS(0.05), loc=Loc(x, y, 0)) + for z in range(N): + create_input_pips("X%dY%dZ%d_CLK" % (x, y, z), 0, Si) + for k in range(K): + create_input_pips("X%dY%dZ%d_I%d" % (x, y, z, k), k % Si, Si) + + # Pips from bel outputs to locals + def create_output_pips(dst, offset, skip): + for i in range(offset % skip, N, skip): + src = "X%dY%dZ%d_F" % (x, y, i) + ctx.addPip(name="X%dY%d.%s.%s" % (x, y, src, dst), type="BEL_OUTPUT", + srcWire=src, dstWire=dst, delay=ctx.getDelayFromNS(0.05), loc=Loc(x, y, 0)) + src = "X%dY%dZ%d_Q" % (x, y, i) + ctx.addPip(name="X%dY%d.%s.%s" % (x, y, src, dst), type="BEL_OUTPUT", + srcWire=src, dstWire=dst, delay=ctx.getDelayFromNS(0.05), loc=Loc(x, y, 0)) + # Pips from neighbour locals to locals + def create_neighbour_pips(dst, nx, ny, offset, skip): + if nx < 0 or nx >= X or ny < 0 or ny >= Y: + return + for i in range(offset % skip, Wl, skip): + src = "X%dY%d_LOCAL%d" % (nx, ny, i) + ctx.addPip(name="X%dY%d.%s.%s" % (x, y, src, dst), type="NEIGHBOUR", + srcWire=src, dstWire=dst, delay=ctx.getDelayFromNS(0.05), loc=Loc(x, y, 0)) + for l in range(Wl): + dst = "X%dY%d_LOCAL%d" % (x, y, l) + create_output_pips(dst, l % Sq, Sq) + create_neighbour_pips(dst, x-1, y-1, (l + 1) % Sl, Sl) + create_neighbour_pips(dst, x-1, y, (l + 2) % Sl, Sl) + create_neighbour_pips(dst, x-1, y+1, (l + 2) % Sl, Sl) + create_neighbour_pips(dst, x, y-1, (l + 3) % Sl, Sl) + create_neighbour_pips(dst, x, y+1, (l + 4) % Sl, Sl) + create_neighbour_pips(dst, x+1, y-1, (l + 5) % Sl, Sl) + create_neighbour_pips(dst, x+1, y, (l + 6) % Sl, Sl) + create_neighbour_pips(dst, x+1, y+1, (l + 7) % Sl, Sl) diff --git a/machxo2/examples/simple.sh b/machxo2/examples/simple.sh new file mode 100644 index 00000000..425bc6ff --- /dev/null +++ b/machxo2/examples/simple.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -ex +yosys -p "tcl ../synth/synth_generic.tcl 4 blinky.json" blinky.v +${NEXTPNR:-../../nextpnr-machxo2} --pre-pack simple.py --pre-place simple_timing.py --json blinky.json --post-route bitstream.py --write pnrblinky.json +yosys -p "read_verilog -lib ../synth/prims.v; read_json pnrblinky.json; dump -o blinky.il; show -format png -prefix blinky" diff --git a/machxo2/examples/simple_config.py b/machxo2/examples/simple_config.py new file mode 100644 index 00000000..dfb38f1c --- /dev/null +++ b/machxo2/examples/simple_config.py @@ -0,0 +1,15 @@ +# Grid size including IOBs at edges +X = 12 +Y = 12 +# SLICEs per tile +N = 8 +# LUT input count +K = 4 +# Number of local wires +Wl = N*(K+1) + 8 +# 1/Fc for bel input wire pips +Si = 4 +# 1/Fc for Q to local wire pips +Sq = 4 +# ~1/Fc local to neighbour local wire pips +Sl = 8 \ No newline at end of file diff --git a/machxo2/examples/simple_timing.py b/machxo2/examples/simple_timing.py new file mode 100644 index 00000000..1067b556 --- /dev/null +++ b/machxo2/examples/simple_timing.py @@ -0,0 +1,13 @@ +for cname, cell in ctx.cells: + if cell.type != "GENERIC_SLICE": + continue + if cname in ("$PACKER_GND", "$PACKER_VCC"): + continue + K = int(cell.params["K"]) + ctx.addCellTimingClock(cell=cname, port="CLK") + for i in range(K): + ctx.addCellTimingSetupHold(cell=cname, port="I[%d]" % i, clock="CLK", + setup=ctx.getDelayFromNS(0.2), hold=ctx.getDelayFromNS(0)) + ctx.addCellTimingClockToOut(cell=cname, port="Q", clock="CLK", clktoq=ctx.getDelayFromNS(0.2)) + for i in range(K): + ctx.addCellTimingDelay(cell=cname, fromPort="I[%d]" % i, toPort="F", delay=ctx.getDelayFromNS(0.2)) diff --git a/machxo2/examples/simtest.sh b/machxo2/examples/simtest.sh new file mode 100644 index 00000000..a53f5c15 --- /dev/null +++ b/machxo2/examples/simtest.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -ex +yosys -p "tcl ../synth/synth_generic.tcl 4 blinky.json" blinky.v +${NEXTPNR:-../../nextpnr-machxo2} --no-iobs --pre-pack simple.py --pre-place simple_timing.py --json blinky.json --post-route bitstream.py --write pnrblinky.json +yosys -p "read_json pnrblinky.json; write_verilog -noattr -norename pnrblinky.v" +iverilog -o blinky_simtest ../synth/prims.v blinky_tb.v pnrblinky.v +vvp -N ./blinky_simtest diff --git a/machxo2/examples/write_fasm.py b/machxo2/examples/write_fasm.py new file mode 100644 index 00000000..ede8f16b --- /dev/null +++ b/machxo2/examples/write_fasm.py @@ -0,0 +1,51 @@ +from collections import namedtuple + +""" + write: set to True to enable writing this parameter to FASM + + numeric: set to True to write this parameter as a bit array (width>1) or + single bit (width==1) named after the parameter. Otherwise this + parameter will be written as `name.value` + + width: width of numeric parameter (ignored for non-numeric parameters) + + alias: an alternative name for this parameter (parameter name used if alias + is None) +""" +ParameterConfig = namedtuple('ParameterConfig', 'write numeric width alias') + +# FIXME use defaults= once Python 3.7 is standard +ParameterConfig.__new__.__defaults__ = (False, True, 1, None) + + +""" +Write a design as FASM + + ctx: nextpnr context + paramCfg: map from (celltype, parametername) -> ParameterConfig describing how to write parameters + f: output file +""" +def write_fasm(ctx, paramCfg, f): + for nname, net in sorted(ctx.nets, key=lambda x: str(x[1].name)): + print("# Net %s" % nname, file=f) + for wire, pip in sorted(net.wires, key=lambda x: str(x[1])): + if pip.pip != "": + print("%s" % pip.pip, file=f) + print("", file=f) + for cname, cell in sorted(ctx.cells, key=lambda x: str(x[1].name)): + print("# Cell %s at %s" % (cname, cell.bel), file=f) + for param, val in sorted(cell.params, key=lambda x: str(x)): + cfg = paramCfg[(cell.type, param)] + if not cfg.write: + continue + fasm_name = cfg.alias if cfg.alias is not None else param + if cfg.numeric: + if cfg.width == 1: + if int(val) != 0: + print("%s.%s" % (cell.bel, fasm_name), file=f) + else: + # Parameters with width >32 are direct binary, otherwise denary + print("%s.%s[%d:0] = %d'b%s" % (cell.bel, fasm_name, cfg.width-1, cfg.width, val), file=f) + else: + print("%s.%s.%s" % (cell.bel, fasm_name, val), file=f) + print("", file=f) \ No newline at end of file diff --git a/machxo2/family.cmake b/machxo2/family.cmake new file mode 100644 index 00000000..e69de29b diff --git a/machxo2/main.cc b/machxo2/main.cc new file mode 100644 index 00000000..bb780996 --- /dev/null +++ b/machxo2/main.cc @@ -0,0 +1,75 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifdef MAIN_EXECUTABLE + +#include +#include "command.h" +#include "design_utils.h" +#include "log.h" +#include "timing.h" + +USING_NEXTPNR_NAMESPACE + +class GenericCommandHandler : public CommandHandler +{ + public: + GenericCommandHandler(int argc, char **argv); + virtual ~GenericCommandHandler(){}; + std::unique_ptr createContext(std::unordered_map &values) override; + void setupArchContext(Context *ctx) override{}; + void customBitstream(Context *ctx) override; + + protected: + po::options_description getArchOptions() override; +}; + +GenericCommandHandler::GenericCommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {} + +po::options_description GenericCommandHandler::getArchOptions() +{ + po::options_description specific("Architecture specific options"); + specific.add_options()("generic", "set device type to generic"); + specific.add_options()("no-iobs", "disable automatic IO buffer insertion"); + return specific; +} + +void GenericCommandHandler::customBitstream(Context *ctx) {} + +std::unique_ptr GenericCommandHandler::createContext(std::unordered_map &values) +{ + ArchArgs chipArgs; + if (values.find("arch.name") != values.end()) { + std::string arch_name = values["arch.name"].as_string(); + if (arch_name != "generic") + log_error("Unsuported architecture '%s'.\n", arch_name.c_str()); + } + auto ctx = std::unique_ptr(new Context(chipArgs)); + if (vm.count("no-iobs")) + ctx->settings[ctx->id("disable_iobs")] = Property::State::S1; + return ctx; +} + +int main(int argc, char *argv[]) +{ + GenericCommandHandler handler(argc, argv); + return handler.exec(); +} + +#endif diff --git a/machxo2/pack.cc b/machxo2/pack.cc new file mode 100644 index 00000000..43157b6c --- /dev/null +++ b/machxo2/pack.cc @@ -0,0 +1,288 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018-19 David Shah + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include +#include +#include "cells.h" +#include "design_utils.h" +#include "log.h" +#include "util.h" + +NEXTPNR_NAMESPACE_BEGIN + +// Pack LUTs and LUT-FF pairs +static void pack_lut_lutffs(Context *ctx) +{ + log_info("Packing LUT-FFs..\n"); + + std::unordered_set packed_cells; + std::vector> new_cells; + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + 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 packed = + create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), ci->name.str(ctx) + "_LC"); + std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); + packed_cells.insert(ci->name); + if (ctx->verbose) + log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); + // See if we can pack into a DFF + // TODO: LUT cascade + NetInfo *o = ci->ports.at(ctx->id("Q")).net; + CellInfo *dff = net_only_drives(ctx, o, is_ff, ctx->id("D"), true); + auto lut_bel = ci->attrs.find(ctx->id("BEL")); + bool packed_dff = false; + if (dff) { + if (ctx->verbose) + log_info("found attached dff %s\n", dff->name.c_str(ctx)); + auto dff_bel = dff->attrs.find(ctx->id("BEL")); + if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) { + // Locations don't match, can't pack + } else { + lut_to_lc(ctx, ci, packed.get(), false); + dff_to_lc(ctx, dff, packed.get(), false); + ctx->nets.erase(o->name); + if (dff_bel != dff->attrs.end()) + packed->attrs[ctx->id("BEL")] = dff_bel->second; + packed_cells.insert(dff->name); + if (ctx->verbose) + log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx)); + packed_dff = true; + } + } + if (!packed_dff) { + lut_to_lc(ctx, ci, packed.get(), true); + } + new_cells.push_back(std::move(packed)); + } + } + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + +// Pack FFs not packed as LUTFFs +static void pack_nonlut_ffs(Context *ctx) +{ + log_info("Packing non-LUT FFs..\n"); + + std::unordered_set packed_cells; + std::vector> new_cells; + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_ff(ctx, ci)) { + std::unique_ptr packed = + create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), ci->name.str(ctx) + "_DFFLC"); + std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); + if (ctx->verbose) + log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); + packed_cells.insert(ci->name); + dff_to_lc(ctx, ci, packed.get(), true); + new_cells.push_back(std::move(packed)); + } + } + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + +// Merge a net into a constant net +static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval) +{ + orig->driver.cell = nullptr; + for (auto user : orig->users) { + if (user.cell != nullptr) { + CellInfo *uc = user.cell; + if (ctx->verbose) + log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx)); + if ((is_lut(ctx, uc) || is_lc(ctx, uc)) && (user.port.str(ctx).at(0) == 'I') && !constval) { + uc->ports[user.port].net = nullptr; + } else { + uc->ports[user.port].net = constnet; + constnet->users.push_back(user); + } + } + } + orig->users.clear(); +} + +// Pack constants (simple implementation) +static void pack_constants(Context *ctx) +{ + log_info("Packing constants..\n"); + + std::unique_ptr gnd_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_GND"); + gnd_cell->params[ctx->id("INIT")] = Property(0, 1 << ctx->args.K); + std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); + gnd_net->name = ctx->id("$PACKER_GND_NET"); + gnd_net->driver.cell = gnd_cell.get(); + gnd_net->driver.port = ctx->id("F"); + gnd_cell->ports.at(ctx->id("F")).net = gnd_net.get(); + + std::unique_ptr vcc_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_VCC"); + // Fill with 1s + vcc_cell->params[ctx->id("INIT")] = Property(Property::S1).extract(0, (1 << ctx->args.K), Property::S1); + std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); + vcc_net->name = ctx->id("$PACKER_VCC_NET"); + vcc_net->driver.cell = vcc_cell.get(); + vcc_net->driver.port = ctx->id("F"); + vcc_cell->ports.at(ctx->id("F")).net = vcc_net.get(); + + std::vector dead_nets; + + bool gnd_used = false; + + for (auto net : sorted(ctx->nets)) { + NetInfo *ni = net.second; + if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { + IdString drv_cell = ni->driver.cell->name; + set_net_constant(ctx, ni, gnd_net.get(), false); + gnd_used = true; + dead_nets.push_back(net.first); + ctx->cells.erase(drv_cell); + } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) { + IdString drv_cell = ni->driver.cell->name; + set_net_constant(ctx, ni, vcc_net.get(), true); + dead_nets.push_back(net.first); + ctx->cells.erase(drv_cell); + } + } + + if (gnd_used) { + ctx->cells[gnd_cell->name] = std::move(gnd_cell); + ctx->nets[gnd_net->name] = std::move(gnd_net); + } + // Vcc cell always inserted for now, as it may be needed during carry legalisation (TODO: trim later if actually + // never used?) + ctx->cells[vcc_cell->name] = std::move(vcc_cell); + ctx->nets[vcc_net->name] = std::move(vcc_net); + + for (auto dn : dead_nets) { + ctx->nets.erase(dn); + } +} + +static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) +{ + return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") || + cell->type == ctx->id("$nextpnr_iobuf"); +} + +static bool is_generic_iob(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("GENERIC_IOB"); } + +// Pack IO buffers +static void pack_io(Context *ctx) +{ + std::unordered_set packed_cells; + std::unordered_set delete_nets; + + std::vector> new_cells; + log_info("Packing IOs..\n"); + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_nextpnr_iob(ctx, ci)) { + CellInfo *iob = nullptr; + if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { + iob = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_generic_iob, ctx->id("PAD"), true, ci); + + } else if (ci->type == ctx->id("$nextpnr_obuf")) { + NetInfo *net = ci->ports.at(ctx->id("I")).net; + iob = net_only_drives(ctx, net, is_generic_iob, ctx->id("PAD"), true, ci); + } + if (iob != nullptr) { + // Trivial case, GENERIC_IOB used. Just destroy the net and the + // iobuf + log_info("%s feeds GENERIC_IOB %s, removing %s %s.\n", ci->name.c_str(ctx), iob->name.c_str(ctx), + ci->type.c_str(ctx), ci->name.c_str(ctx)); + NetInfo *net = iob->ports.at(ctx->id("PAD")).net; + if (((ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) && + net->users.size() > 1) || + (ci->type == ctx->id("$nextpnr_obuf") && (net->users.size() > 2 || net->driver.cell != nullptr))) + log_error("PAD of %s '%s' connected to more than a single top level IO.\n", iob->type.c_str(ctx), + iob->name.c_str(ctx)); + + if (net != nullptr) { + delete_nets.insert(net->name); + iob->ports.at(ctx->id("PAD")).net = nullptr; + } + if (ci->type == ctx->id("$nextpnr_iobuf")) { + NetInfo *net2 = ci->ports.at(ctx->id("I")).net; + if (net2 != nullptr) { + delete_nets.insert(net2->name); + } + } + } else if (bool_or_default(ctx->settings, ctx->id("disable_iobs"))) { + // No IO buffer insertion; just remove nextpnr_[io]buf + for (auto &p : ci->ports) + disconnect_port(ctx, ci, p.first); + } else { + // Create a GENERIC_IOB buffer + std::unique_ptr ice_cell = + create_generic_cell(ctx, ctx->id("GENERIC_IOB"), ci->name.str(ctx) + "$iob"); + nxio_to_iob(ctx, ci, ice_cell.get(), packed_cells); + new_cells.push_back(std::move(ice_cell)); + iob = new_cells.back().get(); + } + packed_cells.insert(ci->name); + if (iob != nullptr) + std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(iob->attrs, iob->attrs.begin())); + } + } + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto dnet : delete_nets) { + ctx->nets.erase(dnet); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + +// Main pack function +bool Arch::pack() +{ + Context *ctx = getCtx(); + try { + log_break(); + pack_constants(ctx); + pack_io(ctx); + pack_lut_lutffs(ctx); + pack_nonlut_ffs(ctx); + ctx->settings[ctx->id("pack")] = 1; + ctx->assignArchInfo(); + log_info("Checksum: 0x%08x\n", ctx->checksum()); + return true; + } catch (log_execution_error_exception) { + return false; + } +} + +NEXTPNR_NAMESPACE_END diff --git a/machxo2/synth/cells_map.v b/machxo2/synth/cells_map.v new file mode 100644 index 00000000..1d0939e0 --- /dev/null +++ b/machxo2/synth/cells_map.v @@ -0,0 +1,12 @@ +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + input [WIDTH-1:0] A; + output Y; + + localparam rep = 1<<(`LUT_K-WIDTH); + + LUT #(.K(`LUT_K), .INIT({rep{LUT}})) _TECHMAP_REPLACE_ (.I(A), .Q(Y)); +endmodule + +module \$_DFF_P_ (input D, C, output Q); DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule diff --git a/machxo2/synth/prims.v b/machxo2/synth/prims.v new file mode 100644 index 00000000..ca445e6e --- /dev/null +++ b/machxo2/synth/prims.v @@ -0,0 +1,67 @@ +// LUT and DFF are combined to a GENERIC_SLICE + +module LUT #( + parameter K = 4, + parameter [2**K-1:0] INIT = 0 +) ( + input [K-1:0] I, + output Q +); + wire [K-1:0] I_pd; + + genvar ii; + generate + for (ii = 0; ii < K; ii = ii + 1'b1) + assign I_pd[ii] = (I[ii] === 1'bz) ? 1'b0 : I[ii]; + endgenerate + + assign Q = INIT[I_pd]; +endmodule + +module DFF ( + input CLK, D, + output reg Q +); + initial Q = 1'b0; + always @(posedge CLK) + Q <= D; +endmodule + +module GENERIC_SLICE #( + parameter K = 4, + parameter [2**K-1:0] INIT = 0, + parameter FF_USED = 1'b0 +) ( + input CLK, + input [K-1:0] I, + output F, + output Q +); + wire f_wire; + + LUT #(.K(K), .INIT(INIT)) lut_i(.I(I), .Q(f_wire)); + + DFF dff_i(.CLK(CLK), .D(f_wire), .Q(Q)); + + assign F = f_wire; +endmodule + +module GENERIC_IOB #( + parameter INPUT_USED = 1'b0, + parameter OUTPUT_USED = 1'b0, + parameter ENABLE_USED = 1'b0 +) ( + inout PAD, + input I, EN, + output O +); + generate if (OUTPUT_USED && ENABLE_USED) + assign PAD = EN ? I : 1'bz; + else if (OUTPUT_USED) + assign PAD = I; + endgenerate + + generate if (INPUT_USED) + assign O = PAD; + endgenerate +endmodule diff --git a/machxo2/synth/synth_machxo2.tcl b/machxo2/synth/synth_machxo2.tcl new file mode 100644 index 00000000..e5d88e0d --- /dev/null +++ b/machxo2/synth/synth_machxo2.tcl @@ -0,0 +1,24 @@ +# Usage +# tcl synth_generic.tcl {K} {out.json} + +set LUT_K 4 +if {$argc > 0} { set LUT_K [lindex $argv 0] } +yosys read_verilog -lib [file dirname [file normalize $argv0]]/prims.v +yosys hierarchy -check +yosys proc +yosys flatten +yosys tribuf -logic +yosys deminout +yosys synth -run coarse +yosys memory_map +yosys opt -full +yosys techmap -map +/techmap.v +yosys opt -fast +yosys abc -lut $LUT_K -dress +yosys clean +yosys techmap -D LUT_K=$LUT_K -map [file dirname [file normalize $argv0]]/cells_map.v +yosys clean +yosys hierarchy -check +yosys stat + +if {$argc > 1} { yosys write_json [lindex $argv 1] } -- cgit v1.2.3 From 81d6bc36148b408f4e79837f832b22c6bfb0b69c Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 5 Jun 2020 04:46:59 -0400 Subject: Create sub import of facade DB for 1200 device. Signed-off-by: William D. Jones --- machxo2/constids.inc | 0 machxo2/facade_import.py | 77 ++++++++++++++++++++++++++++++++ machxo2/family.cmake | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 machxo2/constids.inc create mode 100644 machxo2/facade_import.py (limited to 'machxo2') diff --git a/machxo2/constids.inc b/machxo2/constids.inc new file mode 100644 index 00000000..e69de29b diff --git a/machxo2/facade_import.py b/machxo2/facade_import.py new file mode 100644 index 00000000..f12461db --- /dev/null +++ b/machxo2/facade_import.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +import pytrellis +import database +import argparse +import json + +class BinaryBlobAssembler: + def l(self, name, ltype = None, export = False): + if ltype is None: + print("label %s" % (name,)) + else: + print("label %s %s" % (name, ltype)) + + def r(self, name, comment): + if comment is None: + print("ref %s" % (name,)) + else: + print("ref %s %s" % (name, comment)) + + def s(self, s, comment): + assert "|" not in s + print("str |%s| %s" % (s, comment)) + + def u8(self, v, comment): + if comment is None: + print("u8 %d" % (v,)) + else: + print("u8 %d %s" % (v, comment)) + + def u16(self, v, comment): + if comment is None: + print("u16 %d" % (v,)) + else: + print("u16 %d %s" % (v, comment)) + + def u32(self, v, comment): + if comment is None: + print("u32 %d" % (v,)) + else: + print("u32 %d %s" % (v, comment)) + + def pre(self, s): + print("pre %s" % s) + + def post(self, s): + print("post %s" % s) + + def push(self, name): + print("push %s" % name) + + def pop(self): + print("pop") + + +dev_names = {"1200": "LCMXO2-1200HC"} + +def main(): + global max_row, max_col, const_id_count + + parser = argparse.ArgumentParser(description="import MachXO2 routing and bels from Project Trellis") + parser.add_argument("device", type=str, help="target device") + parser.add_argument("-p", "--constids", type=str, help="path to constids.inc") + parser.add_argument("-g", "--gfxh", type=str, help="path to gfx.h (unused)") + args = parser.parse_args() + + pytrellis.load_database(database.get_db_root()) + + bba = BinaryBlobAssembler() + bba.pre('#include "nextpnr.h"') + bba.pre('NEXTPNR_NAMESPACE_BEGIN') + bba.post('NEXTPNR_NAMESPACE_END') + bba.push("chipdb_blob_%s" % args.device) + bba.u8(0, None) + bba.pop() + +if __name__ == "__main__": + main() diff --git a/machxo2/family.cmake b/machxo2/family.cmake index e69de29b..091b4379 100644 --- a/machxo2/family.cmake +++ b/machxo2/family.cmake @@ -0,0 +1,114 @@ +if (BUILD_GUI) + message(FATAL_ERROR "GUI support is not implemented for MachXO2.") +endif() + +if (NOT EXTERNAL_CHIPDB) + set(devices 1200) + + set(TRELLIS_PROGRAM_PREFIX "" CACHE STRING "Name prefix for trellis") + + if (NOT DEFINED TRELLIS_INSTALL_PREFIX) + message(STATUS "TRELLIS_INSTALL_PREFIX not defined using -DTRELLIS_INSTALL_PREFIX=/path-prefix/to/prjtrellis-installation. Defaulted to ${CMAKE_INSTALL_PREFIX}") + set(TRELLIS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) + endif() + + if (NOT DEFINED PYTRELLIS_LIBDIR) + find_library(PYTRELLIS pytrellis.so + PATHS ${TRELLIS_INSTALL_PREFIX}/lib/${TRELLIS_PROGRAM_PREFIX}trellis + PATH_SUFFIXES ${TRELLIS_PROGRAM_PREFIX}trellis + DOC "Location of pytrellis library") + + if ("${PYTRELLIS}" STREQUAL "PYTRELLIS-NOTFOUND") + message(FATAL_ERROR "Failed to locate pytrellis library!") + endif() + + get_filename_component(PYTRELLIS_LIBDIR ${PYTRELLIS} DIRECTORY) + endif() + + set(DB_PY ${CMAKE_CURRENT_SOURCE_DIR}/machxo2/facade_import.py) + + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/) + add_library(machxo2_chipdb OBJECT ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/) + target_compile_definitions(machxo2_chipdb PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family}) + target_include_directories(machxo2_chipdb PRIVATE ${family}/) + + if (CMAKE_HOST_WIN32) + set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=\"${PYTRELLIS_LIBDIR}\;${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/util/common\;${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/timing/util\"") + else() + set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=${PYTRELLIS_LIBDIR}\:${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/util/common:${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/timing/util") + endif() + + if (MSVC) + target_sources(machxo2_chipdb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/machxo2/resource/embed.cc) + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/machxo2/resources/chipdb.rc PROPERTIES LANGUAGE RC) + set(PREV_DEV_CC_BBA_DB) + foreach (dev ${devices}) + set(DEV_CC_DB ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/chipdb-${dev}.bin) + set(DEV_CC_BBA_DB ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/chipdb-${dev}.bba) + set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/machxo2/constids.inc) + if (PREGENERATED_BBA_PATH) + add_custom_command(OUTPUT ${DEV_CC_DB} + COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${PREGENERATED_BBA_PATH}/chipdb-${dev}.bba ${DEV_CC_DB} + ) + else() + add_custom_command(OUTPUT ${DEV_CC_BBA_DB} + COMMAND ${ENV_CMD} ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB} + DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${PREV_DEV_CC_BBA_DB} + ) + add_custom_command(OUTPUT ${DEV_CC_DB} + COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB} + DEPENDS bbasm ${DEV_CC_BBA_DB} + ) + endif() + if (SERIALIZE_CHIPDB) + set(PREV_DEV_CC_BBA_DB ${DEV_CC_BBA_DB}) + endif() + target_sources(machxo2_chipdb PRIVATE ${DEV_CC_DB}) + set_source_files_properties(${DEV_CC_DB} PROPERTIES HEADER_FILE_ONLY TRUE) + foreach (target ${family_targets}) + target_sources(${target} PRIVATE $ ${CMAKE_CURRENT_SOURCE_DIR}/machxo2/resource/chipdb.rc) + endforeach() + endforeach() + else() + target_compile_options(machxo2_chipdb PRIVATE -g0 -O0 -w) + set(PREV_DEV_CC_BBA_DB) + foreach (dev ${devices}) + set(DEV_CC_BBA_DB ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/chipdb-${dev}.bba) + set(DEV_CC_DB ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/chipdb-${dev}.cc) + set(DEV_BIN_DB ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/chipdb-${dev}.bin) + set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/machxo2/constids.inc) + if (PREGENERATED_BBA_PATH) + add_custom_command(OUTPUT ${DEV_CC_DB} + COMMAND bbasm --c ${BBASM_ENDIAN_FLAG} ${PREGENERATED_BBA_PATH}/chipdb-${dev}.bba ${DEV_CC_DB}.new + COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB} + ) + else() + add_custom_command(OUTPUT ${DEV_CC_BBA_DB} + COMMAND ${ENV_CMD} ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB}.new + COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB} + DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${PREV_DEV_CC_BBA_DB} + ) + if(USE_C_EMBED) + add_custom_command(OUTPUT ${DEV_CC_DB} + COMMAND bbasm --e ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new ${DEV_BIN_DB} + COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB} + DEPENDS bbasm ${DEV_CC_BBA_DB} + ) + else() + add_custom_command(OUTPUT ${DEV_CC_DB} + COMMAND bbasm --c ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new + COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB} + DEPENDS bbasm ${DEV_CC_BBA_DB} + ) + endif() + endif() + if (SERIALIZE_CHIPDB) + set(PREV_DEV_CC_BBA_DB ${DEV_CC_BBA_DB}) + endif() + target_sources(machxo2_chipdb PRIVATE ${DEV_CC_DB}) + foreach (target ${family_targets}) + target_sources(${target} PRIVATE $) + endforeach() + endforeach() + endif() +endif() -- cgit v1.2.3 From c38762f91f649815ab1162dc981da84cab98dd61 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 25 Jun 2020 20:13:11 -0400 Subject: Update machxo2 backend with build system changes. --- machxo2/CMakeLists.txt | 91 ++++++++++++++++++++++++++ machxo2/facade_import.py | 21 +++--- machxo2/family.cmake | 153 +++++++++++++------------------------------- machxo2/resource/chipdb.rc | 3 + machxo2/resource/embed.cc | 24 +++++++ machxo2/resource/resource.h | 2 + 6 files changed, 178 insertions(+), 116 deletions(-) create mode 100644 machxo2/CMakeLists.txt create mode 100644 machxo2/resource/chipdb.rc create mode 100644 machxo2/resource/embed.cc create mode 100644 machxo2/resource/resource.h (limited to 'machxo2') diff --git a/machxo2/CMakeLists.txt b/machxo2/CMakeLists.txt new file mode 100644 index 00000000..ab4eded6 --- /dev/null +++ b/machxo2/CMakeLists.txt @@ -0,0 +1,91 @@ +cmake_minimum_required(VERSION 3.5) +project(chipdb-machxo2 NONE) + +# set(ALL_MACHXO2_DEVICES 256 640 1200 2000 4000 7000) +set(ALL_MACHXO2_DEVICES 1200) +set(MACHXO2_DEVICES 1200 CACHE STRING + "Include support for these MachXO2 devices (available: ${ALL_MACHXO2_DEVICES})") +message(STATUS "Enabled MachXO2 devices: ${MACHXO2_DEVICES}") + +if(DEFINED MACHXO2_CHIPDB) + add_custom_target(chipdb-machxo2-bbas ALL) +else() + find_package(PythonInterp 3.5 REQUIRED) + + # shared among all families + set(SERIALIZE_CHIPDBS TRUE CACHE BOOL + "Serialize device data preprocessing to minimize memory use") + + set(TRELLIS_PROGRAM_PREFIX "" CACHE STRING + "Trellis name prefix") + if(TRELLIS_PROGRAM_PREFIX) + message(STATUS "Trellis program prefix: ${TRELLIS_PROGRAM_PREFIX}") + endif() + + set(TRELLIS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE STRING + "Trellis install prefix") + message(STATUS "Trellis install prefix: ${TRELLIS_INSTALL_PREFIX}") + + if(NOT DEFINED TRELLIS_LIBDIR) + if(WIN32) + set(pytrellis_lib pytrellis.pyd) + else() + set(pytrellis_lib pytrellis${CMAKE_SHARED_LIBRARY_SUFFIX}) + endif() + find_path(TRELLIS_LIBDIR ${pytrellis_lib} + HINTS ${TRELLIS_INSTALL_PREFIX}/lib/${TRELLIS_PROGRAM_PREFIX}trellis + PATHS ${CMAKE_SYSTEM_LIBRARY_PATH} ${CMAKE_LIBRARY_PATH} + PATH_SUFFIXES ${TRELLIS_PROGRAM_PREFIX}trellis + DOC "Location of the pytrellis library") + if(NOT TRELLIS_LIBDIR) + message(FATAL_ERROR "Failed to locate the pytrellis library") + endif() + endif() + message(STATUS "Trellis library directory: ${TRELLIS_LIBDIR}") + + if(NOT DEFINED TRELLIS_DATADIR) + set(TRELLIS_DATADIR ${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis) + endif() + message(STATUS "Trellis data directory: ${TRELLIS_DATADIR}") + + set(all_device_bbas) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chipdb) + foreach(device ${MACHXO2_DEVICES}) + if(NOT device IN_LIST ALL_MACHXO2_DEVICES) + message(FATAL_ERROR "Device ${device} is not a supported MachXO2 device") + endif() + + set(device_bba chipdb/chipdb-${device}.bba) + add_custom_command( + OUTPUT ${device_bba} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/facade_import.py + -L ${TRELLIS_LIBDIR} + -L ${TRELLIS_DATADIR}/util/common + -L ${TRELLIS_DATADIR}/timing/util + -p ${CMAKE_CURRENT_SOURCE_DIR}/constids.inc + ${device} + > ${device_bba}.new + # atomically update + COMMAND ${CMAKE_COMMAND} -E rename ${device_bba}.new ${device_bba} + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/facade_import.py + ${CMAKE_CURRENT_SOURCE_DIR}/constids.inc + ${PREVIOUS_CHIPDB_TARGET} + VERBATIM) + list(APPEND all_device_bbas ${device_bba}) + if(SERIALIZE_CHIPDBS) + set(PREVIOUS_CHIPDB_TARGET ${CMAKE_CURRENT_BINARY_DIR}/${device_bba}) + endif() + endforeach() + + add_custom_target(chipdb-machxo2-bbas ALL DEPENDS ${all_device_bbas}) + + get_directory_property(has_parent PARENT_DIRECTORY) + if(has_parent) + set(MACHXO2_CHIPDB ${CMAKE_CURRENT_BINARY_DIR}/chipdb PARENT_SCOPE) + # serialize chipdb build across multiple architectures + set(PREVIOUS_CHIPDB_TARGET chipdb-machxo2-bbas PARENT_SCOPE) + else() + message(STATUS "Build nextpnr with -DMACHXO2_CHIPDB=${CMAKE_CURRENT_BINARY_DIR}") + endif() +endif() diff --git a/machxo2/facade_import.py b/machxo2/facade_import.py index f12461db..dd21a698 100644 --- a/machxo2/facade_import.py +++ b/machxo2/facade_import.py @@ -1,8 +1,19 @@ #!/usr/bin/env python3 -import pytrellis -import database import argparse import json +import sys + +parser = argparse.ArgumentParser(description="import MachXO2 routing and bels from Project Trellis") +parser.add_argument("device", type=str, help="target device") +parser.add_argument("-p", "--constids", type=str, help="path to constids.inc") +parser.add_argument("-g", "--gfxh", type=str, help="path to gfx.h (unused)") +parser.add_argument("-L", "--libdir", type=str, action="append", help="extra Python library path") +args = parser.parse_args() + +sys.path += args.libdir +import pytrellis +import database + class BinaryBlobAssembler: def l(self, name, ltype = None, export = False): @@ -57,12 +68,6 @@ dev_names = {"1200": "LCMXO2-1200HC"} def main(): global max_row, max_col, const_id_count - parser = argparse.ArgumentParser(description="import MachXO2 routing and bels from Project Trellis") - parser.add_argument("device", type=str, help="target device") - parser.add_argument("-p", "--constids", type=str, help="path to constids.inc") - parser.add_argument("-g", "--gfxh", type=str, help="path to gfx.h (unused)") - args = parser.parse_args() - pytrellis.load_database(database.get_db_root()) bba = BinaryBlobAssembler() diff --git a/machxo2/family.cmake b/machxo2/family.cmake index 091b4379..0c829d55 100644 --- a/machxo2/family.cmake +++ b/machxo2/family.cmake @@ -1,114 +1,51 @@ if (BUILD_GUI) - message(FATAL_ERROR "GUI support is not implemented for MachXO2.") + message(FATAL_ERROR "GUI support is not implemented for MachXO2. Build with -DBUILD_GUI=OFF.") endif() - -if (NOT EXTERNAL_CHIPDB) - set(devices 1200) - - set(TRELLIS_PROGRAM_PREFIX "" CACHE STRING "Name prefix for trellis") - - if (NOT DEFINED TRELLIS_INSTALL_PREFIX) - message(STATUS "TRELLIS_INSTALL_PREFIX not defined using -DTRELLIS_INSTALL_PREFIX=/path-prefix/to/prjtrellis-installation. Defaulted to ${CMAKE_INSTALL_PREFIX}") - set(TRELLIS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) - endif() - - if (NOT DEFINED PYTRELLIS_LIBDIR) - find_library(PYTRELLIS pytrellis.so - PATHS ${TRELLIS_INSTALL_PREFIX}/lib/${TRELLIS_PROGRAM_PREFIX}trellis - PATH_SUFFIXES ${TRELLIS_PROGRAM_PREFIX}trellis - DOC "Location of pytrellis library") - - if ("${PYTRELLIS}" STREQUAL "PYTRELLIS-NOTFOUND") - message(FATAL_ERROR "Failed to locate pytrellis library!") - endif() - - get_filename_component(PYTRELLIS_LIBDIR ${PYTRELLIS} DIRECTORY) +add_subdirectory(${family}) +message(STATUS "Using MachXO2 chipdb: ${MACHXO2_CHIPDB}") + +set(chipdb_sources) +set(chipdb_binaries) +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${family}/chipdb) +foreach(device ${MACHXO2_DEVICES}) + set(chipdb_bba ${MACHXO2_CHIPDB}/chipdb-${device}.bba) + set(chipdb_bin ${family}/chipdb/chipdb-${device}.bin) + set(chipdb_cc ${family}/chipdb/chipdb-${device}.cc) + if(BBASM_MODE STREQUAL "binary") + add_custom_command( + OUTPUT ${chipdb_bin} + COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${chipdb_bba} ${chipdb_bin} + DEPENDS bbasm chipdb-${family}-bbas ${chipdb_bba}) + list(APPEND chipdb_binaries ${chipdb_bin}) + elseif(BBASM_MODE STREQUAL "embed") + add_custom_command( + OUTPUT ${chipdb_cc} ${chipdb_bin} + COMMAND bbasm ${BBASM_ENDIAN_FLAG} --e ${chipdb_bba} ${chipdb_cc} ${chipdb_bin} + DEPENDS bbasm chipdb-${family}-bbas ${chipdb_bba}) + list(APPEND chipdb_sources ${chipdb_cc}) + list(APPEND chipdb_binaries ${chipdb_bin}) + elseif(BBASM_MODE STREQUAL "string") + add_custom_command( + OUTPUT ${chipdb_cc} + COMMAND bbasm ${BBASM_ENDIAN_FLAG} --c ${chipdb_bba} ${chipdb_cc} + DEPENDS bbasm chipdb-${family}-bbas ${chipdb_bba}) + list(APPEND chipdb_sources ${chipdb_cc}) endif() +endforeach() +if(WIN32) + list(APPEND chipdb_sources + ${CMAKE_CURRENT_SOURCE_DIR}/${family}/resource/embed.cc + ${CMAKE_CURRENT_SOURCE_DIR}/${family}/resource/chipdb.rc) +endif() - set(DB_PY ${CMAKE_CURRENT_SOURCE_DIR}/machxo2/facade_import.py) - - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/) - add_library(machxo2_chipdb OBJECT ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/) - target_compile_definitions(machxo2_chipdb PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family}) - target_include_directories(machxo2_chipdb PRIVATE ${family}/) +add_custom_target(chipdb-${family}-bins DEPENDS ${chipdb_sources} ${chipdb_binaries}) - if (CMAKE_HOST_WIN32) - set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=\"${PYTRELLIS_LIBDIR}\;${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/util/common\;${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/timing/util\"") - else() - set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=${PYTRELLIS_LIBDIR}\:${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/util/common:${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/timing/util") - endif() +add_library(chipdb-${family} OBJECT ${MACHXO2_CHIPDB} ${chipdb_sources}) +add_dependencies(chipdb-${family} chipdb-${family}-bins) +target_compile_options(chipdb-${family} PRIVATE -g0 -O0 -w) +target_compile_definitions(chipdb-${family} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family}) +target_include_directories(chipdb-${family} PRIVATE ${family}) - if (MSVC) - target_sources(machxo2_chipdb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/machxo2/resource/embed.cc) - set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/machxo2/resources/chipdb.rc PROPERTIES LANGUAGE RC) - set(PREV_DEV_CC_BBA_DB) - foreach (dev ${devices}) - set(DEV_CC_DB ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/chipdb-${dev}.bin) - set(DEV_CC_BBA_DB ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/chipdb-${dev}.bba) - set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/machxo2/constids.inc) - if (PREGENERATED_BBA_PATH) - add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${PREGENERATED_BBA_PATH}/chipdb-${dev}.bba ${DEV_CC_DB} - ) - else() - add_custom_command(OUTPUT ${DEV_CC_BBA_DB} - COMMAND ${ENV_CMD} ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB} - DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${PREV_DEV_CC_BBA_DB} - ) - add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB} - DEPENDS bbasm ${DEV_CC_BBA_DB} - ) - endif() - if (SERIALIZE_CHIPDB) - set(PREV_DEV_CC_BBA_DB ${DEV_CC_BBA_DB}) - endif() - target_sources(machxo2_chipdb PRIVATE ${DEV_CC_DB}) - set_source_files_properties(${DEV_CC_DB} PROPERTIES HEADER_FILE_ONLY TRUE) - foreach (target ${family_targets}) - target_sources(${target} PRIVATE $ ${CMAKE_CURRENT_SOURCE_DIR}/machxo2/resource/chipdb.rc) - endforeach() - endforeach() - else() - target_compile_options(machxo2_chipdb PRIVATE -g0 -O0 -w) - set(PREV_DEV_CC_BBA_DB) - foreach (dev ${devices}) - set(DEV_CC_BBA_DB ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/chipdb-${dev}.bba) - set(DEV_CC_DB ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/chipdb-${dev}.cc) - set(DEV_BIN_DB ${CMAKE_CURRENT_BINARY_DIR}/machxo2/chipdbs/chipdb-${dev}.bin) - set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/machxo2/constids.inc) - if (PREGENERATED_BBA_PATH) - add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND bbasm --c ${BBASM_ENDIAN_FLAG} ${PREGENERATED_BBA_PATH}/chipdb-${dev}.bba ${DEV_CC_DB}.new - COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB} - ) - else() - add_custom_command(OUTPUT ${DEV_CC_BBA_DB} - COMMAND ${ENV_CMD} ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} ${dev} > ${DEV_CC_BBA_DB}.new - COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB} - DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${PREV_DEV_CC_BBA_DB} - ) - if(USE_C_EMBED) - add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND bbasm --e ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new ${DEV_BIN_DB} - COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB} - DEPENDS bbasm ${DEV_CC_BBA_DB} - ) - else() - add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND bbasm --c ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new - COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB} - DEPENDS bbasm ${DEV_CC_BBA_DB} - ) - endif() - endif() - if (SERIALIZE_CHIPDB) - set(PREV_DEV_CC_BBA_DB ${DEV_CC_BBA_DB}) - endif() - target_sources(machxo2_chipdb PRIVATE ${DEV_CC_DB}) - foreach (target ${family_targets}) - target_sources(${target} PRIVATE $) - endforeach() - endforeach() - endif() -endif() +foreach(family_target ${family_targets}) + target_sources(${family_target} PRIVATE $) +endforeach() diff --git a/machxo2/resource/chipdb.rc b/machxo2/resource/chipdb.rc new file mode 100644 index 00000000..eff237fa --- /dev/null +++ b/machxo2/resource/chipdb.rc @@ -0,0 +1,3 @@ +#include "resource.h" + +IDR_CHIPDB_1200 BINARYFILE "machxo2/chipdb/chipdb-1200.bin" diff --git a/machxo2/resource/embed.cc b/machxo2/resource/embed.cc new file mode 100644 index 00000000..24d4815a --- /dev/null +++ b/machxo2/resource/embed.cc @@ -0,0 +1,24 @@ +#include +#include +#include "nextpnr.h" +#include "resource.h" + +NEXTPNR_NAMESPACE_BEGIN + +const char *chipdb_blob_1200; + +const char *LoadFileInResource(int name, int type, DWORD &size) +{ + HMODULE handle = ::GetModuleHandle(NULL); + HRSRC rc = ::FindResource(handle, MAKEINTRESOURCE(name), MAKEINTRESOURCE(type)); + HGLOBAL rcData = ::LoadResource(handle, rc); + size = ::SizeofResource(handle, rc); + return static_cast(::LockResource(rcData)); +} +void load_chipdb() +{ + DWORD size = 0; + chipdb_blob_1200 = LoadFileInResource(IDR_CHIPDB_1200, BINARYFILE, size); +} + +NEXTPNR_NAMESPACE_END diff --git a/machxo2/resource/resource.h b/machxo2/resource/resource.h new file mode 100644 index 00000000..9ac8c585 --- /dev/null +++ b/machxo2/resource/resource.h @@ -0,0 +1,2 @@ +#define BINARYFILE 256 +#define IDR_CHIPDB_1200 103 -- cgit v1.2.3 From 539651609cf82ab8e05cac636aee997e831b4d29 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 27 Jun 2020 17:08:11 -0400 Subject: Update machxo2 backend with minimal build system changes so nextpnr compiles again. --- machxo2/facade_import.py | 5 +++++ machxo2/family.cmake | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'machxo2') diff --git a/machxo2/facade_import.py b/machxo2/facade_import.py index dd21a698..d21557ae 100644 --- a/machxo2/facade_import.py +++ b/machxo2/facade_import.py @@ -70,9 +70,14 @@ def main(): pytrellis.load_database(database.get_db_root()) + # Dummy + dev_name = "1200" + bba = BinaryBlobAssembler() bba.pre('#include "nextpnr.h"') + bba.pre('#include "embed.h"') bba.pre('NEXTPNR_NAMESPACE_BEGIN') + bba.post('EmbeddedFile chipdb_file_%s("machxo2/chipdb-%s.bin", chipdb_blob_%s);' % (dev_name, dev_name, dev_name)) bba.post('NEXTPNR_NAMESPACE_END') bba.push("chipdb_blob_%s" % args.device) bba.u8(0, None) diff --git a/machxo2/family.cmake b/machxo2/family.cmake index 0c829d55..f19ebc70 100644 --- a/machxo2/family.cmake +++ b/machxo2/family.cmake @@ -33,9 +33,14 @@ foreach(device ${MACHXO2_DEVICES}) endif() endforeach() if(WIN32) - list(APPEND chipdb_sources - ${CMAKE_CURRENT_SOURCE_DIR}/${family}/resource/embed.cc - ${CMAKE_CURRENT_SOURCE_DIR}/${family}/resource/chipdb.rc) + set(chipdb_rc ${CMAKE_CURRENT_BINARY_DIR}/${family}/resource/chipdb.rc) + list(APPEND chipdb_sources ${chipdb_rc}) + + file(WRITE ${chipdb_rc}) + foreach(device ${MACHXO2_DEVICES}) + file(APPEND ${chipdb_rc} + "${family}/chipdb-${device}.bin RCDATA \"${CMAKE_CURRENT_BINARY_DIR}/${family}/chipdb/chipdb-${device}.bin\"") + endforeach() endif() add_custom_target(chipdb-${family}-bins DEPENDS ${chipdb_sources} ${chipdb_binaries}) -- cgit v1.2.3 From 78880e1fdf1721a460c7e4e813f91f427106d3b7 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 27 Jun 2020 17:40:35 -0400 Subject: machxo2: Remove pybindings unneeded files from examples and update README.md and scripts accordingly. Delete resources directory. --- machxo2/arch_pybindings.cc | 241 -------------------------------------- machxo2/arch_pybindings.h | 31 ----- machxo2/examples/.gitignore | 4 +- machxo2/examples/README.md | 23 ++-- machxo2/examples/__init__.py | 0 machxo2/examples/bitstream.py | 17 --- machxo2/examples/simple.py | 77 ------------ machxo2/examples/simple.sh | 4 +- machxo2/examples/simple_config.py | 15 --- machxo2/examples/simple_timing.py | 13 -- machxo2/examples/simtest.sh | 4 +- machxo2/examples/write_fasm.py | 51 -------- machxo2/resource/chipdb.rc | 3 - machxo2/resource/embed.cc | 24 ---- machxo2/resource/resource.h | 2 - 15 files changed, 17 insertions(+), 492 deletions(-) delete mode 100644 machxo2/arch_pybindings.cc delete mode 100644 machxo2/arch_pybindings.h delete mode 100644 machxo2/examples/__init__.py delete mode 100644 machxo2/examples/bitstream.py delete mode 100644 machxo2/examples/simple.py delete mode 100644 machxo2/examples/simple_config.py delete mode 100644 machxo2/examples/simple_timing.py delete mode 100644 machxo2/examples/write_fasm.py delete mode 100644 machxo2/resource/chipdb.rc delete mode 100644 machxo2/resource/embed.cc delete mode 100644 machxo2/resource/resource.h (limited to 'machxo2') diff --git a/machxo2/arch_pybindings.cc b/machxo2/arch_pybindings.cc deleted file mode 100644 index 2600cac0..00000000 --- a/machxo2/arch_pybindings.cc +++ /dev/null @@ -1,241 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Clifford Wolf - * Copyright (C) 2018 David Shah - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef NO_PYTHON - -#include "arch_pybindings.h" -#include "nextpnr.h" -#include "pybindings.h" -#include "pywrappers.h" - -NEXTPNR_NAMESPACE_BEGIN -namespace PythonConversion { -template <> struct string_converter -{ - const IdString &from_str(Context *ctx, std::string name) { NPNR_ASSERT_FALSE("unsupported"); } - - std::string to_str(Context *ctx, const IdString &id) { return id.str(ctx); } -}; -} // namespace PythonConversion - -void arch_wrap_python() -{ - using namespace PythonConversion; - - auto arch_cls = class_, boost::noncopyable>("Arch", init()); - - auto dxy_cls = class_>("DecalXY_", no_init); - readwrite_wrapper, - conv_from_str>::def_wrap(dxy_cls, "decal"); - readwrite_wrapper, pass_through>::def_wrap( - dxy_cls, "x"); - readwrite_wrapper, pass_through>::def_wrap( - dxy_cls, "y"); - - auto ctx_cls = class_, boost::noncopyable>("Context", no_init) - .def("checksum", &Context::checksum) - .def("pack", &Context::pack) - .def("place", &Context::place) - .def("route", &Context::route); - - class_("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); - - class_("DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay); - - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getBelType"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "checkBelAvail"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getBelChecksum"); - fn_wrapper_3a_v, - addr_and_unwrap, pass_through>::def_wrap(ctx_cls, "bindBel"); - fn_wrapper_1a_v>::def_wrap( - ctx_cls, "unbindBel"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getBoundBelCell"); - fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); - fn_wrapper_0a &>>::def_wrap(ctx_cls, "getBels"); - - fn_wrapper_2a, - conv_from_str, conv_from_str>::def_wrap(ctx_cls, "getBelPinWire"); - fn_wrapper_1a &>, conv_from_str>::def_wrap(ctx_cls, - "getWireBelPins"); - - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getWireChecksum"); - fn_wrapper_3a_v, - addr_and_unwrap, pass_through>::def_wrap(ctx_cls, "bindWire"); - fn_wrapper_1a_v>::def_wrap( - ctx_cls, "unbindWire"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "checkWireAvail"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getBoundWireNet"); - fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingWireNet"); - - fn_wrapper_0a &>>::def_wrap(ctx_cls, "getWires"); - - fn_wrapper_0a &>>::def_wrap(ctx_cls, "getPips"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getPipChecksum"); - fn_wrapper_3a_v, - addr_and_unwrap, pass_through>::def_wrap(ctx_cls, "bindPip"); - fn_wrapper_1a_v>::def_wrap( - ctx_cls, "unbindPip"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "checkPipAvail"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getBoundPipNet"); - fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingPipNet"); - - fn_wrapper_1a &>, conv_from_str>::def_wrap(ctx_cls, - "getPipsDownhill"); - fn_wrapper_1a &>, conv_from_str>::def_wrap(ctx_cls, "getPipsUphill"); - fn_wrapper_1a &>, conv_from_str>::def_wrap(ctx_cls, "getWireAliases"); - - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getPipSrcWire"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getPipDstWire"); - fn_wrapper_1a, - conv_from_str>::def_wrap(ctx_cls, "getPipDelay"); - - fn_wrapper_1a, - pass_through>::def_wrap(ctx_cls, "getDelayFromNS"); - - fn_wrapper_0a>::def_wrap( - ctx_cls, "getChipName"); - fn_wrapper_0a>::def_wrap(ctx_cls, - "archId"); - - fn_wrapper_3a, - conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "DecalXY"); - - typedef std::unordered_map> CellMap; - typedef std::unordered_map> NetMap; - typedef std::unordered_map HierarchyMap; - - readonly_wrapper>::def_wrap(ctx_cls, - "cells"); - readonly_wrapper>::def_wrap(ctx_cls, - "nets"); - - fn_wrapper_2a_v, - pass_through>::def_wrap(ctx_cls, "addClock"); - - // Generic arch construction API - fn_wrapper_4a_v, - conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "addWire", - (arg("name"), "type", "x", - "y")); - fn_wrapper_6a_v, - conv_from_str, conv_from_str, conv_from_str, pass_through, - pass_through>::def_wrap(ctx_cls, "addPip", - (arg("name"), "type", "srcWire", "dstWire", "delay", "loc")); - fn_wrapper_5a_v, - conv_from_str, conv_from_str, conv_from_str, - pass_through>::def_wrap(ctx_cls, "addAlias", - (arg("name"), "type", "srcWire", "dstWire", "delay")); - - fn_wrapper_4a_v, - conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "addBel", - (arg("name"), "type", - "loc", "gb")); - fn_wrapper_3a_v, - conv_from_str, conv_from_str>::def_wrap(ctx_cls, "addBelInput", - (arg("bel"), "name", "wire")); - fn_wrapper_3a_v, - conv_from_str, conv_from_str>::def_wrap(ctx_cls, "addBelOutput", - (arg("bel"), "name", "wire")); - fn_wrapper_3a_v, - conv_from_str, conv_from_str>::def_wrap(ctx_cls, "addBelInout", - (arg("bel"), "name", "wire")); - - fn_wrapper_2a_v, - conv_from_str>::def_wrap(ctx_cls, "addGroupBel", (arg("group"), "bel")); - fn_wrapper_2a_v, - conv_from_str>::def_wrap(ctx_cls, "addGroupWire", (arg("group"), "wire")); - fn_wrapper_2a_v, - conv_from_str>::def_wrap(ctx_cls, "addGroupPip", (arg("group"), "pip")); - fn_wrapper_2a_v, - conv_from_str>::def_wrap(ctx_cls, "addGroupGroup", (arg("group"), "grp")); - - fn_wrapper_2a_v, - pass_through>::def_wrap(ctx_cls, "addDecalGraphic", (arg("decal"), "graphic")); - fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setWireDecal", (arg("wire"), "decalxy")); - fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setPipDecal", (arg("pip"), "decalxy")); - fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setBelDecal", (arg("bel"), "decalxy")); - fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setGroupDecal", (arg("group"), "decalxy")); - - fn_wrapper_3a_v, - conv_from_str, pass_through>::def_wrap(ctx_cls, "setWireAttr", - (arg("wire"), "key", "value")); - fn_wrapper_3a_v, - conv_from_str, pass_through>::def_wrap(ctx_cls, "setBelAttr", - (arg("bel"), "key", "value")); - fn_wrapper_3a_v, - conv_from_str, pass_through>::def_wrap(ctx_cls, "setPipAttr", - (arg("pip"), "key", "value")); - - fn_wrapper_1a_v>::def_wrap( - ctx_cls, "setLutK", arg("K")); - fn_wrapper_2a_v, - pass_through>::def_wrap(ctx_cls, "setDelayScaling", (arg("scale"), "offset")); - - fn_wrapper_2a_v, conv_from_str>::def_wrap(ctx_cls, "addCellTimingClock", - (arg("cell"), "port")); - fn_wrapper_4a_v, conv_from_str, conv_from_str, - pass_through>::def_wrap(ctx_cls, "addCellTimingDelay", - (arg("cell"), "fromPort", "toPort", "delay")); - fn_wrapper_5a_v, conv_from_str, conv_from_str, pass_through, - pass_through>::def_wrap(ctx_cls, "addCellTimingSetupHold", - (arg("cell"), "port", "clock", "setup", "hold")); - fn_wrapper_4a_v, conv_from_str, conv_from_str, - pass_through>::def_wrap(ctx_cls, "addCellTimingClockToOut", - (arg("cell"), "port", "clock", "clktoq")); - - WRAP_MAP_UPTR(CellMap, "IdCellMap"); - WRAP_MAP_UPTR(NetMap, "IdNetMap"); - WRAP_MAP(HierarchyMap, wrap_context, "HierarchyMap"); - WRAP_VECTOR(const std::vector, conv_to_str); -} - -NEXTPNR_NAMESPACE_END - -#endif \ No newline at end of file diff --git a/machxo2/arch_pybindings.h b/machxo2/arch_pybindings.h deleted file mode 100644 index f7f07529..00000000 --- a/machxo2/arch_pybindings.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Clifford Wolf - * Copyright (C) 2018 David Shah - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ -#ifndef ARCH_PYBINDINGS_H -#define ARCH_PYBINDINGS_H -#ifndef NO_PYTHON - -#include "nextpnr.h" -#include "pybindings.h" - -NEXTPNR_NAMESPACE_BEGIN - -NEXTPNR_NAMESPACE_END -#endif -#endif diff --git a/machxo2/examples/.gitignore b/machxo2/examples/.gitignore index ad2fba28..f1ee6a8a 100644 --- a/machxo2/examples/.gitignore +++ b/machxo2/examples/.gitignore @@ -1,6 +1,4 @@ -blinky.fasm -__pycache__ -*.pyc pnrblinky.v /blinky_simtest *.vcd +abc.history diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index e064d077..f82da63a 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -1,15 +1,16 @@ # MachXO2 Architecture Example -This contains a simple example of the nextpnr machxo2 API. As time goes on, -python scripts required as boilerplate will be removed. +This contains a simple example of running `nextpnr-machxo2`: - - simple.py procedurally generates a simple FPGA architecture with IO at the edges, - logic slices in all other tiles, and interconnect only between adjacent tiles +* `simple.sh` generates JSON output (`pnrblinky.json`) of a classic blinky + example from `blinky.v`. +* `simtest.sh` will use `yosys` to generate a Verilog file from + `pnrblinky.json`, called `pnrblinky.v`. It will then and compare + `pnrblinky.v`'s simulation behavior to the original verilog file (`blinky.v`) + using the [`iverilog`](http://iverilog.icarus.com) compiler and `vvp` + runtime. This is known as post-place-and-route simulation. - - simple_timing.py annotates cells with timing data (this is a separate script that must be run after packing) - - - write_fasm.py uses the nextpnr Python API to write a FASM file for a design - - - bitstream.py uses write_fasm.py to create a FASM ("FPGA assembly") file for the place-and-routed design - - - Run simple.sh to build an example design on the FPGA above +As `nextpnr-machxo2` is developed the `nextpnr` invocation in `simple.sh` and +`simtest.sh` is subject to change. Other command invocations, such as `yosys`, +_should_ remain unchanged, even as files under the [synth](../synth) directory +change. diff --git a/machxo2/examples/__init__.py b/machxo2/examples/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/machxo2/examples/bitstream.py b/machxo2/examples/bitstream.py deleted file mode 100644 index 7f0b5c07..00000000 --- a/machxo2/examples/bitstream.py +++ /dev/null @@ -1,17 +0,0 @@ -from write_fasm import * -from simple_config import K - -# Need to tell FASM generator how to write parameters -# (celltype, parameter) -> ParameterConfig -param_map = { - ("GENERIC_SLICE", "K"): ParameterConfig(write=False), - ("GENERIC_SLICE", "INIT"): ParameterConfig(write=True, numeric=True, width=2**K), - ("GENERIC_SLICE", "FF_USED"): ParameterConfig(write=True, numeric=True, width=1), - - ("GENERIC_IOB", "INPUT_USED"): ParameterConfig(write=True, numeric=True, width=1), - ("GENERIC_IOB", "OUTPUT_USED"): ParameterConfig(write=True, numeric=True, width=1), - ("GENERIC_IOB", "ENABLE_USED"): ParameterConfig(write=True, numeric=True, width=1), -} - -with open("blinky.fasm", "w") as f: - write_fasm(ctx, param_map, f) diff --git a/machxo2/examples/simple.py b/machxo2/examples/simple.py deleted file mode 100644 index 9379b505..00000000 --- a/machxo2/examples/simple.py +++ /dev/null @@ -1,77 +0,0 @@ -from simple_config import * - -def is_io(x, y): - return x == 0 or x == X-1 or y == 0 or y == Y-1 - -for x in range(X): - for y in range(Y): - # Bel port wires - for z in range(N): - ctx.addWire(name="X%dY%dZ%d_CLK" % (x, y, z), type="BEL_CLK", x=x, y=y) - ctx.addWire(name="X%dY%dZ%d_Q" % (x, y, z), type="BEL_Q", x=x, y=y) - ctx.addWire(name="X%dY%dZ%d_F" % (x, y, z), type="BEL_F", x=x, y=y) - for i in range(K): - ctx.addWire(name="X%dY%dZ%d_I%d" % (x, y, z, i), type="BEL_I", x=x, y=y) - # Local wires - for l in range(Wl): - ctx.addWire(name="X%dY%d_LOCAL%d" % (x, y, l), type="LOCAL", x=x, y=y) - # Create bels - if is_io(x, y): - if x == y: - continue - for z in range(2): - ctx.addBel(name="X%dY%d_IO%d" % (x, y, z), type="GENERIC_IOB", loc=Loc(x, y, z), gb=False) - ctx.addBelInput(bel="X%dY%d_IO%d" % (x, y, z), name="I", wire="X%dY%dZ%d_I0" % (x, y, z)) - ctx.addBelInput(bel="X%dY%d_IO%d" % (x, y, z), name="EN", wire="X%dY%dZ%d_I1" % (x, y, z)) - ctx.addBelOutput(bel="X%dY%d_IO%d" % (x, y, z), name="O", wire="X%dY%dZ%d_Q" % (x, y, z)) - else: - for z in range(N): - ctx.addBel(name="X%dY%d_SLICE%d" % (x, y, z), type="GENERIC_SLICE", loc=Loc(x, y, z), gb=False) - ctx.addBelInput(bel="X%dY%d_SLICE%d" % (x, y, z), name="CLK", wire="X%dY%dZ%d_CLK" % (x, y, z)) - for k in range(K): - ctx.addBelInput(bel="X%dY%d_SLICE%d" % (x, y, z), name="I[%d]" % k, wire="X%dY%dZ%d_I%d" % (x, y, z, k)) - ctx.addBelOutput(bel="X%dY%d_SLICE%d" % (x, y, z), name="F", wire="X%dY%dZ%d_F" % (x, y, z)) - ctx.addBelOutput(bel="X%dY%d_SLICE%d" % (x, y, z), name="Q", wire="X%dY%dZ%d_Q" % (x, y, z)) - -for x in range(X): - for y in range(Y): - # Pips driving bel input wires - # Bel input wires are driven by every Si'th local with an offset - def create_input_pips(dst, offset, skip): - for i in range(offset % skip, Wl, skip): - src = "X%dY%d_LOCAL%d" % (x, y, i) - ctx.addPip(name="X%dY%d.%s.%s" % (x, y, src, dst), type="BEL_INPUT", - srcWire=src, dstWire=dst, delay=ctx.getDelayFromNS(0.05), loc=Loc(x, y, 0)) - for z in range(N): - create_input_pips("X%dY%dZ%d_CLK" % (x, y, z), 0, Si) - for k in range(K): - create_input_pips("X%dY%dZ%d_I%d" % (x, y, z, k), k % Si, Si) - - # Pips from bel outputs to locals - def create_output_pips(dst, offset, skip): - for i in range(offset % skip, N, skip): - src = "X%dY%dZ%d_F" % (x, y, i) - ctx.addPip(name="X%dY%d.%s.%s" % (x, y, src, dst), type="BEL_OUTPUT", - srcWire=src, dstWire=dst, delay=ctx.getDelayFromNS(0.05), loc=Loc(x, y, 0)) - src = "X%dY%dZ%d_Q" % (x, y, i) - ctx.addPip(name="X%dY%d.%s.%s" % (x, y, src, dst), type="BEL_OUTPUT", - srcWire=src, dstWire=dst, delay=ctx.getDelayFromNS(0.05), loc=Loc(x, y, 0)) - # Pips from neighbour locals to locals - def create_neighbour_pips(dst, nx, ny, offset, skip): - if nx < 0 or nx >= X or ny < 0 or ny >= Y: - return - for i in range(offset % skip, Wl, skip): - src = "X%dY%d_LOCAL%d" % (nx, ny, i) - ctx.addPip(name="X%dY%d.%s.%s" % (x, y, src, dst), type="NEIGHBOUR", - srcWire=src, dstWire=dst, delay=ctx.getDelayFromNS(0.05), loc=Loc(x, y, 0)) - for l in range(Wl): - dst = "X%dY%d_LOCAL%d" % (x, y, l) - create_output_pips(dst, l % Sq, Sq) - create_neighbour_pips(dst, x-1, y-1, (l + 1) % Sl, Sl) - create_neighbour_pips(dst, x-1, y, (l + 2) % Sl, Sl) - create_neighbour_pips(dst, x-1, y+1, (l + 2) % Sl, Sl) - create_neighbour_pips(dst, x, y-1, (l + 3) % Sl, Sl) - create_neighbour_pips(dst, x, y+1, (l + 4) % Sl, Sl) - create_neighbour_pips(dst, x+1, y-1, (l + 5) % Sl, Sl) - create_neighbour_pips(dst, x+1, y, (l + 6) % Sl, Sl) - create_neighbour_pips(dst, x+1, y+1, (l + 7) % Sl, Sl) diff --git a/machxo2/examples/simple.sh b/machxo2/examples/simple.sh index 425bc6ff..7f973033 100644 --- a/machxo2/examples/simple.sh +++ b/machxo2/examples/simple.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash set -ex -yosys -p "tcl ../synth/synth_generic.tcl 4 blinky.json" blinky.v -${NEXTPNR:-../../nextpnr-machxo2} --pre-pack simple.py --pre-place simple_timing.py --json blinky.json --post-route bitstream.py --write pnrblinky.json +yosys -p "tcl ../synth/synth_machxo2.tcl 4 blinky.json" blinky.v +${NEXTPNR:-../../nextpnr-machxo2} --json blinky.json --write pnrblinky.json yosys -p "read_verilog -lib ../synth/prims.v; read_json pnrblinky.json; dump -o blinky.il; show -format png -prefix blinky" diff --git a/machxo2/examples/simple_config.py b/machxo2/examples/simple_config.py deleted file mode 100644 index dfb38f1c..00000000 --- a/machxo2/examples/simple_config.py +++ /dev/null @@ -1,15 +0,0 @@ -# Grid size including IOBs at edges -X = 12 -Y = 12 -# SLICEs per tile -N = 8 -# LUT input count -K = 4 -# Number of local wires -Wl = N*(K+1) + 8 -# 1/Fc for bel input wire pips -Si = 4 -# 1/Fc for Q to local wire pips -Sq = 4 -# ~1/Fc local to neighbour local wire pips -Sl = 8 \ No newline at end of file diff --git a/machxo2/examples/simple_timing.py b/machxo2/examples/simple_timing.py deleted file mode 100644 index 1067b556..00000000 --- a/machxo2/examples/simple_timing.py +++ /dev/null @@ -1,13 +0,0 @@ -for cname, cell in ctx.cells: - if cell.type != "GENERIC_SLICE": - continue - if cname in ("$PACKER_GND", "$PACKER_VCC"): - continue - K = int(cell.params["K"]) - ctx.addCellTimingClock(cell=cname, port="CLK") - for i in range(K): - ctx.addCellTimingSetupHold(cell=cname, port="I[%d]" % i, clock="CLK", - setup=ctx.getDelayFromNS(0.2), hold=ctx.getDelayFromNS(0)) - ctx.addCellTimingClockToOut(cell=cname, port="Q", clock="CLK", clktoq=ctx.getDelayFromNS(0.2)) - for i in range(K): - ctx.addCellTimingDelay(cell=cname, fromPort="I[%d]" % i, toPort="F", delay=ctx.getDelayFromNS(0.2)) diff --git a/machxo2/examples/simtest.sh b/machxo2/examples/simtest.sh index a53f5c15..5e7d821d 100644 --- a/machxo2/examples/simtest.sh +++ b/machxo2/examples/simtest.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -ex -yosys -p "tcl ../synth/synth_generic.tcl 4 blinky.json" blinky.v -${NEXTPNR:-../../nextpnr-machxo2} --no-iobs --pre-pack simple.py --pre-place simple_timing.py --json blinky.json --post-route bitstream.py --write pnrblinky.json +yosys -p "tcl ../synth/synth_machxo2.tcl 4 blinky.json" blinky.v +${NEXTPNR:-../../nextpnr-machxo2} --no-iobs --json blinky.json --write pnrblinky.json yosys -p "read_json pnrblinky.json; write_verilog -noattr -norename pnrblinky.v" iverilog -o blinky_simtest ../synth/prims.v blinky_tb.v pnrblinky.v vvp -N ./blinky_simtest diff --git a/machxo2/examples/write_fasm.py b/machxo2/examples/write_fasm.py deleted file mode 100644 index ede8f16b..00000000 --- a/machxo2/examples/write_fasm.py +++ /dev/null @@ -1,51 +0,0 @@ -from collections import namedtuple - -""" - write: set to True to enable writing this parameter to FASM - - numeric: set to True to write this parameter as a bit array (width>1) or - single bit (width==1) named after the parameter. Otherwise this - parameter will be written as `name.value` - - width: width of numeric parameter (ignored for non-numeric parameters) - - alias: an alternative name for this parameter (parameter name used if alias - is None) -""" -ParameterConfig = namedtuple('ParameterConfig', 'write numeric width alias') - -# FIXME use defaults= once Python 3.7 is standard -ParameterConfig.__new__.__defaults__ = (False, True, 1, None) - - -""" -Write a design as FASM - - ctx: nextpnr context - paramCfg: map from (celltype, parametername) -> ParameterConfig describing how to write parameters - f: output file -""" -def write_fasm(ctx, paramCfg, f): - for nname, net in sorted(ctx.nets, key=lambda x: str(x[1].name)): - print("# Net %s" % nname, file=f) - for wire, pip in sorted(net.wires, key=lambda x: str(x[1])): - if pip.pip != "": - print("%s" % pip.pip, file=f) - print("", file=f) - for cname, cell in sorted(ctx.cells, key=lambda x: str(x[1].name)): - print("# Cell %s at %s" % (cname, cell.bel), file=f) - for param, val in sorted(cell.params, key=lambda x: str(x)): - cfg = paramCfg[(cell.type, param)] - if not cfg.write: - continue - fasm_name = cfg.alias if cfg.alias is not None else param - if cfg.numeric: - if cfg.width == 1: - if int(val) != 0: - print("%s.%s" % (cell.bel, fasm_name), file=f) - else: - # Parameters with width >32 are direct binary, otherwise denary - print("%s.%s[%d:0] = %d'b%s" % (cell.bel, fasm_name, cfg.width-1, cfg.width, val), file=f) - else: - print("%s.%s.%s" % (cell.bel, fasm_name, val), file=f) - print("", file=f) \ No newline at end of file diff --git a/machxo2/resource/chipdb.rc b/machxo2/resource/chipdb.rc deleted file mode 100644 index eff237fa..00000000 --- a/machxo2/resource/chipdb.rc +++ /dev/null @@ -1,3 +0,0 @@ -#include "resource.h" - -IDR_CHIPDB_1200 BINARYFILE "machxo2/chipdb/chipdb-1200.bin" diff --git a/machxo2/resource/embed.cc b/machxo2/resource/embed.cc deleted file mode 100644 index 24d4815a..00000000 --- a/machxo2/resource/embed.cc +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include "nextpnr.h" -#include "resource.h" - -NEXTPNR_NAMESPACE_BEGIN - -const char *chipdb_blob_1200; - -const char *LoadFileInResource(int name, int type, DWORD &size) -{ - HMODULE handle = ::GetModuleHandle(NULL); - HRSRC rc = ::FindResource(handle, MAKEINTRESOURCE(name), MAKEINTRESOURCE(type)); - HGLOBAL rcData = ::LoadResource(handle, rc); - size = ::SizeofResource(handle, rc); - return static_cast(::LockResource(rcData)); -} -void load_chipdb() -{ - DWORD size = 0; - chipdb_blob_1200 = LoadFileInResource(IDR_CHIPDB_1200, BINARYFILE, size); -} - -NEXTPNR_NAMESPACE_END diff --git a/machxo2/resource/resource.h b/machxo2/resource/resource.h deleted file mode 100644 index 9ac8c585..00000000 --- a/machxo2/resource/resource.h +++ /dev/null @@ -1,2 +0,0 @@ -#define BINARYFILE 256 -#define IDR_CHIPDB_1200 103 -- cgit v1.2.3 From 98214865bef10f675b864dec4e1ae35bbd22c76f Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 27 Jun 2020 18:00:53 -0400 Subject: machxo2: Remove generic API functions from Arch. --- machxo2/arch.cc | 230 -------------------------------------------------------- machxo2/arch.h | 32 -------- 2 files changed, 262 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 6979673a..56899ced 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -28,236 +28,6 @@ NEXTPNR_NAMESPACE_BEGIN -WireInfo &Arch::wire_info(IdString wire) -{ - auto w = wires.find(wire); - if (w == wires.end()) - NPNR_ASSERT_FALSE_STR("no wire named " + wire.str(this)); - return w->second; -} - -PipInfo &Arch::pip_info(IdString pip) -{ - auto p = pips.find(pip); - if (p == pips.end()) - NPNR_ASSERT_FALSE_STR("no pip named " + pip.str(this)); - return p->second; -} - -BelInfo &Arch::bel_info(IdString bel) -{ - auto b = bels.find(bel); - if (b == bels.end()) - NPNR_ASSERT_FALSE_STR("no bel named " + bel.str(this)); - return b->second; -} - -void Arch::addWire(IdString name, IdString type, int x, int y) -{ - NPNR_ASSERT(wires.count(name) == 0); - WireInfo &wi = wires[name]; - wi.name = name; - wi.type = type; - wi.x = x; - wi.y = y; - - wire_ids.push_back(name); -} - -void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay, Loc loc) -{ - NPNR_ASSERT(pips.count(name) == 0); - PipInfo &pi = pips[name]; - pi.name = name; - pi.type = type; - pi.srcWire = srcWire; - pi.dstWire = dstWire; - pi.delay = delay; - pi.loc = loc; - - wire_info(srcWire).downhill.push_back(name); - wire_info(dstWire).uphill.push_back(name); - pip_ids.push_back(name); - - if (int(tilePipDimZ.size()) <= loc.x) - tilePipDimZ.resize(loc.x + 1); - - if (int(tilePipDimZ[loc.x].size()) <= loc.y) - tilePipDimZ[loc.x].resize(loc.y + 1); - - gridDimX = std::max(gridDimX, loc.x + 1); - gridDimY = std::max(gridDimY, loc.x + 1); - tilePipDimZ[loc.x][loc.y] = std::max(tilePipDimZ[loc.x][loc.y], loc.z + 1); -} - -void Arch::addAlias(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay) -{ - NPNR_ASSERT(pips.count(name) == 0); - PipInfo &pi = pips[name]; - pi.name = name; - pi.type = type; - pi.srcWire = srcWire; - pi.dstWire = dstWire; - pi.delay = delay; - - wire_info(srcWire).aliases.push_back(name); - pip_ids.push_back(name); -} - -void Arch::addBel(IdString name, IdString type, Loc loc, bool gb) -{ - NPNR_ASSERT(bels.count(name) == 0); - NPNR_ASSERT(bel_by_loc.count(loc) == 0); - BelInfo &bi = bels[name]; - bi.name = name; - bi.type = type; - bi.x = loc.x; - bi.y = loc.y; - bi.z = loc.z; - bi.gb = gb; - - bel_ids.push_back(name); - bel_by_loc[loc] = name; - - if (int(bels_by_tile.size()) <= loc.x) - bels_by_tile.resize(loc.x + 1); - - if (int(bels_by_tile[loc.x].size()) <= loc.y) - bels_by_tile[loc.x].resize(loc.y + 1); - - bels_by_tile[loc.x][loc.y].push_back(name); - - if (int(tileBelDimZ.size()) <= loc.x) - tileBelDimZ.resize(loc.x + 1); - - if (int(tileBelDimZ[loc.x].size()) <= loc.y) - tileBelDimZ[loc.x].resize(loc.y + 1); - - gridDimX = std::max(gridDimX, loc.x + 1); - gridDimY = std::max(gridDimY, loc.x + 1); - tileBelDimZ[loc.x][loc.y] = std::max(tileBelDimZ[loc.x][loc.y], loc.z + 1); -} - -void Arch::addBelInput(IdString bel, IdString name, IdString wire) -{ - NPNR_ASSERT(bel_info(bel).pins.count(name) == 0); - PinInfo &pi = bel_info(bel).pins[name]; - pi.name = name; - pi.wire = wire; - pi.type = PORT_IN; - - wire_info(wire).downhill_bel_pins.push_back(BelPin{bel, name}); - wire_info(wire).bel_pins.push_back(BelPin{bel, name}); -} - -void Arch::addBelOutput(IdString bel, IdString name, IdString wire) -{ - NPNR_ASSERT(bel_info(bel).pins.count(name) == 0); - PinInfo &pi = bel_info(bel).pins[name]; - pi.name = name; - pi.wire = wire; - pi.type = PORT_OUT; - - wire_info(wire).uphill_bel_pin = BelPin{bel, name}; - wire_info(wire).bel_pins.push_back(BelPin{bel, name}); -} - -void Arch::addBelInout(IdString bel, IdString name, IdString wire) -{ - NPNR_ASSERT(bel_info(bel).pins.count(name) == 0); - PinInfo &pi = bel_info(bel).pins[name]; - pi.name = name; - pi.wire = wire; - pi.type = PORT_INOUT; - - wire_info(wire).downhill_bel_pins.push_back(BelPin{bel, name}); - wire_info(wire).bel_pins.push_back(BelPin{bel, name}); -} - -void Arch::addGroupBel(IdString group, IdString bel) { groups[group].bels.push_back(bel); } - -void Arch::addGroupWire(IdString group, IdString wire) { groups[group].wires.push_back(wire); } - -void Arch::addGroupPip(IdString group, IdString pip) { groups[group].pips.push_back(pip); } - -void Arch::addGroupGroup(IdString group, IdString grp) { groups[group].groups.push_back(grp); } - -void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic) -{ - decal_graphics[decal].push_back(graphic); - refreshUi(); -} - -void Arch::setWireDecal(WireId wire, DecalXY decalxy) -{ - wire_info(wire).decalxy = decalxy; - refreshUiWire(wire); -} - -void Arch::setPipDecal(PipId pip, DecalXY decalxy) -{ - pip_info(pip).decalxy = decalxy; - refreshUiPip(pip); -} - -void Arch::setBelDecal(BelId bel, DecalXY decalxy) -{ - bel_info(bel).decalxy = decalxy; - refreshUiBel(bel); -} - -void Arch::setGroupDecal(GroupId group, DecalXY decalxy) -{ - groups[group].decalxy = decalxy; - refreshUiGroup(group); -} - -void Arch::setWireAttr(IdString wire, IdString key, const std::string &value) { wire_info(wire).attrs[key] = value; } - -void Arch::setPipAttr(IdString pip, IdString key, const std::string &value) { pip_info(pip).attrs[key] = value; } - -void Arch::setBelAttr(IdString bel, IdString key, const std::string &value) { bel_info(bel).attrs[key] = value; } - -void Arch::setLutK(int K) { args.K = K; } - -void Arch::setDelayScaling(double scale, double offset) -{ - args.delayScale = scale; - args.delayOffset = offset; -} - -void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; } - -void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay) -{ - if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE) - cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT; - if (get_or_default(cellTiming[cell].portClasses, toPort, TMG_IGNORE) == TMG_IGNORE) - cellTiming[cell].portClasses[toPort] = TMG_COMB_OUTPUT; - cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = delay; -} - -void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold) -{ - TimingClockingInfo ci; - ci.clock_port = clock; - ci.edge = RISING_EDGE; - ci.setup = setup; - ci.hold = hold; - cellTiming[cell].clockingInfo[port].push_back(ci); - cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT; -} - -void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq) -{ - TimingClockingInfo ci; - ci.clock_port = clock; - ci.edge = RISING_EDGE; - ci.clockToQ = clktoq; - cellTiming[cell].clockingInfo[port].push_back(ci); - cellTiming[cell].portClasses[port] = TMG_REGISTER_OUTPUT; -} - // --------------------------------------------------------------- Arch::Arch(ArchArgs args) : chipName("generic"), args(args) diff --git a/machxo2/arch.h b/machxo2/arch.h index cbfb943d..ba34f8dc 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -140,38 +140,6 @@ struct Arch : BaseCtx std::unordered_map cellTiming; - void addWire(IdString name, IdString type, int x, int y); - void addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay, Loc loc); - void addAlias(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay); - - void addBel(IdString name, IdString type, Loc loc, bool gb); - void addBelInput(IdString bel, IdString name, IdString wire); - void addBelOutput(IdString bel, IdString name, IdString wire); - void addBelInout(IdString bel, IdString name, IdString wire); - - void addGroupBel(IdString group, IdString bel); - void addGroupWire(IdString group, IdString wire); - void addGroupPip(IdString group, IdString pip); - void addGroupGroup(IdString group, IdString grp); - - void addDecalGraphic(DecalId decal, const GraphicElement &graphic); - void setWireDecal(WireId wire, DecalXY decalxy); - void setPipDecal(PipId pip, DecalXY decalxy); - void setBelDecal(BelId bel, DecalXY decalxy); - void setGroupDecal(GroupId group, DecalXY decalxy); - - void setWireAttr(IdString wire, IdString key, const std::string &value); - void setPipAttr(IdString pip, IdString key, const std::string &value); - void setBelAttr(IdString bel, IdString key, const std::string &value); - - void setLutK(int K); - void setDelayScaling(double scale, double offset); - - void addCellTimingClock(IdString cell, IdString port); - void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay); - void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold); - void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq); - // --------------------------------------------------------------- // Common Arch API. Every arch must provide the following methods. -- cgit v1.2.3 From 9704f422dcae5788d39edf35addd6ee5e9dfd428 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 27 Jun 2020 19:22:58 -0400 Subject: machxo2: Start creating MachXO2CommandHandler. --- machxo2/arch.cc | 54 +++++++++++++++++++++++++++++++++++++++++------------- machxo2/arch.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++++----- machxo2/cells.cc | 6 +++--- machxo2/main.cc | 42 ++++++++++++++++++++++++++++++++---------- machxo2/pack.cc | 4 ++-- 5 files changed, 127 insertions(+), 33 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 56899ced..70de80cf 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -20,6 +20,7 @@ #include #include #include "nextpnr.h" +#include "embed.h" #include "placer1.h" #include "placer_heap.h" #include "router1.h" @@ -36,7 +37,44 @@ Arch::Arch(ArchArgs args) : chipName("generic"), args(args) decal_graphics[IdString()]; } -void IdString::initialize_arch(const BaseCtx *ctx) {} +// ----------------------------------------------------------------------- + +void IdString::initialize_arch(const BaseCtx *ctx) { + #define X(t) initialize_add(ctx, #t, ID_##t); + + #include "constids.inc" + + #undef X +} + +// --------------------------------------------------------------- + +static const ChipInfoPOD *get_chip_info(ArchArgs::ArchArgsTypes chip) +{ + std::string chipdb; + if (chip == ArchArgs::LCMXO2_256HC) { + chipdb = "machxo2/chipdb-256.bin"; + } else if (chip == ArchArgs::LCMXO2_640HC) { + chipdb = "machxo2/chipdb-640.bin"; + } else if (chip == ArchArgs::LCMXO2_1200HC) { + chipdb = "machxo2/chipdb-1200.bin"; + } else if (chip == ArchArgs::LCMXO2_2000HC) { + chipdb = "machxo2/chipdb-2000.bin"; + } else if (chip == ArchArgs::LCMXO2_4000HC) { + chipdb = "machxo2/chipdb-4000.bin"; + } else if (chip == ArchArgs::LCMXO2_7000HC) { + chipdb = "machxo2/chipdb-7000.bin"; + } else { + log_error("Unknown chip\n"); + } + + auto ptr = reinterpret_cast *>(get_chipdb(chipdb)); + if (ptr == nullptr) + return nullptr; + return ptr->get(); +} + +bool Arch::isAvailable(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip) != nullptr; } // --------------------------------------------------------------- @@ -265,22 +303,12 @@ const std::vector &Arch::getGroupGroups(GroupId group) const { return g delay_t Arch::estimateDelay(WireId src, WireId dst) const { - const WireInfo &s = wires.at(src); - const WireInfo &d = wires.at(dst); - int dx = abs(s.x - d.x); - int dy = abs(s.y - d.y); - return (dx + dy) * args.delayScale + args.delayOffset; + return 0; } delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const { - const auto &driver = net_info->driver; - auto driver_loc = getBelLocation(driver.cell->bel); - auto sink_loc = getBelLocation(sink.cell->bel); - - int dx = abs(sink_loc.x - driver_loc.x); - int dy = abs(sink_loc.y - driver_loc.y); - return (dx + dy) * args.delayScale + args.delayOffset; + return 0; } bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; } diff --git a/machxo2/arch.h b/machxo2/arch.h index ba34f8dc..b8b9ce85 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -23,13 +23,55 @@ NEXTPNR_NAMESPACE_BEGIN +/**** Everything in this section must be kept in sync with chipdb.py ****/ + +template struct RelPtr +{ + int32_t offset; + + // void set(const T *ptr) { + // offset = reinterpret_cast(ptr) - + // reinterpret_cast(this); + // } + + const T *get() const { return reinterpret_cast(reinterpret_cast(this) + offset); } + + const T &operator[](size_t index) const { return get()[index]; } + + const T &operator*() const { return *(get()); } + + const T *operator->() const { return get(); } +}; + + +NPNR_PACKED_STRUCT(struct ChipInfoPOD { + int32_t stub; +}); + +/************************ End of chipdb section. ************************/ + struct ArchArgs { - // Number of LUT inputs - int K = 4; - // y = mx + c relationship between distance and delay for interconnect - // delay estimates - double delayScale = 0.1, delayOffset = 0; + enum ArchArgsTypes + { + NONE, + LCMXO2_256HC, + LCMXO2_640HC, + LCMXO2_1200HC, + LCMXO2_2000HC, + LCMXO2_4000HC, + LCMXO2_7000HC, + } type = NONE; + std::string package; + enum SpeedGrade + { + SPEED_1 = 0, + SPEED_2, + SPEED_3, + SPEED_4, + SPEED_5, + SPEED_6, + } speed = SPEED_4; }; struct WireInfo; @@ -146,6 +188,8 @@ struct Arch : BaseCtx ArchArgs args; Arch(ArchArgs args); + static bool isAvailable(ArchArgs::ArchArgsTypes chip); + std::string getChipName() const { return chipName; } IdString archId() const { return id("generic"); } diff --git a/machxo2/cells.cc b/machxo2/cells.cc index c4421f90..21c233d0 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -42,11 +42,11 @@ std::unique_ptr create_generic_cell(Context *ctx, IdString type, std:: } new_cell->type = type; if (type == ctx->id("GENERIC_SLICE")) { - new_cell->params[ctx->id("K")] = ctx->args.K; + new_cell->params[ctx->id("K")] = 4; new_cell->params[ctx->id("INIT")] = 0; new_cell->params[ctx->id("FF_USED")] = 0; - for (int i = 0; i < ctx->args.K; i++) + for (int i = 0; i < 4; i++) add_port(ctx, new_cell.get(), "I[" + std::to_string(i) + "]", PORT_IN); add_port(ctx, new_cell.get(), "CLK", PORT_IN); @@ -73,7 +73,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")]; int lut_k = int_or_default(lut->params, ctx->id("K"), 4); - NPNR_ASSERT(lut_k <= ctx->args.K); + NPNR_ASSERT(lut_k <= 4); for (int i = 0; i < lut_k; i++) { IdString port = ctx->id("I[" + std::to_string(i) + "]"); diff --git a/machxo2/main.cc b/machxo2/main.cc index bb780996..84b99edc 100644 --- a/machxo2/main.cc +++ b/machxo2/main.cc @@ -27,11 +27,11 @@ USING_NEXTPNR_NAMESPACE -class GenericCommandHandler : public CommandHandler +class MachXO2CommandHandler : public CommandHandler { public: - GenericCommandHandler(int argc, char **argv); - virtual ~GenericCommandHandler(){}; + MachXO2CommandHandler(int argc, char **argv); + virtual ~MachXO2CommandHandler(){}; std::unique_ptr createContext(std::unordered_map &values) override; void setupArchContext(Context *ctx) override{}; void customBitstream(Context *ctx) override; @@ -40,26 +40,48 @@ class GenericCommandHandler : public CommandHandler po::options_description getArchOptions() override; }; -GenericCommandHandler::GenericCommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {} +MachXO2CommandHandler::MachXO2CommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {} -po::options_description GenericCommandHandler::getArchOptions() +po::options_description MachXO2CommandHandler::getArchOptions() { po::options_description specific("Architecture specific options"); - specific.add_options()("generic", "set device type to generic"); + if (Arch::isAvailable(ArchArgs::LCMXO2_256HC)) + specific.add_options()("256", "set device type to LCMXO2-256HC"); + if (Arch::isAvailable(ArchArgs::LCMXO2_640HC)) + specific.add_options()("640", "set device type to LCMXO2-640HC"); + if (Arch::isAvailable(ArchArgs::LCMXO2_1200HC)) + specific.add_options()("1200", "set device type to LCMXO2-1200HC"); + if (Arch::isAvailable(ArchArgs::LCMXO2_2000HC)) + specific.add_options()("2000", "set device type to LCMXO2-2000HC"); + if (Arch::isAvailable(ArchArgs::LCMXO2_4000HC)) + specific.add_options()("4000", "set device type to LCMXO2-4000HC"); + if (Arch::isAvailable(ArchArgs::LCMXO2_7000HC)) + specific.add_options()("7000", "set device type to LCMXO2-7000HC"); + + specific.add_options()("package", po::value(), "select device package (defaults to QFN32)"); + specific.add_options()("speed", po::value(), "select device speedgrade (1 to 6 inclusive)"); + + specific.add_options()("override-basecfg", po::value(), + "base chip configuration in Trellis text format"); + specific.add_options()("textcfg", po::value(), "textual configuration in Trellis format to write"); + + specific.add_options()("lpf", po::value>(), "LPF pin constraint file(s)"); + specific.add_options()("no-iobs", "disable automatic IO buffer insertion"); return specific; } -void GenericCommandHandler::customBitstream(Context *ctx) {} +void MachXO2CommandHandler::customBitstream(Context *ctx) {} -std::unique_ptr GenericCommandHandler::createContext(std::unordered_map &values) +std::unique_ptr MachXO2CommandHandler::createContext(std::unordered_map &values) { ArchArgs chipArgs; if (values.find("arch.name") != values.end()) { std::string arch_name = values["arch.name"].as_string(); - if (arch_name != "generic") + if (arch_name != "machxo2") log_error("Unsuported architecture '%s'.\n", arch_name.c_str()); } + auto ctx = std::unique_ptr(new Context(chipArgs)); if (vm.count("no-iobs")) ctx->settings[ctx->id("disable_iobs")] = Property::State::S1; @@ -68,7 +90,7 @@ std::unique_ptr GenericCommandHandler::createContext(std::unordered_map int main(int argc, char *argv[]) { - GenericCommandHandler handler(argc, argv); + MachXO2CommandHandler handler(argc, argv); return handler.exec(); } diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 43157b6c..b995375a 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -138,7 +138,7 @@ static void pack_constants(Context *ctx) log_info("Packing constants..\n"); std::unique_ptr gnd_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_GND"); - gnd_cell->params[ctx->id("INIT")] = Property(0, 1 << ctx->args.K); + gnd_cell->params[ctx->id("INIT")] = Property(0, 1 << 4); std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); gnd_net->driver.cell = gnd_cell.get(); @@ -147,7 +147,7 @@ static void pack_constants(Context *ctx) std::unique_ptr vcc_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_VCC"); // Fill with 1s - vcc_cell->params[ctx->id("INIT")] = Property(Property::S1).extract(0, (1 << ctx->args.K), Property::S1); + vcc_cell->params[ctx->id("INIT")] = Property(Property::S1).extract(0, (1 << 4), Property::S1); std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); vcc_net->name = ctx->id("$PACKER_VCC_NET"); vcc_net->driver.cell = vcc_cell.get(); -- cgit v1.2.3 From 512daf2c897e84738684566188c86024ae5abe8c Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 27 Jun 2020 19:43:16 -0400 Subject: machxo2: Remove generic packing. --- machxo2/arch.cc | 11 +-- machxo2/pack.cc | 244 +------------------------------------------------------- 2 files changed, 2 insertions(+), 253 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 70de80cf..ed62ed37 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -491,16 +491,7 @@ const std::vector Arch::availableRouters = {"router1", "router2"}; void Arch::assignArchInfo() { - for (auto &cell : getCtx()->cells) { - CellInfo *ci = cell.second.get(); - if (ci->type == id("GENERIC_SLICE")) { - ci->is_slice = true; - ci->slice_clk = get_net_or_empty(ci, id("CLK")); - } else { - ci->is_slice = false; - } - ci->user_group = int_or_default(ci->attrs, id("PACK_GROUP"), -1); - } + } bool Arch::cellsCompatible(const CellInfo **cells, int count) const diff --git a/machxo2/pack.cc b/machxo2/pack.cc index b995375a..38edc7aa 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -27,255 +27,13 @@ NEXTPNR_NAMESPACE_BEGIN -// Pack LUTs and LUT-FF pairs -static void pack_lut_lutffs(Context *ctx) -{ - log_info("Packing LUT-FFs..\n"); - - std::unordered_set packed_cells; - std::vector> new_cells; - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; - 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 packed = - create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), ci->name.str(ctx) + "_LC"); - std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); - packed_cells.insert(ci->name); - if (ctx->verbose) - log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); - // See if we can pack into a DFF - // TODO: LUT cascade - NetInfo *o = ci->ports.at(ctx->id("Q")).net; - CellInfo *dff = net_only_drives(ctx, o, is_ff, ctx->id("D"), true); - auto lut_bel = ci->attrs.find(ctx->id("BEL")); - bool packed_dff = false; - if (dff) { - if (ctx->verbose) - log_info("found attached dff %s\n", dff->name.c_str(ctx)); - auto dff_bel = dff->attrs.find(ctx->id("BEL")); - if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) { - // Locations don't match, can't pack - } else { - lut_to_lc(ctx, ci, packed.get(), false); - dff_to_lc(ctx, dff, packed.get(), false); - ctx->nets.erase(o->name); - if (dff_bel != dff->attrs.end()) - packed->attrs[ctx->id("BEL")] = dff_bel->second; - packed_cells.insert(dff->name); - if (ctx->verbose) - log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx)); - packed_dff = true; - } - } - if (!packed_dff) { - lut_to_lc(ctx, ci, packed.get(), true); - } - new_cells.push_back(std::move(packed)); - } - } - for (auto pcell : packed_cells) { - ctx->cells.erase(pcell); - } - for (auto &ncell : new_cells) { - ctx->cells[ncell->name] = std::move(ncell); - } -} - -// Pack FFs not packed as LUTFFs -static void pack_nonlut_ffs(Context *ctx) -{ - log_info("Packing non-LUT FFs..\n"); - - std::unordered_set packed_cells; - std::vector> new_cells; - - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; - if (is_ff(ctx, ci)) { - std::unique_ptr packed = - create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), ci->name.str(ctx) + "_DFFLC"); - std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); - if (ctx->verbose) - log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); - packed_cells.insert(ci->name); - dff_to_lc(ctx, ci, packed.get(), true); - new_cells.push_back(std::move(packed)); - } - } - for (auto pcell : packed_cells) { - ctx->cells.erase(pcell); - } - for (auto &ncell : new_cells) { - ctx->cells[ncell->name] = std::move(ncell); - } -} - -// Merge a net into a constant net -static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval) -{ - orig->driver.cell = nullptr; - for (auto user : orig->users) { - if (user.cell != nullptr) { - CellInfo *uc = user.cell; - if (ctx->verbose) - log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx)); - if ((is_lut(ctx, uc) || is_lc(ctx, uc)) && (user.port.str(ctx).at(0) == 'I') && !constval) { - uc->ports[user.port].net = nullptr; - } else { - uc->ports[user.port].net = constnet; - constnet->users.push_back(user); - } - } - } - orig->users.clear(); -} - -// Pack constants (simple implementation) -static void pack_constants(Context *ctx) -{ - log_info("Packing constants..\n"); - - std::unique_ptr gnd_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_GND"); - gnd_cell->params[ctx->id("INIT")] = Property(0, 1 << 4); - std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); - gnd_net->name = ctx->id("$PACKER_GND_NET"); - gnd_net->driver.cell = gnd_cell.get(); - gnd_net->driver.port = ctx->id("F"); - gnd_cell->ports.at(ctx->id("F")).net = gnd_net.get(); - - std::unique_ptr vcc_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_VCC"); - // Fill with 1s - vcc_cell->params[ctx->id("INIT")] = Property(Property::S1).extract(0, (1 << 4), Property::S1); - std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); - vcc_net->name = ctx->id("$PACKER_VCC_NET"); - vcc_net->driver.cell = vcc_cell.get(); - vcc_net->driver.port = ctx->id("F"); - vcc_cell->ports.at(ctx->id("F")).net = vcc_net.get(); - - std::vector dead_nets; - - bool gnd_used = false; - - for (auto net : sorted(ctx->nets)) { - NetInfo *ni = net.second; - if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { - IdString drv_cell = ni->driver.cell->name; - set_net_constant(ctx, ni, gnd_net.get(), false); - gnd_used = true; - dead_nets.push_back(net.first); - ctx->cells.erase(drv_cell); - } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) { - IdString drv_cell = ni->driver.cell->name; - set_net_constant(ctx, ni, vcc_net.get(), true); - dead_nets.push_back(net.first); - ctx->cells.erase(drv_cell); - } - } - - if (gnd_used) { - ctx->cells[gnd_cell->name] = std::move(gnd_cell); - ctx->nets[gnd_net->name] = std::move(gnd_net); - } - // Vcc cell always inserted for now, as it may be needed during carry legalisation (TODO: trim later if actually - // never used?) - ctx->cells[vcc_cell->name] = std::move(vcc_cell); - ctx->nets[vcc_net->name] = std::move(vcc_net); - - for (auto dn : dead_nets) { - ctx->nets.erase(dn); - } -} - -static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) -{ - return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") || - cell->type == ctx->id("$nextpnr_iobuf"); -} - -static bool is_generic_iob(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("GENERIC_IOB"); } - -// Pack IO buffers -static void pack_io(Context *ctx) -{ - std::unordered_set packed_cells; - std::unordered_set delete_nets; - - std::vector> new_cells; - log_info("Packing IOs..\n"); - - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; - if (is_nextpnr_iob(ctx, ci)) { - CellInfo *iob = nullptr; - if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { - iob = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_generic_iob, ctx->id("PAD"), true, ci); - - } else if (ci->type == ctx->id("$nextpnr_obuf")) { - NetInfo *net = ci->ports.at(ctx->id("I")).net; - iob = net_only_drives(ctx, net, is_generic_iob, ctx->id("PAD"), true, ci); - } - if (iob != nullptr) { - // Trivial case, GENERIC_IOB used. Just destroy the net and the - // iobuf - log_info("%s feeds GENERIC_IOB %s, removing %s %s.\n", ci->name.c_str(ctx), iob->name.c_str(ctx), - ci->type.c_str(ctx), ci->name.c_str(ctx)); - NetInfo *net = iob->ports.at(ctx->id("PAD")).net; - if (((ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) && - net->users.size() > 1) || - (ci->type == ctx->id("$nextpnr_obuf") && (net->users.size() > 2 || net->driver.cell != nullptr))) - log_error("PAD of %s '%s' connected to more than a single top level IO.\n", iob->type.c_str(ctx), - iob->name.c_str(ctx)); - - if (net != nullptr) { - delete_nets.insert(net->name); - iob->ports.at(ctx->id("PAD")).net = nullptr; - } - if (ci->type == ctx->id("$nextpnr_iobuf")) { - NetInfo *net2 = ci->ports.at(ctx->id("I")).net; - if (net2 != nullptr) { - delete_nets.insert(net2->name); - } - } - } else if (bool_or_default(ctx->settings, ctx->id("disable_iobs"))) { - // No IO buffer insertion; just remove nextpnr_[io]buf - for (auto &p : ci->ports) - disconnect_port(ctx, ci, p.first); - } else { - // Create a GENERIC_IOB buffer - std::unique_ptr ice_cell = - create_generic_cell(ctx, ctx->id("GENERIC_IOB"), ci->name.str(ctx) + "$iob"); - nxio_to_iob(ctx, ci, ice_cell.get(), packed_cells); - new_cells.push_back(std::move(ice_cell)); - iob = new_cells.back().get(); - } - packed_cells.insert(ci->name); - if (iob != nullptr) - std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(iob->attrs, iob->attrs.begin())); - } - } - for (auto pcell : packed_cells) { - ctx->cells.erase(pcell); - } - for (auto dnet : delete_nets) { - ctx->nets.erase(dnet); - } - for (auto &ncell : new_cells) { - ctx->cells[ncell->name] = std::move(ncell); - } -} - // Main pack function bool Arch::pack() { Context *ctx = getCtx(); + log_info("Packing implementation goes here.."); try { log_break(); - pack_constants(ctx); - pack_io(ctx); - pack_lut_lutffs(ctx); - pack_nonlut_ffs(ctx); ctx->settings[ctx->id("pack")] = 1; ctx->assignArchInfo(); log_info("Checksum: 0x%08x\n", ctx->checksum()); -- cgit v1.2.3 From e5576448eaf9817163c45d0e8778e64b9b205c26 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 27 Jun 2020 20:22:00 -0400 Subject: machxo2: Remove HeAP placer for now, fix typos. --- machxo2/arch.cc | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index ed62ed37..0b6b448e 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -342,35 +342,13 @@ ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const bool Arch::place() { std::string placer = str_or_default(settings, id("placer"), defaultPlacer); - if (placer == "heap") { - bool have_iobuf_or_constr = false; - for (auto cell : sorted(cells)) { - CellInfo *ci = cell.second; - if (ci->type == id("GENERIC_IOB") || ci->bel != BelId() || ci->attrs.count(id("BEL"))) { - have_iobuf_or_constr = true; - break; - } - } - bool retVal; - if (!have_iobuf_or_constr) { - log_warning("Unable to use HeAP due to a lack of IO buffers or constrained cells as anchors; reverting to " - "SA.\n"); - retVal = placer1(getCtx(), Placer1Cfg(getCtx())); - } else { - PlacerHeapCfg cfg(getCtx()); - cfg.ioBufTypes.insert(id("GENERIC_IOB")); - retVal = placer_heap(getCtx(), cfg); - } - getCtx()->settings[getCtx()->id("place")] = 1; - archInfoToAttributes(); - return retVal; - } else if (placer == "sa") { + if (placer == "sa") { bool retVal = placer1(getCtx(), Placer1Cfg(getCtx())); getCtx()->settings[getCtx()->id("place")] = 1; archInfoToAttributes(); return retVal; } else { - log_error("Generic architecture does not support placer '%s'\n", placer.c_str()); + log_error("MachXO2 architecture does not support placer '%s'\n", placer.c_str()); } } @@ -384,7 +362,7 @@ bool Arch::route() router2(getCtx(), Router2Cfg(getCtx())); result = true; } else { - log_error("iCE40 architecture does not support router '%s'\n", router.c_str()); + log_error("MachXO2 architecture does not support router '%s'\n", router.c_str()); } getCtx()->settings[getCtx()->id("route")] = 1; archInfoToAttributes(); -- cgit v1.2.3 From 88b7dfce58479f3002e5ba6d71856eeecfa41893 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 27 Jun 2020 21:52:03 -0400 Subject: machxo2: Stub out arch API functions and members. --- machxo2/arch.cc | 235 ++++++++++++++------------------------------------------ machxo2/arch.h | 39 ++++------ 2 files changed, 70 insertions(+), 204 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 0b6b448e..5d1cb0cb 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -34,7 +34,7 @@ NEXTPNR_NAMESPACE_BEGIN Arch::Arch(ArchArgs args) : chipName("generic"), args(args) { // Dummy for empty decals - decal_graphics[IdString()]; + // decal_graphics[IdString()]; } // ----------------------------------------------------------------------- @@ -80,8 +80,6 @@ bool Arch::isAvailable(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip BelId Arch::getBelByName(IdString name) const { - if (bels.count(name)) - return name; return BelId(); } @@ -89,21 +87,17 @@ IdString Arch::getBelName(BelId bel) const { return bel; } Loc Arch::getBelLocation(BelId bel) const { - auto &info = bels.at(bel); - return Loc(info.x, info.y, info.z); + return Loc(); } BelId Arch::getBelByLocation(Loc loc) const { - auto it = bel_by_loc.find(loc); - if (it != bel_by_loc.end()) - return it->second; return BelId(); } -const std::vector &Arch::getBelsByTile(int x, int y) const { return bels_by_tile.at(x).at(y); } +const std::vector &Arch::getBelsByTile(int x, int y) const { return bel_id_dummy; } -bool Arch::getBelGlobalBuf(BelId bel) const { return bels.at(bel).gb; } +bool Arch::getBelGlobalBuf(BelId bel) const { return false; } uint32_t Arch::getBelChecksum(BelId bel) const { @@ -113,47 +107,36 @@ uint32_t Arch::getBelChecksum(BelId bel) const void Arch::bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) { - bels.at(bel).bound_cell = cell; - cell->bel = bel; - cell->belStrength = strength; - refreshUiBel(bel); + } void Arch::unbindBel(BelId bel) { - bels.at(bel).bound_cell->bel = BelId(); - bels.at(bel).bound_cell->belStrength = STRENGTH_NONE; - bels.at(bel).bound_cell = nullptr; - refreshUiBel(bel); + } -bool Arch::checkBelAvail(BelId bel) const { return bels.at(bel).bound_cell == nullptr; } +bool Arch::checkBelAvail(BelId bel) const { return false; } -CellInfo *Arch::getBoundBelCell(BelId bel) const { return bels.at(bel).bound_cell; } +CellInfo *Arch::getBoundBelCell(BelId bel) const { return nullptr; } -CellInfo *Arch::getConflictingBelCell(BelId bel) const { return bels.at(bel).bound_cell; } +CellInfo *Arch::getConflictingBelCell(BelId bel) const { return nullptr; } -const std::vector &Arch::getBels() const { return bel_ids; } +const std::vector &Arch::getBels() const { return bel_id_dummy; } -IdString Arch::getBelType(BelId bel) const { return bels.at(bel).type; } +IdString Arch::getBelType(BelId bel) const { return IdString(); } -const std::map &Arch::getBelAttrs(BelId bel) const { return bels.at(bel).attrs; } +const std::map &Arch::getBelAttrs(BelId bel) const { return attrs_dummy; } WireId Arch::getBelPinWire(BelId bel, IdString pin) const { - const auto &bdata = bels.at(bel); - if (!bdata.pins.count(pin)) - log_error("bel '%s' has no pin '%s'\n", bel.c_str(this), pin.c_str(this)); - return bdata.pins.at(pin).wire; + return WireId(); } -PortType Arch::getBelPinType(BelId bel, IdString pin) const { return bels.at(bel).pins.at(pin).type; } +PortType Arch::getBelPinType(BelId bel, IdString pin) const { return PortType(); } std::vector Arch::getBelPins(BelId bel) const { std::vector ret; - for (auto &it : bels.at(bel).pins) - ret.push_back(it.first); return ret; } @@ -161,16 +144,14 @@ std::vector Arch::getBelPins(BelId bel) const WireId Arch::getWireByName(IdString name) const { - if (wires.count(name)) - return name; return WireId(); } -IdString Arch::getWireName(WireId wire) const { return wire; } +IdString Arch::getWireName(WireId wire) const { return IdString(); } -IdString Arch::getWireType(WireId wire) const { return wires.at(wire).type; } +IdString Arch::getWireType(WireId wire) const { return IdString(); } -const std::map &Arch::getWireAttrs(WireId wire) const { return wires.at(wire).attrs; } +const std::map &Arch::getWireAttrs(WireId wire) const { return attrs_dummy; } uint32_t Arch::getWireChecksum(WireId wire) const { @@ -180,51 +161,36 @@ uint32_t Arch::getWireChecksum(WireId wire) const void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength) { - wires.at(wire).bound_net = net; - net->wires[wire].pip = PipId(); - net->wires[wire].strength = strength; - refreshUiWire(wire); + } void Arch::unbindWire(WireId wire) { - auto &net_wires = wires.at(wire).bound_net->wires; - auto pip = net_wires.at(wire).pip; - if (pip != PipId()) { - pips.at(pip).bound_net = nullptr; - refreshUiPip(pip); - } - - net_wires.erase(wire); - wires.at(wire).bound_net = nullptr; - refreshUiWire(wire); } -bool Arch::checkWireAvail(WireId wire) const { return wires.at(wire).bound_net == nullptr; } +bool Arch::checkWireAvail(WireId wire) const { return false; } -NetInfo *Arch::getBoundWireNet(WireId wire) const { return wires.at(wire).bound_net; } +NetInfo *Arch::getBoundWireNet(WireId wire) const { return nullptr; } -NetInfo *Arch::getConflictingWireNet(WireId wire) const { return wires.at(wire).bound_net; } +NetInfo *Arch::getConflictingWireNet(WireId wire) const { return nullptr; } -const std::vector &Arch::getWireBelPins(WireId wire) const { return wires.at(wire).bel_pins; } +const std::vector &Arch::getWireBelPins(WireId wire) const { return bel_pin_dummy; } -const std::vector &Arch::getWires() const { return wire_ids; } +const std::vector &Arch::getWires() const { return wire_id_dummy; } // --------------------------------------------------------------- PipId Arch::getPipByName(IdString name) const { - if (pips.count(name)) - return name; return PipId(); } -IdString Arch::getPipName(PipId pip) const { return pip; } +IdString Arch::getPipName(PipId pip) const { return IdString(); } -IdString Arch::getPipType(PipId pip) const { return pips.at(pip).type; } +IdString Arch::getPipType(PipId pip) const { return IdString(); } -const std::map &Arch::getPipAttrs(PipId pip) const { return pips.at(pip).attrs; } +const std::map &Arch::getPipAttrs(PipId pip) const { return attrs_dummy; } uint32_t Arch::getPipChecksum(PipId wire) const { @@ -234,70 +200,57 @@ uint32_t Arch::getPipChecksum(PipId wire) const void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength) { - WireId wire = pips.at(pip).dstWire; - pips.at(pip).bound_net = net; - wires.at(wire).bound_net = net; - net->wires[wire].pip = pip; - net->wires[wire].strength = strength; - refreshUiPip(pip); - refreshUiWire(wire); + } void Arch::unbindPip(PipId pip) { - WireId wire = pips.at(pip).dstWire; - wires.at(wire).bound_net->wires.erase(wire); - pips.at(pip).bound_net = nullptr; - wires.at(wire).bound_net = nullptr; - refreshUiPip(pip); - refreshUiWire(wire); + } -bool Arch::checkPipAvail(PipId pip) const { return pips.at(pip).bound_net == nullptr; } +bool Arch::checkPipAvail(PipId pip) const { return false; } -NetInfo *Arch::getBoundPipNet(PipId pip) const { return pips.at(pip).bound_net; } +NetInfo *Arch::getBoundPipNet(PipId pip) const { return nullptr; } -NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; } +NetInfo *Arch::getConflictingPipNet(PipId pip) const { return nullptr; } -WireId Arch::getConflictingPipWire(PipId pip) const { return pips.at(pip).bound_net ? pips.at(pip).dstWire : WireId(); } +WireId Arch::getConflictingPipWire(PipId pip) const { return WireId(); } -const std::vector &Arch::getPips() const { return pip_ids; } +const std::vector &Arch::getPips() const { return pip_id_dummy; } -Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; } +Loc Arch::getPipLocation(PipId pip) const { return Loc(); } -WireId Arch::getPipSrcWire(PipId pip) const { return pips.at(pip).srcWire; } +WireId Arch::getPipSrcWire(PipId pip) const { return WireId(); } -WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; } +WireId Arch::getPipDstWire(PipId pip) const { return WireId(); } -DelayInfo Arch::getPipDelay(PipId pip) const { return pips.at(pip).delay; } +DelayInfo Arch::getPipDelay(PipId pip) const { return DelayInfo(); } -const std::vector &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; } +const std::vector &Arch::getPipsDownhill(WireId wire) const { return pip_id_dummy; } -const std::vector &Arch::getPipsUphill(WireId wire) const { return wires.at(wire).uphill; } +const std::vector &Arch::getPipsUphill(WireId wire) const { return pip_id_dummy; } -const std::vector &Arch::getWireAliases(WireId wire) const { return wires.at(wire).aliases; } +const std::vector &Arch::getWireAliases(WireId wire) const { return pip_id_dummy; } // --------------------------------------------------------------- -GroupId Arch::getGroupByName(IdString name) const { return name; } +GroupId Arch::getGroupByName(IdString name) const { return GroupId(); } -IdString Arch::getGroupName(GroupId group) const { return group; } +IdString Arch::getGroupName(GroupId group) const { return IdString(); } std::vector Arch::getGroups() const { std::vector ret; - for (auto &it : groups) - ret.push_back(it.first); return ret; } -const std::vector &Arch::getGroupBels(GroupId group) const { return groups.at(group).bels; } +const std::vector &Arch::getGroupBels(GroupId group) const { return bel_id_dummy; } -const std::vector &Arch::getGroupWires(GroupId group) const { return groups.at(group).wires; } +const std::vector &Arch::getGroupWires(GroupId group) const { return wire_id_dummy; } -const std::vector &Arch::getGroupPips(GroupId group) const { return groups.at(group).pips; } +const std::vector &Arch::getGroupPips(GroupId group) const { return pip_id_dummy; } -const std::vector &Arch::getGroupGroups(GroupId group) const { return groups.at(group).groups; } +const std::vector &Arch::getGroupGroups(GroupId group) const { return group_id_dummy; } // --------------------------------------------------------------- @@ -317,23 +270,6 @@ ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const { ArcBounds bb; - int src_x = wires.at(src).x; - int src_y = wires.at(src).y; - int dst_x = wires.at(dst).x; - int dst_y = wires.at(dst).y; - - bb.x0 = src_x; - bb.y0 = src_y; - bb.x1 = src_x; - bb.y1 = src_y; - - auto extend = [&](int x, int y) { - bb.x0 = std::min(bb.x0, x); - bb.x1 = std::max(bb.x1, x); - bb.y0 = std::min(bb.y0, y); - bb.y1 = std::max(bb.y1, y); - }; - extend(dst_x, dst_y); return bb; } @@ -373,83 +309,43 @@ bool Arch::route() const std::vector &Arch::getDecalGraphics(DecalId decal) const { - if (!decal_graphics.count(decal)) { - std::cerr << "No decal named " << decal.str(this) << std::endl; - log_error("No decal named %s!\n", decal.c_str(this)); - } - return decal_graphics.at(decal); + return graphic_element_dummy; } -DecalXY Arch::getBelDecal(BelId bel) const { return bels.at(bel).decalxy; } +DecalXY Arch::getBelDecal(BelId bel) const { return DecalXY(); } -DecalXY Arch::getWireDecal(WireId wire) const { return wires.at(wire).decalxy; } +DecalXY Arch::getWireDecal(WireId wire) const { return DecalXY(); } -DecalXY Arch::getPipDecal(PipId pip) const { return pips.at(pip).decalxy; } +DecalXY Arch::getPipDecal(PipId pip) const { return DecalXY(); } -DecalXY Arch::getGroupDecal(GroupId group) const { return groups.at(group).decalxy; } +DecalXY Arch::getGroupDecal(GroupId group) const { return DecalXY(); } // --------------------------------------------------------------- bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const { - if (!cellTiming.count(cell->name)) - return false; - const auto &tmg = cellTiming.at(cell->name); - auto fnd = tmg.combDelays.find(CellDelayKey{fromPort, toPort}); - if (fnd != tmg.combDelays.end()) { - delay = fnd->second; - return true; - } else { - return false; - } + return false; } // Get the port class, also setting clockPort if applicable TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const { - if (!cellTiming.count(cell->name)) - return TMG_IGNORE; - const auto &tmg = cellTiming.at(cell->name); - if (tmg.clockingInfo.count(port)) - clockInfoCount = int(tmg.clockingInfo.at(port).size()); - else - clockInfoCount = 0; - return get_or_default(tmg.portClasses, port, TMG_IGNORE); + return TMG_IGNORE; } TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const { - NPNR_ASSERT(cellTiming.count(cell->name)); - const auto &tmg = cellTiming.at(cell->name); - NPNR_ASSERT(tmg.clockingInfo.count(port)); - return tmg.clockingInfo.at(port).at(index); + return TimingClockingInfo(); } bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { - std::vector cells; - cells.push_back(cell); - Loc loc = getBelLocation(bel); - for (auto tbel : getBelsByTile(loc.x, loc.y)) { - if (tbel == bel) - continue; - CellInfo *bound = getBoundBelCell(tbel); - if (bound != nullptr) - cells.push_back(bound); - } - return cellsCompatible(cells.data(), int(cells.size())); + return false; } bool Arch::isBelLocationValid(BelId bel) const { - std::vector cells; - Loc loc = getBelLocation(bel); - for (auto tbel : getBelsByTile(loc.x, loc.y)) { - CellInfo *bound = getBoundBelCell(tbel); - if (bound != nullptr) - cells.push_back(bound); - } - return cellsCompatible(cells.data(), int(cells.size())); + return false; } #ifdef WITH_HEAP @@ -474,24 +370,7 @@ void Arch::assignArchInfo() bool Arch::cellsCompatible(const CellInfo **cells, int count) const { - const NetInfo *clk = nullptr; - int group = -1; - for (int i = 0; i < count; i++) { - const CellInfo *ci = cells[i]; - if (ci->is_slice && ci->slice_clk != nullptr) { - if (clk == nullptr) - clk = ci->slice_clk; - else if (clk != ci->slice_clk) - return false; - } - if (ci->user_group != -1) { - if (group == -1) - group = ci->user_group; - else if (group != ci->user_group) - return false; - } - } - return true; + return false; } NEXTPNR_NAMESPACE_END diff --git a/machxo2/arch.h b/machxo2/arch.h index b8b9ce85..063eb164 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -159,28 +159,15 @@ struct Arch : BaseCtx { std::string chipName; - std::unordered_map wires; - std::unordered_map pips; - std::unordered_map bels; - std::unordered_map groups; - - // These functions include useful errors if not found - WireInfo &wire_info(IdString wire); - PipInfo &pip_info(IdString wire); - BelInfo &bel_info(IdString wire); - - std::vector bel_ids, wire_ids, pip_ids; - + // Placeholders to be removed. std::unordered_map bel_by_loc; - std::vector>> bels_by_tile; - - std::unordered_map> decal_graphics; - - int gridDimX, gridDimY; - std::vector> tileBelDimZ; - std::vector> tilePipDimZ; - - std::unordered_map cellTiming; + std::vector bel_id_dummy; + std::vector bel_pin_dummy; + std::vector wire_id_dummy; + std::vector pip_id_dummy; + std::vector group_id_dummy; + std::vector graphic_element_dummy; + std::map attrs_dummy; // --------------------------------------------------------------- // Common Arch API. Every arch must provide the following methods. @@ -192,14 +179,14 @@ struct Arch : BaseCtx std::string getChipName() const { return chipName; } - IdString archId() const { return id("generic"); } + IdString archId() const { return id("machxo2"); } ArchArgs archArgs() const { return args; } IdString archArgsToId(ArchArgs args) const { return id("none"); } - int getGridDimX() const { return gridDimX; } - int getGridDimY() const { return gridDimY; } - int getTileBelDimZ(int x, int y) const { return tileBelDimZ[x][y]; } - int getTilePipDimZ(int x, int y) const { return tilePipDimZ[x][y]; } + int getGridDimX() const { return 0; } + int getGridDimY() const { return 0; } + int getTileBelDimZ(int x, int y) const { return 0; } + int getTilePipDimZ(int x, int y) const { return 0; } BelId getBelByName(IdString name) const; IdString getBelName(BelId bel) const; -- cgit v1.2.3 From 59efba2fc0c155922bf19e7ef3cbb3dcb09442f0 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 27 Jun 2020 21:59:30 -0400 Subject: machxo2: Stub out cells functions. --- machxo2/cells.cc | 97 ++------------------------------------------------------ machxo2/cells.h | 12 +++---- 2 files changed, 8 insertions(+), 101 deletions(-) (limited to 'machxo2') diff --git a/machxo2/cells.cc b/machxo2/cells.cc index 21c233d0..522295b0 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -26,122 +26,29 @@ NEXTPNR_NAMESPACE_BEGIN void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir) { - IdString id = ctx->id(name); - NPNR_ASSERT(cell->ports.count(id) == 0); - cell->ports[id] = PortInfo{id, nullptr, dir}; + } -std::unique_ptr create_generic_cell(Context *ctx, IdString type, std::string name) +std::unique_ptr create_machxo2_cell(Context *ctx, IdString type, std::string name) { static int auto_idx = 0; std::unique_ptr new_cell = std::unique_ptr(new CellInfo()); - if (name.empty()) { - new_cell->name = ctx->id("$nextpnr_" + type.str(ctx) + "_" + std::to_string(auto_idx++)); - } else { - new_cell->name = ctx->id(name); - } - new_cell->type = type; - if (type == ctx->id("GENERIC_SLICE")) { - new_cell->params[ctx->id("K")] = 4; - new_cell->params[ctx->id("INIT")] = 0; - new_cell->params[ctx->id("FF_USED")] = 0; - - for (int i = 0; i < 4; i++) - add_port(ctx, new_cell.get(), "I[" + std::to_string(i) + "]", PORT_IN); - - add_port(ctx, new_cell.get(), "CLK", PORT_IN); - - add_port(ctx, new_cell.get(), "F", PORT_OUT); - add_port(ctx, new_cell.get(), "Q", PORT_OUT); - } else if (type == ctx->id("GENERIC_IOB")) { - new_cell->params[ctx->id("INPUT_USED")] = 0; - new_cell->params[ctx->id("OUTPUT_USED")] = 0; - new_cell->params[ctx->id("ENABLE_USED")] = 0; - - add_port(ctx, new_cell.get(), "PAD", PORT_INOUT); - add_port(ctx, new_cell.get(), "I", PORT_IN); - add_port(ctx, new_cell.get(), "EN", PORT_IN); - add_port(ctx, new_cell.get(), "O", PORT_OUT); - } else { - log_error("unable to create generic cell of type %s", type.c_str(ctx)); - } return new_cell; } void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { - lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")]; - int lut_k = int_or_default(lut->params, ctx->id("K"), 4); - NPNR_ASSERT(lut_k <= 4); - - for (int i = 0; i < lut_k; i++) { - IdString port = ctx->id("I[" + std::to_string(i) + "]"); - replace_port(lut, port, lc, port); - } - - if (no_dff) { - lc->params[ctx->id("FF_USED")] = 0; - replace_port(lut, ctx->id("Q"), lc, ctx->id("F")); - } } void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) { - lc->params[ctx->id("FF_USED")] = 1; - replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK")); - - if (pass_thru_lut) { - // Fill LUT with alternating 10 - const int init_size = 1 << lc->params[ctx->id("K")].as_int64(); - std::string init; - init.reserve(init_size); - for (int i = 0; i < init_size; i += 2) - init.append("10"); - lc->params[ctx->id("INIT")] = Property::from_string(init); - - replace_port(dff, ctx->id("D"), lc, ctx->id("I[0]")); - } - replace_port(dff, ctx->id("Q"), lc, ctx->id("Q")); } void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set &todelete_cells) { - if (nxio->type == ctx->id("$nextpnr_ibuf")) { - iob->params[ctx->id("INPUT_USED")] = 1; - replace_port(nxio, ctx->id("O"), iob, ctx->id("O")); - } else if (nxio->type == ctx->id("$nextpnr_obuf")) { - iob->params[ctx->id("OUTPUT_USED")] = 1; - replace_port(nxio, ctx->id("I"), iob, ctx->id("I")); - } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { - // N.B. tristate will be dealt with below - iob->params[ctx->id("INPUT_USED")] = 1; - iob->params[ctx->id("OUTPUT_USED")] = 1; - replace_port(nxio, ctx->id("I"), iob, ctx->id("I")); - replace_port(nxio, ctx->id("O"), iob, ctx->id("O")); - } else { - NPNR_ASSERT(false); - } - NetInfo *donet = iob->ports.at(ctx->id("I")).net; - CellInfo *tbuf = net_driven_by( - ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); }, - ctx->id("Y")); - if (tbuf) { - iob->params[ctx->id("ENABLE_USED")] = 1; - replace_port(tbuf, ctx->id("A"), iob, ctx->id("I")); - replace_port(tbuf, ctx->id("E"), iob, ctx->id("EN")); - if (donet->users.size() > 1) { - for (auto user : donet->users) - log_info(" remaining tristate user: %s.%s\n", user.cell->name.c_str(ctx), user.port.c_str(ctx)); - log_error("unsupported tristate IO pattern for IO buffer '%s', " - "instantiate GENERIC_IOB manually to ensure correct behaviour\n", - nxio->name.c_str(ctx)); - } - ctx->nets.erase(donet->name); - todelete_cells.insert(tbuf->name); - } } NEXTPNR_NAMESPACE_END diff --git a/machxo2/cells.h b/machxo2/cells.h index 646d738d..b2971bda 100644 --- a/machxo2/cells.h +++ b/machxo2/cells.h @@ -19,22 +19,22 @@ #include "nextpnr.h" -#ifndef GENERIC_CELLS_H -#define GENERIC_CELLS_H +#ifndef MACHXO2_CELLS_H +#define MACHXO2_CELLS_H NEXTPNR_NAMESPACE_BEGIN // Create a generic arch cell and return it // Name will be automatically assigned if not specified -std::unique_ptr create_generic_cell(Context *ctx, IdString type, std::string name = ""); +std::unique_ptr create_machxo2_cell(Context *ctx, IdString type, std::string name = ""); // Return true if a cell is a LUT -inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("LUT"); } +inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return false; } // Return true if a cell is a flipflop -inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("DFF"); } +inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return false; } -inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("GENERIC_SLICE"); } +inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return false; } // 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 -- cgit v1.2.3 From ade94efbfff721ea94afb1408d0d502be990ec5d Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 21 Nov 2020 12:01:50 -0500 Subject: machxo2: synth directory (simulation, techmaps, synth script) is now provided by yosys. --- machxo2/synth/cells_map.v | 12 -------- machxo2/synth/prims.v | 67 ----------------------------------------- machxo2/synth/synth_machxo2.tcl | 24 --------------- 3 files changed, 103 deletions(-) delete mode 100644 machxo2/synth/cells_map.v delete mode 100644 machxo2/synth/prims.v delete mode 100644 machxo2/synth/synth_machxo2.tcl (limited to 'machxo2') diff --git a/machxo2/synth/cells_map.v b/machxo2/synth/cells_map.v deleted file mode 100644 index 1d0939e0..00000000 --- a/machxo2/synth/cells_map.v +++ /dev/null @@ -1,12 +0,0 @@ -module \$lut (A, Y); - parameter WIDTH = 0; - parameter LUT = 0; - input [WIDTH-1:0] A; - output Y; - - localparam rep = 1<<(`LUT_K-WIDTH); - - LUT #(.K(`LUT_K), .INIT({rep{LUT}})) _TECHMAP_REPLACE_ (.I(A), .Q(Y)); -endmodule - -module \$_DFF_P_ (input D, C, output Q); DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule diff --git a/machxo2/synth/prims.v b/machxo2/synth/prims.v deleted file mode 100644 index ca445e6e..00000000 --- a/machxo2/synth/prims.v +++ /dev/null @@ -1,67 +0,0 @@ -// LUT and DFF are combined to a GENERIC_SLICE - -module LUT #( - parameter K = 4, - parameter [2**K-1:0] INIT = 0 -) ( - input [K-1:0] I, - output Q -); - wire [K-1:0] I_pd; - - genvar ii; - generate - for (ii = 0; ii < K; ii = ii + 1'b1) - assign I_pd[ii] = (I[ii] === 1'bz) ? 1'b0 : I[ii]; - endgenerate - - assign Q = INIT[I_pd]; -endmodule - -module DFF ( - input CLK, D, - output reg Q -); - initial Q = 1'b0; - always @(posedge CLK) - Q <= D; -endmodule - -module GENERIC_SLICE #( - parameter K = 4, - parameter [2**K-1:0] INIT = 0, - parameter FF_USED = 1'b0 -) ( - input CLK, - input [K-1:0] I, - output F, - output Q -); - wire f_wire; - - LUT #(.K(K), .INIT(INIT)) lut_i(.I(I), .Q(f_wire)); - - DFF dff_i(.CLK(CLK), .D(f_wire), .Q(Q)); - - assign F = f_wire; -endmodule - -module GENERIC_IOB #( - parameter INPUT_USED = 1'b0, - parameter OUTPUT_USED = 1'b0, - parameter ENABLE_USED = 1'b0 -) ( - inout PAD, - input I, EN, - output O -); - generate if (OUTPUT_USED && ENABLE_USED) - assign PAD = EN ? I : 1'bz; - else if (OUTPUT_USED) - assign PAD = I; - endgenerate - - generate if (INPUT_USED) - assign O = PAD; - endgenerate -endmodule diff --git a/machxo2/synth/synth_machxo2.tcl b/machxo2/synth/synth_machxo2.tcl deleted file mode 100644 index e5d88e0d..00000000 --- a/machxo2/synth/synth_machxo2.tcl +++ /dev/null @@ -1,24 +0,0 @@ -# Usage -# tcl synth_generic.tcl {K} {out.json} - -set LUT_K 4 -if {$argc > 0} { set LUT_K [lindex $argv 0] } -yosys read_verilog -lib [file dirname [file normalize $argv0]]/prims.v -yosys hierarchy -check -yosys proc -yosys flatten -yosys tribuf -logic -yosys deminout -yosys synth -run coarse -yosys memory_map -yosys opt -full -yosys techmap -map +/techmap.v -yosys opt -fast -yosys abc -lut $LUT_K -dress -yosys clean -yosys techmap -D LUT_K=$LUT_K -map [file dirname [file normalize $argv0]]/cells_map.v -yosys clean -yosys hierarchy -check -yosys stat - -if {$argc > 1} { yosys write_json [lindex $argv 1] } -- cgit v1.2.3 From 1cde40792f2d8cf8d0799fec25c0418a0903547f Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 21 Nov 2020 18:42:30 -0500 Subject: machxo2: Improve examples directory. --- machxo2/examples/README.md | 21 +++++++++++++++++---- machxo2/examples/blinky.v | 2 +- machxo2/examples/simple.sh | 4 ++-- machxo2/examples/simtest.sh | 6 +++--- 4 files changed, 23 insertions(+), 10 deletions(-) (limited to 'machxo2') diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index f82da63a..87f50f6d 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -10,7 +10,20 @@ This contains a simple example of running `nextpnr-machxo2`: using the [`iverilog`](http://iverilog.icarus.com) compiler and `vvp` runtime. This is known as post-place-and-route simulation. -As `nextpnr-machxo2` is developed the `nextpnr` invocation in `simple.sh` and -`simtest.sh` is subject to change. Other command invocations, such as `yosys`, -_should_ remain unchanged, even as files under the [synth](../synth) directory -change. +As `nextpnr-machxo2` is developed the contents `simple.sh` and `simtest.sh` +are subject to change. + +## Environment Variables For `simple.sh` And `simtest.sh` + +* `YOSYS`- Set to the location of the `yosys` binary to test. Defaults to the + `yosys` on the path. You may want to set this to a `yosys` binary in your + source tree if doing development. +* `NEXTPNR`- Set to the location of the `nextpnr-machxo2` binary to test. + Defaults to the `nextpnr-machxo2` binary at the root of the `nextpnr` source + tree. This should be set, for instance, if doing an out-of-tree build of + `nextpnr-machxo2`. +* `CELLS_SIM`- Set to the location of `machxo2/cells_sim.v` simulation models. + Defaults to whatever `yosys-config` associated with the above `YOSYS` binary + returns. You may want to set this to `/path/to/yosys/src/share/machxo2/cells_sim.v` + if doing development; `yosys-config` cannot find these "before-installation" + simulation models. diff --git a/machxo2/examples/blinky.v b/machxo2/examples/blinky.v index 42becb72..c7cde26d 100644 --- a/machxo2/examples/blinky.v +++ b/machxo2/examples/blinky.v @@ -1,4 +1,4 @@ -module top(input clk, rst, output reg [7:0] leds); +module top(input clk, rst, output [7:0] leds); reg [7:0] ctr; always @(posedge clk) diff --git a/machxo2/examples/simple.sh b/machxo2/examples/simple.sh index 7f973033..9eb06886 100644 --- a/machxo2/examples/simple.sh +++ b/machxo2/examples/simple.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash set -ex -yosys -p "tcl ../synth/synth_machxo2.tcl 4 blinky.json" blinky.v +${YOSYS:yosys} -p "synth_machxo2 -json blinky.json" blinky.v ${NEXTPNR:-../../nextpnr-machxo2} --json blinky.json --write pnrblinky.json -yosys -p "read_verilog -lib ../synth/prims.v; read_json pnrblinky.json; dump -o blinky.il; show -format png -prefix blinky" +${YOSYS:yosys} -p "read_verilog -lib +/machxo2/cells_sim.v; read_json pnrblinky.json; dump -o blinky.il; show -format png -prefix blinky" diff --git a/machxo2/examples/simtest.sh b/machxo2/examples/simtest.sh index 5e7d821d..4cb8d5ca 100644 --- a/machxo2/examples/simtest.sh +++ b/machxo2/examples/simtest.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -ex -yosys -p "tcl ../synth/synth_machxo2.tcl 4 blinky.json" blinky.v +${YOSYS:-yosys} -p "synth_machxo2 -json blinky.json" blinky.v ${NEXTPNR:-../../nextpnr-machxo2} --no-iobs --json blinky.json --write pnrblinky.json -yosys -p "read_json pnrblinky.json; write_verilog -noattr -norename pnrblinky.v" -iverilog -o blinky_simtest ../synth/prims.v blinky_tb.v pnrblinky.v +${YOSYS:-yosys} -p "read_json blinky.json; write_verilog -noattr -norename pnrblinky.v" +iverilog -o blinky_simtest ${CELLS_SIM:-`${YOSYS:yosys}-config --datdir/machxo2/cells_sim.v`} blinky_tb.v pnrblinky.v vvp -N ./blinky_simtest -- cgit v1.2.3 From 5c30f95c425540a4ba1cb0b49d7c6663a98b9f57 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 23 Nov 2020 11:20:39 -0500 Subject: machxo2: Add initial set of constids for packing. --- machxo2/archdefs.h | 14 ++++++++ machxo2/constids.inc | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) (limited to 'machxo2') diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h index 978c9c9b..6c861a32 100644 --- a/machxo2/archdefs.h +++ b/machxo2/archdefs.h @@ -46,6 +46,20 @@ struct DelayInfo } }; +enum ConstIds +{ + ID_NONE +#define X(t) , ID_##t +#include "constids.inc" +#undef X + , + DB_CONST_ID_COUNT +}; + +#define X(t) static constexpr auto id_##t = IdString(ID_##t); +#include "constids.inc" +#undef X + typedef IdString BelId; typedef IdString WireId; typedef IdString PipId; diff --git a/machxo2/constids.inc b/machxo2/constids.inc index e69de29b..f93aa9f3 100644 --- a/machxo2/constids.inc +++ b/machxo2/constids.inc @@ -0,0 +1,97 @@ +X(FACADE_SLICE) +X(A0) +X(B0) +X(C0) +X(D0) +X(A1) +X(B1) +X(C1) +X(D1) +X(M0) +X(M1) +X(FCI) +X(FXA) +X(FXB) +X(CLK) +X(LSR) +X(CE) +X(DI0) +X(DI1) +X(WD0) +X(WD1) +X(WAD0) +X(WAD1) +X(WAD2) +X(WAD3) +X(WRE) +X(WCK) +X(F0) +X(Q0) +X(F1) +X(Q1) +X(FCO) +X(OFX0) +X(OFX1) +X(WDO0) +X(WDO1) +X(WDO2) +X(WDO3) +X(WADO0) +X(WADO1) +X(WADO2) +X(WADO3) + +X(MODE) +X(GSR) +X(SRMODE) +X(CEMUX) +X(CLKMUX) +X(LSRMUX) +X(LSRONMUX) +X(LUT0_INITVAL) +X(LUT1_INITVAL) +X(REG0_SD) +X(REG1_SD) +X(REG0_REGSET) +X(REG1_REGSET) +X(REG0_REGMODE) +X(REG1_REGMODE) +X(CCU2_INJECT1_0) +X(CCU2_INJECT1_1) +X(WREMUX) + + +X(FACADE_FF) +X(DI) +X(Q) + +X(REGSET) +X(REGMODE) + + +X(FACADE_IO) +X(PAD) +X(I) +X(EN) +X(O) + +X(DIR) + + +X(LUT4) +X(A) +X(B) +X(C) +X(D) +X(Z) + +X(INIT) + + +X(PFUMX) +X(ALUT) +X(BLUT) + + +X(L6MUX21) +X(SD) -- cgit v1.2.3 From 3424badeff700afd061a78866e720a7cc88a0653 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 23 Nov 2020 13:06:20 -0500 Subject: machxo2: Create basic cells for packing. --- machxo2/cells.cc | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) (limited to 'machxo2') diff --git a/machxo2/cells.cc b/machxo2/cells.cc index 522295b0..aed96e3d 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -26,13 +26,117 @@ NEXTPNR_NAMESPACE_BEGIN void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir) { + IdString id = ctx->id(name); + NPNR_ASSERT(cell->ports.count(id) == 0); + cell->ports[id] = PortInfo{id, nullptr, dir}; +} +void add_port(const Context *ctx, CellInfo *cell, IdString id, PortType dir) +{ + NPNR_ASSERT(cell->ports.count(id) == 0); + cell->ports[id] = PortInfo{id, nullptr, dir}; } std::unique_ptr create_machxo2_cell(Context *ctx, IdString type, std::string name) { static int auto_idx = 0; std::unique_ptr new_cell = std::unique_ptr(new CellInfo()); + if (name.empty()) { + new_cell->name = ctx->id("$nextpnr_" + type.str(ctx) + "_" + std::to_string(auto_idx++)); + } else { + new_cell->name = ctx->id(name); + } + + if (type == id_FACADE_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"); + new_cell->params[id_CEMUX] = std::string("1"); + new_cell->params[id_CLKMUX] = std::string("0"); + new_cell->params[id_LSRMUX] = std::string("LSR"); + new_cell->params[id_LSRONMUX] = std::string("LSRMUX"); + new_cell->params[id_LUT0_INITVAL] = Property(16, 0xFFFF); + new_cell->params[id_LUT1_INITVAL] = Property(16, 0xFFFF); + new_cell->params[id_REG0_SD] = std::string("1"); + new_cell->params[id_REG1_SD] = std::string("1"); + new_cell->params[id_REG0_REGSET] = std::string("SET"); + new_cell->params[id_REG1_REGSET] = std::string("SET"); + new_cell->params[id_REG0_REGMODE] = std::string("FF"); + new_cell->params[id_REG1_REGMODE] = std::string("FF"); + new_cell->params[id_CCU2_INJECT1_0] = std::string("YES"); + new_cell->params[id_CCU2_INJECT1_1] = std::string("YES"); + new_cell->params[id_WREMUX] = std::string("INV"); + + add_port(ctx, new_cell.get(), id_A0, PORT_IN); + add_port(ctx, new_cell.get(), id_B0, PORT_IN); + add_port(ctx, new_cell.get(), id_C0, PORT_IN); + add_port(ctx, new_cell.get(), id_D0, PORT_IN); + + add_port(ctx, new_cell.get(), id_A1, PORT_IN); + add_port(ctx, new_cell.get(), id_B1, PORT_IN); + add_port(ctx, new_cell.get(), id_C1, PORT_IN); + add_port(ctx, new_cell.get(), id_D1, PORT_IN); + + add_port(ctx, new_cell.get(), id_M0, PORT_IN); + add_port(ctx, new_cell.get(), id_M1, PORT_IN); + + add_port(ctx, new_cell.get(), id_FCI, PORT_IN); + add_port(ctx, new_cell.get(), id_FXA, PORT_IN); + add_port(ctx, new_cell.get(), id_FXB, PORT_IN); + + add_port(ctx, new_cell.get(), id_CLK, PORT_IN); + add_port(ctx, new_cell.get(), id_LSR, PORT_IN); + add_port(ctx, new_cell.get(), id_CE, PORT_IN); + + add_port(ctx, new_cell.get(), id_DI0, PORT_IN); + add_port(ctx, new_cell.get(), id_DI1, PORT_IN); + + add_port(ctx, new_cell.get(), id_WD0, PORT_IN); + add_port(ctx, new_cell.get(), id_WD1, PORT_IN); + add_port(ctx, new_cell.get(), id_WAD0, PORT_IN); + add_port(ctx, new_cell.get(), id_WAD1, PORT_IN); + add_port(ctx, new_cell.get(), id_WAD2, PORT_IN); + add_port(ctx, new_cell.get(), id_WAD3, PORT_IN); + add_port(ctx, new_cell.get(), id_WRE, PORT_IN); + add_port(ctx, new_cell.get(), id_WCK, PORT_IN); + + add_port(ctx, new_cell.get(), id_F0, PORT_OUT); + add_port(ctx, new_cell.get(), id_Q0, PORT_OUT); + add_port(ctx, new_cell.get(), id_F1, PORT_OUT); + add_port(ctx, new_cell.get(), id_Q1, PORT_OUT); + + add_port(ctx, new_cell.get(), id_FCO, PORT_OUT); + add_port(ctx, new_cell.get(), id_OFX0, PORT_OUT); + add_port(ctx, new_cell.get(), id_OFX1, PORT_OUT); + + add_port(ctx, new_cell.get(), id_WDO0, PORT_OUT); + add_port(ctx, new_cell.get(), id_WDO1, PORT_OUT); + add_port(ctx, new_cell.get(), id_WDO2, PORT_OUT); + add_port(ctx, new_cell.get(), id_WDO3, PORT_OUT); + add_port(ctx, new_cell.get(), id_WADO0, PORT_OUT); + add_port(ctx, new_cell.get(), id_WADO1, PORT_OUT); + add_port(ctx, new_cell.get(), id_WADO2, PORT_OUT); + add_port(ctx, new_cell.get(), id_WADO3, PORT_OUT); + } else if (type == id_FACADE_IO) { + new_cell->params[id_DIR] = std::string("INPUT"); + new_cell->attrs[ctx->id("IO_TYPE")] = std::string("LVCMOS33"); + + add_port(ctx, new_cell.get(), "PAD", PORT_INOUT); + add_port(ctx, new_cell.get(), "I", PORT_IN); + add_port(ctx, new_cell.get(), "EN", PORT_IN); + add_port(ctx, new_cell.get(), "O", PORT_OUT); + } else if (type == id_LUT4) { + new_cell->params[id_INIT] = Property(0, 16); + + add_port(ctx, new_cell.get(), id_A, PORT_IN); + add_port(ctx, new_cell.get(), id_B, PORT_IN); + add_port(ctx, new_cell.get(), id_C, PORT_IN); + add_port(ctx, new_cell.get(), id_D, PORT_IN); + add_port(ctx, new_cell.get(), id_Z, PORT_OUT); + } else { + log_error("unable to create MachXO2 cell of type %s", type.c_str(ctx)); + } + return new_cell; } -- cgit v1.2.3 From 42214b226fda6647a954cfe4895cfceee9a8cd72 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 23 Nov 2020 16:56:41 -0500 Subject: machxo2: Add constant packing implementation, fix bugs in create_machxo2_cell. --- machxo2/cells.cc | 5 ++-- machxo2/pack.cc | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) (limited to 'machxo2') diff --git a/machxo2/cells.cc b/machxo2/cells.cc index aed96e3d..d56c6d71 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -46,6 +46,7 @@ std::unique_ptr create_machxo2_cell(Context *ctx, IdString type, std:: } else { new_cell->name = ctx->id(name); } + new_cell->type = type; if (type == id_FACADE_SLICE) { new_cell->params[id_MODE] = std::string("LOGIC"); @@ -55,8 +56,8 @@ std::unique_ptr create_machxo2_cell(Context *ctx, IdString type, std:: new_cell->params[id_CLKMUX] = std::string("0"); new_cell->params[id_LSRMUX] = std::string("LSR"); new_cell->params[id_LSRONMUX] = std::string("LSRMUX"); - new_cell->params[id_LUT0_INITVAL] = Property(16, 0xFFFF); - new_cell->params[id_LUT1_INITVAL] = Property(16, 0xFFFF); + new_cell->params[id_LUT0_INITVAL] = Property(0xFFFF, 16); + new_cell->params[id_LUT1_INITVAL] = Property(0xFFFF, 16); new_cell->params[id_REG0_SD] = std::string("1"); new_cell->params[id_REG1_SD] = std::string("1"); new_cell->params[id_REG0_REGSET] = std::string("SET"); diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 38edc7aa..6af7a58b 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -27,6 +27,75 @@ NEXTPNR_NAMESPACE_BEGIN +// Merge a net into a constant net +static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval) +{ + (void) constval; + + orig->driver.cell = nullptr; + for (auto user : orig->users) { + if (user.cell != nullptr) { + CellInfo *uc = user.cell; + if (ctx->verbose) + log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx)); + + uc->ports[user.port].net = constnet; + constnet->users.push_back(user); + } + } + orig->users.clear(); +} + + +// Pack constants (based on simple implementation in generic). +// VCC/GND cells provided by nextpnr automatically. +static void pack_constants(Context *ctx) +{ + log_info("Packing constants..\n"); + + std::unique_ptr const_cell = create_machxo2_cell(ctx, id_FACADE_SLICE, "$PACKER_CONST"); + const_cell->params[id_LUT0_INITVAL] = Property(0, 16); + const_cell->params[id_LUT1_INITVAL] = Property(0xFFFF, 16); + + std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); + gnd_net->name = ctx->id("$PACKER_GND_NET"); + gnd_net->driver.cell = const_cell.get(); + gnd_net->driver.port = id_F0; + const_cell->ports.at(id_F0).net = gnd_net.get(); + + std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); + vcc_net->name = ctx->id("$PACKER_VCC_NET"); + vcc_net->driver.cell = const_cell.get(); + vcc_net->driver.port = id_F1; + const_cell->ports.at(id_F1).net = vcc_net.get(); + + std::vector dead_nets; + + for (auto net : sorted(ctx->nets)) { + NetInfo *ni = net.second; + if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { + IdString drv_cell = ni->driver.cell->name; + set_net_constant(ctx, ni, gnd_net.get(), false); + dead_nets.push_back(net.first); + ctx->cells.erase(drv_cell); + } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) { + IdString drv_cell = ni->driver.cell->name; + set_net_constant(ctx, ni, vcc_net.get(), true); + dead_nets.push_back(net.first); + ctx->cells.erase(drv_cell); + } + } + + ctx->cells[const_cell->name] = std::move(const_cell); + ctx->nets[gnd_net->name] = std::move(gnd_net); + ctx->nets[vcc_net->name] = std::move(vcc_net); + + for (auto dn : dead_nets) { + ctx->nets.erase(dn); + } +} + + // Main pack function bool Arch::pack() { @@ -34,6 +103,7 @@ bool Arch::pack() log_info("Packing implementation goes here.."); try { log_break(); + pack_constants(ctx); ctx->settings[ctx->id("pack")] = 1; ctx->assignArchInfo(); log_info("Checksum: 0x%08x\n", ctx->checksum()); -- cgit v1.2.3 From f2a240550e14184041d3f0cfd7526386d985f27c Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 23 Nov 2020 22:17:47 -0500 Subject: machxo2: Always remove nextpnr_iobufs for now- assume manually instantiated primitives. --- machxo2/main.cc | 2 +- machxo2/pack.cc | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/main.cc b/machxo2/main.cc index 84b99edc..92a60d38 100644 --- a/machxo2/main.cc +++ b/machxo2/main.cc @@ -67,7 +67,7 @@ po::options_description MachXO2CommandHandler::getArchOptions() specific.add_options()("lpf", po::value>(), "LPF pin constraint file(s)"); - specific.add_options()("no-iobs", "disable automatic IO buffer insertion"); + specific.add_options()("no-iobs", "disable automatic IO buffer insertion (unimplemented- always enabled)"); return specific; } diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 6af7a58b..c418ceda 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -95,6 +95,36 @@ static void pack_constants(Context *ctx) } } +static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) +{ + return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") || + cell->type == ctx->id("$nextpnr_iobuf"); +} + +static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("FACADE_IO"); } + +// 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 +// attributes. +static void pack_io(Context *ctx) +{ + std::unordered_set packed_cells; + + log_info("Packing IOs..\n"); + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_nextpnr_iob(ctx, ci)) { + for (auto &p : ci->ports) + disconnect_port(ctx, ci, p.first); + packed_cells.insert(ci->name); + } + } + + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } +} // Main pack function bool Arch::pack() @@ -104,6 +134,7 @@ bool Arch::pack() try { log_break(); pack_constants(ctx); + pack_io(ctx); ctx->settings[ctx->id("pack")] = 1; ctx->assignArchInfo(); log_info("Checksum: 0x%08x\n", ctx->checksum()); -- cgit v1.2.3 From da6204442fb2635ec82621c00cdf4f7e3dfa3499 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 26 Nov 2020 05:01:14 -0500 Subject: machxo2: Add LUT and FF packing functions. --- machxo2/cells.cc | 19 +++++++++++++++++- machxo2/cells.h | 8 ++++---- machxo2/pack.cc | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 5 deletions(-) (limited to 'machxo2') diff --git a/machxo2/cells.cc b/machxo2/cells.cc index d56c6d71..9a682a72 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -143,12 +143,29 @@ std::unique_ptr create_machxo2_cell(Context *ctx, IdString type, std:: void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { + lc->params[ctx->id("LUT0_INITVAL")] = lut->params[ctx->id("INIT")]; + for (std::string i : {"A", "B", "C", "D"}) { + IdString lut_port = ctx->id(i); + IdString lc_port = ctx->id(i + "0"); + replace_port(lut, lut_port, lc, lc_port); + } + + replace_port(lut, ctx->id("Z"), lc, ctx->id("F0")); } void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) { - + // By this point, we have shown that LUT4 Z is attached to FACADE_FF DI. + // This connection will be preserved by port replacement, but the SD mux + // which selects the actual DFF input needs to be told to use the + // FACADE_SLICE DI input instead of the FACADE_SLICE M input. + lc->params[ctx->id("REG0_SD")] = std::string("0"); + + replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK")); + replace_port(dff, ctx->id("DI"), lc, ctx->id("DI0")); + replace_port(dff, ctx->id("LSR"), lc, ctx->id("LSR")); + replace_port(dff, ctx->id("Q"), lc, ctx->id("Q0")); } void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set &todelete_cells) diff --git a/machxo2/cells.h b/machxo2/cells.h index b2971bda..f129f762 100644 --- a/machxo2/cells.h +++ b/machxo2/cells.h @@ -24,17 +24,17 @@ NEXTPNR_NAMESPACE_BEGIN -// Create a generic arch cell and return it +// Create a MachXO2 arch cell and return it // Name will be automatically assigned if not specified std::unique_ptr create_machxo2_cell(Context *ctx, IdString type, std::string name = ""); // Return true if a cell is a LUT -inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return false; } +inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("LUT4"); } // Return true if a cell is a flipflop -inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return false; } +inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("FACADE_FF"); } -inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return false; } +inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("FACADE_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 diff --git a/machxo2/pack.cc b/machxo2/pack.cc index c418ceda..76fd7240 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -27,6 +27,65 @@ NEXTPNR_NAMESPACE_BEGIN +// Pack LUTs and LUT-FF pairs +static void pack_lut_lutffs(Context *ctx) +{ + log_info("Packing LUT-FFs..\n"); + + std::unordered_set packed_cells; + std::vector> new_cells; + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + 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 packed = + create_machxo2_cell(ctx, ctx->id("FACADE_SLICE"), ci->name.str(ctx) + "_LC"); + std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); + + packed_cells.insert(ci->name); + if (ctx->verbose) + log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); + // See if we can pack into a DFF. Both LUT4 and FF outputs are + // available for a given slice, so we can pack a FF even if the + // LUT4 drives more than one FF. + NetInfo *o = ci->ports.at(ctx->id("Z")).net; + CellInfo *dff = net_only_drives(ctx, o, is_ff, ctx->id("DI"), false); + auto lut_bel = ci->attrs.find(ctx->id("BEL")); + bool packed_dff = false; + + if (dff) { + if (ctx->verbose) + log_info("found attached dff %s\n", dff->name.c_str(ctx)); + auto dff_bel = dff->attrs.find(ctx->id("BEL")); + if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) { + // Locations don't match, can't pack + } else { + lut_to_lc(ctx, ci, packed.get(), false); + dff_to_lc(ctx, dff, packed.get(), false); + if (dff_bel != dff->attrs.end()) + packed->attrs[ctx->id("BEL")] = dff_bel->second; + packed_cells.insert(dff->name); + if (ctx->verbose) + log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx)); + packed_dff = true; + } + } + if (!packed_dff) { + lut_to_lc(ctx, ci, packed.get(), true); + } + new_cells.push_back(std::move(packed)); + } + } + + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + // Merge a net into a constant net static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval) { @@ -135,6 +194,7 @@ bool Arch::pack() log_break(); pack_constants(ctx); pack_io(ctx); + pack_lut_lutffs(ctx); ctx->settings[ctx->id("pack")] = 1; ctx->assignArchInfo(); log_info("Checksum: 0x%08x\n", ctx->checksum()); -- cgit v1.2.3 From 5838662b2f8a06aef52eac8218175f59547b5f09 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 26 Nov 2020 19:27:09 -0500 Subject: machxo2: Make sure REGSET FF parameter is set in FACADE_SLICE. Init blinky ctr to 0 for miter circuit. --- machxo2/cells.cc | 3 +++ machxo2/examples/blinky.v | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/cells.cc b/machxo2/cells.cc index 9a682a72..9a522b1a 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -162,6 +162,9 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l // FACADE_SLICE DI input instead of the FACADE_SLICE M input. lc->params[ctx->id("REG0_SD")] = std::string("0"); + // FIXME: This will have to change once we support FFs with reset value of 1. + lc->params[ctx->id("REG0_REGSET")] = std::string("RESET"); + replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK")); replace_port(dff, ctx->id("DI"), lc, ctx->id("DI0")); replace_port(dff, ctx->id("LSR"), lc, ctx->id("LSR")); diff --git a/machxo2/examples/blinky.v b/machxo2/examples/blinky.v index c7cde26d..2137ad58 100644 --- a/machxo2/examples/blinky.v +++ b/machxo2/examples/blinky.v @@ -1,6 +1,7 @@ module top(input clk, rst, output [7:0] leds); -reg [7:0] ctr; +// TODO: Test miter circuit without reset value. +reg [7:0] ctr = 8'h00; always @(posedge clk) if (rst) ctr <= 8'h00; -- cgit v1.2.3 From 4f042eac5338c789ad90ac10dc2a9d8e92ce1acd Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 28 Nov 2020 21:08:09 -0500 Subject: machxo2: Rework examples to test pack, place, and route phases. --- machxo2/examples/.gitignore | 5 ++++- machxo2/examples/README.md | 37 ++++++++++++++++++++++++++++--------- machxo2/examples/blinky.v | 6 +++++- machxo2/examples/mitertest.sh | 43 +++++++++++++++++++++++++++++++++++++++++++ machxo2/examples/simple.sh | 35 ++++++++++++++++++++++++++++++++--- machxo2/examples/simtest.sh | 37 +++++++++++++++++++++++++++++++++---- 6 files changed, 145 insertions(+), 18 deletions(-) create mode 100644 machxo2/examples/mitertest.sh (limited to 'machxo2') diff --git a/machxo2/examples/.gitignore b/machxo2/examples/.gitignore index f1ee6a8a..a4c8185f 100644 --- a/machxo2/examples/.gitignore +++ b/machxo2/examples/.gitignore @@ -1,4 +1,7 @@ -pnrblinky.v /blinky_simtest *.vcd +*.png +pack*.v +place*.v +pnr*.v abc.history diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index 87f50f6d..aac80fb4 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -2,18 +2,37 @@ This contains a simple example of running `nextpnr-machxo2`: -* `simple.sh` generates JSON output (`pnrblinky.json`) of a classic blinky - example from `blinky.v`. +* `simple.sh` generates JSON output (`{pack,place,pnr}blinky.json`) of a + classic blinky example from `blinky.v`. * `simtest.sh` will use `yosys` to generate a Verilog file from - `pnrblinky.json`, called `pnrblinky.v`. It will then and compare - `pnrblinky.v`'s simulation behavior to the original verilog file (`blinky.v`) - using the [`iverilog`](http://iverilog.icarus.com) compiler and `vvp` - runtime. This is known as post-place-and-route simulation. + `{pack,place,pnr}blinky.json`, called `{pack,place,pnr}blinky.v`. It will + then and compare `{pack,place,pnr}blinky.v`'s simulation behavior to the + original verilog file (`blinky.v`) using the [`iverilog`](http://iverilog.icarus.com) + compiler and `vvp` runtime. This is known as post-place-and-route simulation. +* `mitertest.sh` is similar to `simtest.sh`, but more comprehensive. This + script creates a [miter circuit](https://www21.in.tum.de/~lammich/2015_SS_Seminar_SAT/resources/Equivalence_Checking_11_30_08.pdf) + to compare the output port values of `{pack,place,pnr}blinky.v` against the + original `blinky.v` _when both modules are fed the same values on their input + ports._ -As `nextpnr-machxo2` is developed the contents `simple.sh` and `simtest.sh` -are subject to change. + All possible inputs and resulting outputs can be tested in reasonable time by + using yosys' built-in SAT solver. -## Environment Variables For `simple.sh` And `simtest.sh` +As `nextpnr-machxo2` is developed the contents `simple.sh`, `simtest.sh`, and +`mitertest.sh` are subject to change. + +## How To Run + +Each `sh` script runs yosys and nextpnr to validate a blinky design in various +ways. The `mode` argument to each script- `pack`, `place`, or `pnr`- stop +`nextpnr-machxo2` after the specified phase and writes out a JSON file of the +results in `{pack,place,pnr}blinky.json`; `pnr` runs all of the Pack, Place, +and Route phases. + +To keep file count lower, all yosys scripts are written inline inside the +`sh` scripts using the `-p` option. + +## Environment Variables For Scripts * `YOSYS`- Set to the location of the `yosys` binary to test. Defaults to the `yosys` on the path. You may want to set this to a `yosys` binary in your diff --git a/machxo2/examples/blinky.v b/machxo2/examples/blinky.v index 2137ad58..57bad543 100644 --- a/machxo2/examples/blinky.v +++ b/machxo2/examples/blinky.v @@ -1,6 +1,10 @@ module top(input clk, rst, output [7:0] leds); -// TODO: Test miter circuit without reset value. +// TODO: Test miter circuit without reset value. SAT and SMT diverge without +// reset value (SAT succeeds, SMT fails). I haven't figured out the correct +// init set of options to make SAT fail. +// "sat -verify -prove-asserts -set-init-def -seq 1 miter" causes assertion +// failure in yosys. reg [7:0] ctr = 8'h00; always @(posedge clk) if (rst) diff --git a/machxo2/examples/mitertest.sh b/machxo2/examples/mitertest.sh new file mode 100644 index 00000000..e5cc5173 --- /dev/null +++ b/machxo2/examples/mitertest.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +if [ $# -lt 1 ]; then + echo "Usage: $0 mode" + exit -1 +fi + +case $1 in + "pack") + NEXTPNR_MODE="--pack-only" + ;; + "place") + NEXTPNR_MODE="--no-route" + ;; + "pnr") + NEXTPNR_MODE="" + ;; + *) + echo "Mode string must be \"pack\", \"place\", or \"pnr\"" + exit -2 + ;; +esac + +set -ex + +${YOSYS:-yosys} -p "read_verilog blinky.v + synth_machxo2 -noiopad -json blinky.json + show -format png -prefix blinky" +${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --no-iobs --json blinky.json --write ${1}blinky.json +${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v + read_json ${1}blinky.json + clean -purge + show -format png -prefix ${1}blinky + write_verilog -noattr -norename ${1}blinky.v" +${YOSYS:-yosys} -p "read_verilog blinky.v + rename top gold + read_verilog ${1}blinky.v + rename top gate + read_verilog +/machxo2/cells_sim.v + + miter -equiv -make_assert -flatten gold gate miter + hierarchy -top miter + sat -verify -prove-asserts -tempinduct miter" diff --git a/machxo2/examples/simple.sh b/machxo2/examples/simple.sh index 9eb06886..91fa4b91 100644 --- a/machxo2/examples/simple.sh +++ b/machxo2/examples/simple.sh @@ -1,5 +1,34 @@ #!/usr/bin/env bash + +if [ $# -lt 1 ]; then + echo "Usage: $0 mode" + exit -1 +fi + +case $1 in + "pack") + NEXTPNR_MODE="--pack-only" + ;; + "place") + NEXTPNR_MODE="--no-route" + ;; + "pnr") + NEXTPNR_MODE="" + ;; + *) + echo "Mode string must be \"pack\", \"place\", or \"pnr\"" + exit -2 + ;; +esac + set -ex -${YOSYS:yosys} -p "synth_machxo2 -json blinky.json" blinky.v -${NEXTPNR:-../../nextpnr-machxo2} --json blinky.json --write pnrblinky.json -${YOSYS:yosys} -p "read_verilog -lib +/machxo2/cells_sim.v; read_json pnrblinky.json; dump -o blinky.il; show -format png -prefix blinky" + +${YOSYS:-yosys} -p "read_verilog blinky.v + synth_machxo2 -json blinky.json + show -format png -prefix blinky" +${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --no-iobs --json blinky.json --write ${1}blinky.json +${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v + read_json ${1}blinky.json + clean -purge + show -format png -prefix ${1}blinky + write_verilog -noattr -norename ${1}blinky.v" diff --git a/machxo2/examples/simtest.sh b/machxo2/examples/simtest.sh index 4cb8d5ca..ff35bbd6 100644 --- a/machxo2/examples/simtest.sh +++ b/machxo2/examples/simtest.sh @@ -1,7 +1,36 @@ #!/usr/bin/env bash + +if [ $# -lt 1 ]; then + echo "Usage: $0 mode" + exit -1 +fi + +case $1 in + "pack") + NEXTPNR_MODE="--pack-only" + ;; + "place") + NEXTPNR_MODE="--no-route" + ;; + "pnr") + NEXTPNR_MODE="" + ;; + *) + echo "Mode string must be \"pack\", \"place\", or \"pnr\"" + exit -2 + ;; +esac + set -ex -${YOSYS:-yosys} -p "synth_machxo2 -json blinky.json" blinky.v -${NEXTPNR:-../../nextpnr-machxo2} --no-iobs --json blinky.json --write pnrblinky.json -${YOSYS:-yosys} -p "read_json blinky.json; write_verilog -noattr -norename pnrblinky.v" -iverilog -o blinky_simtest ${CELLS_SIM:-`${YOSYS:yosys}-config --datdir/machxo2/cells_sim.v`} blinky_tb.v pnrblinky.v + +${YOSYS:-yosys} -p "read_verilog blinky.v + synth_machxo2 -json blinky.json + show -format png -prefix blinky" +${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --no-iobs --json blinky.json --write ${1}blinky.json +${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v + read_json ${1}blinky.json + clean -purge + show -format png -prefix ${1}blinky + write_verilog -noattr -norename ${1}blinky.v" +iverilog -o blinky_simtest ${CELLS_SIM:-`${YOSYS:yosys}-config --datdir/machxo2/cells_sim.v`} blinky_tb.v ${1}blinky.v vvp -N ./blinky_simtest -- cgit v1.2.3 From 6ce2edc2f109f81adfb143d2732dabe6fc4e36de Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 28 Nov 2020 21:43:03 -0500 Subject: machxo2: Add SMT mode to mitertest.sh --- machxo2/examples/.gitignore | 2 ++ machxo2/examples/README.md | 9 ++++++- machxo2/examples/mitertest.sh | 61 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 60 insertions(+), 12 deletions(-) (limited to 'machxo2') diff --git a/machxo2/examples/.gitignore b/machxo2/examples/.gitignore index a4c8185f..87d5128b 100644 --- a/machxo2/examples/.gitignore +++ b/machxo2/examples/.gitignore @@ -1,6 +1,8 @@ /blinky_simtest *.vcd *.png +*.log +*.smt2 pack*.v place*.v pnr*.v diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index aac80fb4..e940c01c 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -16,7 +16,8 @@ This contains a simple example of running `nextpnr-machxo2`: ports._ All possible inputs and resulting outputs can be tested in reasonable time by - using yosys' built-in SAT solver. + using `yosys`' built-in SAT solver or [`z3`](https://github.com/Z3Prover/z3), + an external SMT solver. As `nextpnr-machxo2` is developed the contents `simple.sh`, `simtest.sh`, and `mitertest.sh` are subject to change. @@ -29,9 +30,15 @@ ways. The `mode` argument to each script- `pack`, `place`, or `pnr`- stop results in `{pack,place,pnr}blinky.json`; `pnr` runs all of the Pack, Place, and Route phases. +`mitertest.sh` requires an additional option- `sat` or `smt`- to choose between +verifying the miter with either yosys' built-in SAT solver, or an external +SMT solver. + To keep file count lower, all yosys scripts are written inline inside the `sh` scripts using the `-p` option. +To clean output files, run: `rm -rf *.dot *.json *.png *.vcd *.smt2 *.log {pack,place,pnr}*.v blinky_simtest*` + ## Environment Variables For Scripts * `YOSYS`- Set to the location of the `yosys` binary to test. Defaults to the diff --git a/machxo2/examples/mitertest.sh b/machxo2/examples/mitertest.sh index e5cc5173..aea5bfff 100644 --- a/machxo2/examples/mitertest.sh +++ b/machxo2/examples/mitertest.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash if [ $# -lt 1 ]; then - echo "Usage: $0 mode" + echo "Usage: $0 nextpnr_mode solve_mode" exit -1 fi @@ -16,11 +16,53 @@ case $1 in NEXTPNR_MODE="" ;; *) - echo "Mode string must be \"pack\", \"place\", or \"pnr\"" + echo "nextpnr_mode string must be \"pack\", \"place\", or \"pnr\"" exit -2 ;; esac +case $2 in + "sat") + SAT=1 + ;; + "smt") + SMT=1 + ;; + *) + echo "solve_mode string must be \"sat\", or \"smt\"" + exit -3 + ;; +esac + +do_sat() { + ${YOSYS:-yosys} -l ${1}miter_sat.log -p "read_verilog blinky.v + rename top gold + read_verilog ${1}blinky.v + rename top gate + read_verilog +/machxo2/cells_sim.v + + miter -equiv -make_assert -flatten gold gate ${1}miter + hierarchy -top ${1}miter + sat -verify -prove-asserts -tempinduct ${1}miter" +} + +do_smt() { + ${YOSYS:-yosys} -l ${1}miter_smt.log -p "read_verilog blinky.v + rename top gold + read_verilog ${1}blinky.v + rename top gate + read_verilog +/machxo2/cells_sim.v + + miter -equiv -make_assert gold gate ${1}miter + hierarchy -auto-top -check; proc; + opt_clean + write_verilog ${1}miter.v + write_smt2 ${1}miter.smt2" + + yosys-smtbmc -s z3 --dump-vcd ${1}miter_bmc.vcd ${1}miter.smt2 + yosys-smtbmc -s z3 -i --dump-vcd ${1}miter_tmp.vcd ${1}miter.smt2 +} + set -ex ${YOSYS:-yosys} -p "read_verilog blinky.v @@ -32,12 +74,9 @@ ${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v clean -purge show -format png -prefix ${1}blinky write_verilog -noattr -norename ${1}blinky.v" -${YOSYS:-yosys} -p "read_verilog blinky.v - rename top gold - read_verilog ${1}blinky.v - rename top gate - read_verilog +/machxo2/cells_sim.v - - miter -equiv -make_assert -flatten gold gate miter - hierarchy -top miter - sat -verify -prove-asserts -tempinduct miter" + +if [ $2 = "sat" ]; then + do_sat $1 +elif [ $2 = "smt" ]; then + do_smt $1 +fi -- cgit v1.2.3 From e0b14ba98e959a23bdc211c96a0917b5761a5116 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 30 Nov 2020 13:33:10 -0500 Subject: machxo2: Begin populating binary blob via facade_import. --- machxo2/facade_import.py | 118 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 109 insertions(+), 9 deletions(-) (limited to 'machxo2') diff --git a/machxo2/facade_import.py b/machxo2/facade_import.py index d21557ae..88ee3b71 100644 --- a/machxo2/facade_import.py +++ b/machxo2/facade_import.py @@ -3,6 +3,8 @@ import argparse import json import sys +tiletype_names = dict() + parser = argparse.ArgumentParser(description="import MachXO2 routing and bels from Project Trellis") parser.add_argument("device", type=str, help="target device") parser.add_argument("-p", "--constids", type=str, help="path to constids.inc") @@ -14,6 +16,14 @@ sys.path += args.libdir import pytrellis import database +# Get the index for a tiletype +def get_tiletype_index(name): + if name in tiletype_names: + return tiletype_names[name] + idx = len(tiletype_names) + tiletype_names[name] = idx + return idx + class BinaryBlobAssembler: def l(self, name, ltype = None, export = False): @@ -62,16 +72,21 @@ class BinaryBlobAssembler: def pop(self): print("pop") +def write_database(dev_name, chip, rg, endianness): + def write_loc(loc, sym_name): + bba.u16(loc.x, "%s.x" % sym_name) + bba.u16(loc.y, "%s.y" % sym_name) -dev_names = {"1200": "LCMXO2-1200HC"} + # Before doing anything, ensure sorted routing graph iteration matches + # y, x + tile_iter = list(sorted(rg.tiles, key=lambda l : (l.key().y, l.key().x))) -def main(): - global max_row, max_col, const_id_count - - pytrellis.load_database(database.get_db_root()) - - # Dummy - dev_name = "1200" + i = 1 # Drop (-2, -2) location. + for y in range(0, max_row+1): + for x in range(0, max_col+1): + l = tile_iter[i] + assert((y, x) == (l.key().y, l.key().x)) + i = i + 1 bba = BinaryBlobAssembler() bba.pre('#include "nextpnr.h"') @@ -80,8 +95,93 @@ def main(): bba.post('EmbeddedFile chipdb_file_%s("machxo2/chipdb-%s.bin", chipdb_blob_%s);' % (dev_name, dev_name, dev_name)) bba.post('NEXTPNR_NAMESPACE_END') bba.push("chipdb_blob_%s" % args.device) - bba.u8(0, None) + bba.r("chip_info", "chip_info") + + # Nominally should be in order, but support situations where python + # decides to iterate over rg.tiles out-of-order. + for lt in sorted(rg.tiles, key=lambda l : (l.key().y, l.key().x)): + l = lt.key() + t = lt.data() + + # Do not include special globals location for now. + if (l.x, l.y) == (-2, -2): + continue + + if len(t.arcs) > 0: + bba.l("loc%d_%d_pips" % (l.y, l.x), "PipInfoPOD") + + if len(t.wires) > 0: + bba.l("loc%d_%d_wires" % (l.y, l.x), "WireInfoPOD") + + if len(t.bels) > 0: + bba.l("loc%d_%d_bels" % (l.y, l.x), "BelInfoPOD") + + bba.l("tiles", "TileTypePOD") + for lt in sorted(rg.tiles, key=lambda l : (l.key().y, l.key().x)): + l = lt.key() + t = lt.data() + + if (l.y, l.x) == (-2, -2): + continue + + bba.u32(len(t.bels), "num_bels") + bba.u32(len(t.wires), "num_wires") + bba.u32(len(t.arcs), "num_pips") + bba.r("loc%d_%d_bels" % (l.y, l.x) if len(t.bels) > 0 else None, "bel_data") + bba.r("loc%d_%d_wires" % (l.y, l.x) if len(t.wires) > 0 else None, "wire_data") + bba.r("loc%d_%d_pips" % (l.y, l.x) if len(t.arcs) > 0 else None, "pips_data") + + for y in range(0, max_row+1): + for x in range(0, max_col+1): + bba.l("tile_info_%d_%d" % (x, y), "TileNamePOD") + for tile in chip.get_tiles_by_position(y, x): + bba.s(tile.info.name, "name") + bba.u16(get_tiletype_index(tile.info.type), "type_idx") + bba.u16(0, "padding") + + bba.l("tiles_info", "TileInfoPOD") + for y in range(0, max_row+1): + for x in range(0, max_col+1): + bba.u32(len(chip.get_tiles_by_position(y, x)), "num_tiles") + bba.r("tile_info_%d_%d" % (x, y), "tile_names") + + bba.l("tiletype_names", "RelPtr") + for tt, idx in sorted(tiletype_names.items(), key=lambda x: x[1]): + bba.s(tt, "name") + + + bba.l("chip_info") + bba.u32(max_col + 1, "width") + bba.u32(max_row + 1, "height") + bba.u32((max_col + 1) * (max_row + 1), "num_tiles") + bba.u32(0, "num_packages") # len(packages) + bba.u32(0, "num_pios") # len(pindata) + bba.u32(const_id_count, "const_id_count") + + bba.r("tiles", "tiles") + bba.r("tiletype_names", "tiletype_names") + bba.r("tiles_info", "tile_info") + bba.pop() + +dev_names = {"1200": "LCMXO2-1200HC"} + +def main(): + global max_row, max_col, const_id_count + + pytrellis.load_database(database.get_db_root()) + args = parser.parse_args() + + const_id_count = 1 # count ID_NONE + + chip = pytrellis.Chip(dev_names[args.device]) + rg = pytrellis.make_optimized_chipdb(chip) + max_row = chip.get_max_row() + max_col = chip.get_max_col() + bba = write_database(args.device, chip, rg, "le") + + + if __name__ == "__main__": main() -- cgit v1.2.3 From dfedef5772fa80baec0b92315ae03715657d205e Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 3 Dec 2020 22:05:44 -0500 Subject: machxo2: Add pip and wire info into facade_import. --- machxo2/facade_import.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'machxo2') diff --git a/machxo2/facade_import.py b/machxo2/facade_import.py index 88ee3b71..24491c3b 100644 --- a/machxo2/facade_import.py +++ b/machxo2/facade_import.py @@ -77,6 +77,11 @@ def write_database(dev_name, chip, rg, endianness): bba.u16(loc.x, "%s.x" % sym_name) bba.u16(loc.y, "%s.y" % sym_name) + # Use Lattice naming conventions, so convert to 1-based col indexing. + def get_wire_name(loc, idx): + tile = rg.tiles[loc] + return "R{}C{}_{}".format(loc.y, loc.x + 1, rg.to_str(tile.wires[idx].name)) + # Before doing anything, ensure sorted routing graph iteration matches # y, x tile_iter = list(sorted(rg.tiles, key=lambda l : (l.key().y, l.key().x))) @@ -109,9 +114,54 @@ def write_database(dev_name, chip, rg, endianness): if len(t.arcs) > 0: bba.l("loc%d_%d_pips" % (l.y, l.x), "PipInfoPOD") + for arc in t.arcs: + write_loc(arc.srcWire.rel, "src") + write_loc(arc.sinkWire.rel, "dst") + bba.u32(arc.srcWire.id, "src_idx {}".format(get_wire_name(arc.srcWire.rel, arc.srcWire.id))) + bba.u32(arc.sinkWire.id, "dst_idx {}".format(get_wire_name(arc.sinkWire.rel, arc.sinkWire.id))) + src_name = get_wire_name(arc.srcWire.rel, arc.srcWire.id) + snk_name = get_wire_name(arc.sinkWire.rel, arc.sinkWire.id) + # bba.u32(get_pip_class(src_name, snk_name), "timing_class") + bba.u16(get_tiletype_index(rg.to_str(arc.tiletype)), "tile_type") + cls = arc.cls + bba.u8(arc.cls, "pip_type") + bba.u8(0, "padding") if len(t.wires) > 0: + for wire_idx in range(len(t.wires)): + wire = t.wires[wire_idx] + if len(wire.arcsDownhill) > 0: + bba.l("loc%d_%d_wire%d_downpips" % (l.y, l.x, wire_idx), "PipLocatorPOD") + for dp in wire.arcsDownhill: + write_loc(dp.rel, "rel_loc") + bba.u32(dp.id, "index") + if len(wire.arcsUphill) > 0: + bba.l("loc%d_%d_wire%d_uppips" % (l.y, l.x, wire_idx), "PipLocatorPOD") + for up in wire.arcsUphill: + write_loc(up.rel, "rel_loc") + bba.u32(up.id, "index") + if len(wire.belPins) > 0: + bba.l("loc%d_%d_wire%d_belpins" % (l.y, l.x, wire_idx), "BelPortPOD") + for bp in wire.belPins: + write_loc(bp.bel.rel, "rel_bel_loc") + bba.u32(bp.bel.id, "bel_index") + # bba.u32(constids[rg.to_str(bp.pin)], "port") + bba.l("loc%d_%d_wires" % (l.y, l.x), "WireInfoPOD") + for wire_idx in range(len(t.wires)): + wire = t.wires[wire_idx] + bba.s(rg.to_str(wire.name), "name") + # bba.u32(constids[wire_type(ddrg.to_str(wire.name))], "type") + # if ("TILE_WIRE_" + ddrg.to_str(wire.name)) in gfx_wire_ids: + # bba.u32(gfx_wire_ids["TILE_WIRE_" + ddrg.to_str(wire.name)], "tile_wire") + # else: + bba.u32(0, "tile_wire") + bba.u32(len(wire.arcsUphill), "num_uphill") + bba.u32(len(wire.arcsDownhill), "num_downhill") + bba.r("loc%d_%d_wire%d_uppips" % (l.y, l.x, wire_idx) if len(wire.arcsUphill) > 0 else None, "pips_uphill") + bba.r("loc%d_%d_wire%d_downpips" % (l.y, l.x, wire_idx) if len(wire.arcsDownhill) > 0 else None, "pips_downhill") + bba.u32(len(wire.belPins), "num_bel_pins") + bba.r("loc%d_%d_wire%d_belpins" % (l.y, l.x, wire_idx) if len(wire.belPins) > 0 else None, "bel_pins") if len(t.bels) > 0: bba.l("loc%d_%d_bels" % (l.y, l.x), "BelInfoPOD") -- cgit v1.2.3 From b739513894cedbc13c73150220f0ee8b09826464 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 3 Dec 2020 22:36:38 -0500 Subject: machxo2: Import constids and BELs into facade_import. --- machxo2/constids.inc | 23 +++++++++++++++++++++++ machxo2/facade_import.py | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/constids.inc b/machxo2/constids.inc index f93aa9f3..b60cfe54 100644 --- a/machxo2/constids.inc +++ b/machxo2/constids.inc @@ -95,3 +95,26 @@ X(BLUT) X(L6MUX21) X(SD) + + +X(T) +X(IOLDO) +X(IOLTO) + + +X(OSCH) +X(STDBY) +X(OSC) +X(SEDSTDBY) + + +X(DCCA) +X(CLKI) +X(CLKO) + + +X(DCMA) +X(CLK0) +X(CLK1) +X(SEL) +X(DCMOUT) diff --git a/machxo2/facade_import.py b/machxo2/facade_import.py index 24491c3b..82c4963d 100644 --- a/machxo2/facade_import.py +++ b/machxo2/facade_import.py @@ -25,6 +25,9 @@ def get_tiletype_index(name): return idx +constids = dict() + + class BinaryBlobAssembler: def l(self, name, ltype = None, export = False): if ltype is None: @@ -145,7 +148,7 @@ def write_database(dev_name, chip, rg, endianness): for bp in wire.belPins: write_loc(bp.bel.rel, "rel_bel_loc") bba.u32(bp.bel.id, "bel_index") - # bba.u32(constids[rg.to_str(bp.pin)], "port") + bba.u32(constids[rg.to_str(bp.pin)], "port") bba.l("loc%d_%d_wires" % (l.y, l.x), "WireInfoPOD") for wire_idx in range(len(t.wires)): @@ -164,7 +167,22 @@ def write_database(dev_name, chip, rg, endianness): bba.r("loc%d_%d_wire%d_belpins" % (l.y, l.x, wire_idx) if len(wire.belPins) > 0 else None, "bel_pins") if len(t.bels) > 0: + for bel_idx in range(len(t.bels)): + bel = t.bels[bel_idx] + bba.l("loc%d_%d_bel%d_wires" % (l.y, l.x, bel_idx), "BelWirePOD") + for pin in bel.wires: + write_loc(pin.wire.rel, "rel_wire_loc") + bba.u32(pin.wire.id, "wire_index") + bba.u32(constids[rg.to_str(pin.pin)], "port") + bba.u32(int(pin.dir), "dir") bba.l("loc%d_%d_bels" % (l.y, l.x), "BelInfoPOD") + for bel_idx in range(len(t.bels)): + bel = t.bels[bel_idx] + bba.s(rg.to_str(bel.name), "name") + bba.u32(constids[rg.to_str(bel.type)], "type") + bba.u32(bel.z, "z") + bba.u32(len(bel.wires), "num_bel_wires") + bba.r("loc%d_%d_bel%d_wires" % (l.y, l.x, bel_idx), "bel_wires") bba.l("tiles", "TileTypePOD") for lt in sorted(rg.tiles, key=lambda l : (l.key().y, l.key().x)): @@ -224,6 +242,21 @@ def main(): args = parser.parse_args() const_id_count = 1 # count ID_NONE + with open(args.constids) as f: + for line in f: + line = line.replace("(", " ") + line = line.replace(")", " ") + line = line.split() + if len(line) == 0: + continue + assert len(line) == 2 + assert line[0] == "X" + idx = len(constids) + 1 + constids[line[1]] = idx + const_id_count += 1 + + constids["SLICE"] = constids["FACADE_SLICE"] + constids["PIO"] = constids["FACADE_IO"] chip = pytrellis.Chip(dev_names[args.device]) rg = pytrellis.make_optimized_chipdb(chip) -- cgit v1.2.3 From 3d287adbcfb4f96a2cff1db06cff0057faf66f53 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 4 Dec 2020 00:55:38 -0500 Subject: machxo2: Add package/IO info to facade_import. --- machxo2/facade_import.py | 101 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) (limited to 'machxo2') diff --git a/machxo2/facade_import.py b/machxo2/facade_import.py index 82c4963d..0f983013 100644 --- a/machxo2/facade_import.py +++ b/machxo2/facade_import.py @@ -2,6 +2,7 @@ import argparse import json import sys +from os import path tiletype_names = dict() @@ -75,6 +76,72 @@ class BinaryBlobAssembler: def pop(self): print("pop") +def get_bel_index(rg, loc, name): + tile = rg.tiles[loc] + idx = 0 + for bel in tile.bels: + if rg.to_str(bel.name) == name: + return idx + idx += 1 + # FIXME: I/O pins can be missing in various rows. Is there a nice way to + # assert on each device size? + return None + + +packages = {} +pindata = [] + +def process_pio_db(rg, device): + piofile = path.join(database.get_db_root(), "MachXO2", dev_names[device], "iodb.json") + with open(piofile, 'r') as f: + piodb = json.load(f) + for pkgname, pkgdata in sorted(piodb["packages"].items()): + pins = [] + for name, pinloc in sorted(pkgdata.items()): + x = pinloc["col"] + y = pinloc["row"] + if x == 0 or x == max_col: + # FIXME: Oversight in read_pinout.py. We use 0-based + # columns for 0 and max row, but we otherwise extract + # the names from the CSV, and... + loc = pytrellis.Location(x, y) + else: + # Lattice uses 1-based columns! + loc = pytrellis.Location(x - 1, y) + pio = "PIO" + pinloc["pio"] + bel_idx = get_bel_index(rg, loc, pio) + if bel_idx is not None: + pins.append((name, loc, bel_idx)) + packages[pkgname] = pins + for metaitem in piodb["pio_metadata"]: + x = metaitem["col"] + y = metaitem["row"] + if x == 0 or x == max_col: + loc = pytrellis.Location(x, y) + else: + loc = pytrellis.Location(x - 1, y) + pio = "PIO" + metaitem["pio"] + bank = metaitem["bank"] + if "function" in metaitem: + pinfunc = metaitem["function"] + else: + pinfunc = None + dqs = -1 + if "dqs" in metaitem: + pass + # tdqs = metaitem["dqs"] + # if tdqs[0] == "L": + # dqs = 0 + # elif tdqs[0] == "R": + # dqs = 2048 + # suffix_size = 0 + # while tdqs[-(suffix_size+1)].isdigit(): + # suffix_size += 1 + # dqs |= int(tdqs[-suffix_size:]) + bel_idx = get_bel_index(rg, loc, pio) + if bel_idx is not None: + pindata.append((loc, bel_idx, bank, pinfunc, dqs)) + def write_database(dev_name, chip, rg, endianness): def write_loc(loc, sym_name): bba.u16(loc.x, "%s.x" % sym_name) @@ -213,6 +280,33 @@ def write_database(dev_name, chip, rg, endianness): bba.u32(len(chip.get_tiles_by_position(y, x)), "num_tiles") bba.r("tile_info_%d_%d" % (x, y), "tile_names") + for package, pkgdata in sorted(packages.items()): + bba.l("package_data_%s" % package, "PackagePinPOD") + for pin in pkgdata: + name, loc, bel_idx = pin + bba.s(name, "name") + write_loc(loc, "abs_loc") + bba.u32(bel_idx, "bel_index") + + bba.l("package_data", "PackageInfoPOD") + for package, pkgdata in sorted(packages.items()): + bba.s(package, "name") + bba.u32(len(pkgdata), "num_pins") + bba.r("package_data_%s" % package, "pin_data") + + bba.l("pio_info", "PIOInfoPOD") + for pin in pindata: + loc, bel_idx, bank, func, dqs = pin + write_loc(loc, "abs_loc") + bba.u32(bel_idx, "bel_index") + if func is not None and func != "WRITEN": + bba.s(func, "function_name") + else: + bba.r(None, "function_name") + # TODO: io_grouping? + bba.u16(bank, "bank") + bba.u16(dqs, "dqsgroup") + bba.l("tiletype_names", "RelPtr") for tt, idx in sorted(tiletype_names.items(), key=lambda x: x[1]): bba.s(tt, "name") @@ -222,12 +316,14 @@ def write_database(dev_name, chip, rg, endianness): bba.u32(max_col + 1, "width") bba.u32(max_row + 1, "height") bba.u32((max_col + 1) * (max_row + 1), "num_tiles") - bba.u32(0, "num_packages") # len(packages) - bba.u32(0, "num_pios") # len(pindata) + bba.u32(len(packages), "num_packages") + bba.u32(len(pindata), "num_pios") bba.u32(const_id_count, "const_id_count") bba.r("tiles", "tiles") bba.r("tiletype_names", "tiletype_names") + bba.r("package_data", "package_info") + bba.r("pio_info", "pio_info") bba.r("tiles_info", "tile_info") bba.pop() @@ -262,6 +358,7 @@ def main(): rg = pytrellis.make_optimized_chipdb(chip) max_row = chip.get_max_row() max_col = chip.get_max_col() + process_pio_db(rg, args.device) bba = write_database(args.device, chip, rg, "le") -- cgit v1.2.3 From c5292e0db50b0aeceefa8f14282d5ddf6b6f6678 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 4 Dec 2020 18:09:30 -0500 Subject: machxo2: Finalize (hopefully) facade_import for prototype. --- machxo2/facade_import.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/facade_import.py b/machxo2/facade_import.py index 0f983013..9be791ff 100644 --- a/machxo2/facade_import.py +++ b/machxo2/facade_import.py @@ -191,7 +191,9 @@ def write_database(dev_name, chip, rg, endianness): bba.u32(arc.sinkWire.id, "dst_idx {}".format(get_wire_name(arc.sinkWire.rel, arc.sinkWire.id))) src_name = get_wire_name(arc.srcWire.rel, arc.srcWire.id) snk_name = get_wire_name(arc.sinkWire.rel, arc.sinkWire.id) + # TODO: ECP5 timing-model-specific. Reuse for MachXO2? # bba.u32(get_pip_class(src_name, snk_name), "timing_class") + bba.u32(0, "timing_class") bba.u16(get_tiletype_index(rg.to_str(arc.tiletype)), "tile_type") cls = arc.cls bba.u8(arc.cls, "pip_type") @@ -221,6 +223,7 @@ def write_database(dev_name, chip, rg, endianness): for wire_idx in range(len(t.wires)): wire = t.wires[wire_idx] bba.s(rg.to_str(wire.name), "name") + # TODO: Padding until GUI support is added. # bba.u32(constids[wire_type(ddrg.to_str(wire.name))], "type") # if ("TILE_WIRE_" + ddrg.to_str(wire.name)) in gfx_wire_ids: # bba.u32(gfx_wire_ids["TILE_WIRE_" + ddrg.to_str(wire.name)], "tile_wire") @@ -303,7 +306,7 @@ def write_database(dev_name, chip, rg, endianness): bba.s(func, "function_name") else: bba.r(None, "function_name") - # TODO: io_grouping? + # TODO: io_grouping? And DQS. bba.u16(bank, "bank") bba.u16(dqs, "dqsgroup") -- cgit v1.2.3 From a3a3a91b72942bf857e8c6ef14a211f06dfe4f2b Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 4 Dec 2020 18:19:31 -0500 Subject: machxo2: Clean up packing pass a bit. --- machxo2/pack.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'machxo2') diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 76fd7240..695d8e95 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -40,7 +40,7 @@ static void pack_lut_lutffs(Context *ctx) 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 packed = - create_machxo2_cell(ctx, ctx->id("FACADE_SLICE"), ci->name.str(ctx) + "_LC"); + create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); packed_cells.insert(ci->name); @@ -49,8 +49,8 @@ static void pack_lut_lutffs(Context *ctx) // See if we can pack into a DFF. Both LUT4 and FF outputs are // available for a given slice, so we can pack a FF even if the // LUT4 drives more than one FF. - NetInfo *o = ci->ports.at(ctx->id("Z")).net; - CellInfo *dff = net_only_drives(ctx, o, is_ff, ctx->id("DI"), false); + NetInfo *o = ci->ports.at(id_Z).net; + CellInfo *dff = net_only_drives(ctx, o, is_ff, id_DI, false); auto lut_bel = ci->attrs.find(ctx->id("BEL")); bool packed_dff = false; @@ -160,7 +160,7 @@ 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 == ctx->id("FACADE_IO"); } +static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cell->type == id_FACADE_IO; } // 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 @@ -189,7 +189,6 @@ static void pack_io(Context *ctx) bool Arch::pack() { Context *ctx = getCtx(); - log_info("Packing implementation goes here.."); try { log_break(); pack_constants(ctx); -- cgit v1.2.3 From 6f6aaa4a97b32196d41f3c26f5281ac5bd2994c5 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 4 Dec 2020 21:52:31 -0500 Subject: machxo2: Add binary blob struct definitions. --- machxo2/arch.h | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++- machxo2/archdefs.h | 2 ++ 2 files changed, 101 insertions(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/arch.h b/machxo2/arch.h index 063eb164..ec7939f4 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -43,9 +43,107 @@ template struct RelPtr const T *operator->() const { return get(); } }; +// FIXME: All "rel locs" are actually absolute, naming typo in facade_import. +// Does not affect runtime functionality. + +NPNR_PACKED_STRUCT(struct BelWirePOD { + LocationPOD rel_wire_loc; + uint32_t wire_index; + uint32_t port; + uint32_t dir; +}); + +NPNR_PACKED_STRUCT(struct BelInfoPOD { + RelPtr name; + uint32_t type; + uint32_t z; + uint32_t num_bel_wires; + RelPtr bel_wires; +}); + +NPNR_PACKED_STRUCT(struct PipLocatorPOD { + LocationPOD rel_loc; + uint32_t index; +}); + +NPNR_PACKED_STRUCT(struct BelPortPOD { + LocationPOD rel_bel_loc; + uint32_t bel_index; + uint32_t port; +}); + +NPNR_PACKED_STRUCT(struct PipInfoPOD { + LocationPOD src; + LocationPOD dst; + uint32_t src_idx; + uint32_t dst_idx; + uint32_t timing_class; + uint16_t tile_type; + uint8_t pip_type; + uint8_t padding; +}); + +NPNR_PACKED_STRUCT(struct WireInfoPOD { + RelPtr name; + uint32_t tile_wire; + uint32_t num_uphill; + uint32_t num_downhill; + RelPtr pips_uphill; + RelPtr pips_downhill; + uint32_t num_bel_pins; + RelPtr bel_pins; +}); + +NPNR_PACKED_STRUCT(struct TileTypePOD { + uint32_t num_bels; + uint32_t num_wires; + uint32_t num_pips; + RelPtr bel_data; + RelPtr wire_data; + RelPtr pips_data; +}); + +NPNR_PACKED_STRUCT(struct PackagePinPOD { + RelPtr name; + LocationPOD abs_loc; + int32_t bel_index; +}); + +NPNR_PACKED_STRUCT(struct PackageInfoPOD { + RelPtr name; + int32_t num_pins; + RelPtr pin_data; +}); + +NPNR_PACKED_STRUCT(struct PIOInfoPOD { + LocationPOD abs_loc; + int32_t bel_index; + RelPtr function_name; + int16_t bank; + int16_t dqsgroup; +}); + +NPNR_PACKED_STRUCT(struct TileNamePOD { + RelPtr name; + int16_t type_idx; + int16_t padding; +}); + +NPNR_PACKED_STRUCT(struct TileInfoPOD { + int32_t num_tiles; + RelPtr tile_names; +}); NPNR_PACKED_STRUCT(struct ChipInfoPOD { - int32_t stub; + int32_t width, height; + int32_t num_tiles; + int32_t num_packages, num_pios; + int32_t const_id_count; + RelPtr locations; + RelPtr> tiletype_names; + RelPtr package_info; + RelPtr pio_info; + RelPtr tile_info; }); /************************ End of chipdb section. ************************/ diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h index 6c861a32..56b546da 100644 --- a/machxo2/archdefs.h +++ b/machxo2/archdefs.h @@ -60,6 +60,8 @@ enum ConstIds #include "constids.inc" #undef X +NPNR_PACKED_STRUCT(struct LocationPOD { int16_t x, y; }); + typedef IdString BelId; typedef IdString WireId; typedef IdString PipId; -- cgit v1.2.3 From ec4a9685abf0fd7d7b2cfecc5dbfc09b963b6ea8 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 5 Dec 2020 00:38:00 -0500 Subject: machxo2: Initialize Arch context with device type and package. --- machxo2/arch.cc | 49 ++++++++++++++++++++++++++++++++++++------- machxo2/arch.h | 5 +++-- machxo2/examples/mitertest.sh | 2 +- machxo2/examples/simple.sh | 2 +- machxo2/examples/simtest.sh | 2 +- machxo2/main.cc | 18 +++++++++++++++- 6 files changed, 64 insertions(+), 14 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 5d1cb0cb..0a3f345f 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -29,14 +29,6 @@ NEXTPNR_NAMESPACE_BEGIN -// --------------------------------------------------------------- - -Arch::Arch(ArchArgs args) : chipName("generic"), args(args) -{ - // Dummy for empty decals - // decal_graphics[IdString()]; -} - // ----------------------------------------------------------------------- void IdString::initialize_arch(const BaseCtx *ctx) { @@ -74,8 +66,49 @@ static const ChipInfoPOD *get_chip_info(ArchArgs::ArchArgsTypes chip) return ptr->get(); } +// --------------------------------------------------------------- + +Arch::Arch(ArchArgs args) : args(args) +{ + chip_info = get_chip_info(args.type); + if (chip_info == nullptr) + log_error("Unsupported MachXO2 chip type.\n"); + if (chip_info->const_id_count != DB_CONST_ID_COUNT) + log_error("Chip database 'bba' and nextpnr code are out of sync; please rebuild (or contact distribution " + "maintainer)!\n"); + + package_info = nullptr; + for (int i = 0; i < chip_info->num_packages; i++) { + if (args.package == chip_info->package_info[i].name.get()) { + package_info = &(chip_info->package_info[i]); + break; + } + } + if (!package_info) + log_error("Unsupported package '%s' for '%s'.\n", args.package.c_str(), getChipName().c_str()); +} + bool Arch::isAvailable(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip) != nullptr; } +std::string Arch::getChipName() const +{ + if (args.type == ArchArgs::LCMXO2_256HC) { + return "LCMXO2-256HC"; + } else if (args.type == ArchArgs::LCMXO2_640HC) { + return "LCMXO2-640HC"; + } else if (args.type == ArchArgs::LCMXO2_1200HC) { + return "LCMXO2-1200HC"; + } else if (args.type == ArchArgs::LCMXO2_2000HC) { + return "LCMXO2-2000HC"; + } else if (args.type == ArchArgs::LCMXO2_4000HC) { + return "LCMXO2-4000HC"; + } else if (args.type == ArchArgs::LCMXO2_7000HC) { + return "LCMXO2-7000HC"; + } else { + log_error("Unknown chip\n"); + } +} + // --------------------------------------------------------------- BelId Arch::getBelByName(IdString name) const diff --git a/machxo2/arch.h b/machxo2/arch.h index ec7939f4..762412e2 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -255,7 +255,8 @@ struct CellTiming struct Arch : BaseCtx { - std::string chipName; + const ChipInfoPOD *chip_info; + const PackageInfoPOD *package_info; // Placeholders to be removed. std::unordered_map bel_by_loc; @@ -275,7 +276,7 @@ struct Arch : BaseCtx static bool isAvailable(ArchArgs::ArchArgsTypes chip); - std::string getChipName() const { return chipName; } + std::string getChipName() const; IdString archId() const { return id("machxo2"); } ArchArgs archArgs() const { return args; } diff --git a/machxo2/examples/mitertest.sh b/machxo2/examples/mitertest.sh index aea5bfff..5190af31 100644 --- a/machxo2/examples/mitertest.sh +++ b/machxo2/examples/mitertest.sh @@ -68,7 +68,7 @@ set -ex ${YOSYS:-yosys} -p "read_verilog blinky.v synth_machxo2 -noiopad -json blinky.json show -format png -prefix blinky" -${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --no-iobs --json blinky.json --write ${1}blinky.json +${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json blinky.json --write ${1}blinky.json ${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v read_json ${1}blinky.json clean -purge diff --git a/machxo2/examples/simple.sh b/machxo2/examples/simple.sh index 91fa4b91..c977bf1a 100644 --- a/machxo2/examples/simple.sh +++ b/machxo2/examples/simple.sh @@ -26,7 +26,7 @@ set -ex ${YOSYS:-yosys} -p "read_verilog blinky.v synth_machxo2 -json blinky.json show -format png -prefix blinky" -${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --no-iobs --json blinky.json --write ${1}blinky.json +${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json blinky.json --write ${1}blinky.json ${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v read_json ${1}blinky.json clean -purge diff --git a/machxo2/examples/simtest.sh b/machxo2/examples/simtest.sh index ff35bbd6..53f2e728 100644 --- a/machxo2/examples/simtest.sh +++ b/machxo2/examples/simtest.sh @@ -26,7 +26,7 @@ set -ex ${YOSYS:-yosys} -p "read_verilog blinky.v synth_machxo2 -json blinky.json show -format png -prefix blinky" -${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --no-iobs --json blinky.json --write ${1}blinky.json +${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json blinky.json --write ${1}blinky.json ${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v read_json ${1}blinky.json clean -purge diff --git a/machxo2/main.cc b/machxo2/main.cc index 92a60d38..5a5c7f82 100644 --- a/machxo2/main.cc +++ b/machxo2/main.cc @@ -58,7 +58,7 @@ po::options_description MachXO2CommandHandler::getArchOptions() if (Arch::isAvailable(ArchArgs::LCMXO2_7000HC)) specific.add_options()("7000", "set device type to LCMXO2-7000HC"); - specific.add_options()("package", po::value(), "select device package (defaults to QFN32)"); + specific.add_options()("package", po::value(), "select device package"); specific.add_options()("speed", po::value(), "select device speedgrade (1 to 6 inclusive)"); specific.add_options()("override-basecfg", po::value(), @@ -76,6 +76,22 @@ void MachXO2CommandHandler::customBitstream(Context *ctx) {} std::unique_ptr MachXO2CommandHandler::createContext(std::unordered_map &values) { ArchArgs chipArgs; + chipArgs.type = ArchArgs::NONE; + if (vm.count("256")) + chipArgs.type = ArchArgs::LCMXO2_256HC; + if (vm.count("640")) + chipArgs.type = ArchArgs::LCMXO2_640HC; + if (vm.count("1200")) + chipArgs.type = ArchArgs::LCMXO2_1200HC; + if (vm.count("2000")) + chipArgs.type = ArchArgs::LCMXO2_2000HC; + if (vm.count("4000")) + chipArgs.type = ArchArgs::LCMXO2_4000HC; + if (vm.count("7000")) + chipArgs.type = ArchArgs::LCMXO2_7000HC; + if (vm.count("package")) + chipArgs.package = vm["package"].as(); + if (values.find("arch.name") != values.end()) { std::string arch_name = values["arch.name"].as_string(); if (arch_name != "machxo2") -- cgit v1.2.3 From dc07054ee8c28b9c553be4a61562c5b294de0c06 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 5 Dec 2020 22:01:28 -0500 Subject: machxo2: Implement functions to get device utilization (throws std::out_of_range during place phase). --- machxo2/arch.cc | 6 +--- machxo2/arch.h | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- machxo2/archdefs.h | 52 ++++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 9 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 0a3f345f..431fcc88 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -116,7 +116,7 @@ BelId Arch::getBelByName(IdString name) const return BelId(); } -IdString Arch::getBelName(BelId bel) const { return bel; } +IdString Arch::getBelName(BelId bel) const { return IdString(); } Loc Arch::getBelLocation(BelId bel) const { @@ -154,10 +154,6 @@ CellInfo *Arch::getBoundBelCell(BelId bel) const { return nullptr; } CellInfo *Arch::getConflictingBelCell(BelId bel) const { return nullptr; } -const std::vector &Arch::getBels() const { return bel_id_dummy; } - -IdString Arch::getBelType(BelId bel) const { return IdString(); } - const std::map &Arch::getBelAttrs(BelId bel) const { return attrs_dummy; } WireId Arch::getBelPinWire(BelId bel, IdString pin) const diff --git a/machxo2/arch.h b/machxo2/arch.h index 762412e2..1d62a84e 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -139,7 +139,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { int32_t num_tiles; int32_t num_packages, num_pios; int32_t const_id_count; - RelPtr locations; + RelPtr tiles; RelPtr> tiletype_names; RelPtr package_info; RelPtr pio_info; @@ -148,6 +148,59 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { /************************ End of chipdb section. ************************/ +// Iterators +struct BelIterator +{ + const ChipInfoPOD *chip; + int cursor_index; + int cursor_tile; + + BelIterator operator++() + { + cursor_index++; + while (cursor_tile < chip->num_tiles && + cursor_index >= chip->tiles[cursor_tile].num_bels) { + cursor_index = 0; + cursor_tile++; + } + return *this; + } + BelIterator operator++(int) + { + BelIterator prior(*this); + ++(*this); + return prior; + } + + bool operator!=(const BelIterator &other) const + { + return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; + } + + bool operator==(const BelIterator &other) const + { + return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; + } + + BelId operator*() const + { + BelId ret; + ret.location.x = cursor_tile % chip->width; + ret.location.y = cursor_tile / chip->width; + ret.index = cursor_index; + return ret; + } +}; + +struct BelRange +{ + BelIterator b, e; + BelIterator begin() const { return b; } + BelIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + struct ArchArgs { enum ArchArgsTypes @@ -268,6 +321,12 @@ struct Arch : BaseCtx std::vector graphic_element_dummy; std::map attrs_dummy; + // Helpers + template const TileTypePOD *tileInfo(Id &id) const + { + return &(chip_info->tiles[id.location.y * chip_info->width + id.location.x]); + } + // --------------------------------------------------------------- // Common Arch API. Every arch must provide the following methods. @@ -299,8 +358,28 @@ struct Arch : BaseCtx bool checkBelAvail(BelId bel) const; CellInfo *getBoundBelCell(BelId bel) const; CellInfo *getConflictingBelCell(BelId bel) const; - const std::vector &getBels() const; - IdString getBelType(BelId bel) const; + + BelRange getBels() const + { + BelRange range; + range.b.cursor_tile = 0; + range.b.cursor_index = -1; + range.b.chip = chip_info; + ++range.b; //-1 and then ++ deals with the case of no Bels in the first tile + range.e.cursor_tile = chip_info->width * chip_info->height; + range.e.cursor_index = 0; + range.e.chip = chip_info; + return range; + } + + IdString getBelType(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + IdString id; + id.index = tileInfo(bel)->bel_data[bel.index].type; + return id; + } + const std::map &getBelAttrs(BelId bel) const; WireId getBelPinWire(BelId bel, IdString pin) const; PortType getBelPinType(BelId bel, IdString pin) const; diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h index 56b546da..d33a3a3d 100644 --- a/machxo2/archdefs.h +++ b/machxo2/archdefs.h @@ -62,7 +62,34 @@ enum ConstIds NPNR_PACKED_STRUCT(struct LocationPOD { int16_t x, y; }); -typedef IdString BelId; +struct Location +{ + int16_t x = -1, y = -1; + Location() : x(-1), y(-1){}; + Location(int16_t x, int16_t y) : x(x), y(y){}; + Location(const LocationPOD &pod) : x(pod.x), y(pod.y){}; + Location(const Location &loc) : x(loc.x), y(loc.y){}; + + bool operator==(const Location &other) const { return x == other.x && y == other.y; } + bool operator!=(const Location &other) const { return x != other.x || y != other.y; } + bool operator<(const Location &other) const { return y == other.y ? x < other.x : y < other.y; } +}; + +inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } + +struct BelId +{ + Location location; + int32_t index = -1; + + bool operator==(const BelId &other) const { return index == other.index && location == other.location; } + bool operator!=(const BelId &other) const { return index != other.index || location != other.location; } + bool operator<(const BelId &other) const + { + return location == other.location ? index < other.index : location < other.location; + } +}; + typedef IdString WireId; typedef IdString PipId; typedef IdString GroupId; @@ -86,3 +113,26 @@ struct ArchCellInfo }; NEXTPNR_NAMESPACE_END + +namespace std { +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Location &loc) const noexcept + { + std::size_t seed = std::hash()(loc.x); + seed ^= std::hash()(loc.y) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept + { + std::size_t seed = std::hash()(bel.location); + seed ^= std::hash()(bel.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + +} -- cgit v1.2.3 From 52b424c385a488c48ff91ba8ba52913f1b10995f Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 6 Dec 2020 01:23:07 -0500 Subject: machxo2: Convert uint_t to int_t in packed structs. --- machxo2/arch.h | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.h b/machxo2/arch.h index 1d62a84e..1cf24892 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -48,56 +48,56 @@ template struct RelPtr NPNR_PACKED_STRUCT(struct BelWirePOD { LocationPOD rel_wire_loc; - uint32_t wire_index; - uint32_t port; - uint32_t dir; + int32_t wire_index; + int32_t port; + int32_t dir; }); NPNR_PACKED_STRUCT(struct BelInfoPOD { RelPtr name; - uint32_t type; - uint32_t z; - uint32_t num_bel_wires; + int32_t type; + int32_t z; + int32_t num_bel_wires; RelPtr bel_wires; }); NPNR_PACKED_STRUCT(struct PipLocatorPOD { LocationPOD rel_loc; - uint32_t index; + int32_t index; }); NPNR_PACKED_STRUCT(struct BelPortPOD { LocationPOD rel_bel_loc; - uint32_t bel_index; - uint32_t port; + int32_t bel_index; + int32_t port; }); NPNR_PACKED_STRUCT(struct PipInfoPOD { LocationPOD src; LocationPOD dst; - uint32_t src_idx; - uint32_t dst_idx; - uint32_t timing_class; - uint16_t tile_type; - uint8_t pip_type; - uint8_t padding; + int32_t src_idx; + int32_t dst_idx; + int32_t timing_class; + int16_t tile_type; + int8_t pip_type; + int8_t padding; }); NPNR_PACKED_STRUCT(struct WireInfoPOD { RelPtr name; - uint32_t tile_wire; - uint32_t num_uphill; - uint32_t num_downhill; + int32_t tile_wire; + int32_t num_uphill; + int32_t num_downhill; RelPtr pips_uphill; RelPtr pips_downhill; - uint32_t num_bel_pins; + int32_t num_bel_pins; RelPtr bel_pins; }); NPNR_PACKED_STRUCT(struct TileTypePOD { - uint32_t num_bels; - uint32_t num_wires; - uint32_t num_pips; + int32_t num_bels; + int32_t num_wires; + int32_t num_pips; RelPtr bel_data; RelPtr wire_data; RelPtr pips_data; -- cgit v1.2.3 From 094233a4ab49245d8fbdbae83f3241ff3c6585b0 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 6 Dec 2020 21:50:04 -0500 Subject: machxo2: Implement getBelLocation to stop std::out_of_range in place phase. --- machxo2/arch.cc | 5 ----- machxo2/arch.h | 11 ++++++++++- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 431fcc88..dccbcb87 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -118,11 +118,6 @@ BelId Arch::getBelByName(IdString name) const IdString Arch::getBelName(BelId bel) const { return IdString(); } -Loc Arch::getBelLocation(BelId bel) const -{ - return Loc(); -} - BelId Arch::getBelByLocation(Loc loc) const { return BelId(); diff --git a/machxo2/arch.h b/machxo2/arch.h index 1cf24892..527c6572 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -348,7 +348,16 @@ struct Arch : BaseCtx BelId getBelByName(IdString name) const; IdString getBelName(BelId bel) const; - Loc getBelLocation(BelId bel) const; + Loc getBelLocation(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + Loc loc; + loc.x = bel.location.x; + loc.y = bel.location.y; + loc.z = tileInfo(bel)->bel_data[bel.index].z; + return loc; + } + BelId getBelByLocation(Loc loc) const; const std::vector &getBelsByTile(int x, int y) const; bool getBelGlobalBuf(BelId bel) const; -- cgit v1.2.3 From 3e6be4bbfd3be2bb57075d8b76ba239ff6a0ee54 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 6 Dec 2020 22:06:24 -0500 Subject: machxo2: Implement General Methods. --- machxo2/arch.cc | 19 +++++++++++++++++++ machxo2/arch.h | 14 +++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index dccbcb87..821fb7e7 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -109,6 +109,25 @@ std::string Arch::getChipName() const } } +IdString Arch::archArgsToId(ArchArgs args) const +{ + if (args.type == ArchArgs::LCMXO2_256HC) { + return id("lcmxo2_256hc"); + } else if (args.type == ArchArgs::LCMXO2_640HC) { + return id("lcmxo2_640hc"); + } else if (args.type == ArchArgs::LCMXO2_1200HC) { + return id("lcmxo2_1200hc"); + } else if (args.type == ArchArgs::LCMXO2_2000HC) { + return id("lcmxo2_2000hc"); + } else if (args.type == ArchArgs::LCMXO2_4000HC) { + return id("lcmxo2_4000hc"); + } else if (args.type == ArchArgs::LCMXO2_7000HC) { + return id("lcmxo2_7000hc"); + } + + return IdString(); +} + // --------------------------------------------------------------- BelId Arch::getBelByName(IdString name) const diff --git a/machxo2/arch.h b/machxo2/arch.h index 527c6572..c6aae931 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -339,12 +339,16 @@ struct Arch : BaseCtx IdString archId() const { return id("machxo2"); } ArchArgs archArgs() const { return args; } - IdString archArgsToId(ArchArgs args) const { return id("none"); } + IdString archArgsToId(ArchArgs args) const; - int getGridDimX() const { return 0; } - int getGridDimY() const { return 0; } - int getTileBelDimZ(int x, int y) const { return 0; } - int getTilePipDimZ(int x, int y) const { return 0; } + static const int max_loc_bels = 20; + + int getGridDimX() const { return chip_info->width; } + int getGridDimY() const { return chip_info->height; } + int getTileBelDimZ(int x, int y) const { return max_loc_bels; } + // TODO: Make more precise? The CENTER MUX having config bits across + // tiles can complicate this? + int getTilePipDimZ(int x, int y) const { return 2; } BelId getBelByName(IdString name) const; IdString getBelName(BelId bel) const; -- cgit v1.2.3 From 682de724a8f84ee5106a1fd8ad68888605eafa89 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 6 Dec 2020 22:35:25 -0500 Subject: machxo2: Implement 2 Bel API functions. --- machxo2/arch.cc | 19 +++++++++++++++++-- machxo2/arch.h | 9 ++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 821fb7e7..8c8dda5e 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -135,10 +135,25 @@ BelId Arch::getBelByName(IdString name) const return BelId(); } -IdString Arch::getBelName(BelId bel) const { return IdString(); } - BelId Arch::getBelByLocation(Loc loc) const { + BelId ret; + + if(loc.x >= chip_info->width || loc.y >= chip_info->height) + return BelId(); + + ret.location.x = loc.x; + ret.location.y = loc.y; + + const TileTypePOD *tilei = tileInfo(ret); + for(int i = 0; i < tilei->num_bels; i++) { + if(tilei->bel_data[i].z == loc.z) + { + ret.index = i; + return ret; + } + } + return BelId(); } diff --git a/machxo2/arch.h b/machxo2/arch.h index c6aae931..1c848388 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -351,7 +351,14 @@ struct Arch : BaseCtx int getTilePipDimZ(int x, int y) const { return 2; } BelId getBelByName(IdString name) const; - IdString getBelName(BelId bel) const; + IdString getBelName(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + std::stringstream name; + name << "X" << bel.location.x << "/Y" << bel.location.y << "/" << tileInfo(bel)->bel_data[bel.index].name.get(); + return id(name.str()); + } + Loc getBelLocation(BelId bel) const { NPNR_ASSERT(bel != BelId()); -- cgit v1.2.3 From 5f748272fc118f5fdf8b5389188434c6070ca917 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 6 Dec 2020 22:50:15 -0500 Subject: machxo2: Implement bel_to_cell and API functions using it. --- machxo2/arch.cc | 16 ---------------- machxo2/arch.h | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 21 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 8c8dda5e..42d93f16 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -167,22 +167,6 @@ uint32_t Arch::getBelChecksum(BelId bel) const return 0; } -void Arch::bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) -{ - -} - -void Arch::unbindBel(BelId bel) -{ - -} - -bool Arch::checkBelAvail(BelId bel) const { return false; } - -CellInfo *Arch::getBoundBelCell(BelId bel) const { return nullptr; } - -CellInfo *Arch::getConflictingBelCell(BelId bel) const { return nullptr; } - const std::map &Arch::getBelAttrs(BelId bel) const { return attrs_dummy; } WireId Arch::getBelPinWire(BelId bel, IdString pin) const diff --git a/machxo2/arch.h b/machxo2/arch.h index 1c848388..b5d6c522 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -311,6 +311,8 @@ struct Arch : BaseCtx const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; + std::vector bel_to_cell; + // Placeholders to be removed. std::unordered_map bel_by_loc; std::vector bel_id_dummy; @@ -327,6 +329,11 @@ struct Arch : BaseCtx return &(chip_info->tiles[id.location.y * chip_info->width + id.location.x]); } + int getBelFlatIndex(BelId bel) const + { + return (bel.location.y * chip_info->width + bel.location.x) * max_loc_bels + bel.index; + } + // --------------------------------------------------------------- // Common Arch API. Every arch must provide the following methods. @@ -373,11 +380,46 @@ struct Arch : BaseCtx const std::vector &getBelsByTile(int x, int y) const; bool getBelGlobalBuf(BelId bel) const; uint32_t getBelChecksum(BelId bel) const; - void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength); - void unbindBel(BelId bel); - bool checkBelAvail(BelId bel) const; - CellInfo *getBoundBelCell(BelId bel) const; - CellInfo *getConflictingBelCell(BelId bel) const; + + void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) + { + NPNR_ASSERT(bel != BelId()); + int idx = getBelFlatIndex(bel); + NPNR_ASSERT(bel_to_cell.at(idx) == nullptr); + bel_to_cell[idx] = cell; + cell->bel = bel; + cell->belStrength = strength; + refreshUiBel(bel); + } + + void unbindBel(BelId bel) + { + NPNR_ASSERT(bel != BelId()); + int idx = getBelFlatIndex(bel); + NPNR_ASSERT(bel_to_cell.at(idx) != nullptr); + bel_to_cell[idx]->bel = BelId(); + bel_to_cell[idx]->belStrength = STRENGTH_NONE; + bel_to_cell[idx] = nullptr; + refreshUiBel(bel); + } + + bool checkBelAvail(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[getBelFlatIndex(bel)] == nullptr; + } + + CellInfo *getBoundBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[getBelFlatIndex(bel)]; + } + + CellInfo *getConflictingBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[getBelFlatIndex(bel)]; + } BelRange getBels() const { -- cgit v1.2.3 From 8a94a3451f88ca6632991ef3f2a61e4ed9a4ac5b Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 7 Dec 2020 02:15:29 -0500 Subject: machxo2: Stub valid BEL functions with comment. Place phase segfaults. --- machxo2/arch.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 42d93f16..d9753528 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -382,12 +382,17 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { - return false; + // FIXME: Unlike ECP5, SLICEs in a given tile do not share a clock, so + // any SLICE Cell is valid for any BEL, even if some cells are already + // bound to BELs in the tile. However, this may need to be filled in once + // more than one LUT4 and DFF type is supported. + return true; } bool Arch::isBelLocationValid(BelId bel) const { - return false; + // FIXME: Same deal as isValidBelForCell. + return true; } #ifdef WITH_HEAP -- cgit v1.2.3 From 138519d820cd25cdd6700fabf13e855d67030e1a Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 7 Dec 2020 02:15:51 -0500 Subject: machxo2: Fix place phase segfault. Placement suceeds with warning of no clock. --- machxo2/arch.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index d9753528..6c7efbe5 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -86,6 +86,8 @@ Arch::Arch(ArchArgs args) : args(args) } if (!package_info) log_error("Unsupported package '%s' for '%s'.\n", args.package.c_str(), getChipName().c_str()); + + bel_to_cell.resize(chip_info->height * chip_info->width * max_loc_bels, nullptr); } bool Arch::isAvailable(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip) != nullptr; } -- cgit v1.2.3 From bbc683dd75fcf54b8f215704a932c5c2f1a39c93 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 7 Dec 2020 11:48:15 -0500 Subject: machxo2: Implement all of Bel API except getBelPinWire. --- machxo2/arch.cc | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++------- machxo2/arch.h | 12 ++++++--- 2 files changed, 79 insertions(+), 12 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 6c7efbe5..a01f96e6 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -29,6 +29,18 @@ NEXTPNR_NAMESPACE_BEGIN +static std::tuple split_identifier_name(const std::string &name) +{ + size_t first_slash = name.find('/'); + NPNR_ASSERT(first_slash != std::string::npos); + size_t second_slash = name.find('/', first_slash + 1); + NPNR_ASSERT(second_slash != std::string::npos); + return std::make_tuple(std::stoi(name.substr(1, first_slash)), + std::stoi(name.substr(first_slash + 2, second_slash - first_slash)), + name.substr(second_slash + 1)); +}; + + // ----------------------------------------------------------------------- void IdString::initialize_arch(const BaseCtx *ctx) { @@ -134,7 +146,25 @@ IdString Arch::archArgsToId(ArchArgs args) const BelId Arch::getBelByName(IdString name) const { - return BelId(); + BelId ret; + auto it = bel_by_name.find(name); + if (it != bel_by_name.end()) + return it->second; + + Location loc; + std::string basename; + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + ret.location = loc; + const TileTypePOD *tilei = tileInfo(ret); + for (int i = 0; i < tilei->num_bels; i++) { + if (std::strcmp(tilei->bel_data[i].name.get(), basename.c_str()) == 0) { + ret.index = i; + break; + } + } + if (ret.index >= 0) + bel_by_name[name] = ret; + return ret; } BelId Arch::getBelByLocation(Loc loc) const @@ -159,16 +189,25 @@ BelId Arch::getBelByLocation(Loc loc) const return BelId(); } -const std::vector &Arch::getBelsByTile(int x, int y) const { return bel_id_dummy; } - -bool Arch::getBelGlobalBuf(BelId bel) const { return false; } - -uint32_t Arch::getBelChecksum(BelId bel) const +BelRange Arch::getBelsByTile(int x, int y) const { - // FIXME - return 0; + BelRange br; + + br.b.cursor_tile = y * chip_info->width + x; + br.e.cursor_tile = y * chip_info->width + x; + br.b.cursor_index = 0; + br.e.cursor_index = chip_info->tiles[y * chip_info->width + x].num_bels - 1; + br.b.chip = chip_info; + br.e.chip = chip_info; + if (br.e.cursor_index == -1) + ++br.e.cursor_index; + else + ++br.e; + return br; } +bool Arch::getBelGlobalBuf(BelId bel) const { return false; } + const std::map &Arch::getBelAttrs(BelId bel) const { return attrs_dummy; } WireId Arch::getBelPinWire(BelId bel, IdString pin) const @@ -176,11 +215,33 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const return WireId(); } -PortType Arch::getBelPinType(BelId bel, IdString pin) const { return PortType(); } +PortType Arch::getBelPinType(BelId bel, IdString pin) const +{ + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = tileInfo(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = &*tileInfo(bel)->bel_data[bel.index].bel_wires; + + for(int i = 0; i < num_bel_wires; i++) + if(bel_wires[i].port == pin.index) + return PortType(bel_wires[i].dir); + + return PORT_INOUT; +} std::vector Arch::getBelPins(BelId bel) const { std::vector ret; + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = tileInfo(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = &*tileInfo(bel)->bel_data[bel.index].bel_wires; + + for(int i = 0; i < num_bel_wires; i++) { + IdString id(bel_wires[i].port); + ret.push_back(id); + } + return ret; } diff --git a/machxo2/arch.h b/machxo2/arch.h index b5d6c522..b68a83ef 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -50,7 +50,7 @@ NPNR_PACKED_STRUCT(struct BelWirePOD { LocationPOD rel_wire_loc; int32_t wire_index; int32_t port; - int32_t dir; + int32_t dir; // FIXME: Corresponds to "type" in ECP5. }); NPNR_PACKED_STRUCT(struct BelInfoPOD { @@ -312,6 +312,7 @@ struct Arch : BaseCtx const PackageInfoPOD *package_info; std::vector bel_to_cell; + mutable std::unordered_map bel_by_name; // Placeholders to be removed. std::unordered_map bel_by_loc; @@ -377,9 +378,14 @@ struct Arch : BaseCtx } BelId getBelByLocation(Loc loc) const; - const std::vector &getBelsByTile(int x, int y) const; + BelRange getBelsByTile(int x, int y) const; bool getBelGlobalBuf(BelId bel) const; - uint32_t getBelChecksum(BelId bel) const; + + uint32_t getBelChecksum(BelId bel) const + { + // FIXME- Copied from ECP5. Should be return val from getBelFlatIndex? + return bel.index; + } void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) { -- cgit v1.2.3 From a7917c9c63efe654a24a4136a91fa4558ee2c625 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 7 Dec 2020 17:41:34 -0500 Subject: machxo2: Implement WireId/PipId, complete Bel part of API. --- machxo2/arch.cc | 16 ++++++++++++++++ machxo2/arch.h | 10 ++++++++++ machxo2/archdefs.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 2 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index a01f96e6..ee334ed4 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -212,6 +212,22 @@ const std::map &Arch::getBelAttrs(BelId bel) const { retu WireId Arch::getBelPinWire(BelId bel, IdString pin) const { + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = tileInfo(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = &*tileInfo(bel)->bel_data[bel.index].bel_wires; + + for(int i = 0; i < num_bel_wires; i++) + if(bel_wires[i].port == pin.index) { + WireId ret; + + ret.location.x = bel_wires[i].rel_wire_loc.x; + ret.location.y = bel_wires[i].rel_wire_loc.y; + ret.index = bel_wires[i].wire_index; + + return ret; + } + return WireId(); } diff --git a/machxo2/arch.h b/machxo2/arch.h index b68a83ef..833866f7 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -338,6 +338,7 @@ struct Arch : BaseCtx // --------------------------------------------------------------- // Common Arch API. Every arch must provide the following methods. + // General ArchArgs args; Arch(ArchArgs args); @@ -358,6 +359,7 @@ struct Arch : BaseCtx // tiles can complicate this? int getTilePipDimZ(int x, int y) const { return 2; } + // Bels BelId getBelByName(IdString name) const; IdString getBelName(BelId bel) const { @@ -453,6 +455,7 @@ struct Arch : BaseCtx PortType getBelPinType(BelId bel, IdString pin) const; std::vector getBelPins(BelId bel) const; + // Wires WireId getWireByName(IdString name) const; IdString getWireName(WireId wire) const; IdString getWireType(WireId wire) const; @@ -468,6 +471,7 @@ struct Arch : BaseCtx const std::vector &getWires() const; const std::vector &getWireBelPins(WireId wire) const; + // Pips PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; IdString getPipType(PipId pip) const; @@ -488,6 +492,7 @@ struct Arch : BaseCtx const std::vector &getPipsUphill(WireId wire) const; const std::vector &getWireAliases(WireId wire) const; + // Group GroupId getGroupByName(IdString name) const; IdString getGroupName(GroupId group) const; std::vector getGroups() const; @@ -496,6 +501,7 @@ struct Arch : BaseCtx const std::vector &getGroupPips(GroupId group) const; const std::vector &getGroupGroups(GroupId group) const; + // Delay delay_t estimateDelay(WireId src, WireId dst) const; delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const; delay_t getDelayEpsilon() const { return 0.001; } @@ -514,22 +520,26 @@ struct Arch : BaseCtx ArcBounds getRouteBoundingBox(WireId src, WireId dst) const; + // Flow bool pack(); bool place(); bool route(); + // Graphics const std::vector &getDecalGraphics(DecalId decal) const; DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; DecalXY getPipDecal(PipId pip) const; DecalXY getGroupDecal(GroupId group) const; + // Cell Delay bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; // Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const; // Get the TimingClockingInfo of a port TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const; + // Placer bool isValidBelForCell(CellInfo *cell, BelId bel) const; bool isBelLocationValid(BelId bel) const; diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h index d33a3a3d..5852d24b 100644 --- a/machxo2/archdefs.h +++ b/machxo2/archdefs.h @@ -90,8 +90,32 @@ struct BelId } }; -typedef IdString WireId; -typedef IdString PipId; +struct WireId +{ + Location location; + int32_t index = -1; + + bool operator==(const WireId &other) const { return index == other.index && location == other.location; } + bool operator!=(const WireId &other) const { return index != other.index || location != other.location; } + bool operator<(const WireId &other) const + { + return location == other.location ? index < other.index : location < other.location; + } +}; + +struct PipId +{ + Location location; + int32_t index = -1; + + bool operator==(const PipId &other) const { return index == other.index && location == other.location; } + bool operator!=(const PipId &other) const { return index != other.index || location != other.location; } + bool operator<(const PipId &other) const + { + return location == other.location ? index < other.index : location < other.location; + } +}; + typedef IdString GroupId; typedef IdString DecalId; @@ -135,4 +159,24 @@ template <> struct hash } }; +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept + { + std::size_t seed = std::hash()(wire.location); + seed ^= std::hash()(wire.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept + { + std::size_t seed = std::hash()(pip.location); + seed ^= std::hash()(pip.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + } -- cgit v1.2.3 From 91ad06424931a80c092d89b0fbc524f706deaa61 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 7 Dec 2020 18:13:54 -0500 Subject: machxo2: Import remaining iterators from ECP5. --- machxo2/arch.h | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) (limited to 'machxo2') diff --git a/machxo2/arch.h b/machxo2/arch.h index 833866f7..553c8d3d 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -149,6 +149,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { /************************ End of chipdb section. ************************/ // Iterators +// Iterate over Bels across tiles. struct BelIterator { const ChipInfoPOD *chip; @@ -199,6 +200,159 @@ struct BelRange BelIterator end() const { return e; } }; +// Iterate over Downstream/Upstream Bels for a Wire. +struct BelPinIterator +{ + const BelPortPOD *ptr = nullptr; + Location wire_loc; + void operator++() { ptr++; } + bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; } + + BelPin operator*() const + { + BelPin ret; + ret.bel.index = ptr->bel_index; + ret.bel.location = wire_loc + ptr->rel_bel_loc; + ret.pin.index = ptr->port; + return ret; + } +}; + +struct BelPinRange +{ + BelPinIterator b, e; + BelPinIterator begin() const { return b; } + BelPinIterator end() const { return e; } +}; + +// Iterator over Wires across tiles. +struct WireIterator +{ + const ChipInfoPOD *chip; + int cursor_index; + int cursor_tile; + + WireIterator operator++() + { + cursor_index++; + while (cursor_tile < chip->num_tiles && + cursor_index >= chip->tiles[cursor_tile].num_wires) { + cursor_index = 0; + cursor_tile++; + } + return *this; + } + WireIterator operator++(int) + { + WireIterator prior(*this); + ++(*this); + return prior; + } + + bool operator!=(const WireIterator &other) const + { + return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; + } + + bool operator==(const WireIterator &other) const + { + return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; + } + + WireId operator*() const + { + WireId ret; + ret.location.x = cursor_tile % chip->width; + ret.location.y = cursor_tile / chip->width; + ret.index = cursor_index; + return ret; + } +}; + +struct WireRange +{ + WireIterator b, e; + WireIterator begin() const { return b; } + WireIterator end() const { return e; } +}; + +// Iterator over Pips across tiles. +struct AllPipIterator +{ + const ChipInfoPOD *chip; + int cursor_index; + int cursor_tile; + + AllPipIterator operator++() + { + cursor_index++; + while (cursor_tile < chip->num_tiles && + cursor_index >= chip->tiles[cursor_tile].num_pips) { + cursor_index = 0; + cursor_tile++; + } + return *this; + } + AllPipIterator operator++(int) + { + AllPipIterator prior(*this); + ++(*this); + return prior; + } + + bool operator!=(const AllPipIterator &other) const + { + return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; + } + + bool operator==(const AllPipIterator &other) const + { + return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; + } + + PipId operator*() const + { + PipId ret; + ret.location.x = cursor_tile % chip->width; + ret.location.y = cursor_tile / chip->width; + ret.index = cursor_index; + return ret; + } +}; + +struct AllPipRange +{ + AllPipIterator b, e; + AllPipIterator begin() const { return b; } + AllPipIterator end() const { return e; } +}; + +// Iterate over Downstream/Upstream Pips for a Wire. +struct PipIterator +{ + + const PipLocatorPOD *cursor = nullptr; + Location wire_loc; + + void operator++() { cursor++; } + bool operator!=(const PipIterator &other) const { return cursor != other.cursor; } + + PipId operator*() const + { + PipId ret; + ret.index = cursor->index; + ret.location = wire_loc + cursor->rel_loc; + return ret; + } +}; + +struct PipRange +{ + PipIterator b, e; + PipIterator begin() const { return b; } + PipIterator end() const { return e; } +}; + // ----------------------------------------------------------------------- struct ArchArgs -- cgit v1.2.3 From 0e63178fe196dc042f2dc873ab40a929678dc53a Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 7 Dec 2020 18:56:27 -0500 Subject: machxo2: clang format. --- machxo2/arch.cc | 84 ++++++++++++++++-------------------------------------- machxo2/arch.h | 9 ++---- machxo2/archdefs.h | 2 +- machxo2/cells.cc | 5 +--- machxo2/pack.cc | 6 ++-- 5 files changed, 32 insertions(+), 74 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index ee334ed4..20c68065 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -19,8 +19,8 @@ #include #include -#include "nextpnr.h" #include "embed.h" +#include "nextpnr.h" #include "placer1.h" #include "placer_heap.h" #include "router1.h" @@ -40,15 +40,15 @@ static std::tuple split_identifier_name(const std::string name.substr(second_slash + 1)); }; - // ----------------------------------------------------------------------- -void IdString::initialize_arch(const BaseCtx *ctx) { - #define X(t) initialize_add(ctx, #t, ID_##t); +void IdString::initialize_arch(const BaseCtx *ctx) +{ +#define X(t) initialize_add(ctx, #t, ID_##t); - #include "constids.inc" +#include "constids.inc" - #undef X +#undef X } // --------------------------------------------------------------- @@ -171,16 +171,15 @@ BelId Arch::getBelByLocation(Loc loc) const { BelId ret; - if(loc.x >= chip_info->width || loc.y >= chip_info->height) + if (loc.x >= chip_info->width || loc.y >= chip_info->height) return BelId(); ret.location.x = loc.x; ret.location.y = loc.y; const TileTypePOD *tilei = tileInfo(ret); - for(int i = 0; i < tilei->num_bels; i++) { - if(tilei->bel_data[i].z == loc.z) - { + for (int i = 0; i < tilei->num_bels; i++) { + if (tilei->bel_data[i].z == loc.z) { ret.index = i; return ret; } @@ -217,8 +216,8 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const int num_bel_wires = tileInfo(bel)->bel_data[bel.index].num_bel_wires; const BelWirePOD *bel_wires = &*tileInfo(bel)->bel_data[bel.index].bel_wires; - for(int i = 0; i < num_bel_wires; i++) - if(bel_wires[i].port == pin.index) { + for (int i = 0; i < num_bel_wires; i++) + if (bel_wires[i].port == pin.index) { WireId ret; ret.location.x = bel_wires[i].rel_wire_loc.x; @@ -238,8 +237,8 @@ PortType Arch::getBelPinType(BelId bel, IdString pin) const int num_bel_wires = tileInfo(bel)->bel_data[bel.index].num_bel_wires; const BelWirePOD *bel_wires = &*tileInfo(bel)->bel_data[bel.index].bel_wires; - for(int i = 0; i < num_bel_wires; i++) - if(bel_wires[i].port == pin.index) + for (int i = 0; i < num_bel_wires; i++) + if (bel_wires[i].port == pin.index) return PortType(bel_wires[i].dir); return PORT_INOUT; @@ -253,7 +252,7 @@ std::vector Arch::getBelPins(BelId bel) const int num_bel_wires = tileInfo(bel)->bel_data[bel.index].num_bel_wires; const BelWirePOD *bel_wires = &*tileInfo(bel)->bel_data[bel.index].bel_wires; - for(int i = 0; i < num_bel_wires; i++) { + for (int i = 0; i < num_bel_wires; i++) { IdString id(bel_wires[i].port); ret.push_back(id); } @@ -263,10 +262,7 @@ std::vector Arch::getBelPins(BelId bel) const // --------------------------------------------------------------- -WireId Arch::getWireByName(IdString name) const -{ - return WireId(); -} +WireId Arch::getWireByName(IdString name) const { return WireId(); } IdString Arch::getWireName(WireId wire) const { return IdString(); } @@ -280,15 +276,9 @@ uint32_t Arch::getWireChecksum(WireId wire) const return 0; } -void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength) -{ - -} - -void Arch::unbindWire(WireId wire) -{ +void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength) {} -} +void Arch::unbindWire(WireId wire) {} bool Arch::checkWireAvail(WireId wire) const { return false; } @@ -302,10 +292,7 @@ const std::vector &Arch::getWires() const { return wire_id_dummy; } // --------------------------------------------------------------- -PipId Arch::getPipByName(IdString name) const -{ - return PipId(); -} +PipId Arch::getPipByName(IdString name) const { return PipId(); } IdString Arch::getPipName(PipId pip) const { return IdString(); } @@ -319,15 +306,9 @@ uint32_t Arch::getPipChecksum(PipId wire) const return 0; } -void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength) -{ - -} - -void Arch::unbindPip(PipId pip) -{ +void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength) {} -} +void Arch::unbindPip(PipId pip) {} bool Arch::checkPipAvail(PipId pip) const { return false; } @@ -375,15 +356,9 @@ const std::vector &Arch::getGroupGroups(GroupId group) const { return g // --------------------------------------------------------------- -delay_t Arch::estimateDelay(WireId src, WireId dst) const -{ - return 0; -} +delay_t Arch::estimateDelay(WireId src, WireId dst) const { return 0; } -delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const -{ - return 0; -} +delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const { return 0; } bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; } @@ -428,10 +403,7 @@ bool Arch::route() // --------------------------------------------------------------- -const std::vector &Arch::getDecalGraphics(DecalId decal) const -{ - return graphic_element_dummy; -} +const std::vector &Arch::getDecalGraphics(DecalId decal) const { return graphic_element_dummy; } DecalXY Arch::getBelDecal(BelId bel) const { return DecalXY(); } @@ -489,14 +461,8 @@ const std::vector Arch::availablePlacers = {"sa", const std::string Arch::defaultRouter = "router1"; const std::vector Arch::availableRouters = {"router1", "router2"}; -void Arch::assignArchInfo() -{ +void Arch::assignArchInfo() {} -} - -bool Arch::cellsCompatible(const CellInfo **cells, int count) const -{ - return false; -} +bool Arch::cellsCompatible(const CellInfo **cells, int count) const { return false; } NEXTPNR_NAMESPACE_END diff --git a/machxo2/arch.h b/machxo2/arch.h index 553c8d3d..bcac5390 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -159,8 +159,7 @@ struct BelIterator BelIterator operator++() { cursor_index++; - while (cursor_tile < chip->num_tiles && - cursor_index >= chip->tiles[cursor_tile].num_bels) { + while (cursor_tile < chip->num_tiles && cursor_index >= chip->tiles[cursor_tile].num_bels) { cursor_index = 0; cursor_tile++; } @@ -235,8 +234,7 @@ struct WireIterator WireIterator operator++() { cursor_index++; - while (cursor_tile < chip->num_tiles && - cursor_index >= chip->tiles[cursor_tile].num_wires) { + while (cursor_tile < chip->num_tiles && cursor_index >= chip->tiles[cursor_tile].num_wires) { cursor_index = 0; cursor_tile++; } @@ -286,8 +284,7 @@ struct AllPipIterator AllPipIterator operator++() { cursor_index++; - while (cursor_tile < chip->num_tiles && - cursor_index >= chip->tiles[cursor_tile].num_pips) { + while (cursor_tile < chip->num_tiles && cursor_index >= chip->tiles[cursor_tile].num_pips) { cursor_index = 0; cursor_tile++; } diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h index 5852d24b..f8fee5d7 100644 --- a/machxo2/archdefs.h +++ b/machxo2/archdefs.h @@ -179,4 +179,4 @@ template <> struct hash } }; -} +} // namespace std diff --git a/machxo2/cells.cc b/machxo2/cells.cc index 9a522b1a..ba4afad0 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -171,9 +171,6 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l replace_port(dff, ctx->id("Q"), lc, ctx->id("Q0")); } -void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set &todelete_cells) -{ - -} +void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set &todelete_cells) {} NEXTPNR_NAMESPACE_END diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 695d8e95..5984b740 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -39,8 +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 packed = - create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC"); + std::unique_ptr packed = create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); packed_cells.insert(ci->name); @@ -89,7 +88,7 @@ static void pack_lut_lutffs(Context *ctx) // Merge a net into a constant net static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval) { - (void) constval; + (void)constval; orig->driver.cell = nullptr; for (auto user : orig->users) { @@ -105,7 +104,6 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constne orig->users.clear(); } - // Pack constants (based on simple implementation in generic). // VCC/GND cells provided by nextpnr automatically. static void pack_constants(Context *ctx) -- cgit v1.2.3 From 9c37aef499b584ca464d8ceb238aec9321c0a274 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Tue, 8 Dec 2020 01:42:58 -0500 Subject: machxo2: Detect LOC attributes during packing to implement rudimentary user constraints. --- machxo2/arch.cc | 15 +++++++++++++++ machxo2/arch.h | 3 +++ machxo2/pack.cc | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 20c68065..abc281cb 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -262,6 +262,21 @@ std::vector Arch::getBelPins(BelId bel) const // --------------------------------------------------------------- +BelId Arch::getPackagePinBel(const std::string &pin) const +{ + for (int i = 0; i < package_info->num_pins; i++) { + if (package_info->pin_data[i].name.get() == pin) { + BelId bel; + bel.location = package_info->pin_data[i].abs_loc; + bel.index = package_info->pin_data[i].bel_index; + return bel; + } + } + return BelId(); +} + +// --------------------------------------------------------------- + WireId Arch::getWireByName(IdString name) const { return WireId(); } IdString Arch::getWireName(WireId wire) const { return IdString(); } diff --git a/machxo2/arch.h b/machxo2/arch.h index bcac5390..d620be4e 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -606,6 +606,9 @@ struct Arch : BaseCtx PortType getBelPinType(BelId bel, IdString pin) const; std::vector getBelPins(BelId bel) const; + // Package + BelId getPackagePinBel(const std::string &pin) const; + // Wires WireId getWireByName(IdString name) const; IdString getWireName(WireId wire) const; diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 5984b740..7c05b22a 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -175,6 +175,49 @@ static void pack_io(Context *ctx) for (auto &p : ci->ports) disconnect_port(ctx, ci, p.first); packed_cells.insert(ci->name); + } else if(is_facade_iob(ctx, ci)) { + // If net attached to PAD port of FACADE_IO has a LOC attribute OR + // FACADE_IO has LOC attribute, convert the LOC (pin) to a BEL + // attribute and place FACADE_IO at resulting BEL location. + + auto pad_net = ci->ports[id_PAD].net; + auto loc_attr_pad = pad_net->attrs.find(ctx->id("LOC")); + auto loc_attr_cell = ci->attrs.find(ctx->id("LOC")); + auto bel_attr_cell = ci->attrs.find(ctx->id("BEL")); + + // Handle errors + if(loc_attr_pad != pad_net->attrs.end() && loc_attr_cell != ci->attrs.end()) + log_error("IO buffer %s and attached PAD net %s both have LOC attributes.\n", + ci->name.c_str(ctx), pad_net->name.c_str(ctx)); + else if(loc_attr_pad != pad_net->attrs.end() && bel_attr_cell != ci->attrs.end()) + log_error("IO buffer %s has a BEL attribute and attached PAD net %s has a LOC attribute.\n", + ci->name.c_str(ctx), pad_net->name.c_str(ctx)); + else if(loc_attr_cell != ci->attrs.end() && bel_attr_cell != ci->attrs.end()) + log_error("IO buffer %s has both a BEL attribute and LOC attribute.\n", + ci->name.c_str(ctx)); + + std::string pin; + // At this point only PAD net or FACADE_IO has LOC attribute. + if(loc_attr_pad != pad_net->attrs.end()) { + pin = loc_attr_pad->second.as_string(); + log_info("found LOC attribute on net %s. Will constrain IO buffer %s.\n", + pad_net->name.c_str(ctx), ci->name.c_str(ctx)); + } else if(loc_attr_cell != ci->attrs.end()) { + log_info("found LOC attribute on IO buffer %s.\n", ci->name.c_str(ctx)); + pin = loc_attr_cell->second.as_string(); + } else + // Nothing to do if no LOC attrs. + continue; + + BelId pinBel = ctx->getPackagePinBel(pin); + if (pinBel == BelId()) { + log_error("IO buffer '%s' constrained to pin '%s', which does not exist for package '%s'.\n", + ci->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str()); + } else { + log_info("pin '%s' constrained to Bel '%s'.\n", ci->name.c_str(ctx), + ctx->getBelName(pinBel).c_str(ctx)); + } + ci->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx); } } -- cgit v1.2.3 From 31ea8f8719807513a9ba0b230ea0f5ef223d9d07 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 12 Dec 2020 22:05:39 -0500 Subject: machxo2: Use attrmvcp in yosys to implement LOC constraint and only check for LOC on FACADE_IO. --- machxo2/pack.cc | 59 +++++++++++++++++++++------------------------------------ 1 file changed, 22 insertions(+), 37 deletions(-) (limited to 'machxo2') diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 7c05b22a..ecf8b88d 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -176,48 +176,33 @@ static void pack_io(Context *ctx) disconnect_port(ctx, ci, p.first); packed_cells.insert(ci->name); } else if(is_facade_iob(ctx, ci)) { - // If net attached to PAD port of FACADE_IO has a LOC attribute OR - // FACADE_IO has LOC attribute, convert the LOC (pin) to a BEL - // attribute and place FACADE_IO at resulting BEL location. - - auto pad_net = ci->ports[id_PAD].net; - auto loc_attr_pad = pad_net->attrs.find(ctx->id("LOC")); + // 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 + // packing phase. auto loc_attr_cell = ci->attrs.find(ctx->id("LOC")); auto bel_attr_cell = ci->attrs.find(ctx->id("BEL")); - // Handle errors - if(loc_attr_pad != pad_net->attrs.end() && loc_attr_cell != ci->attrs.end()) - log_error("IO buffer %s and attached PAD net %s both have LOC attributes.\n", - ci->name.c_str(ctx), pad_net->name.c_str(ctx)); - else if(loc_attr_pad != pad_net->attrs.end() && bel_attr_cell != ci->attrs.end()) - log_error("IO buffer %s has a BEL attribute and attached PAD net %s has a LOC attribute.\n", - ci->name.c_str(ctx), pad_net->name.c_str(ctx)); - else if(loc_attr_cell != ci->attrs.end() && bel_attr_cell != ci->attrs.end()) - log_error("IO buffer %s has both a BEL attribute and LOC attribute.\n", - ci->name.c_str(ctx)); - - std::string pin; - // At this point only PAD net or FACADE_IO has LOC attribute. - if(loc_attr_pad != pad_net->attrs.end()) { - pin = loc_attr_pad->second.as_string(); - log_info("found LOC attribute on net %s. Will constrain IO buffer %s.\n", - pad_net->name.c_str(ctx), ci->name.c_str(ctx)); - } else if(loc_attr_cell != ci->attrs.end()) { + if(loc_attr_cell != ci->attrs.end()) { + if (bel_attr_cell != ci->attrs.end()) { + log_error("IO buffer %s has both a BEL attribute and LOC attribute.\n", + ci->name.c_str(ctx)); + } + log_info("found LOC attribute on IO buffer %s.\n", ci->name.c_str(ctx)); - pin = loc_attr_cell->second.as_string(); - } else - // Nothing to do if no LOC attrs. - continue; - - BelId pinBel = ctx->getPackagePinBel(pin); - if (pinBel == BelId()) { - log_error("IO buffer '%s' constrained to pin '%s', which does not exist for package '%s'.\n", - ci->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str()); - } else { - log_info("pin '%s' constrained to Bel '%s'.\n", ci->name.c_str(ctx), - ctx->getBelName(pinBel).c_str(ctx)); + std::string pin = loc_attr_cell->second.as_string(); + + BelId pinBel = ctx->getPackagePinBel(pin); + if (pinBel == BelId()) { + log_error("IO buffer '%s' constrained to pin '%s', which does not exist for package '%s'.\n", + ci->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str()); + } else { + log_info("pin '%s' constrained to Bel '%s'.\n", ci->name.c_str(ctx), + ctx->getBelName(pinBel).c_str(ctx)); + } + ci->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx); } - ci->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx); } } -- cgit v1.2.3 From e4a6fd35716b8d587eff971b23d20af4b1a1a2cb Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 25 Jan 2021 22:45:12 -0500 Subject: machxo2: Convert facade_import to use pybind API from pytrellis. --- machxo2/facade_import.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'machxo2') diff --git a/machxo2/facade_import.py b/machxo2/facade_import.py index 9be791ff..5bb2d78b 100644 --- a/machxo2/facade_import.py +++ b/machxo2/facade_import.py @@ -154,13 +154,13 @@ def write_database(dev_name, chip, rg, endianness): # Before doing anything, ensure sorted routing graph iteration matches # y, x - tile_iter = list(sorted(rg.tiles, key=lambda l : (l.key().y, l.key().x))) + loc_iter = list(sorted(rg.tiles, key=lambda l : (l.y, l.x))) i = 1 # Drop (-2, -2) location. for y in range(0, max_row+1): for x in range(0, max_col+1): - l = tile_iter[i] - assert((y, x) == (l.key().y, l.key().x)) + l = loc_iter[i] + assert((y, x) == (l.y, l.x)) i = i + 1 bba = BinaryBlobAssembler() @@ -174,9 +174,8 @@ def write_database(dev_name, chip, rg, endianness): # Nominally should be in order, but support situations where python # decides to iterate over rg.tiles out-of-order. - for lt in sorted(rg.tiles, key=lambda l : (l.key().y, l.key().x)): - l = lt.key() - t = lt.data() + for l in loc_iter: + t = rg.tiles[l] # Do not include special globals location for now. if (l.x, l.y) == (-2, -2): @@ -255,9 +254,8 @@ def write_database(dev_name, chip, rg, endianness): bba.r("loc%d_%d_bel%d_wires" % (l.y, l.x, bel_idx), "bel_wires") bba.l("tiles", "TileTypePOD") - for lt in sorted(rg.tiles, key=lambda l : (l.key().y, l.key().x)): - l = lt.key() - t = lt.data() + for l in loc_iter: + t = rg.tiles[l] if (l.y, l.x) == (-2, -2): continue -- cgit v1.2.3 From 9a9054188c52d76670dace9777981ffd28de5599 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 27 Jan 2021 01:46:32 -0500 Subject: machxo2: Implement getByName/getName for Wires and Pips. --- machxo2/arch.cc | 70 +++++++++++++++++++++++++++++++++++++++++++++++++-------- machxo2/arch.h | 37 ++++++++++++++++++++++++++---- 2 files changed, 94 insertions(+), 13 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index abc281cb..3fc4dcd8 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -277,9 +277,30 @@ BelId Arch::getPackagePinBel(const std::string &pin) const // --------------------------------------------------------------- -WireId Arch::getWireByName(IdString name) const { return WireId(); } +WireId Arch::getWireByName(IdString name) const +{ + WireId ret; + + auto it = wire_by_name.find(name); + if (it != wire_by_name.end()) + return it->second; -IdString Arch::getWireName(WireId wire) const { return IdString(); } + Location loc; + std::string basename; + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + ret.location = loc; + + const TileTypePOD *tilei = tileInfo(ret); + for (int i = 0; i < tilei->num_wires; i++) { + if (std::strcmp(tilei->wire_data[i].name.get(), basename.c_str()) == 0) { + ret.index = i; + break; + } + } + if (ret.index >= 0) + wire_by_name[name] = ret; + return ret; +} IdString Arch::getWireType(WireId wire) const { return IdString(); } @@ -307,11 +328,46 @@ const std::vector &Arch::getWires() const { return wire_id_dummy; } // --------------------------------------------------------------- -PipId Arch::getPipByName(IdString name) const { return PipId(); } +PipId Arch::getPipByName(IdString name) const +{ + PipId ret; -IdString Arch::getPipName(PipId pip) const { return IdString(); } + auto it = pip_by_name.find(name); + if (it != pip_by_name.end()) + return it->second; -IdString Arch::getPipType(PipId pip) const { return IdString(); } + Location loc; + std::string basename; + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + ret.location = loc; + + const TileTypePOD *tilei = tileInfo(ret); + for (int i = 0; i < tilei->num_pips; i++) { + PipId curr; + curr.location = loc; + curr.index = i; + pip_by_name[getPipName(curr)] = curr; + } + if (pip_by_name.find(name) == pip_by_name.end()) + NPNR_ASSERT_FALSE_STR("no pip named " + name.str(this)); + return pip_by_name[name]; +} + +IdString Arch::getPipName(PipId pip) const +{ + NPNR_ASSERT(pip != PipId()); + + int x = pip.location.x; + int y = pip.location.y; + + std::string src_name = getWireName(getPipSrcWire(pip)).str(this); + std::replace(src_name.begin(), src_name.end(), '/', '.'); + + std::string dst_name = getWireName(getPipDstWire(pip)).str(this); + std::replace(dst_name.begin(), dst_name.end(), '/', '.'); + + return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); +} const std::map &Arch::getPipAttrs(PipId pip) const { return attrs_dummy; } @@ -337,10 +393,6 @@ const std::vector &Arch::getPips() const { return pip_id_dummy; } Loc Arch::getPipLocation(PipId pip) const { return Loc(); } -WireId Arch::getPipSrcWire(PipId pip) const { return WireId(); } - -WireId Arch::getPipDstWire(PipId pip) const { return WireId(); } - DelayInfo Arch::getPipDelay(PipId pip) const { return DelayInfo(); } const std::vector &Arch::getPipsDownhill(WireId wire) const { return pip_id_dummy; } diff --git a/machxo2/arch.h b/machxo2/arch.h index d620be4e..d8442ec8 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -464,6 +464,8 @@ struct Arch : BaseCtx std::vector bel_to_cell; mutable std::unordered_map bel_by_name; + mutable std::unordered_map wire_by_name; + mutable std::unordered_map pip_by_name; // Placeholders to be removed. std::unordered_map bel_by_loc; @@ -512,6 +514,7 @@ struct Arch : BaseCtx // Bels BelId getBelByName(IdString name) const; + IdString getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); @@ -611,7 +614,15 @@ struct Arch : BaseCtx // Wires WireId getWireByName(IdString name) const; - IdString getWireName(WireId wire) const; + + IdString getWireName(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + std::stringstream name; + name << "X" << wire.location.x << "/Y" << wire.location.y << "/" << tileInfo(wire)->bel_data[wire.index].name.get(); + return id(name.str()); + } + IdString getWireType(WireId wire) const; const std::map &getWireAttrs(WireId wire) const; uint32_t getWireChecksum(WireId wire) const; @@ -628,7 +639,8 @@ struct Arch : BaseCtx // Pips PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; - IdString getPipType(PipId pip) const; + + IdString getPipType(PipId pip) const { return IdString(); } const std::map &getPipAttrs(PipId pip) const; uint32_t getPipChecksum(PipId pip) const; void bindPip(PipId pip, NetInfo *net, PlaceStrength strength); @@ -639,8 +651,25 @@ struct Arch : BaseCtx NetInfo *getConflictingPipNet(PipId pip) const; const std::vector &getPips() const; Loc getPipLocation(PipId pip) const; - WireId getPipSrcWire(PipId pip) const; - WireId getPipDstWire(PipId pip) const; + + WireId getPipSrcWire(PipId pip) const + { + WireId wire; + NPNR_ASSERT(pip != PipId()); + wire.index = tileInfo(pip)->pips_data[pip.index].src_idx; + wire.location = pip.location + tileInfo(pip)->pips_data[pip.index].src; + return wire; + } + + WireId getPipDstWire(PipId pip) const + { + WireId wire; + NPNR_ASSERT(pip != PipId()); + wire.index = tileInfo(pip)->pips_data[pip.index].dst_idx; + wire.location = pip.location + tileInfo(pip)->pips_data[pip.index].dst; + return wire; + } + DelayInfo getPipDelay(PipId pip) const; const std::vector &getPipsDownhill(WireId wire) const; const std::vector &getPipsUphill(WireId wire) const; -- cgit v1.2.3 From 19a9554bdadf19eec2fb83e6a04ecabfeafc1ed7 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 27 Jan 2021 02:03:50 -0500 Subject: machxo2: Add stub getAttrs API functions. --- machxo2/arch.cc | 8 -------- machxo2/arch.h | 26 +++++++++++++++++++++----- 2 files changed, 21 insertions(+), 13 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 3fc4dcd8..9ac4f3ae 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -207,8 +207,6 @@ BelRange Arch::getBelsByTile(int x, int y) const bool Arch::getBelGlobalBuf(BelId bel) const { return false; } -const std::map &Arch::getBelAttrs(BelId bel) const { return attrs_dummy; } - WireId Arch::getBelPinWire(BelId bel, IdString pin) const { NPNR_ASSERT(bel != BelId()); @@ -302,10 +300,6 @@ WireId Arch::getWireByName(IdString name) const return ret; } -IdString Arch::getWireType(WireId wire) const { return IdString(); } - -const std::map &Arch::getWireAttrs(WireId wire) const { return attrs_dummy; } - uint32_t Arch::getWireChecksum(WireId wire) const { // FIXME @@ -369,8 +363,6 @@ IdString Arch::getPipName(PipId pip) const return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); } -const std::map &Arch::getPipAttrs(PipId pip) const { return attrs_dummy; } - uint32_t Arch::getPipChecksum(PipId wire) const { // FIXME diff --git a/machxo2/arch.h b/machxo2/arch.h index d8442ec8..e645f225 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -475,7 +475,6 @@ struct Arch : BaseCtx std::vector pip_id_dummy; std::vector group_id_dummy; std::vector graphic_element_dummy; - std::map attrs_dummy; // Helpers template const TileTypePOD *tileInfo(Id &id) const @@ -604,7 +603,12 @@ struct Arch : BaseCtx return id; } - const std::map &getBelAttrs(BelId bel) const; + std::vector> getBelAttrs(BelId) const + { + std::vector> ret; + return ret; + } + WireId getBelPinWire(BelId bel, IdString pin) const; PortType getBelPinType(BelId bel, IdString pin) const; std::vector getBelPins(BelId bel) const; @@ -623,8 +627,14 @@ struct Arch : BaseCtx return id(name.str()); } - IdString getWireType(WireId wire) const; - const std::map &getWireAttrs(WireId wire) const; + IdString getWireType(WireId wire) const { return IdString(); } + + std::vector> getWireAttrs(WireId) const + { + std::vector> ret; + return ret; + } + uint32_t getWireChecksum(WireId wire) const; void bindWire(WireId wire, NetInfo *net, PlaceStrength strength); void unbindWire(WireId wire); @@ -641,7 +651,13 @@ struct Arch : BaseCtx IdString getPipName(PipId pip) const; IdString getPipType(PipId pip) const { return IdString(); } - const std::map &getPipAttrs(PipId pip) const; + + std::vector> getPipAttrs(PipId) const + { + std::vector> ret; + return ret; + } + uint32_t getPipChecksum(PipId pip) const; void bindPip(PipId pip, NetInfo *net, PlaceStrength strength); void unbindPip(PipId pip); -- cgit v1.2.3 From 0adde4aede134f5ed37d1fc0f081a7eaf325c7ee Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 28 Jan 2021 02:14:34 -0500 Subject: machxo2: Implement 4 more Wire/Pip API functions. --- machxo2/arch.cc | 24 ------------- machxo2/arch.h | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 94 insertions(+), 32 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 9ac4f3ae..0f1a0670 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -300,18 +300,6 @@ WireId Arch::getWireByName(IdString name) const return ret; } -uint32_t Arch::getWireChecksum(WireId wire) const -{ - // FIXME - return 0; -} - -void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength) {} - -void Arch::unbindWire(WireId wire) {} - -bool Arch::checkWireAvail(WireId wire) const { return false; } - NetInfo *Arch::getBoundWireNet(WireId wire) const { return nullptr; } NetInfo *Arch::getConflictingWireNet(WireId wire) const { return nullptr; } @@ -363,18 +351,6 @@ IdString Arch::getPipName(PipId pip) const return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); } -uint32_t Arch::getPipChecksum(PipId wire) const -{ - // FIXME - return 0; -} - -void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength) {} - -void Arch::unbindPip(PipId pip) {} - -bool Arch::checkPipAvail(PipId pip) const { return false; } - NetInfo *Arch::getBoundPipNet(PipId pip) const { return nullptr; } NetInfo *Arch::getConflictingPipNet(PipId pip) const { return nullptr; } diff --git a/machxo2/arch.h b/machxo2/arch.h index e645f225..b87d622c 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -463,6 +463,9 @@ struct Arch : BaseCtx const PackageInfoPOD *package_info; std::vector bel_to_cell; + std::unordered_map wire_to_net; + std::unordered_map pip_to_net; + mutable std::unordered_map bel_by_name; mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; @@ -635,10 +638,50 @@ struct Arch : BaseCtx return ret; } - uint32_t getWireChecksum(WireId wire) const; - void bindWire(WireId wire, NetInfo *net, PlaceStrength strength); - void unbindWire(WireId wire); - bool checkWireAvail(WireId wire) const; + uint32_t getWireChecksum(WireId wire) const { return wire.index; } + + void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire] == nullptr); + wire_to_net[wire] = net; + + // Needs to be set; bindWires is meant for source wires attached + // to a Bel. + net->wires[wire].pip = PipId(); + net->wires[wire].strength = strength; + refreshUiWire(wire); + } + + void unbindWire(WireId wire) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire] != nullptr); + + auto &net_wires = wire_to_net[wire]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + // If we have unbound a wire, then the upstream pip is no longer + // used either. + auto pip = it->second.pip; + if (pip != PipId()) { + // TODO: fanout + // wire_fanout[getPipSrcWire(pip)]--; + pip_to_net[pip] = nullptr; + } + + net_wires.erase(it); + wire_to_net[wire] = nullptr; + refreshUiWire(wire); + } + + bool checkWireAvail(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == nullptr; + } + NetInfo *getBoundWireNet(WireId wire) const; WireId getConflictingWireWire(WireId wire) const { return wire; } NetInfo *getConflictingWireNet(WireId wire) const; @@ -658,10 +701,53 @@ struct Arch : BaseCtx return ret; } - uint32_t getPipChecksum(PipId pip) const; - void bindPip(PipId pip, NetInfo *net, PlaceStrength strength); - void unbindPip(PipId pip); - bool checkPipAvail(PipId pip) const; + uint32_t getPipChecksum(PipId pip) const { return pip.index; } + + void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip] == nullptr); + + pip_to_net[pip] = net; + // wire_fanout[getPipSrcWire(pip)]++; + + WireId dst; + dst.index = tileInfo(pip)->pips_data[pip.index].dst_idx; + dst.location = pip.location + tileInfo(pip)->pips_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst] == nullptr); + + // Since NetInfo::wires holds info about uphill pips, bind info about + // this pip to the downhill wire. + wire_to_net[dst] = net; + net->wires[dst].pip = pip; + net->wires[dst].strength = strength; + } + + void unbindPip(PipId pip) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip] == nullptr); + + // wire_fanout[getPipSrcWire(pip)]--; + + WireId dst; + dst.index = tileInfo(pip)->pips_data[pip.index].dst_idx; + dst.location = pip.location + tileInfo(pip)->pips_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst] != nullptr); + + // If we unbind a pip, then the downstream wire is no longer in use + // either. + wire_to_net[dst] = nullptr; + pip_to_net[pip]->wires.erase(dst); + pip_to_net[pip] = nullptr; + } + + bool checkPipAvail(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == nullptr; + } + NetInfo *getBoundPipNet(PipId pip) const; WireId getConflictingPipWire(PipId pip) const; NetInfo *getConflictingPipNet(PipId pip) const; -- cgit v1.2.3 From 861c12e6eba1ae1c0d6b1ea0ed27c060b2ceb671 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 28 Jan 2021 03:16:57 -0500 Subject: machxo2: Finish implementing Pip API functions. --- machxo2/arch.cc | 18 -------------- machxo2/arch.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 67 insertions(+), 27 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 0f1a0670..eb050598 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -351,24 +351,6 @@ IdString Arch::getPipName(PipId pip) const return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); } -NetInfo *Arch::getBoundPipNet(PipId pip) const { return nullptr; } - -NetInfo *Arch::getConflictingPipNet(PipId pip) const { return nullptr; } - -WireId Arch::getConflictingPipWire(PipId pip) const { return WireId(); } - -const std::vector &Arch::getPips() const { return pip_id_dummy; } - -Loc Arch::getPipLocation(PipId pip) const { return Loc(); } - -DelayInfo Arch::getPipDelay(PipId pip) const { return DelayInfo(); } - -const std::vector &Arch::getPipsDownhill(WireId wire) const { return pip_id_dummy; } - -const std::vector &Arch::getPipsUphill(WireId wire) const { return pip_id_dummy; } - -const std::vector &Arch::getWireAliases(WireId wire) const { return pip_id_dummy; } - // --------------------------------------------------------------- GroupId Arch::getGroupByName(IdString name) const { return GroupId(); } diff --git a/machxo2/arch.h b/machxo2/arch.h index b87d622c..560099aa 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -748,11 +748,50 @@ struct Arch : BaseCtx return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == nullptr; } - NetInfo *getBoundPipNet(PipId pip) const; - WireId getConflictingPipWire(PipId pip) const; - NetInfo *getConflictingPipNet(PipId pip) const; - const std::vector &getPips() const; - Loc getPipLocation(PipId pip) const; + NetInfo *getBoundPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + if (pip_to_net.find(pip) == pip_to_net.end()) + return nullptr; + else + return pip_to_net.at(pip); + } + + WireId getConflictingPipWire(PipId pip) const { return WireId(); } + + NetInfo *getConflictingPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + if (pip_to_net.find(pip) == pip_to_net.end()) + return nullptr; + else + return pip_to_net.at(pip); + } + + AllPipRange getPips() const + { + AllPipRange range; + range.b.cursor_tile = 0; + range.b.cursor_index = -1; + range.b.chip = chip_info; + ++range.b; //-1 and then ++ deals with the case of no Bels in the first tile + range.e.cursor_tile = chip_info->width * chip_info->height; + range.e.cursor_index = 0; + range.e.chip = chip_info; + return range; + } + + Loc getPipLocation(PipId pip) const + { + Loc loc; + loc.x = pip.location.x; + loc.y = pip.location.y; + + // FIXME: Some Pip's config bits span across tiles. Will Z + // be affected by this? + loc.z = 0; + return loc; + } WireId getPipSrcWire(PipId pip) const { @@ -772,10 +811,29 @@ struct Arch : BaseCtx return wire; } - DelayInfo getPipDelay(PipId pip) const; - const std::vector &getPipsDownhill(WireId wire) const; - const std::vector &getPipsUphill(WireId wire) const; - const std::vector &getWireAliases(WireId wire) const; + DelayInfo getPipDelay(PipId pip) const { return DelayInfo(); } + + PipRange getPipsDownhill(WireId wire) const + { + PipRange range; + NPNR_ASSERT(wire != WireId()); + range.b.cursor = tileInfo(wire)->wire_data[wire.index].pips_downhill.get(); + range.b.wire_loc = wire.location; + range.e.cursor = range.b.cursor + tileInfo(wire)->wire_data[wire.index].num_downhill; + range.e.wire_loc = wire.location; + return range; + } + + PipRange getPipsUphill(WireId wire) const + { + PipRange range; + NPNR_ASSERT(wire != WireId()); + range.b.cursor = tileInfo(wire)->wire_data[wire.index].pips_uphill.get(); + range.b.wire_loc = wire.location; + range.e.cursor = range.b.cursor + tileInfo(wire)->wire_data[wire.index].num_uphill; + range.e.wire_loc = wire.location; + return range; + } // Group GroupId getGroupByName(IdString name) const; -- cgit v1.2.3 From 722d1f254284638515accc8c1d4562807f6452cc Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 28 Jan 2021 03:24:52 -0500 Subject: machxo2: Finish implementing Wire API functions. nextpnr segfaults on example with constraints. --- machxo2/arch.cc | 8 -------- machxo2/arch.h | 47 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 12 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index eb050598..3410ec16 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -300,14 +300,6 @@ WireId Arch::getWireByName(IdString name) const return ret; } -NetInfo *Arch::getBoundWireNet(WireId wire) const { return nullptr; } - -NetInfo *Arch::getConflictingWireNet(WireId wire) const { return nullptr; } - -const std::vector &Arch::getWireBelPins(WireId wire) const { return bel_pin_dummy; } - -const std::vector &Arch::getWires() const { return wire_id_dummy; } - // --------------------------------------------------------------- PipId Arch::getPipByName(IdString name) const diff --git a/machxo2/arch.h b/machxo2/arch.h index 560099aa..d87b5dbb 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -682,12 +682,51 @@ struct Arch : BaseCtx return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == nullptr; } - NetInfo *getBoundWireNet(WireId wire) const; + NetInfo *getBoundWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + if (wire_to_net.find(wire) == wire_to_net.end()) + return nullptr; + else + return wire_to_net.at(wire); + } + WireId getConflictingWireWire(WireId wire) const { return wire; } - NetInfo *getConflictingWireNet(WireId wire) const; + + NetInfo *getConflictingWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + if (wire_to_net.find(wire) == wire_to_net.end()) + return nullptr; + else + return wire_to_net.at(wire); + } + DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); } - const std::vector &getWires() const; - const std::vector &getWireBelPins(WireId wire) const; + + WireRange getWires() const + { + WireRange range; + range.b.cursor_tile = 0; + range.b.cursor_index = -1; + range.b.chip = chip_info; + ++range.b; //-1 and then ++ deals with the case of no wries in the first tile + range.e.cursor_tile = chip_info->width * chip_info->height; + range.e.cursor_index = 0; + range.e.chip = chip_info; + return range; + } + + BelPinRange getWireBelPins(WireId wire) const + { + BelPinRange range; + NPNR_ASSERT(wire != WireId()); + range.b.ptr = tileInfo(wire)->wire_data[wire.index].bel_pins.get(); + range.b.wire_loc = wire.location; + range.e.ptr = range.b.ptr + tileInfo(wire)->wire_data[wire.index].num_bel_pins; + range.e.wire_loc = wire.location; + return range; + } // Pips PipId getPipByName(IdString name) const; -- cgit v1.2.3 From 385917059b2d06e3b96140418c966a9099ef1e09 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Thu, 28 Jan 2021 23:42:15 -0500 Subject: machxo2: Fix typos where absolute positions were treated as relative. --- machxo2/arch.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.h b/machxo2/arch.h index d87b5dbb..aa4138f2 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -211,7 +211,7 @@ struct BelPinIterator { BelPin ret; ret.bel.index = ptr->bel_index; - ret.bel.location = wire_loc + ptr->rel_bel_loc; + ret.bel.location = ptr->rel_bel_loc; ret.pin.index = ptr->port; return ret; } @@ -338,7 +338,7 @@ struct PipIterator { PipId ret; ret.index = cursor->index; - ret.location = wire_loc + cursor->rel_loc; + ret.location = cursor->rel_loc; return ret; } }; @@ -752,7 +752,7 @@ struct Arch : BaseCtx WireId dst; dst.index = tileInfo(pip)->pips_data[pip.index].dst_idx; - dst.location = pip.location + tileInfo(pip)->pips_data[pip.index].dst; + dst.location = tileInfo(pip)->pips_data[pip.index].dst; NPNR_ASSERT(wire_to_net[dst] == nullptr); // Since NetInfo::wires holds info about uphill pips, bind info about @@ -771,7 +771,7 @@ struct Arch : BaseCtx WireId dst; dst.index = tileInfo(pip)->pips_data[pip.index].dst_idx; - dst.location = pip.location + tileInfo(pip)->pips_data[pip.index].dst; + dst.location = tileInfo(pip)->pips_data[pip.index].dst; NPNR_ASSERT(wire_to_net[dst] != nullptr); // If we unbind a pip, then the downstream wire is no longer in use @@ -837,7 +837,7 @@ struct Arch : BaseCtx WireId wire; NPNR_ASSERT(pip != PipId()); wire.index = tileInfo(pip)->pips_data[pip.index].src_idx; - wire.location = pip.location + tileInfo(pip)->pips_data[pip.index].src; + wire.location = tileInfo(pip)->pips_data[pip.index].src; return wire; } @@ -846,7 +846,7 @@ struct Arch : BaseCtx WireId wire; NPNR_ASSERT(pip != PipId()); wire.index = tileInfo(pip)->pips_data[pip.index].dst_idx; - wire.location = pip.location + tileInfo(pip)->pips_data[pip.index].dst; + wire.location = tileInfo(pip)->pips_data[pip.index].dst; return wire; } -- cgit v1.2.3 From 447b3a060c791b926e954e8e36e63aba718fbeb6 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Fri, 29 Jan 2021 15:46:42 -0500 Subject: machxo2: Fix getWireName. --- machxo2/arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/arch.h b/machxo2/arch.h index aa4138f2..a438424f 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -626,7 +626,7 @@ struct Arch : BaseCtx { NPNR_ASSERT(wire != WireId()); std::stringstream name; - name << "X" << wire.location.x << "/Y" << wire.location.y << "/" << tileInfo(wire)->bel_data[wire.index].name.get(); + name << "X" << wire.location.x << "/Y" << wire.location.y << "/" << tileInfo(wire)->wire_data[wire.index].name.get(); return id(name.str()); } -- cgit v1.2.3 From e1f72318e0b126de119cbc5e7f7b143e7beadd09 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 30 Jan 2021 12:39:57 -0500 Subject: machxo2: Tweak A-star parameters for acceptable performance. --- machxo2/arch.cc | 20 ++++++++++++++++++-- machxo2/arch.h | 9 ++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 3410ec16..58c48044 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -365,9 +365,25 @@ const std::vector &Arch::getGroupGroups(GroupId group) const { return g // --------------------------------------------------------------- -delay_t Arch::estimateDelay(WireId src, WireId dst) const { return 0; } +delay_t Arch::estimateDelay(WireId src, WireId dst) const +{ + // Taxicab distance multiplied by pipDelay (0.01) and fake wireDelay (0.01). + // TODO: This function will not work well for entrance to global routing, + // as the entrances are located physically far from the DCCAs. + return (abs(dst.location.x - src.location.x) + abs(dst.location.y - src.location.y)) * (0.01 + 0.01); +} + +delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const +{ + BelId src = net_info->driver.cell->bel; + BelId dst = sink.cell->bel; + + NPNR_ASSERT(src != BelId()); + NPNR_ASSERT(dst != BelId()); -delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const { return 0; } + // TODO: Same deal applies here as with estimateDelay. + return (abs(dst.location.x - src.location.x) + abs(dst.location.y - src.location.y)) * (0.01 + 0.01); +} bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; } diff --git a/machxo2/arch.h b/machxo2/arch.h index a438424f..8fdb63fc 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -850,7 +850,14 @@ struct Arch : BaseCtx return wire; } - DelayInfo getPipDelay(PipId pip) const { return DelayInfo(); } + DelayInfo getPipDelay(PipId pip) const + { + DelayInfo delay; + + delay.delay = 0.01; + + return delay; + } PipRange getPipsDownhill(WireId wire) const { -- cgit v1.2.3 From 75f33e0c55b97c665f36ab2b4a8013c86635d47f Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 30 Jan 2021 18:03:40 -0500 Subject: machxo2: Add stub bitstream writer plus support files. --- machxo2/bitstream.cc | 32 +++++ machxo2/bitstream.h | 32 +++++ machxo2/config.cc | 357 +++++++++++++++++++++++++++++++++++++++++++++++++++ machxo2/config.h | 128 ++++++++++++++++++ machxo2/main.cc | 12 +- 5 files changed, 559 insertions(+), 2 deletions(-) create mode 100644 machxo2/bitstream.cc create mode 100644 machxo2/bitstream.h create mode 100644 machxo2/config.cc create mode 100644 machxo2/config.h (limited to 'machxo2') diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc new file mode 100644 index 00000000..6e1dbb11 --- /dev/null +++ b/machxo2/bitstream.cc @@ -0,0 +1,32 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * Copyright (C) 2021 William D. Jones + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "bitstream.h" +#include "config.h" + +NEXTPNR_NAMESPACE_BEGIN + +void write_bitstream(Context *ctx, std::string text_config_file) +{ + ChipConfig cc; + +} + +NEXTPNR_NAMESPACE_END diff --git a/machxo2/bitstream.h b/machxo2/bitstream.h new file mode 100644 index 00000000..f7965c4f --- /dev/null +++ b/machxo2/bitstream.h @@ -0,0 +1,32 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * Copyright (C) 2021 William D. Jones + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef BITSTREAM_H +#define BITSTREAM_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +void write_bitstream(Context *ctx, std::string text_config_file = ""); + +NEXTPNR_NAMESPACE_END + +#endif // BITSTREAM_H diff --git a/machxo2/config.cc b/machxo2/config.cc new file mode 100644 index 00000000..2e17ce24 --- /dev/null +++ b/machxo2/config.cc @@ -0,0 +1,357 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * Copyright (C) 2021 William D. Jones + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "config.h" +#include +#include +#include "log.h" +NEXTPNR_NAMESPACE_BEGIN + +#define fmt(x) (static_cast(std::ostringstream() << x).str()) + +inline std::string to_string(const std::vector &bv) +{ + std::ostringstream os; + for (auto bit : boost::adaptors::reverse(bv)) + os << (bit ? '1' : '0'); + return os.str(); +} + +inline std::istream &operator>>(std::istream &in, std::vector &bv) +{ + bv.clear(); + std::string s; + in >> s; + for (auto c : boost::adaptors::reverse(s)) { + assert((c == '0') || (c == '1')); + bv.push_back((c == '1')); + } + return in; +} + +struct ConfigBit +{ + int frame; + int bit; + bool inv; +}; + +static ConfigBit cbit_from_str(const std::string &s) +{ + size_t idx = 0; + ConfigBit b; + if (s[idx] == '!') { + b.inv = true; + ++idx; + } else { + b.inv = false; + } + NPNR_ASSERT(s[idx] == 'F'); + ++idx; + size_t b_pos = s.find('B'); + NPNR_ASSERT(b_pos != std::string::npos); + b.frame = stoi(s.substr(idx, b_pos - idx)); + b.bit = stoi(s.substr(b_pos + 1)); + return b; +} + +inline std::string to_string(ConfigBit b) +{ + std::ostringstream ss; + if (b.inv) + ss << "!"; + ss << "F" << b.frame; + ss << "B" << b.bit; + return ss.str(); +} + +// Skip whitespace, optionally including newlines +inline void skip_blank(std::istream &in, bool nl = false) +{ + int c = in.peek(); + while (in && (((c == ' ') || (c == '\t')) || (nl && ((c == '\n') || (c == '\r'))))) { + in.get(); + c = in.peek(); + } +} +// Return true if end of line (or file) +inline bool skip_check_eol(std::istream &in) +{ + skip_blank(in, false); + if (!in) + return false; + int c = in.peek(); + // Comments count as end of line + if (c == '#') { + in.get(); + c = in.peek(); + while (in && c != EOF && c != '\n') { + in.get(); + c = in.peek(); + } + return true; + } + return (c == EOF || c == '\n'); +} + +// Skip past blank lines and comments +inline void skip(std::istream &in) +{ + skip_blank(in, true); + while (in && (in.peek() == '#')) { + // Skip comment line + skip_check_eol(in); + skip_blank(in, true); + } +} + +// Return true if at the end of a record (or file) +inline bool skip_check_eor(std::istream &in) +{ + skip(in); + int c = in.peek(); + return (c == EOF || c == '.'); +} + +// Return true if at the end of file +inline bool skip_check_eof(std::istream &in) +{ + skip(in); + int c = in.peek(); + return (c == EOF); +} + +std::ostream &operator<<(std::ostream &out, const ConfigArc &arc) +{ + out << "arc: " << arc.sink << " " << arc.source << std::endl; + return out; +} + +std::istream &operator>>(std::istream &in, ConfigArc &arc) +{ + in >> arc.sink; + in >> arc.source; + return in; +} + +std::ostream &operator<<(std::ostream &out, const ConfigWord &cw) +{ + out << "word: " << cw.name << " " << to_string(cw.value) << std::endl; + return out; +} + +std::istream &operator>>(std::istream &in, ConfigWord &cw) +{ + in >> cw.name; + in >> cw.value; + return in; +} + +std::ostream &operator<<(std::ostream &out, const ConfigEnum &cw) +{ + out << "enum: " << cw.name << " " << cw.value << std::endl; + return out; +} + +std::istream &operator>>(std::istream &in, ConfigEnum &ce) +{ + in >> ce.name; + in >> ce.value; + return in; +} + +std::ostream &operator<<(std::ostream &out, const ConfigUnknown &cu) +{ + out << "unknown: " << to_string(ConfigBit{cu.frame, cu.bit, false}) << std::endl; + return out; +} + +std::istream &operator>>(std::istream &in, ConfigUnknown &cu) +{ + std::string s; + in >> s; + ConfigBit c = cbit_from_str(s); + cu.frame = c.frame; + cu.bit = c.bit; + assert(!c.inv); + return in; +} + +std::ostream &operator<<(std::ostream &out, const TileConfig &tc) +{ + for (const auto &arc : tc.carcs) + out << arc; + for (const auto &cword : tc.cwords) + out << cword; + for (const auto &cenum : tc.cenums) + out << cenum; + for (const auto &cunk : tc.cunknowns) + out << cunk; + return out; +} + +std::istream &operator>>(std::istream &in, TileConfig &tc) +{ + tc.carcs.clear(); + tc.cwords.clear(); + tc.cenums.clear(); + while (!skip_check_eor(in)) { + std::string type; + in >> type; + if (type == "arc:") { + ConfigArc a; + in >> a; + tc.carcs.push_back(a); + } else if (type == "word:") { + ConfigWord w; + in >> w; + tc.cwords.push_back(w); + } else if (type == "enum:") { + ConfigEnum e; + in >> e; + tc.cenums.push_back(e); + } else if (type == "unknown:") { + ConfigUnknown u; + in >> u; + tc.cunknowns.push_back(u); + } else { + NPNR_ASSERT_FALSE_STR("unexpected token " + type + " while reading config text"); + } + } + return in; +} + +void TileConfig::add_arc(const std::string &sink, const std::string &source) { carcs.push_back({sink, source}); } + +void TileConfig::add_word(const std::string &name, const std::vector &value) { cwords.push_back({name, value}); } + +void TileConfig::add_enum(const std::string &name, const std::string &value) { cenums.push_back({name, value}); } + +void TileConfig::add_unknown(int frame, int bit) { cunknowns.push_back({frame, bit}); } + +std::string TileConfig::to_string() const +{ + std::stringstream ss; + ss << *this; + return ss.str(); +} + +TileConfig TileConfig::from_string(const std::string &str) +{ + std::stringstream ss(str); + TileConfig tc; + ss >> tc; + return tc; +} + +bool TileConfig::empty() const { return carcs.empty() && cwords.empty() && cenums.empty() && cunknowns.empty(); } + +std::ostream &operator<<(std::ostream &out, const ChipConfig &cc) +{ + out << ".device " << cc.chip_name << std::endl << std::endl; + for (const auto &meta : cc.metadata) + out << ".comment " << meta << std::endl; + for (const auto &sc : cc.sysconfig) + out << ".sysconfig " << sc.first << " " << sc.second << std::endl; + out << std::endl; + for (const auto &tile : cc.tiles) { + if (!tile.second.empty()) { + out << ".tile " << tile.first << std::endl; + out << tile.second; + out << std::endl; + } + } + for (const auto &bram : cc.bram_data) { + out << ".bram_init " << bram.first << std::endl; + std::ios_base::fmtflags f(out.flags()); + for (size_t i = 0; i < bram.second.size(); i++) { + out << std::setw(3) << std::setfill('0') << std::hex << bram.second.at(i); + if (i % 8 == 7) + out << std::endl; + else + out << " "; + } + out.flags(f); + out << std::endl; + } + for (const auto &tg : cc.tilegroups) { + out << ".tile_group"; + for (const auto &tile : tg.tiles) { + out << " " << tile; + } + out << std::endl; + out << tg.config; + out << std::endl; + } + return out; +} + +std::istream &operator>>(std::istream &in, ChipConfig &cc) +{ + while (!skip_check_eof(in)) { + std::string verb; + in >> verb; + if (verb == ".device") { + in >> cc.chip_name; + } else if (verb == ".comment") { + std::string line; + getline(in, line); + cc.metadata.push_back(line); + } else if (verb == ".sysconfig") { + std::string key, value; + in >> key >> value; + cc.sysconfig[key] = value; + } else if (verb == ".tile") { + std::string tilename; + in >> tilename; + TileConfig tc; + in >> tc; + cc.tiles[tilename] = tc; + } else if (verb == ".tile_group") { + TileGroup tg; + std::string line; + getline(in, line); + std::stringstream ss2(line); + + std::string tile; + while (ss2) { + ss2 >> tile; + tg.tiles.push_back(tile); + } + in >> tg.config; + cc.tilegroups.push_back(tg); + } else if (verb == ".bram_init") { + uint16_t bram; + in >> bram; + std::ios_base::fmtflags f(in.flags()); + while (!skip_check_eor(in)) { + uint16_t value; + in >> std::hex >> value; + cc.bram_data[bram].push_back(value); + } + in.flags(f); + } else { + log_error("unrecognised config entry %s\n", verb.c_str()); + } + } + return in; +} + +NEXTPNR_NAMESPACE_END diff --git a/machxo2/config.h b/machxo2/config.h new file mode 100644 index 00000000..9e09d721 --- /dev/null +++ b/machxo2/config.h @@ -0,0 +1,128 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah + * Copyright (C) 2021 William D. Jones + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef MACHXO2_CONFIG_H +#define MACHXO2_CONFIG_H + +#include +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +// This represents configuration at "FASM" level, in terms of routing arcs and non-routing configuration settings - +// either words or enums. + +// A connection in a tile +struct ConfigArc +{ + std::string sink; + std::string source; + inline bool operator==(const ConfigArc &other) const { return other.source == source && other.sink == sink; } +}; + +std::ostream &operator<<(std::ostream &out, const ConfigArc &arc); + +std::istream &operator>>(std::istream &in, ConfigArc &arc); + +// A configuration setting in a tile that takes one or more bits (such as LUT init) +struct ConfigWord +{ + std::string name; + std::vector value; + inline bool operator==(const ConfigWord &other) const { return other.name == name && other.value == value; } +}; + +std::ostream &operator<<(std::ostream &out, const ConfigWord &cw); + +std::istream &operator>>(std::istream &in, ConfigWord &cw); + +// A configuration setting in a tile that takes an enumeration value (such as IO type) +struct ConfigEnum +{ + std::string name; + std::string value; + inline bool operator==(const ConfigEnum &other) const { return other.name == name && other.value == value; } +}; + +std::ostream &operator<<(std::ostream &out, const ConfigEnum &ce); + +std::istream &operator>>(std::istream &in, ConfigEnum &ce); + +// An unknown bit, specified by position only +struct ConfigUnknown +{ + int frame, bit; + inline bool operator==(const ConfigUnknown &other) const { return other.frame == frame && other.bit == bit; } +}; + +std::ostream &operator<<(std::ostream &out, const ConfigUnknown &tc); + +std::istream &operator>>(std::istream &in, ConfigUnknown &ce); + +struct TileConfig +{ + std::vector carcs; + std::vector cwords; + std::vector cenums; + std::vector cunknowns; + int total_known_bits = 0; + + void add_arc(const std::string &sink, const std::string &source); + void add_word(const std::string &name, const std::vector &value); + void add_enum(const std::string &name, const std::string &value); + void add_unknown(int frame, int bit); + + std::string to_string() const; + static TileConfig from_string(const std::string &str); + + bool empty() const; +}; + +std::ostream &operator<<(std::ostream &out, const TileConfig &tc); + +std::istream &operator>>(std::istream &in, TileConfig &ce); + +// A group of tiles to configure at once for a particular feature that is split across tiles +// TileGroups are currently for non-routing configuration only +struct TileGroup +{ + std::vector tiles; + TileConfig config; +}; + +// This represents the configuration of a chip at a high level +class ChipConfig +{ + public: + std::string chip_name; + std::vector metadata; + std::map tiles; + std::vector tilegroups; + std::map sysconfig; + std::map> bram_data; +}; + +std::ostream &operator<<(std::ostream &out, const ChipConfig &cc); + +std::istream &operator>>(std::istream &in, ChipConfig &cc); + +NEXTPNR_NAMESPACE_END + +#endif diff --git a/machxo2/main.cc b/machxo2/main.cc index 5a5c7f82..1d393fac 100644 --- a/machxo2/main.cc +++ b/machxo2/main.cc @@ -20,6 +20,7 @@ #ifdef MAIN_EXECUTABLE #include +#include "bitstream.h" #include "command.h" #include "design_utils.h" #include "log.h" @@ -65,13 +66,20 @@ po::options_description MachXO2CommandHandler::getArchOptions() "base chip configuration in Trellis text format"); specific.add_options()("textcfg", po::value(), "textual configuration in Trellis format to write"); - specific.add_options()("lpf", po::value>(), "LPF pin constraint file(s)"); + //specific.add_options()("lpf", po::value>(), "LPF pin constraint file(s)"); specific.add_options()("no-iobs", "disable automatic IO buffer insertion (unimplemented- always enabled)"); return specific; } -void MachXO2CommandHandler::customBitstream(Context *ctx) {} +void MachXO2CommandHandler::customBitstream(Context *ctx) +{ + std::string textcfg; + if (vm.count("textcfg")) + textcfg = vm["textcfg"].as(); + + write_bitstream(ctx, textcfg); +} std::unique_ptr MachXO2CommandHandler::createContext(std::unordered_map &values) { -- cgit v1.2.3 From 695fb7e569a9b8368ecf623029997248910d753e Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 30 Jan 2021 18:06:55 -0500 Subject: machxo2: Add/fix copyright banners. --- machxo2/arch.cc | 3 ++- machxo2/arch.h | 3 ++- machxo2/archdefs.h | 3 ++- machxo2/bitstream.h | 2 +- machxo2/cells.cc | 1 + machxo2/cells.h | 1 + machxo2/main.cc | 3 ++- machxo2/pack.cc | 1 + 8 files changed, 12 insertions(+), 5 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 58c48044..4ab3dc5b 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -1,7 +1,8 @@ /* * nextpnr -- Next Generation Place and Route * - * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Claire Xen + * Copyright (C) 2021 William D. Jones * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/machxo2/arch.h b/machxo2/arch.h index 8fdb63fc..f06739e4 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -1,7 +1,8 @@ /* * nextpnr -- Next Generation Place and Route * - * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Claire Xen + * Copyright (C) 2021 William D. Jones * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h index f8fee5d7..9b62a6c3 100644 --- a/machxo2/archdefs.h +++ b/machxo2/archdefs.h @@ -1,7 +1,8 @@ /* * nextpnr -- Next Generation Place and Route * - * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Claire Xen + * Copyright (C) 2021 William D. Jones * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/machxo2/bitstream.h b/machxo2/bitstream.h index f7965c4f..e54e134a 100644 --- a/machxo2/bitstream.h +++ b/machxo2/bitstream.h @@ -2,7 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 David Shah - * Copyright (C) 2021 William D. Jones + * Copyright (C) 2021 William D. Jones * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/machxo2/cells.cc b/machxo2/cells.cc index ba4afad0..6b6aeda2 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2019 David Shah + * Copyright (C) 2021 William D. Jones * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/machxo2/cells.h b/machxo2/cells.h index f129f762..351780ec 100644 --- a/machxo2/cells.h +++ b/machxo2/cells.h @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2019 David Shah + * Copyright (C) 2021 William D. Jones * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/machxo2/main.cc b/machxo2/main.cc index 1d393fac..8dadca94 100644 --- a/machxo2/main.cc +++ b/machxo2/main.cc @@ -1,7 +1,8 @@ /* * nextpnr -- Next Generation Place and Route * - * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Claire Xen + * Copyright (C) 2021 William D. Jones * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/machxo2/pack.cc b/machxo2/pack.cc index ecf8b88d..b18bde1f 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018-19 David Shah + * Copyright (C) 2021 William D. Jones * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above -- cgit v1.2.3 From 56656b2b244127763ced9cb95332b09e1aa5ab81 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 30 Jan 2021 22:10:37 -0500 Subject: machxo2: Emit empty bitstream file. --- machxo2/bitstream.cc | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'machxo2') diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index 6e1dbb11..eec07cb1 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -18,15 +18,52 @@ * */ +#include + #include "bitstream.h" #include "config.h" NEXTPNR_NAMESPACE_BEGIN +// These seem simple enough to do inline for now. +namespace BaseConfigs { + void config_empty_lcmxo2_1200hc(ChipConfig &cc) + { + cc.chip_name = "LCMXO2-1200HC"; + + cc.tiles["EBR_R6C11:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C15:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C18:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C21:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C2:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C5:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C8:EBR1"].add_unknown(0, 12); + + cc.tiles["PT4:CFG0"].add_unknown(5, 30); + cc.tiles["PT4:CFG0"].add_unknown(5, 32); + cc.tiles["PT4:CFG0"].add_unknown(5, 36); + + cc.tiles["PT7:CFG3"].add_unknown(5, 18); + } +} // namespace BaseConfigs + void write_bitstream(Context *ctx, std::string text_config_file) { ChipConfig cc; + switch (ctx->args.type) { + case ArchArgs::LCMXO2_1200HC: + BaseConfigs::config_empty_lcmxo2_1200hc(cc); + break; + default: + NPNR_ASSERT_FALSE("Unsupported device type"); + } + + // Configure chip + if (!text_config_file.empty()) { + std::ofstream out_config(text_config_file); + out_config << cc; + } } NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From cf2db7a4c474569d372c176e9790dd4f6ae24a03 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 30 Jan 2021 22:42:16 -0500 Subject: machxo2: Write out pips to bitstream. --- machxo2/arch.cc | 27 +++++++++++++++++++++++++++ machxo2/arch.h | 15 +++++++++++++++ machxo2/bitstream.cc | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 4ab3dc5b..dbe17fd9 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -124,6 +124,33 @@ std::string Arch::getChipName() const } } +std::string Arch::getFullChipName() const +{ + std::string name = getChipName(); + name += "-"; + switch (args.speed) { + case ArchArgs::SPEED_1: + name += "1"; + break; + case ArchArgs::SPEED_2: + name += "2"; + break; + case ArchArgs::SPEED_3: + name += "3"; + case ArchArgs::SPEED_4: + name += "4"; + break; + case ArchArgs::SPEED_5: + name += "5"; + break; + case ArchArgs::SPEED_6: + name += "6"; + break; + } + name += args.package; + return name; +} + IdString Arch::archArgsToId(ArchArgs args) const { if (args.type == ArchArgs::LCMXO2_256HC) { diff --git a/machxo2/arch.h b/machxo2/arch.h index f06739e4..6cca9798 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -501,6 +501,8 @@ struct Arch : BaseCtx static bool isAvailable(ArchArgs::ArchArgsTypes chip); std::string getChipName() const; + // Extra helper + std::string getFullChipName() const; IdString archId() const { return id("machxo2"); } ArchArgs archArgs() const { return args; } @@ -882,6 +884,19 @@ struct Arch : BaseCtx return range; } + // Extra Pip helpers. + int8_t getPipClass(PipId pip) const { return tileInfo(pip)->pips_data[pip.index].pip_type; } + + std::string getPipTilename(PipId pip) const + { + auto &tileloc = chip_info->tile_info[pip.location.y * chip_info->width + pip.location.x]; + for (int i = 0; i < tileloc.num_tiles; i++) { + if (tileloc.tile_names[i].type_idx == tileInfo(pip)->pips_data[pip.index].tile_type) + return tileloc.tile_names[i].name.get(); + } + NPNR_ASSERT_FALSE("failed to find Pip tile"); + } + // Group GroupId getGroupByName(IdString name) const; IdString getGroupName(GroupId group) const; diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index eec07cb1..58f5f85e 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -22,6 +22,7 @@ #include "bitstream.h" #include "config.h" +#include "nextpnr.h" NEXTPNR_NAMESPACE_BEGIN @@ -47,6 +48,35 @@ namespace BaseConfigs { } } // namespace BaseConfigs +// Convert an absolute wire name to a relative Trellis one +static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) +{ + std::string basename = ctx->tileInfo(wire)->wire_data[wire.index].name.get(); + std::string prefix2 = basename.substr(0, 2); + if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_") + return basename; + if (loc == wire.location) + return basename; + std::string rel_prefix; + if (wire.location.y < loc.y) + rel_prefix += "N" + std::to_string(loc.y - wire.location.y); + if (wire.location.y > loc.y) + rel_prefix += "S" + std::to_string(wire.location.y - loc.y); + if (wire.location.x > loc.x) + rel_prefix += "E" + std::to_string(wire.location.x - loc.x); + if (wire.location.x < loc.x) + rel_prefix += "W" + std::to_string(loc.x - wire.location.x); + return rel_prefix + "_" + basename; +} + +static void set_pip(Context *ctx, ChipConfig &cc, PipId pip) +{ + std::string tile = ctx->getPipTilename(pip); + std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip)); + std::string sink = get_trellis_wirename(ctx, pip.location, ctx->getPipDstWire(pip)); + cc.tiles[tile].add_arc(sink, source); +} + void write_bitstream(Context *ctx, std::string text_config_file) { ChipConfig cc; @@ -59,6 +89,17 @@ void write_bitstream(Context *ctx, std::string text_config_file) NPNR_ASSERT_FALSE("Unsupported device type"); } + cc.metadata.push_back("Part: " + ctx->getFullChipName()); + + // Add all set, configurable pips to the config + for (auto pip : ctx->getPips()) { + if (ctx->getBoundPipNet(pip) != nullptr) { + if (ctx->getPipClass(pip) == 0) { // ignore fixed pips + set_pip(ctx, cc, pip); + } + } + } + // Configure chip if (!text_config_file.empty()) { std::ofstream out_config(text_config_file); -- cgit v1.2.3 From 5415194b39c0e7ade963f5c52f2977f00ed5feeb Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sat, 30 Jan 2021 23:14:48 -0500 Subject: machxo2: Checkpoint commit for slice bitstream generation. --- machxo2/arch.cc | 11 ++++++++ machxo2/arch.h | 33 ++++++++++++++++++++++ machxo2/bitstream.cc | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 121 insertions(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index dbe17fd9..101ceae7 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -518,4 +518,15 @@ void Arch::assignArchInfo() {} bool Arch::cellsCompatible(const CellInfo **cells, int count) const { return false; } +std::vector> Arch::getTilesAtLocation(int row, int col) +{ + std::vector> ret; + auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; + for (int i = 0; i < tileloc.num_tiles; i++) { + ret.push_back(std::make_pair(tileloc.tile_names[i].name.get(), + chip_info->tiletype_names[tileloc.tile_names[i].type_idx].get())); + } + return ret; +} + NEXTPNR_NAMESPACE_END diff --git a/machxo2/arch.h b/machxo2/arch.h index 6cca9798..5da12a24 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -957,6 +957,39 @@ struct Arch : BaseCtx // Internal usage void assignArchInfo(); bool cellsCompatible(const CellInfo **cells, int count) const; + + std::vector> getTilesAtLocation(int row, int col); + std::string getTileByTypeAndLocation(int row, int col, std::string type) const + { + auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; + for (int i = 0; i < tileloc.num_tiles; i++) { + if (chip_info->tiletype_names[tileloc.tile_names[i].type_idx].get() == type) + return tileloc.tile_names[i].name.get(); + } + NPNR_ASSERT_FALSE_STR("no tile at (" + std::to_string(col) + ", " + std::to_string(row) + ") with type " + + type); + } + + std::string getTileByTypeAndLocation(int row, int col, const std::set &type) const + { + auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; + for (int i = 0; i < tileloc.num_tiles; i++) { + if (type.count(chip_info->tiletype_names[tileloc.tile_names[i].type_idx].get())) + return tileloc.tile_names[i].name.get(); + } + NPNR_ASSERT_FALSE_STR("no tile at (" + std::to_string(col) + ", " + std::to_string(row) + ") with type in set"); + } + + std::string getTileByType(std::string type) const + { + for (int i = 0; i < chip_info->height * chip_info->width; i++) { + auto &tileloc = chip_info->tile_info[i]; + for (int j = 0; j < tileloc.num_tiles; j++) + if (chip_info->tiletype_names[tileloc.tile_names[j].type_idx].get() == type) + return tileloc.tile_names[j].name.get(); + } + NPNR_ASSERT_FALSE_STR("no tile with type " + type); + } }; NEXTPNR_NAMESPACE_END diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index 58f5f85e..419b8f07 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -23,6 +23,7 @@ #include "bitstream.h" #include "config.h" #include "nextpnr.h" +#include "util.h" NEXTPNR_NAMESPACE_BEGIN @@ -53,7 +54,8 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) { std::string basename = ctx->tileInfo(wire)->wire_data[wire.index].name.get(); std::string prefix2 = basename.substr(0, 2); - if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_") + std::string prefix7 = basename.substr(0, 7); + if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_" || prefix2 == "U_" || prefix2 == "D_" || prefix7 == "BRANCH_") return basename; if (loc == wire.location) return basename; @@ -77,6 +79,43 @@ static void set_pip(Context *ctx, ChipConfig &cc, PipId pip) cc.tiles[tile].add_arc(sink, source); } +static std::vector int_to_bitvector(int val, int size) +{ + std::vector bv; + for (int i = 0; i < size; i++) { + bv.push_back((val & (1 << i)) != 0); + } + return bv; +} + +static std::vector str_to_bitvector(std::string str, int size) +{ + std::vector bv; + bv.resize(size, 0); + if (str.substr(0, 2) != "0b") + log_error("error parsing value '%s', expected 0b prefix\n", str.c_str()); + for (int i = 0; i < int(str.size()) - 2; i++) { + char c = str.at((str.size() - i) - 1); + NPNR_ASSERT(c == '0' || c == '1'); + bv.at(i) = (c == '1'); + } + return bv; +} + +std::string intstr_or_default(const std::unordered_map &ct, const IdString &key, + std::string def = "0") +{ + auto found = ct.find(key); + if (found == ct.end()) + return def; + else { + if (found->second.is_string) + return found->second.as_string(); + else + return std::to_string(found->second.as_int64()); + } +}; + void write_bitstream(Context *ctx, std::string text_config_file) { ChipConfig cc; @@ -100,6 +139,43 @@ void write_bitstream(Context *ctx, std::string text_config_file) } } + // TODO: Bank Voltages + + // Configure slices + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); + if (ci->bel == BelId()) { + log_warning("found unplaced cell '%s' during bitstream gen\n", ci->name.c_str(ctx)); + } + BelId bel = ci->bel; + if (ci->type == id_FACADE_SLICE) { + std::string tname = ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, "PLC"); + std::string slice = ctx->tileInfo(bel)->bel_data[bel.index].name.get(); + + NPNR_ASSERT(slice.substr(0, 5) == "SLICE"); + int int_index = slice[5] - 'A'; + NPNR_ASSERT(int_index >= 0 && int_index < 4); + + int lut0_init = int_or_default(ci->params, ctx->id("LUT0_INITVAL")); + int lut1_init = int_or_default(ci->params, ctx->id("LUT1_INITVAL")); + cc.tiles[tname].add_word(slice + ".K0.INIT", int_to_bitvector(lut0_init, 16)); + cc.tiles[tname].add_word(slice + ".K1.INIT", int_to_bitvector(lut1_init, 16)); + cc.tiles[tname].add_enum(slice + ".MODE", str_or_default(ci->params, ctx->id("MODE"), "LOGIC")); + cc.tiles[tname].add_enum(slice + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "ENABLED")); + cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".SRMODE", str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE")); + cc.tiles[tname].add_enum(slice + ".CEMUX", intstr_or_default(ci->params, ctx->id("CEMUX"), "1")); + cc.tiles[tname].add_enum("CLK" + std::to_string(int_index) + ".CLKMUX", intstr_or_default(ci->params, ctx->id("CLKMUX"), "0")); + cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRMUX", str_or_default(ci->params, ctx->id("LSRMUX"), "LSR")); + cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRONMUX", intstr_or_default(ci->params, ctx->id("LSRONMUX"), "LSRMUX")); + cc.tiles[tname].add_enum(slice + ".REG0.SD", intstr_or_default(ci->params, ctx->id("REG0_SD"), "0")); + cc.tiles[tname].add_enum(slice + ".REG1.SD", intstr_or_default(ci->params, ctx->id("REG1_SD"), "0")); + cc.tiles[tname].add_enum(slice + ".REG0.REGSET", + str_or_default(ci->params, ctx->id("REG0_REGSET"), "RESET")); + cc.tiles[tname].add_enum(slice + ".REG1.REGSET", + str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET")); + } + } + // Configure chip if (!text_config_file.empty()) { std::ofstream out_config(text_config_file); -- cgit v1.2.3 From d485dc6ef684c3ad469614036f1f343064a378da Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 31 Jan 2021 00:05:41 -0500 Subject: machxo2: Add REGMODE to bitstream output. --- machxo2/bitstream.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'machxo2') diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index 419b8f07..1502166a 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -167,6 +167,7 @@ void write_bitstream(Context *ctx, std::string text_config_file) cc.tiles[tname].add_enum("CLK" + std::to_string(int_index) + ".CLKMUX", intstr_or_default(ci->params, ctx->id("CLKMUX"), "0")); cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRMUX", str_or_default(ci->params, ctx->id("LSRMUX"), "LSR")); cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRONMUX", intstr_or_default(ci->params, ctx->id("LSRONMUX"), "LSRMUX")); + cc.tiles[tname].add_enum(slice + ".REGMODE", str_or_default(ci->params, ctx->id("REGMODE"), "FF")); cc.tiles[tname].add_enum(slice + ".REG0.SD", intstr_or_default(ci->params, ctx->id("REG0_SD"), "0")); cc.tiles[tname].add_enum(slice + ".REG1.SD", intstr_or_default(ci->params, ctx->id("REG1_SD"), "0")); cc.tiles[tname].add_enum(slice + ".REG0.REGSET", -- cgit v1.2.3 From 884e7d9a9820a5eaff000a3ee8a5d56d1e15d50b Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 31 Jan 2021 00:36:19 -0500 Subject: machxo2: Add basic bitstream generation for PIC tiles and I/O. --- machxo2/bitstream.cc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'machxo2') diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index 1502166a..450ab140 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -116,6 +116,26 @@ std::string intstr_or_default(const std::unordered_map &ct, } }; +// Get the PIC tile corresponding to a PIO bel +static std::string get_pic_tile(Context *ctx, BelId bel) +{ + static const std::set pio_l = {"PIC_L0", "PIC_LS0", "PIC_L0_VREF3"}; + static const std::set pio_r = {"PIC_R0", "PIC_RS0"}; + + std::string pio_name = ctx->tileInfo(bel)->bel_data[bel.index].name.get(); + if (bel.location.y == 0) { + return ctx->getTileByTypeAndLocation(0, bel.location.x, "PIC_T0"); + } else if (bel.location.y == ctx->chip_info->height - 1) { + return ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, "PIC_B0"); + } else if (bel.location.x == 0) { + return ctx->getTileByTypeAndLocation(bel.location.y, 0, pio_l); + } else if (bel.location.x == ctx->chip_info->width - 1) { + return ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, pio_r); + } else { + NPNR_ASSERT_FALSE("bad PIO location"); + } +} + void write_bitstream(Context *ctx, std::string text_config_file) { ChipConfig cc; @@ -174,6 +194,12 @@ void write_bitstream(Context *ctx, std::string text_config_file) str_or_default(ci->params, ctx->id("REG0_REGSET"), "RESET")); cc.tiles[tname].add_enum(slice + ".REG1.REGSET", str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET")); + } else if (ci->type == ctx->id("FACADE_IO")) { + std::string pio = ctx->tileInfo(bel)->bel_data[bel.index].name.get(); + std::string iotype = str_or_default(ci->attrs, ctx->id("IO_TYPE"), "LVCMOS33"); + std::string dir = str_or_default(ci->params, ctx->id("DIR"), "INPUT"); + std::string pic_tile = get_pic_tile(ctx, bel); + cc.tiles[pic_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype); } } -- cgit v1.2.3 From 0d00c10e2f3dfdc188f598e17c8aa89a9c502f55 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 31 Jan 2021 00:45:08 -0500 Subject: machxo2: Add bitstream generation for OSCH. --- machxo2/bitstream.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'machxo2') diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index 450ab140..23cc1b8c 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -200,6 +200,10 @@ void write_bitstream(Context *ctx, std::string text_config_file) std::string dir = str_or_default(ci->params, ctx->id("DIR"), "INPUT"); std::string pic_tile = get_pic_tile(ctx, bel); cc.tiles[pic_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype); + } else if (ci->type == ctx->id("OSCH")) { + std::string freq = str_or_default(ci->params, ctx->id("NOM_FREQ"), "2.08"); + cc.tiles[ctx->getTileByType("CFG1")].add_enum("OSCH.MODE", "OSCH"); + cc.tiles[ctx->getTileByType("CFG1")].add_enum("OSCH.NOM_FREQ", freq); } } -- cgit v1.2.3 From 2c9d4ba9ae8123e6aea2a690ec03b052ea7a53af Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 31 Jan 2021 19:05:36 -0500 Subject: machxo2: Fix reversed interpretation of REG_SD config bits. --- machxo2/cells.cc | 6 ------ 1 file changed, 6 deletions(-) (limited to 'machxo2') diff --git a/machxo2/cells.cc b/machxo2/cells.cc index 6b6aeda2..dd673c38 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -157,12 +157,6 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) { - // By this point, we have shown that LUT4 Z is attached to FACADE_FF DI. - // This connection will be preserved by port replacement, but the SD mux - // which selects the actual DFF input needs to be told to use the - // FACADE_SLICE DI input instead of the FACADE_SLICE M input. - lc->params[ctx->id("REG0_SD")] = std::string("0"); - // FIXME: This will have to change once we support FFs with reset value of 1. lc->params[ctx->id("REG0_REGSET")] = std::string("RESET"); -- cgit v1.2.3 From 0250aaaddd499bce9a6739823f5511859ec57232 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 31 Jan 2021 19:27:32 -0500 Subject: machxo2: clang format. --- machxo2/arch.h | 3 ++- machxo2/bitstream.cc | 51 ++++++++++++++++++++++++++++----------------------- machxo2/main.cc | 2 +- machxo2/pack.cc | 7 +++---- 4 files changed, 34 insertions(+), 29 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.h b/machxo2/arch.h index 5da12a24..439d54a5 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -629,7 +629,8 @@ struct Arch : BaseCtx { NPNR_ASSERT(wire != WireId()); std::stringstream name; - name << "X" << wire.location.x << "/Y" << wire.location.y << "/" << tileInfo(wire)->wire_data[wire.index].name.get(); + name << "X" << wire.location.x << "/Y" << wire.location.y << "/" + << tileInfo(wire)->wire_data[wire.index].name.get(); return id(name.str()); } diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index 23cc1b8c..6f37e66b 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -29,24 +29,24 @@ NEXTPNR_NAMESPACE_BEGIN // These seem simple enough to do inline for now. namespace BaseConfigs { - void config_empty_lcmxo2_1200hc(ChipConfig &cc) - { - cc.chip_name = "LCMXO2-1200HC"; - - cc.tiles["EBR_R6C11:EBR1"].add_unknown(0, 12); - cc.tiles["EBR_R6C15:EBR1"].add_unknown(0, 12); - cc.tiles["EBR_R6C18:EBR1"].add_unknown(0, 12); - cc.tiles["EBR_R6C21:EBR1"].add_unknown(0, 12); - cc.tiles["EBR_R6C2:EBR1"].add_unknown(0, 12); - cc.tiles["EBR_R6C5:EBR1"].add_unknown(0, 12); - cc.tiles["EBR_R6C8:EBR1"].add_unknown(0, 12); - - cc.tiles["PT4:CFG0"].add_unknown(5, 30); - cc.tiles["PT4:CFG0"].add_unknown(5, 32); - cc.tiles["PT4:CFG0"].add_unknown(5, 36); - - cc.tiles["PT7:CFG3"].add_unknown(5, 18); - } +void config_empty_lcmxo2_1200hc(ChipConfig &cc) +{ + cc.chip_name = "LCMXO2-1200HC"; + + cc.tiles["EBR_R6C11:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C15:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C18:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C21:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C2:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C5:EBR1"].add_unknown(0, 12); + cc.tiles["EBR_R6C8:EBR1"].add_unknown(0, 12); + + cc.tiles["PT4:CFG0"].add_unknown(5, 30); + cc.tiles["PT4:CFG0"].add_unknown(5, 32); + cc.tiles["PT4:CFG0"].add_unknown(5, 36); + + cc.tiles["PT7:CFG3"].add_unknown(5, 18); +} } // namespace BaseConfigs // Convert an absolute wire name to a relative Trellis one @@ -55,7 +55,8 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) std::string basename = ctx->tileInfo(wire)->wire_data[wire.index].name.get(); std::string prefix2 = basename.substr(0, 2); std::string prefix7 = basename.substr(0, 7); - if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_" || prefix2 == "U_" || prefix2 == "D_" || prefix7 == "BRANCH_") + if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_" || prefix2 == "U_" || prefix2 == "D_" || + prefix7 == "BRANCH_") return basename; if (loc == wire.location) return basename; @@ -182,11 +183,15 @@ void write_bitstream(Context *ctx, std::string text_config_file) cc.tiles[tname].add_word(slice + ".K1.INIT", int_to_bitvector(lut1_init, 16)); cc.tiles[tname].add_enum(slice + ".MODE", str_or_default(ci->params, ctx->id("MODE"), "LOGIC")); cc.tiles[tname].add_enum(slice + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "ENABLED")); - cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".SRMODE", str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE")); + cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".SRMODE", + str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE")); cc.tiles[tname].add_enum(slice + ".CEMUX", intstr_or_default(ci->params, ctx->id("CEMUX"), "1")); - cc.tiles[tname].add_enum("CLK" + std::to_string(int_index) + ".CLKMUX", intstr_or_default(ci->params, ctx->id("CLKMUX"), "0")); - cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRMUX", str_or_default(ci->params, ctx->id("LSRMUX"), "LSR")); - cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRONMUX", intstr_or_default(ci->params, ctx->id("LSRONMUX"), "LSRMUX")); + cc.tiles[tname].add_enum("CLK" + std::to_string(int_index) + ".CLKMUX", + intstr_or_default(ci->params, ctx->id("CLKMUX"), "0")); + cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRMUX", + str_or_default(ci->params, ctx->id("LSRMUX"), "LSR")); + cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRONMUX", + intstr_or_default(ci->params, ctx->id("LSRONMUX"), "LSRMUX")); cc.tiles[tname].add_enum(slice + ".REGMODE", str_or_default(ci->params, ctx->id("REGMODE"), "FF")); cc.tiles[tname].add_enum(slice + ".REG0.SD", intstr_or_default(ci->params, ctx->id("REG0_SD"), "0")); cc.tiles[tname].add_enum(slice + ".REG1.SD", intstr_or_default(ci->params, ctx->id("REG1_SD"), "0")); diff --git a/machxo2/main.cc b/machxo2/main.cc index 8dadca94..3d0884bf 100644 --- a/machxo2/main.cc +++ b/machxo2/main.cc @@ -67,7 +67,7 @@ po::options_description MachXO2CommandHandler::getArchOptions() "base chip configuration in Trellis text format"); specific.add_options()("textcfg", po::value(), "textual configuration in Trellis format to write"); - //specific.add_options()("lpf", po::value>(), "LPF pin constraint file(s)"); + // specific.add_options()("lpf", po::value>(), "LPF pin constraint file(s)"); specific.add_options()("no-iobs", "disable automatic IO buffer insertion (unimplemented- always enabled)"); return specific; diff --git a/machxo2/pack.cc b/machxo2/pack.cc index b18bde1f..d7d40d5d 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -176,7 +176,7 @@ static void pack_io(Context *ctx) for (auto &p : ci->ports) disconnect_port(ctx, ci, p.first); packed_cells.insert(ci->name); - } else if(is_facade_iob(ctx, ci)) { + } 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 @@ -185,10 +185,9 @@ static void pack_io(Context *ctx) auto loc_attr_cell = ci->attrs.find(ctx->id("LOC")); auto bel_attr_cell = ci->attrs.find(ctx->id("BEL")); - if(loc_attr_cell != ci->attrs.end()) { + if (loc_attr_cell != ci->attrs.end()) { if (bel_attr_cell != ci->attrs.end()) { - log_error("IO buffer %s has both a BEL attribute and LOC attribute.\n", - ci->name.c_str(ctx)); + log_error("IO buffer %s has both a BEL attribute and LOC attribute.\n", ci->name.c_str(ctx)); } log_info("found LOC attribute on IO buffer %s.\n", ci->name.c_str(ctx)); -- cgit v1.2.3 From d0b822c0365c52a8a8439094f2268cfa0c461b5e Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 31 Jan 2021 22:42:15 -0500 Subject: machxo2: Add demo.sh TinyFPGA Ax example. --- machxo2/examples/.gitignore | 2 ++ machxo2/examples/README.md | 11 ++++++++++- machxo2/examples/demo.sh | 10 ++++++++++ machxo2/examples/tinyfpga.v | 28 ++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 machxo2/examples/demo.sh create mode 100644 machxo2/examples/tinyfpga.v (limited to 'machxo2') diff --git a/machxo2/examples/.gitignore b/machxo2/examples/.gitignore index 87d5128b..91167252 100644 --- a/machxo2/examples/.gitignore +++ b/machxo2/examples/.gitignore @@ -7,3 +7,5 @@ pack*.v place*.v pnr*.v abc.history +/tinyfpga.txt +/tinyfpga.bit diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index e940c01c..bcffeea3 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -18,11 +18,16 @@ This contains a simple example of running `nextpnr-machxo2`: All possible inputs and resulting outputs can be tested in reasonable time by using `yosys`' built-in SAT solver or [`z3`](https://github.com/Z3Prover/z3), an external SMT solver. +* `demo.sh` creates a blinky bitstream for [TinyFPGA Ax](https://tinyfpga.com/a-series-guide.html) + and writes the resulting bitstream to MachXO2's internal flash using + [`tinyproga`](https://github.com/tinyfpga/TinyFPGA-A-Programmer). As `nextpnr-machxo2` is developed the contents `simple.sh`, `simtest.sh`, and `mitertest.sh` are subject to change. ## How To Run +The following applies to all `sh` scripts except `demo.sh`, which requires no +arguments. Each `sh` script runs yosys and nextpnr to validate a blinky design in various ways. The `mode` argument to each script- `pack`, `place`, or `pnr`- stop @@ -37,7 +42,8 @@ SMT solver. To keep file count lower, all yosys scripts are written inline inside the `sh` scripts using the `-p` option. -To clean output files, run: `rm -rf *.dot *.json *.png *.vcd *.smt2 *.log {pack,place,pnr}*.v blinky_simtest*` +### Clean +To clean output files from _all_ scripts, run: `rm -rf *.dot *.json *.png *.vcd *.smt2 *.log tinyfpga.txt tinyfpga.bit {pack,place,pnr}*.v blinky_simtest*` ## Environment Variables For Scripts @@ -53,3 +59,6 @@ To clean output files, run: `rm -rf *.dot *.json *.png *.vcd *.smt2 *.log {pack, returns. You may want to set this to `/path/to/yosys/src/share/machxo2/cells_sim.v` if doing development; `yosys-config` cannot find these "before-installation" simulation models. +* `TRELLIS_DB`- Set to the location of the Project Trellis database to use. + Defaults to nothing, which means `ecppack` will use whatever database is on + its path. diff --git a/machxo2/examples/demo.sh b/machxo2/examples/demo.sh new file mode 100644 index 00000000..6979f111 --- /dev/null +++ b/machxo2/examples/demo.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +if [ ! -z ${TRELLIS_DB+x} ]; then + DB_ARG="--db $TRELLIS_DB" +fi + +${YOSYS:-yosys} -p 'synth_machxo2 -json tinyfpga.json' tinyfpga.v +${NEXTPNR:-../../nextpnr-machxo2} --1200 --package QFN32 --no-iobs --json tinyfpga.json --textcfg tinyfpga.txt +ecppack --compress $DB_ARG tinyfpga.txt tinyfpga.bit +tinyproga -b tinyfpga.bit diff --git a/machxo2/examples/tinyfpga.v b/machxo2/examples/tinyfpga.v new file mode 100644 index 00000000..dfc2710d --- /dev/null +++ b/machxo2/examples/tinyfpga.v @@ -0,0 +1,28 @@ +// Modified from: +// https://github.com/tinyfpga/TinyFPGA-A-Series/tree/master/template_a2 +// https://tinyfpga.com/a-series-guide.html used as a basis. + +module TinyFPGA_A2 ( + (* LOC="13" *) + inout pin1 +); + + + wire clk; + + OSCH #( + .NOM_FREQ("16.63") + ) internal_oscillator_inst ( + .STDBY(1'b0), + .OSC(clk) + ); + + reg [23:0] led_timer; + + always @(posedge clk) begin + led_timer <= led_timer + 1; + end + + // left side of board + assign pin1 = led_timer[23]; +endmodule -- cgit v1.2.3 From c9487293e9e85a34879a3e5a45b637c7f24e5584 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 31 Jan 2021 23:29:04 -0500 Subject: machxo2: Fix REGMODE identifier (per slice, not per-FF). --- machxo2/cells.cc | 3 +-- machxo2/constids.inc | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'machxo2') diff --git a/machxo2/cells.cc b/machxo2/cells.cc index dd673c38..20e68ab5 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -59,12 +59,11 @@ std::unique_ptr create_machxo2_cell(Context *ctx, IdString type, std:: new_cell->params[id_LSRONMUX] = std::string("LSRMUX"); new_cell->params[id_LUT0_INITVAL] = Property(0xFFFF, 16); new_cell->params[id_LUT1_INITVAL] = Property(0xFFFF, 16); + new_cell->params[id_REGMODE] = std::string("FF"); new_cell->params[id_REG0_SD] = std::string("1"); new_cell->params[id_REG1_SD] = std::string("1"); new_cell->params[id_REG0_REGSET] = std::string("SET"); new_cell->params[id_REG1_REGSET] = std::string("SET"); - new_cell->params[id_REG0_REGMODE] = std::string("FF"); - new_cell->params[id_REG1_REGMODE] = std::string("FF"); new_cell->params[id_CCU2_INJECT1_0] = std::string("YES"); new_cell->params[id_CCU2_INJECT1_1] = std::string("YES"); new_cell->params[id_WREMUX] = std::string("INV"); diff --git a/machxo2/constids.inc b/machxo2/constids.inc index b60cfe54..b2ff51ae 100644 --- a/machxo2/constids.inc +++ b/machxo2/constids.inc @@ -50,12 +50,11 @@ X(LSRMUX) X(LSRONMUX) X(LUT0_INITVAL) X(LUT1_INITVAL) +X(REGMODE) X(REG0_SD) X(REG1_SD) X(REG0_REGSET) X(REG1_REGSET) -X(REG0_REGMODE) -X(REG1_REGMODE) X(CCU2_INJECT1_0) X(CCU2_INJECT1_1) X(WREMUX) @@ -66,7 +65,6 @@ X(DI) X(Q) X(REGSET) -X(REGMODE) X(FACADE_IO) -- cgit v1.2.3 From 07bc6bac53038879c446478d58fb07024a166260 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 1 Feb 2021 02:56:39 -0500 Subject: machxo2: Fail CMake configuration is BUILD_PYTHON is ON (not supported for now). --- machxo2/family.cmake | 3 +++ 1 file changed, 3 insertions(+) (limited to 'machxo2') diff --git a/machxo2/family.cmake b/machxo2/family.cmake index f19ebc70..b898e396 100644 --- a/machxo2/family.cmake +++ b/machxo2/family.cmake @@ -1,6 +1,9 @@ if (BUILD_GUI) message(FATAL_ERROR "GUI support is not implemented for MachXO2. Build with -DBUILD_GUI=OFF.") endif() +if (BUILD_PYTHON) + message(FATAL_ERROR "Python support is not implemented for MachXO2. Build with -DBUILD_PYTHON=OFF.") +endif() add_subdirectory(${family}) message(STATUS "Using MachXO2 chipdb: ${MACHXO2_CHIPDB}") -- cgit v1.2.3 From 8629d7b69285556cbf4edcb51916b5fb67693c02 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 1 Feb 2021 03:39:13 -0500 Subject: machxo2: Add quickstart README.md. --- machxo2/README.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 machxo2/README.md (limited to 'machxo2') diff --git a/machxo2/README.md b/machxo2/README.md new file mode 100644 index 00000000..1c728722 --- /dev/null +++ b/machxo2/README.md @@ -0,0 +1,73 @@ +# `nextpnr-machxo2` + +To be filled in w/ details later. + +## Quick Start + +The following commands are known to work on a near-fresh Linux Mint system +(thank you [securelyfitz](https://twitter.com/securelyfitz)!): + +### Prerequisites + +``` +sudo apt install cmake clang-format libboost-all-dev build-essential +qt5-default libeigen3-dev build-essential clang bison flex libreadline-dev +gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 +libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev +python3-setuptools python3-serial +``` + +### Installation + +Use an empty directory to hold all the cloned repositories. + +``` +git clone git@github.com:cr1901/prjtrellis.git +cd prjtrellis +git checkout facade +git submodule update --init --recursive +cd libtrellis +cmake -DCMAKE_INSTALL_PREFIX=/usr +make -j 8 +sudo make install + +cd ../../ + +git clone git@github.com:cr1901/yosys.git +cd yosys/ +git checkout machxo2 +make config-gcc +make +sudo make install + +cd ../ + +git clone git@github.com:tinyfpga/TinyFPGA-A-Programmer.git +cd TinyFPGA-A-Programmer/ +sudo python setup.py install + +cd ../ + +git clone git@github.com:cr1901/nextpnr.git +cd nextpnr +git checkout machxo2 +git submodule update --init --recursive +cmake . -DARCH=machxo2 -DBUILD_GUI=OFF -DTRELLIS_INSTALL_PREFIX=/usr -DBUILD_PYTHON=OFF -DBUILD_HEAP=OFF +make +``` + +### Demo + +If you have a [TinyFPGA Ax2](https://store.tinyfpga.com/products/tinyfpga-a2) board +with the [TinyFPGA Programmer](https://store.tinyfpga.com/products/tinyfpga-programmer), +the following script will build a blinky bitstream and load it onto the +MachXO2; the gateware will flash the LED! + +``` +cd machxo2/examples/ +sh demo.sh +``` + +The `tinyfpga.v` code used in `demo.sh` is slightly modified from the +[user's guide](https://tinyfpga.com/a-series-guide.html) to accommodate +`(* LOC = "pin" *)` constraints. -- cgit v1.2.3 From da1b15d6f5a80653f7de848532227bfa58191998 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Tue, 2 Feb 2021 01:41:44 -0500 Subject: machxo2: Special-case left and right I/O wire names in ASCII generation. --- machxo2/bitstream.cc | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index 6f37e66b..a499d8a3 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -55,11 +55,45 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) std::string basename = ctx->tileInfo(wire)->wire_data[wire.index].name.get(); std::string prefix2 = basename.substr(0, 2); std::string prefix7 = basename.substr(0, 7); + int max_col = ctx->chip_info->width - 1; + + // Handle MachXO2's wonderful naming quirks for wires in left/right tiles, whose + // relative coords push them outside the bounds of the chip. + auto is_pio_wire = [](std::string name) { + return ( + name.find("DI") != std::string::npos || + name.find("JDI") != std::string::npos || + name.find("PADD") != std::string::npos || + name.find("INDD") != std::string::npos || + name.find("IOLDO") != std::string::npos || + name.find("IOLTO") != std::string::npos || + name.find("JCE") != std::string::npos || + name.find("JCLK") != std::string::npos || + name.find("JLSR") != std::string::npos || + name.find("JONEG") != std::string::npos || + name.find("JOPOS") != std::string::npos || + name.find("JTS") != std::string::npos || + name.find("JIN") != std::string::npos || + name.find("JIP") != std::string::npos || + // Connections to global mux + name.find("JINCK") != std::string::npos + ); + }; + if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_" || prefix2 == "U_" || prefix2 == "D_" || prefix7 == "BRANCH_") return basename; - if (loc == wire.location) + if (loc == wire.location) { + // TODO: JINCK is not currently handled by this. + if(is_pio_wire(basename)) { + if(wire.location.x == 0) + return "W1_" + basename; + else if(wire.location.x == max_col) + return "E1_" + basename; + } return basename; + } + std::string rel_prefix; if (wire.location.y < loc.y) rel_prefix += "N" + std::to_string(loc.y - wire.location.y); -- cgit v1.2.3 From f18df5ed59f7c119fba8cdd264d329e5ea8fd9b6 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Tue, 2 Feb 2021 03:37:04 -0500 Subject: machxo2: Don't write out config bits for cells without location info. --- machxo2/bitstream.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index a499d8a3..a095333a 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -200,7 +200,8 @@ void write_bitstream(Context *ctx, std::string text_config_file) for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); if (ci->bel == BelId()) { - log_warning("found unplaced cell '%s' during bitstream gen\n", ci->name.c_str(ctx)); + log_warning("found unplaced cell '%s' during bitstream gen. Not writing to bitstream.\n", ci->name.c_str(ctx)); + continue; } BelId bel = ci->bel; if (ci->type == id_FACADE_SLICE) { -- cgit v1.2.3 From 3ab300a28e9fcfbc7c2d35424eab849da0d4b866 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Tue, 2 Feb 2021 03:37:28 -0500 Subject: machxo2: Add additional packing phase to pack remaining FFs. --- machxo2/pack.cc | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'machxo2') diff --git a/machxo2/pack.cc b/machxo2/pack.cc index d7d40d5d..47f8c907 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -86,6 +86,43 @@ static void pack_lut_lutffs(Context *ctx) } } +static void pack_remaining_ffs(Context *ctx) +{ + log_info("Packing remaining FFs..\n"); + + std::unordered_set packed_cells; + std::vector> new_cells; + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + + if (is_ff(ctx, ci)) { + 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 packed = create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC"); + std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); + + auto dff_bel = ci->attrs.find(ctx->id("BEL")); + dff_to_lc(ctx, ci, packed.get(), false); + if (dff_bel != ci->attrs.end()) + packed->attrs[ctx->id("BEL")] = dff_bel->second; + packed_cells.insert(ci->name); + if (ctx->verbose) + log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); + + new_cells.push_back(std::move(packed)); + } + } + + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + // Merge a net into a constant net static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval) { @@ -220,6 +257,7 @@ bool Arch::pack() pack_constants(ctx); pack_io(ctx); pack_lut_lutffs(ctx); + pack_remaining_ffs(ctx); ctx->settings[ctx->id("pack")] = 1; ctx->assignArchInfo(); log_info("Checksum: 0x%08x\n", ctx->checksum()); -- cgit v1.2.3 From 086bca18b828488cab4f2a825cffa34812ab8c8f Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Tue, 2 Feb 2021 09:55:42 -0500 Subject: machxo2: Add packing logic to handle FFs fed with constant value; UART test core routes. --- machxo2/cells.cc | 13 +++++++++++-- machxo2/cells.h | 2 +- machxo2/pack.cc | 29 +++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 5 deletions(-) (limited to 'machxo2') diff --git a/machxo2/cells.cc b/machxo2/cells.cc index 20e68ab5..7d15b1af 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -154,15 +154,24 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) replace_port(lut, ctx->id("Z"), lc, ctx->id("F0")); } -void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) +void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) { // FIXME: This will have to change once we support FFs with reset value of 1. lc->params[ctx->id("REG0_REGSET")] = std::string("RESET"); replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK")); - replace_port(dff, ctx->id("DI"), lc, ctx->id("DI0")); replace_port(dff, ctx->id("LSR"), lc, ctx->id("LSR")); replace_port(dff, ctx->id("Q"), lc, ctx->id("Q0")); + + // If a register's DI port is fed by a constant, options for placing are + // limited. Use the LUT to get around this. + if(pass_thru_lut) { + lc->params[ctx->id("LUT0_INITVAL")] = 0xAAAA; + replace_port(dff, ctx->id("DI"), lc, ctx->id("A0")); + connect_ports(ctx, lc, ctx->id("F0"), lc, ctx->id("DI0")); + } else { + replace_port(dff, ctx->id("DI"), lc, ctx->id("DI0")); + } } void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set &todelete_cells) {} diff --git a/machxo2/cells.h b/machxo2/cells.h index 351780ec..a6de219e 100644 --- a/machxo2/cells.h +++ b/machxo2/cells.h @@ -46,7 +46,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff = tr // and reconnecting signals as necessary. If pass_thru_lut is True, the LUT will // be configured as pass through and D connected to I0, otherwise D will be // ignored -void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false); +void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false); // Convert a nextpnr IO buffer to a GENERIC_IOB void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set &todelete_cells); diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 47f8c907..786a84d6 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -124,10 +124,13 @@ static void pack_remaining_ffs(Context *ctx) } // Merge a net into a constant net -static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval) +static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval) { (void)constval; + std::unordered_set packed_cells; + std::vector> new_cells; + orig->driver.cell = nullptr; for (auto user : orig->users) { if (user.cell != nullptr) { @@ -135,11 +138,33 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constne if (ctx->verbose) log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx)); - uc->ports[user.port].net = constnet; + 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)); + + std::unique_ptr lc = create_machxo2_cell(ctx, id_FACADE_SLICE, uc->name.str(ctx) + "_CONST"); + dff_to_lc(ctx, uc, lc.get(), true); + packed_cells.insert(uc->name); + + lc->ports[id_A0].net = constnet; + user.cell = lc.get(); + user.port = id_A0; + + new_cells.push_back(std::move(lc)); + } else { + uc->ports[user.port].net = constnet; + } + constnet->users.push_back(user); } } orig->users.clear(); + + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } } // Pack constants (based on simple implementation in generic). -- cgit v1.2.3 From 4948e8d914ec5d77777d197d7b2138cba933d33e Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Sun, 7 Feb 2021 22:06:23 -0500 Subject: machxo2: Fix packing when FF is driven by a constant; UART test core working on silicon, fails post-synth sim. --- machxo2/cells.cc | 2 +- machxo2/pack.cc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/cells.cc b/machxo2/cells.cc index 7d15b1af..5dea36e2 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -166,7 +166,7 @@ void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) // If a register's DI port is fed by a constant, options for placing are // limited. Use the LUT to get around this. if(pass_thru_lut) { - lc->params[ctx->id("LUT0_INITVAL")] = 0xAAAA; + lc->params[ctx->id("LUT0_INITVAL")] = Property(0xAAAA, 16);; replace_port(dff, ctx->id("DI"), lc, ctx->id("A0")); connect_ports(ctx, lc, ctx->id("F0"), lc, ctx->id("DI0")); } else { diff --git a/machxo2/pack.cc b/machxo2/pack.cc index 786a84d6..c745a1c0 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -142,6 +142,8 @@ static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, boo log_info("FACADE_FF %s is driven by a constant\n", uc->name.c_str(ctx)); std::unique_ptr lc = create_machxo2_cell(ctx, id_FACADE_SLICE, uc->name.str(ctx) + "_CONST"); + std::copy(uc->attrs.begin(), uc->attrs.end(), std::inserter(lc->attrs, lc->attrs.begin())); + dff_to_lc(ctx, uc, lc.get(), true); packed_cells.insert(uc->name); -- cgit v1.2.3 From b9eb443e549ab8c81e0c6bc94538f9f2fe2821d4 Mon Sep 17 00:00:00 2001 From: mtnrbq Date: Thu, 4 Feb 2021 07:31:14 +1100 Subject: Add demo with RGB LED --- machxo2/examples/demorgb.sh | 10 ++++++++++ machxo2/examples/rgbcount.v | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 machxo2/examples/demorgb.sh create mode 100644 machxo2/examples/rgbcount.v (limited to 'machxo2') diff --git a/machxo2/examples/demorgb.sh b/machxo2/examples/demorgb.sh new file mode 100644 index 00000000..f68db8c3 --- /dev/null +++ b/machxo2/examples/demorgb.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +if [ ! -z ${TRELLIS_DB+x} ]; then + DB_ARG="--db $TRELLIS_DB" +fi + +${YOSYS:-yosys} -p 'synth_machxo2 -json rgbcount.json' rgbcount.v +${NEXTPNR:-../../nextpnr-machxo2} --1200 --package QFN32 --no-iobs --json rgbcount.json --textcfg rgbcount.txt +ecppack --compress $DB_ARG rgbcount.txt rgbcount.bit +tinyproga -b rgbcount.bit diff --git a/machxo2/examples/rgbcount.v b/machxo2/examples/rgbcount.v new file mode 100644 index 00000000..230fc73c --- /dev/null +++ b/machxo2/examples/rgbcount.v @@ -0,0 +1,33 @@ +// Modified from: +// https://github.com/tinyfpga/TinyFPGA-A-Series/tree/master/template_a2 +// https://tinyfpga.com/a-series-guide.html used as a basis. + +module TinyFPGA_A2 ( + (* LOC="21" *) + inout pin6, + (* LOC="26" *) + inout pin9_jtgnb, + (* LOC="27" *) + inout pin10_sda, +); + wire clk; + + OSCH #( + .NOM_FREQ("2.08") + ) internal_oscillator_inst ( + .STDBY(1'b0), + .OSC(clk) + ); + + reg [23:0] led_timer; + + always @(posedge clk) begin + led_timer <= led_timer + 1; + end + + // left side of board + assign pin9_jtgnb = led_timer[23]; + assign pin10_sda = led_timer[22]; + assign pin6 = led_timer[21]; + +endmodule \ No newline at end of file -- cgit v1.2.3 From 0aa472fb3adac0b76ef0b69831d5b83ff1200fe2 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 8 Feb 2021 00:07:39 -0500 Subject: machxo2: Add prefix paramter to demo.sh. --- machxo2/examples/.gitignore | 4 ++-- machxo2/examples/README.md | 25 +++++++++++++++++++------ machxo2/examples/demo.sh | 20 ++++++++++++++++---- machxo2/examples/demorgb.sh | 10 ---------- 4 files changed, 37 insertions(+), 22 deletions(-) delete mode 100644 machxo2/examples/demorgb.sh (limited to 'machxo2') diff --git a/machxo2/examples/.gitignore b/machxo2/examples/.gitignore index 91167252..955c6e29 100644 --- a/machxo2/examples/.gitignore +++ b/machxo2/examples/.gitignore @@ -7,5 +7,5 @@ pack*.v place*.v pnr*.v abc.history -/tinyfpga.txt -/tinyfpga.bit +*.txt +*.bit diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index bcffeea3..fd84dc93 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -18,16 +18,14 @@ This contains a simple example of running `nextpnr-machxo2`: All possible inputs and resulting outputs can be tested in reasonable time by using `yosys`' built-in SAT solver or [`z3`](https://github.com/Z3Prover/z3), an external SMT solver. -* `demo.sh` creates a blinky bitstream for [TinyFPGA Ax](https://tinyfpga.com/a-series-guide.html) +* `demo.sh` creates bitstreams for [TinyFPGA Ax](https://tinyfpga.com/a-series-guide.html) and writes the resulting bitstream to MachXO2's internal flash using [`tinyproga`](https://github.com/tinyfpga/TinyFPGA-A-Programmer). -As `nextpnr-machxo2` is developed the contents `simple.sh`, `simtest.sh`, and -`mitertest.sh` are subject to change. +As `nextpnr-machxo2` is developed the contents `simple.sh`, `simtest.sh`, `mitertest.sh`, and `demo.sh` are subject to change. ## How To Run -The following applies to all `sh` scripts except `demo.sh`, which requires no -arguments. +The following applies to all `sh` scripts except `demo.sh`. Each `sh` script runs yosys and nextpnr to validate a blinky design in various ways. The `mode` argument to each script- `pack`, `place`, or `pnr`- stop @@ -42,8 +40,23 @@ SMT solver. To keep file count lower, all yosys scripts are written inline inside the `sh` scripts using the `-p` option. +`demo.sh` requires a prefix that matches one of the self-contained Verilog +examples in this directory. For instance, to create a bitstream from +`tinyfpga.v`, use `demo.sh tinyfpga`. The script will catch Verilog files which +are not meant to be programmed onto TinyFPA Ax. + ### Clean -To clean output files from _all_ scripts, run: `rm -rf *.dot *.json *.png *.vcd *.smt2 *.log tinyfpga.txt tinyfpga.bit {pack,place,pnr}*.v blinky_simtest*` +To clean output files from _all_ scripts, run: + +``` +rm -rf *.dot *.json *.png *.vcd *.smt2 *.log *.txt *.bit {pack,place,pnr}*.v blinky_simtest* +``` + +## Verilog Examples +* `blinky.v`/`blinky_tb.v`- A blinky example meant for simulation. +* `tinyfpga.v`- Blink the LED on TinyFPA Ax. +* `rgbcount.v`- Blink an RGB LED using TinyFPGA Ax, more closely-based on + [the TinyFPGA Ax guide](https://tinyfpga.com/a-series-guide.html). ## Environment Variables For Scripts diff --git a/machxo2/examples/demo.sh b/machxo2/examples/demo.sh index 6979f111..00cb0cd0 100644 --- a/machxo2/examples/demo.sh +++ b/machxo2/examples/demo.sh @@ -1,10 +1,22 @@ #!/bin/sh +if [ $# -lt 1 ]; then + echo "Usage: $0 prefix" + exit -1 +fi + +if ! grep -q "(\*.*LOC.*\*)" $1.v; then + echo "$1.v does not have LOC constraints for tinyfpga_a." + exit -2 +fi + if [ ! -z ${TRELLIS_DB+x} ]; then DB_ARG="--db $TRELLIS_DB" fi -${YOSYS:-yosys} -p 'synth_machxo2 -json tinyfpga.json' tinyfpga.v -${NEXTPNR:-../../nextpnr-machxo2} --1200 --package QFN32 --no-iobs --json tinyfpga.json --textcfg tinyfpga.txt -ecppack --compress $DB_ARG tinyfpga.txt tinyfpga.bit -tinyproga -b tinyfpga.bit +set -ex + +${YOSYS:-yosys} -p "synth_machxo2 -json $1.json" $1.v +${NEXTPNR:-../../nextpnr-machxo2} --1200 --package QFN32 --no-iobs --json $1.json --textcfg $1.txt +ecppack --compress $DB_ARG $1.txt $1.bit +tinyproga -b $1.bit diff --git a/machxo2/examples/demorgb.sh b/machxo2/examples/demorgb.sh deleted file mode 100644 index f68db8c3..00000000 --- a/machxo2/examples/demorgb.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -if [ ! -z ${TRELLIS_DB+x} ]; then - DB_ARG="--db $TRELLIS_DB" -fi - -${YOSYS:-yosys} -p 'synth_machxo2 -json rgbcount.json' rgbcount.v -${NEXTPNR:-../../nextpnr-machxo2} --1200 --package QFN32 --no-iobs --json rgbcount.json --textcfg rgbcount.txt -ecppack --compress $DB_ARG rgbcount.txt rgbcount.bit -tinyproga -b rgbcount.bit -- cgit v1.2.3 From a3a38b0536a59be8f2fd7afd1914989d0ed23da7 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 8 Feb 2021 01:37:14 -0500 Subject: machxo2: Add prefix parameter to mitertest.sh. All Verilog files top modules named "top". --- machxo2/examples/mitertest.sh | 54 +++++++++++++++++++++---------------------- machxo2/examples/rgbcount.v | 18 +++++++-------- machxo2/examples/tinyfpga.v | 2 +- 3 files changed, 37 insertions(+), 37 deletions(-) (limited to 'machxo2') diff --git a/machxo2/examples/mitertest.sh b/machxo2/examples/mitertest.sh index 5190af31..f2c7ba57 100644 --- a/machxo2/examples/mitertest.sh +++ b/machxo2/examples/mitertest.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash -if [ $# -lt 1 ]; then - echo "Usage: $0 nextpnr_mode solve_mode" +if [ $# -lt 3 ]; then + echo "Usage: $0 prefix nextpnr_mode solve_mode" exit -1 fi -case $1 in +case $2 in "pack") NEXTPNR_MODE="--pack-only" ;; @@ -21,7 +21,7 @@ case $1 in ;; esac -case $2 in +case $3 in "sat") SAT=1 ;; @@ -35,48 +35,48 @@ case $2 in esac do_sat() { - ${YOSYS:-yosys} -l ${1}miter_sat.log -p "read_verilog blinky.v + ${YOSYS:-yosys} -l ${2}${1}_miter_sat.log -p "read_verilog ${1}.v rename top gold - read_verilog ${1}blinky.v + read_verilog ${2}${1}.v rename top gate read_verilog +/machxo2/cells_sim.v - miter -equiv -make_assert -flatten gold gate ${1}miter - hierarchy -top ${1}miter - sat -verify -prove-asserts -tempinduct ${1}miter" + miter -equiv -make_assert -flatten gold gate ${2}${1}_miter + hierarchy -top ${2}${1}_miter + sat -verify -prove-asserts -tempinduct ${2}${1}_miter" } do_smt() { - ${YOSYS:-yosys} -l ${1}miter_smt.log -p "read_verilog blinky.v + ${YOSYS:-yosys} -l ${2}${1}_miter_smt.log -p "read_verilog ${1}.v rename top gold - read_verilog ${1}blinky.v + read_verilog ${2}${1}.v rename top gate read_verilog +/machxo2/cells_sim.v - miter -equiv -make_assert gold gate ${1}miter + miter -equiv -make_assert gold gate ${2}${1}_miter hierarchy -auto-top -check; proc; opt_clean - write_verilog ${1}miter.v - write_smt2 ${1}miter.smt2" + write_verilog ${2}${1}_miter.v + write_smt2 ${2}${1}_miter.smt2" - yosys-smtbmc -s z3 --dump-vcd ${1}miter_bmc.vcd ${1}miter.smt2 - yosys-smtbmc -s z3 -i --dump-vcd ${1}miter_tmp.vcd ${1}miter.smt2 + yosys-smtbmc -s z3 --dump-vcd ${2}${1}_miter_bmc.vcd ${2}${1}_miter.smt2 + yosys-smtbmc -s z3 -i --dump-vcd ${2}${1}_miter_tmp.vcd ${2}${1}_miter.smt2 } set -ex -${YOSYS:-yosys} -p "read_verilog blinky.v - synth_machxo2 -noiopad -json blinky.json - show -format png -prefix blinky" -${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json blinky.json --write ${1}blinky.json +${YOSYS:-yosys} -p "read_verilog ${1}.v + synth_machxo2 -noiopad -json ${1}.json" +# FIXME: --json option really not needed here. +${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json ${1}.json --write ${2}${1}.json ${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v - read_json ${1}blinky.json + read_json ${2}${1}.json clean -purge - show -format png -prefix ${1}blinky - write_verilog -noattr -norename ${1}blinky.v" + show -format png -prefix ${2}${1} + write_verilog -noattr -norename ${2}${1}.v" -if [ $2 = "sat" ]; then - do_sat $1 -elif [ $2 = "smt" ]; then - do_smt $1 +if [ $3 = "sat" ]; then + do_sat $1 $2 +elif [ $3 = "smt" ]; then + do_smt $1 $2 fi diff --git a/machxo2/examples/rgbcount.v b/machxo2/examples/rgbcount.v index 230fc73c..bf5c7518 100644 --- a/machxo2/examples/rgbcount.v +++ b/machxo2/examples/rgbcount.v @@ -2,7 +2,7 @@ // https://github.com/tinyfpga/TinyFPGA-A-Series/tree/master/template_a2 // https://tinyfpga.com/a-series-guide.html used as a basis. -module TinyFPGA_A2 ( +module top ( (* LOC="21" *) inout pin6, (* LOC="26" *) @@ -11,23 +11,23 @@ module TinyFPGA_A2 ( inout pin10_sda, ); wire clk; - + OSCH #( .NOM_FREQ("2.08") ) internal_oscillator_inst ( - .STDBY(1'b0), + .STDBY(1'b0), .OSC(clk) - ); - + ); + reg [23:0] led_timer; - + always @(posedge clk) begin - led_timer <= led_timer + 1; + led_timer <= led_timer + 1; end - + // left side of board assign pin9_jtgnb = led_timer[23]; assign pin10_sda = led_timer[22]; assign pin6 = led_timer[21]; -endmodule \ No newline at end of file +endmodule diff --git a/machxo2/examples/tinyfpga.v b/machxo2/examples/tinyfpga.v index dfc2710d..bd26d8eb 100644 --- a/machxo2/examples/tinyfpga.v +++ b/machxo2/examples/tinyfpga.v @@ -2,7 +2,7 @@ // https://github.com/tinyfpga/TinyFPGA-A-Series/tree/master/template_a2 // https://tinyfpga.com/a-series-guide.html used as a basis. -module TinyFPGA_A2 ( +module top ( (* LOC="13" *) inout pin1 ); -- cgit v1.2.3 From 2b54e87548befa65ce058d23aec82d389190ba55 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 8 Feb 2021 01:43:06 -0500 Subject: machxo2: Verilog examples using OSCH cannot be simulated in mitertest.sh. Remove show from mitertest.sh. --- machxo2/examples/mitertest.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'machxo2') diff --git a/machxo2/examples/mitertest.sh b/machxo2/examples/mitertest.sh index f2c7ba57..06b99125 100644 --- a/machxo2/examples/mitertest.sh +++ b/machxo2/examples/mitertest.sh @@ -5,6 +5,11 @@ if [ $# -lt 3 ]; then exit -1 fi +if grep -q "OSCH" $1.v; then + echo "$1.v uses blackbox primitive OSCH and cannot be simulated." + exit -2 +fi + case $2 in "pack") NEXTPNR_MODE="--pack-only" @@ -17,7 +22,7 @@ case $2 in ;; *) echo "nextpnr_mode string must be \"pack\", \"place\", or \"pnr\"" - exit -2 + exit -3 ;; esac @@ -30,7 +35,7 @@ case $3 in ;; *) echo "solve_mode string must be \"sat\", or \"smt\"" - exit -3 + exit -4 ;; esac @@ -72,7 +77,6 @@ ${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs ${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v read_json ${2}${1}.json clean -purge - show -format png -prefix ${2}${1} write_verilog -noattr -norename ${2}${1}.v" if [ $3 = "sat" ]; then -- cgit v1.2.3 From 77bb3e73cd2cb771d04522f4b8e33017a28424c7 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 8 Feb 2021 01:45:42 -0500 Subject: machxo2: Fix unhelpful comment in mitertest.sh. --- machxo2/examples/mitertest.sh | 1 - 1 file changed, 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/examples/mitertest.sh b/machxo2/examples/mitertest.sh index 06b99125..14c6fe61 100644 --- a/machxo2/examples/mitertest.sh +++ b/machxo2/examples/mitertest.sh @@ -72,7 +72,6 @@ set -ex ${YOSYS:-yosys} -p "read_verilog ${1}.v synth_machxo2 -noiopad -json ${1}.json" -# FIXME: --json option really not needed here. ${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json ${1}.json --write ${2}${1}.json ${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v read_json ${2}${1}.json -- cgit v1.2.3 From 74b5e846a526670dcef78da73c5bf95d61d82a90 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 8 Feb 2021 02:28:03 -0500 Subject: machxo2: auto-top does not work for smt miter either. --- machxo2/examples/mitertest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'machxo2') diff --git a/machxo2/examples/mitertest.sh b/machxo2/examples/mitertest.sh index 14c6fe61..cfae28b7 100644 --- a/machxo2/examples/mitertest.sh +++ b/machxo2/examples/mitertest.sh @@ -59,7 +59,7 @@ do_smt() { read_verilog +/machxo2/cells_sim.v miter -equiv -make_assert gold gate ${2}${1}_miter - hierarchy -auto-top -check; proc; + hierarchy -top ${2}${1}_miter; proc; opt_clean write_verilog ${2}${1}_miter.v write_smt2 ${2}${1}_miter.smt2" -- cgit v1.2.3 From 73c851d8e0073010329edc6c9e5de7d63037fefe Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 8 Feb 2021 03:27:49 -0500 Subject: machxo2: Add two new examples: blinky_ext and aforementioned UART. --- machxo2/examples/README.md | 10 ++ machxo2/examples/blinky_ext.v | 19 ++++ machxo2/examples/uart.v | 209 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 machxo2/examples/blinky_ext.v create mode 100644 machxo2/examples/uart.v (limited to 'machxo2') diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index fd84dc93..977d6d8a 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -57,6 +57,16 @@ rm -rf *.dot *.json *.png *.vcd *.smt2 *.log *.txt *.bit {pack,place,pnr}*.v bli * `tinyfpga.v`- Blink the LED on TinyFPA Ax. * `rgbcount.v`- Blink an RGB LED using TinyFPGA Ax, more closely-based on [the TinyFPGA Ax guide](https://tinyfpga.com/a-series-guide.html). +* `blinky_ext.v`- Blink the LED on TinyFPA Ax using an external pin (pin 6). +* `uart.v`- UART loopback demo at 19200 baud. Requires the following pins: + * Pin 1- RX LED + * Pin 2- TX (will echo RX) + * Pin 3- RX + * Pin 4- TX LED + * Pin 5- Load LED + * Pin 6- 12 MHz clock input + * Pin 7- Take LED + * Pin 8- Empty LED ## Environment Variables For Scripts diff --git a/machxo2/examples/blinky_ext.v b/machxo2/examples/blinky_ext.v new file mode 100644 index 00000000..a8bdd588 --- /dev/null +++ b/machxo2/examples/blinky_ext.v @@ -0,0 +1,19 @@ +// Modified from: +// https://github.com/tinyfpga/TinyFPGA-A-Series/tree/master/template_a2 + +module top ( + (* LOC="13" *) + output pin1, + (* LOC="21" *) + input clk +); + + reg [23:0] led_timer; + + always @(posedge clk) begin + led_timer <= led_timer + 1; + end + + // left side of board + assign pin1 = led_timer[23]; +endmodule diff --git a/machxo2/examples/uart.v b/machxo2/examples/uart.v new file mode 100644 index 00000000..f1d95bd8 --- /dev/null +++ b/machxo2/examples/uart.v @@ -0,0 +1,209 @@ +/* Example UART derived from: https://github.com/cr1901/migen_uart. + Requires 12MHz clock and runs at 19,200 baud. */ + +/* Machine-generated using Migen */ + +module top( + (* LOC = "14" *) + output tx, + (* LOC = "16" *) + input rx, + (* LOC = "13" *) + output rx_led, + (* LOC = "17" *) + output tx_led, + (* LOC = "20" *) + output load_led, + (* LOC = "23" *) + output take_led, + (* LOC = "25" *) + output empty_led, + (* LOC = "21" *) + input clk +); + +wire [7:0] out_data; +wire [7:0] in_data; +reg wr = 1'd0; +reg rd = 1'd0; +wire tx_empty; +wire rx_empty; +wire tx_ov; +wire rx_ov; +wire sout_load; +wire [7:0] sout_out_data; +wire sout_shift; +reg sout_empty = 1'd1; +reg sout_overrun = 1'd0; +reg [3:0] sout_count = 4'd0; +reg [9:0] sout_reg = 10'd0; +reg sout_tx; +wire sin_rx; +wire sin_shift; +wire sin_take; +reg [7:0] sin_in_data = 8'd0; +wire sin_edge; +reg sin_empty = 1'd1; +reg sin_busy = 1'd0; +reg sin_overrun = 1'd0; +reg sin_sync_rx = 1'd0; +reg [8:0] sin_reg = 9'd0; +reg sin_rx_prev = 1'd0; +reg [3:0] sin_count = 4'd0; +wire out_active; +wire in_active; +reg shift_out_strobe = 1'd0; +reg shift_in_strobe = 1'd0; +reg [9:0] in_counter = 10'd0; +reg [9:0] out_counter = 10'd0; +wire sys_clk; +wire sys_rst; +wire por_clk; +reg int_rst = 1'd1; + +// synthesis translate_off +reg dummy_s; +initial dummy_s <= 1'd0; +// synthesis translate_on + +assign tx_led = (~tx); +assign rx_led = (~rx); +assign load_led = sout_load; +assign take_led = sin_take; +assign empty_led = sin_empty; +assign out_data = in_data; +assign in_data = sin_in_data; +assign sout_out_data = out_data; +assign sin_take = rd; +assign sout_load = wr; +assign tx = sout_tx; +assign sin_rx = rx; +assign tx_empty = sout_empty; +assign rx_empty = sin_empty; +assign tx_ov = sout_overrun; +assign rx_ov = sin_overrun; +assign sout_shift = shift_out_strobe; +assign sin_shift = shift_in_strobe; +assign out_active = (~sout_empty); +assign in_active = sin_busy; + +// synthesis translate_off +reg dummy_d; +// synthesis translate_on +always @(*) begin + sout_tx <= 1'd0; + if (sout_empty) begin + sout_tx <= 1'd1; + end else begin + sout_tx <= sout_reg[0]; + end +// synthesis translate_off + dummy_d <= dummy_s; +// synthesis translate_on +end +assign sin_edge = ((sin_rx_prev == 1'd1) & (sin_sync_rx == 1'd0)); +assign sys_clk = clk; +assign por_clk = clk; +assign sys_rst = int_rst; + +always @(posedge por_clk) begin + int_rst <= 1'd0; +end + +always @(posedge sys_clk) begin + wr <= 1'd0; + rd <= 1'd0; + if ((~sin_empty)) begin + wr <= 1'd1; + rd <= 1'd1; + end + if (sout_load) begin + if (sout_empty) begin + sout_reg[0] <= 1'd0; + sout_reg[8:1] <= sout_out_data; + sout_reg[9] <= 1'd1; + sout_empty <= 1'd0; + sout_overrun <= 1'd0; + sout_count <= 1'd0; + end else begin + sout_overrun <= 1'd1; + end + end + if (((~sout_empty) & sout_shift)) begin + sout_reg[8:0] <= sout_reg[9:1]; + sout_reg[9] <= 1'd0; + if ((sout_count == 4'd9)) begin + sout_empty <= 1'd1; + sout_count <= 1'd0; + end else begin + sout_count <= (sout_count + 1'd1); + end + end + sin_sync_rx <= sin_rx; + sin_rx_prev <= sin_sync_rx; + if (sin_take) begin + sin_empty <= 1'd1; + sin_overrun <= 1'd0; + end + if (((~sin_busy) & sin_edge)) begin + sin_busy <= 1'd1; + end + if ((sin_shift & sin_busy)) begin + sin_reg[8] <= sin_sync_rx; + sin_reg[7:0] <= sin_reg[8:1]; + if ((sin_count == 4'd9)) begin + sin_in_data <= sin_reg[8:1]; + sin_count <= 1'd0; + sin_busy <= 1'd0; + if ((~sin_empty)) begin + sin_overrun <= 1'd1; + end else begin + sin_empty <= 1'd0; + end + end else begin + sin_count <= (sin_count + 1'd1); + end + end + out_counter <= 1'd0; + in_counter <= 1'd0; + if (in_active) begin + shift_in_strobe <= 1'd0; + in_counter <= (in_counter + 1'd1); + if ((in_counter == 9'd311)) begin + shift_in_strobe <= 1'd1; + end + if ((in_counter == 10'd623)) begin + in_counter <= 1'd0; + end + end + if (out_active) begin + shift_out_strobe <= 1'd0; + out_counter <= (out_counter + 1'd1); + if ((out_counter == 10'd623)) begin + out_counter <= 1'd0; + shift_out_strobe <= 1'd1; + end + end + if (sys_rst) begin + wr <= 1'd0; + rd <= 1'd0; + sout_empty <= 1'd1; + sout_overrun <= 1'd0; + sout_count <= 4'd0; + sout_reg <= 10'd0; + sin_in_data <= 8'd0; + sin_empty <= 1'd1; + sin_busy <= 1'd0; + sin_overrun <= 1'd0; + sin_sync_rx <= 1'd0; + sin_reg <= 9'd0; + sin_rx_prev <= 1'd0; + sin_count <= 4'd0; + shift_out_strobe <= 1'd0; + shift_in_strobe <= 1'd0; + in_counter <= 10'd0; + out_counter <= 10'd0; + end +end + +endmodule -- cgit v1.2.3 From 0b0faa2f1c1e0cf148a6cee37041320def12678c Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 8 Feb 2021 04:06:54 -0500 Subject: machxo2: Fill in more about mitertest.sh in README.md and clean up a bit. --- machxo2/examples/README.md | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'machxo2') diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index 977d6d8a..13964602 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -1,6 +1,5 @@ # MachXO2 Architecture Example - -This contains a simple example of running `nextpnr-machxo2`: +This directory contains a simple example of running `nextpnr-machxo2`: * `simple.sh` generates JSON output (`{pack,place,pnr}blinky.json`) of a classic blinky example from `blinky.v`. @@ -22,7 +21,8 @@ This contains a simple example of running `nextpnr-machxo2`: and writes the resulting bitstream to MachXO2's internal flash using [`tinyproga`](https://github.com/tinyfpga/TinyFPGA-A-Programmer). -As `nextpnr-machxo2` is developed the contents `simple.sh`, `simtest.sh`, `mitertest.sh`, and `demo.sh` are subject to change. +As `nextpnr-machxo2` is developed the contents `simple.sh`, `simtest.sh`, +`mitertest.sh`, and `demo.sh` are subject to change. ## How To Run The following applies to all `sh` scripts except `demo.sh`. @@ -37,6 +37,29 @@ and Route phases. verifying the miter with either yosys' built-in SAT solver, or an external SMT solver. +In principle, `mitertest.sh` should work in `sat` or `smt` mode with all +example Verilog files which don't use the internal oscillator (OSCH) or other +hard IP. However, as of this writing, only `blinky.v` passes correctly for a +few reasons: + + 1. The sim models for MachXO2 primitives used by the `gate` module contain + `initial` values _by design_, as it matches chip behavior. Without any of + the following in the `gold` module (like `blinky_ext.v` currently): + + * An external reset signal + * Internal power-on reset signal (e.g. `reg int_rst = 1'd1;`) + * `initial` values to manually set registers + + the `gold` and `gate` modules will inherently not match. + + Examples using an internal power-on reset (e.g. `uart.v`) also have issues + that I haven't debugged yet in both `sat` and `smt` mode. + 2. To keep the `gold`/`gate` generation simpler, examples are currently + assumed to _not_ instantiate MachXO2 simulation primitives directly + (`FACADE_IO`, `FACADE_FF`, etc). + 3. `synth_machxo2` runs `deminout` on `inouts` when generating the `gate` + module. This is not handled yet when generating the `gold` module. + To keep file count lower, all yosys scripts are written inline inside the `sh` scripts using the `-p` option. @@ -59,6 +82,7 @@ rm -rf *.dot *.json *.png *.vcd *.smt2 *.log *.txt *.bit {pack,place,pnr}*.v bli [the TinyFPGA Ax guide](https://tinyfpga.com/a-series-guide.html). * `blinky_ext.v`- Blink the LED on TinyFPA Ax using an external pin (pin 6). * `uart.v`- UART loopback demo at 19200 baud. Requires the following pins: + * Pin 1- RX LED * Pin 2- TX (will echo RX) * Pin 3- RX @@ -69,7 +93,6 @@ rm -rf *.dot *.json *.png *.vcd *.smt2 *.log *.txt *.bit {pack,place,pnr}*.v bli * Pin 8- Empty LED ## Environment Variables For Scripts - * `YOSYS`- Set to the location of the `yosys` binary to test. Defaults to the `yosys` on the path. You may want to set this to a `yosys` binary in your source tree if doing development. -- cgit v1.2.3 From 730e543ca65e97f1518fd0a9e692b233e15dcdbd Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 8 Feb 2021 16:55:26 -0500 Subject: machxo2: Add prefix parameter to simple.sh. Update README.md. --- machxo2/examples/README.md | 8 ++++---- machxo2/examples/simple.sh | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'machxo2') diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index 13964602..d4a89f7a 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -1,8 +1,8 @@ # MachXO2 Architecture Example This directory contains a simple example of running `nextpnr-machxo2`: -* `simple.sh` generates JSON output (`{pack,place,pnr}blinky.json`) of a - classic blinky example from `blinky.v`. +* `simple.sh` produces nextpnr output in the files `{pack,place,pnr}*.json`, + as well as pre-pnr and post-pnr diagrams in `{pack,place,pnr}*.{dot, png}`. * `simtest.sh` will use `yosys` to generate a Verilog file from `{pack,place,pnr}blinky.json`, called `{pack,place,pnr}blinky.v`. It will then and compare `{pack,place,pnr}blinky.v`'s simulation behavior to the @@ -10,8 +10,8 @@ This directory contains a simple example of running `nextpnr-machxo2`: compiler and `vvp` runtime. This is known as post-place-and-route simulation. * `mitertest.sh` is similar to `simtest.sh`, but more comprehensive. This script creates a [miter circuit](https://www21.in.tum.de/~lammich/2015_SS_Seminar_SAT/resources/Equivalence_Checking_11_30_08.pdf) - to compare the output port values of `{pack,place,pnr}blinky.v` against the - original `blinky.v` _when both modules are fed the same values on their input + to compare the output port values of `{pack,place,pnr}*.v` against the + original Verilog code _when both modules are fed the same values on their input ports._ All possible inputs and resulting outputs can be tested in reasonable time by diff --git a/machxo2/examples/simple.sh b/machxo2/examples/simple.sh index c977bf1a..1da60933 100644 --- a/machxo2/examples/simple.sh +++ b/machxo2/examples/simple.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash -if [ $# -lt 1 ]; then - echo "Usage: $0 mode" +if [ $# -lt 2 ]; then + echo "Usage: $0 prefix mode" exit -1 fi -case $1 in +case $2 in "pack") NEXTPNR_MODE="--pack-only" ;; @@ -23,12 +23,12 @@ esac set -ex -${YOSYS:-yosys} -p "read_verilog blinky.v - synth_machxo2 -json blinky.json - show -format png -prefix blinky" -${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json blinky.json --write ${1}blinky.json +${YOSYS:-yosys} -p "read_verilog ${1}.v + synth_machxo2 -json ${1}.json + show -format png -prefix ${1}" +${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json ${1}.json --write ${2}${1}.json ${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v - read_json ${1}blinky.json + read_json ${2}${1}.json clean -purge - show -format png -prefix ${1}blinky - write_verilog -noattr -norename ${1}blinky.v" + show -format png -prefix ${2}${1} + write_verilog -noattr -norename ${2}${1}.v" -- cgit v1.2.3 From 3dbd5b0932d4851ac6c3cddf63ed0d6642d3c842 Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Mon, 8 Feb 2021 17:22:09 -0500 Subject: machxo2: Add prefix parameter to simtest.sh. Remove show command from simtest.sh. Update README.md. --- machxo2/examples/.gitignore | 2 +- machxo2/examples/README.md | 54 ++++++++++++++++++++++----------------------- machxo2/examples/simtest.sh | 27 +++++++++++++---------- 3 files changed, 43 insertions(+), 40 deletions(-) (limited to 'machxo2') diff --git a/machxo2/examples/.gitignore b/machxo2/examples/.gitignore index 955c6e29..8a87cc8d 100644 --- a/machxo2/examples/.gitignore +++ b/machxo2/examples/.gitignore @@ -1,4 +1,4 @@ -/blinky_simtest +*_simtest* *.vcd *.png *.log diff --git a/machxo2/examples/README.md b/machxo2/examples/README.md index d4a89f7a..3542da70 100644 --- a/machxo2/examples/README.md +++ b/machxo2/examples/README.md @@ -3,11 +3,11 @@ This directory contains a simple example of running `nextpnr-machxo2`: * `simple.sh` produces nextpnr output in the files `{pack,place,pnr}*.json`, as well as pre-pnr and post-pnr diagrams in `{pack,place,pnr}*.{dot, png}`. -* `simtest.sh` will use `yosys` to generate a Verilog file from - `{pack,place,pnr}blinky.json`, called `{pack,place,pnr}blinky.v`. It will - then and compare `{pack,place,pnr}blinky.v`'s simulation behavior to the - original verilog file (`blinky.v`) using the [`iverilog`](http://iverilog.icarus.com) - compiler and `vvp` runtime. This is known as post-place-and-route simulation. +* `simtest.sh` extends `simple.sh` by generating `{pack,place,pnr}*.v` from + `{pack,place,pnr}*.json`. The script calls the [`iverilog`](http://iverilog.icarus.com) + compiler and `vvp` runtime to compare the behavior of `{pack,place,pnr}*.v` + and the original Verilog input (using a testbench `*_tb.v`). This is known as + post-place-and-route simulation. * `mitertest.sh` is similar to `simtest.sh`, but more comprehensive. This script creates a [miter circuit](https://www21.in.tum.de/~lammich/2015_SS_Seminar_SAT/resources/Equivalence_Checking_11_30_08.pdf) to compare the output port values of `{pack,place,pnr}*.v` against the @@ -25,18 +25,33 @@ As `nextpnr-machxo2` is developed the contents `simple.sh`, `simtest.sh`, `mitertest.sh`, and `demo.sh` are subject to change. ## How To Run -The following applies to all `sh` scripts except `demo.sh`. +Each script requires a prefix that matches one of the self-contained Verilog +examples in this directory. For instance, to create a bitstream from +`tinyfpga.v`, use `demo.sh tinyfpga` (the `*` glob used throughout this file +is filled with the the prefix). -Each `sh` script runs yosys and nextpnr to validate a blinky design in various -ways. The `mode` argument to each script- `pack`, `place`, or `pnr`- stop -`nextpnr-machxo2` after the specified phase and writes out a JSON file of the -results in `{pack,place,pnr}blinky.json`; `pnr` runs all of the Pack, Place, -and Route phases. +Each of `simple.sh`, `simtest.sh`, and `mitertest.sh` runs yosys and nextpnr +to validate a Verilog design in various ways. They require an additional `mode` +argument- `pack`, `place`, or `pnr`- which stops `nextpnr-machxo2` after the +specified phase and writes out a JSON file of the results in +`{pack,place,pnr}*.json`; `pnr` runs all of the Pack, Place, and Route phases. -`mitertest.sh` requires an additional option- `sat` or `smt`- to choose between +`mitertest.sh` requires an third option- `sat` or `smt`- to choose between verifying the miter with either yosys' built-in SAT solver, or an external SMT solver. +Each script will exit if it finds an input Verilog example it knows it can't +handle. To keep file count lower, all yosys scripts are written inline inside +the `sh` scripts using the `-p` option. + +### Clean +To clean output files from _all_ scripts, run: + +``` +rm -rf *.dot *.json *.png *.vcd *.smt2 *.log *.txt *.bit {pack,place,pnr}*.v *_simtest* +``` + +## Known Issues In principle, `mitertest.sh` should work in `sat` or `smt` mode with all example Verilog files which don't use the internal oscillator (OSCH) or other hard IP. However, as of this writing, only `blinky.v` passes correctly for a @@ -60,21 +75,6 @@ few reasons: 3. `synth_machxo2` runs `deminout` on `inouts` when generating the `gate` module. This is not handled yet when generating the `gold` module. -To keep file count lower, all yosys scripts are written inline inside the -`sh` scripts using the `-p` option. - -`demo.sh` requires a prefix that matches one of the self-contained Verilog -examples in this directory. For instance, to create a bitstream from -`tinyfpga.v`, use `demo.sh tinyfpga`. The script will catch Verilog files which -are not meant to be programmed onto TinyFPA Ax. - -### Clean -To clean output files from _all_ scripts, run: - -``` -rm -rf *.dot *.json *.png *.vcd *.smt2 *.log *.txt *.bit {pack,place,pnr}*.v blinky_simtest* -``` - ## Verilog Examples * `blinky.v`/`blinky_tb.v`- A blinky example meant for simulation. * `tinyfpga.v`- Blink the LED on TinyFPA Ax. diff --git a/machxo2/examples/simtest.sh b/machxo2/examples/simtest.sh index 53f2e728..2c7f6f30 100644 --- a/machxo2/examples/simtest.sh +++ b/machxo2/examples/simtest.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash -if [ $# -lt 1 ]; then - echo "Usage: $0 mode" +if [ $# -lt 2 ]; then + echo "Usage: $0 prefix mode" exit -1 fi -case $1 in +case $2 in "pack") NEXTPNR_MODE="--pack-only" ;; @@ -21,16 +21,19 @@ case $1 in ;; esac +if [ ! -f ${1}_tb.v ]; then + echo "No testbench file (${1}_tb.v) found for ${1}.v" + exit -3 +fi + set -ex -${YOSYS:-yosys} -p "read_verilog blinky.v - synth_machxo2 -json blinky.json - show -format png -prefix blinky" -${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json blinky.json --write ${1}blinky.json +${YOSYS:-yosys} -p "read_verilog ${1}.v + synth_machxo2 -json ${1}.json" +${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json ${1}.json --write ${2}${1}.json ${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v - read_json ${1}blinky.json + read_json ${2}${1}.json clean -purge - show -format png -prefix ${1}blinky - write_verilog -noattr -norename ${1}blinky.v" -iverilog -o blinky_simtest ${CELLS_SIM:-`${YOSYS:yosys}-config --datdir/machxo2/cells_sim.v`} blinky_tb.v ${1}blinky.v -vvp -N ./blinky_simtest + write_verilog -noattr -norename ${2}${1}.v" +iverilog -o ${1}_simtest ${CELLS_SIM:-`${YOSYS:yosys}-config --datdir/machxo2/cells_sim.v`} ${1}_tb.v ${2}${1}.v +vvp -N ./${1}_simtest -- cgit v1.2.3 From 32433db7aeda19e7f37f4e21f084f6017e85030b Mon Sep 17 00:00:00 2001 From: "William D. Jones" Date: Wed, 10 Feb 2021 19:27:34 -0500 Subject: machxo2: Prepare README.md for first PR. --- machxo2/README.md | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) (limited to 'machxo2') diff --git a/machxo2/README.md b/machxo2/README.md index 1c728722..55cc5763 100644 --- a/machxo2/README.md +++ b/machxo2/README.md @@ -1,6 +1,33 @@ # `nextpnr-machxo2` -To be filled in w/ details later. +_Experimental_ FOSS Place And Route backend for the Lattice MachXO2 family of +FPGAs. Fuzzing takes place as a subproject of [`prjtrellis`](https://github.com/YosysHQ/prjtrellis). + +Known to work: + +* Basic routing from pads to SLICEs and back! +* Basic packing of one type of FF and LUT into _half_ of a SLICE! +* Using the internal oscillator `OSCH` as a clock +* `LOGIC` SLICE mode + +Things that probably work but are untested: + +* Any non-3.3V I/O standard that doesn't use bank VREFs. + +Things remaining to do include (but not limited to): + +* More intelligent and efficient packing +* Global Routing (exists in database/sim models, `nextpnr-machxo2` doesn't use + it yet) +* Secondary High Fanout Nets +* Edge Clocks (clock pads work, but not routed to global routing yet) +* PLLs +* Synchronous Release Global Set/Reset Interface (`SGSR`) +* Embedded Function Block (`EFB`) +* All DDR-related functionality +* Bank VREFs +* Embedded Block RAM (`EBR`) +* `CCU2` and `DPRAM` SLICE modes ## Quick Start @@ -19,7 +46,9 @@ python3-setuptools python3-serial ### Installation -Use an empty directory to hold all the cloned repositories. +Use an empty directory to hold all the cloned repositories. Upstream repos +can be used as well (e.g. [`YosysHQ/prjtrellis`](https://github.com/YosysHQ/prjtrellis), +etc.). ``` git clone git@github.com:cr1901/prjtrellis.git @@ -56,6 +85,9 @@ cmake . -DARCH=machxo2 -DBUILD_GUI=OFF -DTRELLIS_INSTALL_PREFIX=/usr -DBUILD_PY make ``` +Although uncommon, the `facade` and `machxo2` branches of the above repos are +occassionally rebased; use `git pull -f` if necessary. + ### Demo If you have a [TinyFPGA Ax2](https://store.tinyfpga.com/products/tinyfpga-a2) board @@ -65,9 +97,9 @@ MachXO2; the gateware will flash the LED! ``` cd machxo2/examples/ -sh demo.sh +sh demo.sh tinyfpga ``` The `tinyfpga.v` code used in `demo.sh` is slightly modified from the [user's guide](https://tinyfpga.com/a-series-guide.html) to accommodate -`(* LOC = "pin" *)` constraints. +`(* LOC = "pin" *)` constraints and the built-in user LED. -- cgit v1.2.3 From 3f7618283d1eed2a35bbce161f905a4088020d8e Mon Sep 17 00:00:00 2001 From: gatecat Date: Thu, 11 Feb 2021 11:34:08 +0000 Subject: machxo2: Update with Arch API changes Signed-off-by: gatecat --- machxo2/.gitignore | 1 + machxo2/arch.cc | 105 ++++--------- machxo2/arch.h | 426 ++++++++------------------------------------------- machxo2/archdefs.h | 1 + machxo2/bitstream.cc | 36 ++--- machxo2/cells.cc | 5 +- machxo2/pack.cc | 5 +- 7 files changed, 115 insertions(+), 464 deletions(-) create mode 100644 machxo2/.gitignore (limited to 'machxo2') diff --git a/machxo2/.gitignore b/machxo2/.gitignore new file mode 100644 index 00000000..48c9c5ce --- /dev/null +++ b/machxo2/.gitignore @@ -0,0 +1 @@ +chipdb/ diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 101ceae7..4c0f9b9c 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -100,7 +100,8 @@ Arch::Arch(ArchArgs args) : args(args) if (!package_info) log_error("Unsupported package '%s' for '%s'.\n", args.package.c_str(), getChipName().c_str()); - bel_to_cell.resize(chip_info->height * chip_info->width * max_loc_bels, nullptr); + BaseArch::init_cell_types(); + BaseArch::init_bel_buckets(); } bool Arch::isAvailable(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip) != nullptr; } @@ -172,16 +173,18 @@ IdString Arch::archArgsToId(ArchArgs args) const // --------------------------------------------------------------- -BelId Arch::getBelByName(IdString name) const +BelId Arch::getBelByName(IdStringList name) const { BelId ret; - auto it = bel_by_name.find(name); + IdString name_id = name[0]; + + auto it = bel_by_name.find(name_id); if (it != bel_by_name.end()) return it->second; Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name_id.str(this)); ret.location = loc; const TileTypePOD *tilei = tileInfo(ret); for (int i = 0; i < tilei->num_bels; i++) { @@ -191,7 +194,7 @@ BelId Arch::getBelByName(IdString name) const } } if (ret.index >= 0) - bel_by_name[name] = ret; + bel_by_name[name_id] = ret; return ret; } @@ -303,17 +306,18 @@ BelId Arch::getPackagePinBel(const std::string &pin) const // --------------------------------------------------------------- -WireId Arch::getWireByName(IdString name) const +WireId Arch::getWireByName(IdStringList name) const { WireId ret; + IdString name_id = name[0]; - auto it = wire_by_name.find(name); + auto it = wire_by_name.find(name_id); if (it != wire_by_name.end()) return it->second; Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name_id.str(this)); ret.location = loc; const TileTypePOD *tilei = tileInfo(ret); @@ -324,23 +328,24 @@ WireId Arch::getWireByName(IdString name) const } } if (ret.index >= 0) - wire_by_name[name] = ret; + wire_by_name[name_id] = ret; return ret; } // --------------------------------------------------------------- -PipId Arch::getPipByName(IdString name) const +PipId Arch::getPipByName(IdStringList name) const { PipId ret; + IdString name_id = name[0]; - auto it = pip_by_name.find(name); + auto it = pip_by_name.find(name_id); if (it != pip_by_name.end()) return it->second; Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + std::tie(loc.x, loc.y, basename) = split_identifier_name(name_id.str(this)); ret.location = loc; const TileTypePOD *tilei = tileInfo(ret); @@ -348,49 +353,29 @@ PipId Arch::getPipByName(IdString name) const PipId curr; curr.location = loc; curr.index = i; - pip_by_name[getPipName(curr)] = curr; + pip_by_name[getPipName(curr)[0]] = curr; } - if (pip_by_name.find(name) == pip_by_name.end()) - NPNR_ASSERT_FALSE_STR("no pip named " + name.str(this)); - return pip_by_name[name]; + if (pip_by_name.find(name_id) == pip_by_name.end()) + NPNR_ASSERT_FALSE_STR("no pip named " + name_id.str(this)); + return pip_by_name[name_id]; } -IdString Arch::getPipName(PipId pip) const +IdStringList Arch::getPipName(PipId pip) const { NPNR_ASSERT(pip != PipId()); int x = pip.location.x; int y = pip.location.y; - std::string src_name = getWireName(getPipSrcWire(pip)).str(this); + std::string src_name = getWireName(getPipSrcWire(pip)).str(getCtx()); std::replace(src_name.begin(), src_name.end(), '/', '.'); - std::string dst_name = getWireName(getPipDstWire(pip)).str(this); + std::string dst_name = getWireName(getPipDstWire(pip)).str(getCtx()); std::replace(dst_name.begin(), dst_name.end(), '/', '.'); - return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); -} - -// --------------------------------------------------------------- - -GroupId Arch::getGroupByName(IdString name) const { return GroupId(); } - -IdString Arch::getGroupName(GroupId group) const { return IdString(); } - -std::vector Arch::getGroups() const -{ - std::vector ret; - return ret; + return IdStringList(id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name)); } -const std::vector &Arch::getGroupBels(GroupId group) const { return bel_id_dummy; } - -const std::vector &Arch::getGroupWires(GroupId group) const { return wire_id_dummy; } - -const std::vector &Arch::getGroupPips(GroupId group) const { return pip_id_dummy; } - -const std::vector &Arch::getGroupGroups(GroupId group) const { return group_id_dummy; } - // --------------------------------------------------------------- delay_t Arch::estimateDelay(WireId src, WireId dst) const @@ -413,8 +398,6 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const return (abs(dst.location.x - src.location.x) + abs(dst.location.y - src.location.y)) * (0.01 + 0.01); } -bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; } - ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const { ArcBounds bb; @@ -432,6 +415,13 @@ bool Arch::place() getCtx()->settings[getCtx()->id("place")] = 1; archInfoToAttributes(); return retVal; + } else if (placer == "heap") { + PlacerHeapCfg cfg(getCtx()); + cfg.ioBufTypes.insert(id_FACADE_IO); + bool retVal = placer_heap(getCtx(), cfg); + getCtx()->settings[getCtx()->id("place")] = 1; + archInfoToAttributes(); + return retVal; } else { log_error("MachXO2 architecture does not support placer '%s'\n", placer.c_str()); } @@ -455,35 +445,6 @@ bool Arch::route() } // --------------------------------------------------------------- - -const std::vector &Arch::getDecalGraphics(DecalId decal) const { return graphic_element_dummy; } - -DecalXY Arch::getBelDecal(BelId bel) const { return DecalXY(); } - -DecalXY Arch::getWireDecal(WireId wire) const { return DecalXY(); } - -DecalXY Arch::getPipDecal(PipId pip) const { return DecalXY(); } - -DecalXY Arch::getGroupDecal(GroupId group) const { return DecalXY(); } - -// --------------------------------------------------------------- - -bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const -{ - return false; -} - -// Get the port class, also setting clockPort if applicable -TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const -{ - return TMG_IGNORE; -} - -TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const -{ - return TimingClockingInfo(); -} - bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { // FIXME: Unlike ECP5, SLICEs in a given tile do not share a clock, so @@ -514,8 +475,6 @@ const std::vector Arch::availablePlacers = {"sa", const std::string Arch::defaultRouter = "router1"; const std::vector Arch::availableRouters = {"router1", "router2"}; -void Arch::assignArchInfo() {} - bool Arch::cellsCompatible(const CellInfo **cells, int count) const { return false; } std::vector> Arch::getTilesAtLocation(int row, int col) diff --git a/machxo2/arch.h b/machxo2/arch.h index 439d54a5..466eca79 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -377,109 +377,31 @@ struct ArchArgs } speed = SPEED_4; }; -struct WireInfo; - -struct PipInfo -{ - IdString name, type; - std::map attrs; - NetInfo *bound_net; - WireId srcWire, dstWire; - DelayInfo delay; - DecalXY decalxy; - Loc loc; -}; - -struct WireInfo -{ - IdString name, type; - std::map attrs; - NetInfo *bound_net; - std::vector downhill, uphill, aliases; - BelPin uphill_bel_pin; - std::vector downhill_bel_pins; - std::vector bel_pins; - DecalXY decalxy; - int x, y; -}; - -struct PinInfo -{ - IdString name; - WireId wire; - PortType type; -}; - -struct BelInfo -{ - IdString name, type; - std::map attrs; - CellInfo *bound_cell; - std::unordered_map pins; - DecalXY decalxy; - int x, y, z; - bool gb; -}; - -struct GroupInfo -{ - IdString name; - std::vector bels; - std::vector wires; - std::vector pips; - std::vector groups; - DecalXY decalxy; -}; - -struct CellDelayKey +struct ArchRanges : BaseArchRanges { - IdString from, to; - inline bool operator==(const CellDelayKey &other) const { return from == other.from && to == other.to; } -}; - -NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX CellDelayKey &dk) const noexcept - { - std::size_t seed = std::hash()(dk.from); - seed ^= std::hash()(dk.to) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } -}; -} // namespace std -NEXTPNR_NAMESPACE_BEGIN - -struct CellTiming -{ - std::unordered_map portClasses; - std::unordered_map combDelays; - std::unordered_map> clockingInfo; + using ArchArgsT = ArchArgs; + // Bels + using AllBelsRangeT = BelRange; + using TileBelsRangeT = BelRange; + using BelPinsRangeT = std::vector; + // Wires + using AllWiresRangeT = WireRange; + using DownhillPipRangeT = PipRange; + using UphillPipRangeT = PipRange; + using WireBelPinRangeT = BelPinRange; + // Pips + using AllPipsRangeT = AllPipRange; }; -struct Arch : BaseCtx +struct Arch : BaseArch { const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; - std::vector bel_to_cell; - std::unordered_map wire_to_net; - std::unordered_map pip_to_net; - mutable std::unordered_map bel_by_name; mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; - // Placeholders to be removed. - std::unordered_map bel_by_loc; - std::vector bel_id_dummy; - std::vector bel_pin_dummy; - std::vector wire_id_dummy; - std::vector pip_id_dummy; - std::vector group_id_dummy; - std::vector graphic_element_dummy; - // Helpers template const TileTypePOD *tileInfo(Id &id) const { @@ -500,35 +422,35 @@ struct Arch : BaseCtx static bool isAvailable(ArchArgs::ArchArgsTypes chip); - std::string getChipName() const; + std::string getChipName() const override; // Extra helper std::string getFullChipName() const; - IdString archId() const { return id("machxo2"); } - ArchArgs archArgs() const { return args; } - IdString archArgsToId(ArchArgs args) const; + IdString archId() const override { return id("machxo2"); } + ArchArgs archArgs() const override { return args; } + IdString archArgsToId(ArchArgs args) const override; static const int max_loc_bels = 20; - int getGridDimX() const { return chip_info->width; } - int getGridDimY() const { return chip_info->height; } - int getTileBelDimZ(int x, int y) const { return max_loc_bels; } + int getGridDimX() const override { return chip_info->width; } + int getGridDimY() const override { return chip_info->height; } + int getTileBelDimZ(int x, int y) const override { return max_loc_bels; } // TODO: Make more precise? The CENTER MUX having config bits across // tiles can complicate this? - int getTilePipDimZ(int x, int y) const { return 2; } + int getTilePipDimZ(int x, int y) const override { return 2; } // Bels - BelId getBelByName(IdString name) const; + BelId getBelByName(IdStringList name) const override; - IdString getBelName(BelId bel) const + IdStringList getBelName(BelId bel) const override { NPNR_ASSERT(bel != BelId()); std::stringstream name; name << "X" << bel.location.x << "/Y" << bel.location.y << "/" << tileInfo(bel)->bel_data[bel.index].name.get(); - return id(name.str()); + return IdStringList(id(name.str())); } - Loc getBelLocation(BelId bel) const + Loc getBelLocation(BelId bel) const override { NPNR_ASSERT(bel != BelId()); Loc loc; @@ -538,57 +460,11 @@ struct Arch : BaseCtx return loc; } - BelId getBelByLocation(Loc loc) const; - BelRange getBelsByTile(int x, int y) const; - bool getBelGlobalBuf(BelId bel) const; + BelId getBelByLocation(Loc loc) const override; + BelRange getBelsByTile(int x, int y) const override; + bool getBelGlobalBuf(BelId bel) const override; - uint32_t getBelChecksum(BelId bel) const - { - // FIXME- Copied from ECP5. Should be return val from getBelFlatIndex? - return bel.index; - } - - void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) - { - NPNR_ASSERT(bel != BelId()); - int idx = getBelFlatIndex(bel); - NPNR_ASSERT(bel_to_cell.at(idx) == nullptr); - bel_to_cell[idx] = cell; - cell->bel = bel; - cell->belStrength = strength; - refreshUiBel(bel); - } - - void unbindBel(BelId bel) - { - NPNR_ASSERT(bel != BelId()); - int idx = getBelFlatIndex(bel); - NPNR_ASSERT(bel_to_cell.at(idx) != nullptr); - bel_to_cell[idx]->bel = BelId(); - bel_to_cell[idx]->belStrength = STRENGTH_NONE; - bel_to_cell[idx] = nullptr; - refreshUiBel(bel); - } - - bool checkBelAvail(BelId bel) const - { - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[getBelFlatIndex(bel)] == nullptr; - } - - CellInfo *getBoundBelCell(BelId bel) const - { - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[getBelFlatIndex(bel)]; - } - - CellInfo *getConflictingBelCell(BelId bel) const - { - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[getBelFlatIndex(bel)]; - } - - BelRange getBels() const + BelRange getBels() const override { BelRange range; range.b.cursor_tile = 0; @@ -601,7 +477,7 @@ struct Arch : BaseCtx return range; } - IdString getBelType(BelId bel) const + IdString getBelType(BelId bel) const override { NPNR_ASSERT(bel != BelId()); IdString id; @@ -609,106 +485,28 @@ struct Arch : BaseCtx return id; } - std::vector> getBelAttrs(BelId) const - { - std::vector> ret; - return ret; - } - - WireId getBelPinWire(BelId bel, IdString pin) const; - PortType getBelPinType(BelId bel, IdString pin) const; - std::vector getBelPins(BelId bel) const; + WireId getBelPinWire(BelId bel, IdString pin) const override; + PortType getBelPinType(BelId bel, IdString pin) const override; + std::vector getBelPins(BelId bel) const override; // Package BelId getPackagePinBel(const std::string &pin) const; // Wires - WireId getWireByName(IdString name) const; + WireId getWireByName(IdStringList name) const override; - IdString getWireName(WireId wire) const + IdStringList getWireName(WireId wire) const override { NPNR_ASSERT(wire != WireId()); std::stringstream name; name << "X" << wire.location.x << "/Y" << wire.location.y << "/" << tileInfo(wire)->wire_data[wire.index].name.get(); - return id(name.str()); - } - - IdString getWireType(WireId wire) const { return IdString(); } - - std::vector> getWireAttrs(WireId) const - { - std::vector> ret; - return ret; - } - - uint32_t getWireChecksum(WireId wire) const { return wire.index; } - - void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) - { - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire] == nullptr); - wire_to_net[wire] = net; - - // Needs to be set; bindWires is meant for source wires attached - // to a Bel. - net->wires[wire].pip = PipId(); - net->wires[wire].strength = strength; - refreshUiWire(wire); + return IdStringList(id(name.str())); } - void unbindWire(WireId wire) - { - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire] != nullptr); - - auto &net_wires = wire_to_net[wire]->wires; - auto it = net_wires.find(wire); - NPNR_ASSERT(it != net_wires.end()); - - // If we have unbound a wire, then the upstream pip is no longer - // used either. - auto pip = it->second.pip; - if (pip != PipId()) { - // TODO: fanout - // wire_fanout[getPipSrcWire(pip)]--; - pip_to_net[pip] = nullptr; - } - - net_wires.erase(it); - wire_to_net[wire] = nullptr; - refreshUiWire(wire); - } + DelayInfo getWireDelay(WireId wire) const override { return DelayInfo(); } - bool checkWireAvail(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); - return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == nullptr; - } - - NetInfo *getBoundWireNet(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); - if (wire_to_net.find(wire) == wire_to_net.end()) - return nullptr; - else - return wire_to_net.at(wire); - } - - WireId getConflictingWireWire(WireId wire) const { return wire; } - - NetInfo *getConflictingWireNet(WireId wire) const - { - NPNR_ASSERT(wire != WireId()); - if (wire_to_net.find(wire) == wire_to_net.end()) - return nullptr; - else - return wire_to_net.at(wire); - } - - DelayInfo getWireDelay(WireId wire) const { return DelayInfo(); } - - WireRange getWires() const + WireRange getWires() const override { WireRange range; range.b.cursor_tile = 0; @@ -721,7 +519,7 @@ struct Arch : BaseCtx return range; } - BelPinRange getWireBelPins(WireId wire) const + BelPinRange getWireBelPins(WireId wire) const override { BelPinRange range; NPNR_ASSERT(wire != WireId()); @@ -733,85 +531,10 @@ struct Arch : BaseCtx } // Pips - PipId getPipByName(IdString name) const; - IdString getPipName(PipId pip) const; - - IdString getPipType(PipId pip) const { return IdString(); } + PipId getPipByName(IdStringList name) const override; + IdStringList getPipName(PipId pip) const override; - std::vector> getPipAttrs(PipId) const - { - std::vector> ret; - return ret; - } - - uint32_t getPipChecksum(PipId pip) const { return pip.index; } - - void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) - { - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip] == nullptr); - - pip_to_net[pip] = net; - // wire_fanout[getPipSrcWire(pip)]++; - - WireId dst; - dst.index = tileInfo(pip)->pips_data[pip.index].dst_idx; - dst.location = tileInfo(pip)->pips_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst] == nullptr); - - // Since NetInfo::wires holds info about uphill pips, bind info about - // this pip to the downhill wire. - wire_to_net[dst] = net; - net->wires[dst].pip = pip; - net->wires[dst].strength = strength; - } - - void unbindPip(PipId pip) - { - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip] == nullptr); - - // wire_fanout[getPipSrcWire(pip)]--; - - WireId dst; - dst.index = tileInfo(pip)->pips_data[pip.index].dst_idx; - dst.location = tileInfo(pip)->pips_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst] != nullptr); - - // If we unbind a pip, then the downstream wire is no longer in use - // either. - wire_to_net[dst] = nullptr; - pip_to_net[pip]->wires.erase(dst); - pip_to_net[pip] = nullptr; - } - - bool checkPipAvail(PipId pip) const - { - NPNR_ASSERT(pip != PipId()); - return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == nullptr; - } - - NetInfo *getBoundPipNet(PipId pip) const - { - NPNR_ASSERT(pip != PipId()); - if (pip_to_net.find(pip) == pip_to_net.end()) - return nullptr; - else - return pip_to_net.at(pip); - } - - WireId getConflictingPipWire(PipId pip) const { return WireId(); } - - NetInfo *getConflictingPipNet(PipId pip) const - { - NPNR_ASSERT(pip != PipId()); - if (pip_to_net.find(pip) == pip_to_net.end()) - return nullptr; - else - return pip_to_net.at(pip); - } - - AllPipRange getPips() const + AllPipRange getPips() const override { AllPipRange range; range.b.cursor_tile = 0; @@ -824,7 +547,7 @@ struct Arch : BaseCtx return range; } - Loc getPipLocation(PipId pip) const + Loc getPipLocation(PipId pip) const override { Loc loc; loc.x = pip.location.x; @@ -836,7 +559,7 @@ struct Arch : BaseCtx return loc; } - WireId getPipSrcWire(PipId pip) const + WireId getPipSrcWire(PipId pip) const override { WireId wire; NPNR_ASSERT(pip != PipId()); @@ -845,7 +568,7 @@ struct Arch : BaseCtx return wire; } - WireId getPipDstWire(PipId pip) const + WireId getPipDstWire(PipId pip) const override { WireId wire; NPNR_ASSERT(pip != PipId()); @@ -854,7 +577,7 @@ struct Arch : BaseCtx return wire; } - DelayInfo getPipDelay(PipId pip) const + DelayInfo getPipDelay(PipId pip) const override { DelayInfo delay; @@ -863,7 +586,7 @@ struct Arch : BaseCtx return delay; } - PipRange getPipsDownhill(WireId wire) const + PipRange getPipsDownhill(WireId wire) const override { PipRange range; NPNR_ASSERT(wire != WireId()); @@ -874,7 +597,7 @@ struct Arch : BaseCtx return range; } - PipRange getPipsUphill(WireId wire) const + PipRange getPipsUphill(WireId wire) const override { PipRange range; NPNR_ASSERT(wire != WireId()); @@ -898,56 +621,32 @@ struct Arch : BaseCtx NPNR_ASSERT_FALSE("failed to find Pip tile"); } - // Group - GroupId getGroupByName(IdString name) const; - IdString getGroupName(GroupId group) const; - std::vector getGroups() const; - const std::vector &getGroupBels(GroupId group) const; - const std::vector &getGroupWires(GroupId group) const; - const std::vector &getGroupPips(GroupId group) const; - const std::vector &getGroupGroups(GroupId group) const; - // Delay - delay_t estimateDelay(WireId src, WireId dst) const; - delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const; - delay_t getDelayEpsilon() const { return 0.001; } - delay_t getRipupDelayPenalty() const { return 0.015; } - float getDelayNS(delay_t v) const { return v; } + delay_t estimateDelay(WireId src, WireId dst) const override; + delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const override; + delay_t getDelayEpsilon() const override { return 0.001; } + delay_t getRipupDelayPenalty() const override { return 0.015; } + float getDelayNS(delay_t v) const override { return v; } - DelayInfo getDelayFromNS(float ns) const + DelayInfo getDelayFromNS(float ns) const override { DelayInfo del; del.delay = ns; return del; } - uint32_t getDelayChecksum(delay_t v) const { return 0; } - bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const; + uint32_t getDelayChecksum(delay_t v) const override { return v; } - ArcBounds getRouteBoundingBox(WireId src, WireId dst) const; + ArcBounds getRouteBoundingBox(WireId src, WireId dst) const override; // Flow - bool pack(); - bool place(); - bool route(); - - // Graphics - const std::vector &getDecalGraphics(DecalId decal) const; - DecalXY getBelDecal(BelId bel) const; - DecalXY getWireDecal(WireId wire) const; - DecalXY getPipDecal(PipId pip) const; - DecalXY getGroupDecal(GroupId group) const; - - // Cell Delay - bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; - // Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port - TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const; - // Get the TimingClockingInfo of a port - TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const; + bool pack() override; + bool place() override; + bool route() override; // Placer - bool isValidBelForCell(CellInfo *cell, BelId bel) const; - bool isBelLocationValid(BelId bel) const; + bool isValidBelForCell(CellInfo *cell, BelId bel) const override; + bool isBelLocationValid(BelId bel) const override; static const std::string defaultPlacer; static const std::vector availablePlacers; @@ -956,7 +655,6 @@ struct Arch : BaseCtx // --------------------------------------------------------------- // Internal usage - void assignArchInfo(); bool cellsCompatible(const CellInfo **cells, int count) const; std::vector> getTilesAtLocation(int row, int col); diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h index 9b62a6c3..caa15ece 100644 --- a/machxo2/archdefs.h +++ b/machxo2/archdefs.h @@ -119,6 +119,7 @@ struct PipId typedef IdString GroupId; typedef IdString DecalId; +typedef IdString BelBucketId; struct ArchNetInfo { diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index a095333a..1711326f 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -60,24 +60,15 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) // Handle MachXO2's wonderful naming quirks for wires in left/right tiles, whose // relative coords push them outside the bounds of the chip. auto is_pio_wire = [](std::string name) { - return ( - name.find("DI") != std::string::npos || - name.find("JDI") != std::string::npos || - name.find("PADD") != std::string::npos || - name.find("INDD") != std::string::npos || - name.find("IOLDO") != std::string::npos || - name.find("IOLTO") != std::string::npos || - name.find("JCE") != std::string::npos || - name.find("JCLK") != std::string::npos || - name.find("JLSR") != std::string::npos || - name.find("JONEG") != std::string::npos || - name.find("JOPOS") != std::string::npos || - name.find("JTS") != std::string::npos || - name.find("JIN") != std::string::npos || - name.find("JIP") != std::string::npos || - // Connections to global mux - name.find("JINCK") != std::string::npos - ); + return (name.find("DI") != std::string::npos || name.find("JDI") != std::string::npos || + name.find("PADD") != std::string::npos || name.find("INDD") != std::string::npos || + name.find("IOLDO") != std::string::npos || name.find("IOLTO") != std::string::npos || + name.find("JCE") != std::string::npos || name.find("JCLK") != std::string::npos || + name.find("JLSR") != std::string::npos || name.find("JONEG") != std::string::npos || + name.find("JOPOS") != std::string::npos || name.find("JTS") != std::string::npos || + name.find("JIN") != std::string::npos || name.find("JIP") != std::string::npos || + // Connections to global mux + name.find("JINCK") != std::string::npos); }; if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_" || prefix2 == "U_" || prefix2 == "D_" || @@ -85,10 +76,10 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) return basename; if (loc == wire.location) { // TODO: JINCK is not currently handled by this. - if(is_pio_wire(basename)) { - if(wire.location.x == 0) + if (is_pio_wire(basename)) { + if (wire.location.x == 0) return "W1_" + basename; - else if(wire.location.x == max_col) + else if (wire.location.x == max_col) return "E1_" + basename; } return basename; @@ -200,7 +191,8 @@ void write_bitstream(Context *ctx, std::string text_config_file) for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); if (ci->bel == BelId()) { - log_warning("found unplaced cell '%s' during bitstream gen. Not writing to bitstream.\n", ci->name.c_str(ctx)); + log_warning("found unplaced cell '%s' during bitstream gen. Not writing to bitstream.\n", + ci->name.c_str(ctx)); continue; } BelId bel = ci->bel; diff --git a/machxo2/cells.cc b/machxo2/cells.cc index 5dea36e2..03ba0a41 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -165,8 +165,9 @@ void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) // If a register's DI port is fed by a constant, options for placing are // limited. Use the LUT to get around this. - if(pass_thru_lut) { - lc->params[ctx->id("LUT0_INITVAL")] = Property(0xAAAA, 16);; + if (pass_thru_lut) { + lc->params[ctx->id("LUT0_INITVAL")] = Property(0xAAAA, 16); + ; replace_port(dff, ctx->id("DI"), lc, ctx->id("A0")); connect_ports(ctx, lc, ctx->id("F0"), lc, ctx->id("DI0")); } else { diff --git a/machxo2/pack.cc b/machxo2/pack.cc index c745a1c0..5a6cd97b 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -138,7 +138,7 @@ 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) { + 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)); std::unique_ptr lc = create_machxo2_cell(ctx, id_FACADE_SLICE, uc->name.str(ctx) + "_CONST"); @@ -262,8 +262,7 @@ static void pack_io(Context *ctx) log_error("IO buffer '%s' constrained to pin '%s', which does not exist for package '%s'.\n", ci->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str()); } else { - log_info("pin '%s' constrained to Bel '%s'.\n", ci->name.c_str(ctx), - ctx->getBelName(pinBel).c_str(ctx)); + log_info("pin '%s' constrained to Bel '%s'.\n", ci->name.c_str(ctx), ctx->nameOfBel(pinBel)); } ci->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx); } -- cgit v1.2.3 From b539363cd05a2841661be3cc4fb0c2804dc35376 Mon Sep 17 00:00:00 2001 From: gatecat Date: Thu, 11 Feb 2021 12:46:31 +0000 Subject: machxo2: Use IdStringLists in earnest Signed-off-by: gatecat --- machxo2/arch.cc | 122 ++++++++++++++++++++++++++------------------------------ machxo2/arch.h | 24 ++++++----- 2 files changed, 70 insertions(+), 76 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 4c0f9b9c..c2b2e0ad 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -30,17 +30,6 @@ NEXTPNR_NAMESPACE_BEGIN -static std::tuple split_identifier_name(const std::string &name) -{ - size_t first_slash = name.find('/'); - NPNR_ASSERT(first_slash != std::string::npos); - size_t second_slash = name.find('/', first_slash + 1); - NPNR_ASSERT(second_slash != std::string::npos); - return std::make_tuple(std::stoi(name.substr(1, first_slash)), - std::stoi(name.substr(first_slash + 2, second_slash - first_slash)), - name.substr(second_slash + 1)); -}; - // ----------------------------------------------------------------------- void IdString::initialize_arch(const BaseCtx *ctx) @@ -102,6 +91,22 @@ Arch::Arch(ArchArgs args) : args(args) BaseArch::init_cell_types(); BaseArch::init_bel_buckets(); + + for (int i = 0; i < chip_info->width; i++) + x_ids.push_back(id(stringf("X%d", i))); + for (int i = 0; i < chip_info->height; i++) + y_ids.push_back(id(stringf("Y%d", i))); + + for (int i = 0; i < chip_info->width; i++) { + IdString x_id = id(stringf("X%d", i)); + x_ids.push_back(x_id); + id_to_x[x_id] = i; + } + for (int i = 0; i < chip_info->height; i++) { + IdString y_id = id(stringf("Y%d", i)); + y_ids.push_back(y_id); + id_to_y[y_id] = i; + } } bool Arch::isAvailable(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip) != nullptr; } @@ -175,27 +180,21 @@ IdString Arch::archArgsToId(ArchArgs args) const BelId Arch::getBelByName(IdStringList name) const { + if (name.size() != 3) + return BelId(); BelId ret; - IdString name_id = name[0]; - - auto it = bel_by_name.find(name_id); - if (it != bel_by_name.end()) - return it->second; - Location loc; - std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name_id.str(this)); + loc.x = id_to_x.at(name[0]); + loc.y = id_to_y.at(name[1]); ret.location = loc; - const TileTypePOD *tilei = tileInfo(ret); - for (int i = 0; i < tilei->num_bels; i++) { - if (std::strcmp(tilei->bel_data[i].name.get(), basename.c_str()) == 0) { + const TileTypePOD *loci = tileInfo(ret); + for (int i = 0; i < loci->num_bels; i++) { + if (std::strcmp(loci->bel_data[i].name.get(), name[2].c_str(this)) == 0) { ret.index = i; - break; + return ret; } } - if (ret.index >= 0) - bel_by_name[name_id] = ret; - return ret; + return BelId(); } BelId Arch::getBelByLocation(Loc loc) const @@ -308,72 +307,63 @@ BelId Arch::getPackagePinBel(const std::string &pin) const WireId Arch::getWireByName(IdStringList name) const { + if (name.size() != 3) + return WireId(); WireId ret; - IdString name_id = name[0]; - - auto it = wire_by_name.find(name_id); - if (it != wire_by_name.end()) - return it->second; - Location loc; - std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name_id.str(this)); + loc.x = id_to_x.at(name[0]); + loc.y = id_to_y.at(name[1]); ret.location = loc; - - const TileTypePOD *tilei = tileInfo(ret); - for (int i = 0; i < tilei->num_wires; i++) { - if (std::strcmp(tilei->wire_data[i].name.get(), basename.c_str()) == 0) { + const TileTypePOD *loci = tileInfo(ret); + for (int i = 0; i < loci->num_wires; i++) { + if (std::strcmp(loci->wire_data[i].name.get(), name[2].c_str(this)) == 0) { ret.index = i; - break; + return ret; } } - if (ret.index >= 0) - wire_by_name[name_id] = ret; - return ret; + return WireId(); } // --------------------------------------------------------------- PipId Arch::getPipByName(IdStringList name) const { - PipId ret; - IdString name_id = name[0]; - - auto it = pip_by_name.find(name_id); + if (name.size() != 3) + return PipId(); + auto it = pip_by_name.find(name); if (it != pip_by_name.end()) return it->second; + PipId ret; Location loc; std::string basename; - std::tie(loc.x, loc.y, basename) = split_identifier_name(name_id.str(this)); + loc.x = id_to_x.at(name[0]); + loc.y = id_to_y.at(name[1]); ret.location = loc; - - const TileTypePOD *tilei = tileInfo(ret); - for (int i = 0; i < tilei->num_pips; i++) { + const TileTypePOD *loci = tileInfo(ret); + for (int i = 0; i < loci->num_pips; i++) { PipId curr; curr.location = loc; curr.index = i; - pip_by_name[getPipName(curr)[0]] = curr; + pip_by_name[getPipName(curr)] = curr; } - if (pip_by_name.find(name_id) == pip_by_name.end()) - NPNR_ASSERT_FALSE_STR("no pip named " + name_id.str(this)); - return pip_by_name[name_id]; + if (pip_by_name.find(name) == pip_by_name.end()) + NPNR_ASSERT_FALSE_STR("no pip named " + name.str(getCtx())); + return pip_by_name[name]; } IdStringList Arch::getPipName(PipId pip) const { - NPNR_ASSERT(pip != PipId()); - - int x = pip.location.x; - int y = pip.location.y; - - std::string src_name = getWireName(getPipSrcWire(pip)).str(getCtx()); - std::replace(src_name.begin(), src_name.end(), '/', '.'); - - std::string dst_name = getWireName(getPipDstWire(pip)).str(getCtx()); - std::replace(dst_name.begin(), dst_name.end(), '/', '.'); - - return IdStringList(id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name)); + auto &pip_data = tileInfo(pip)->pips_data[pip.index]; + WireId src = getPipSrcWire(pip), dst = getPipDstWire(pip); + const char *src_name = tileInfo(src)->wire_data[src.index].name.get(); + const char *dst_name = tileInfo(dst)->wire_data[dst.index].name.get(); + std::string pip_name = + stringf("%d_%d_%s->%d_%d_%s", pip_data.src.x - pip.location.x, pip_data.src.y - pip.location.y, src_name, + pip_data.dst.x - pip.location.x, pip_data.dst.y - pip.location.y, dst_name); + + std::array ids{x_ids.at(pip.location.x), y_ids.at(pip.location.y), id(pip_name)}; + return IdStringList(ids); } // --------------------------------------------------------------- diff --git a/machxo2/arch.h b/machxo2/arch.h index 466eca79..fae7523e 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -398,9 +398,12 @@ struct Arch : BaseArch const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; - mutable std::unordered_map bel_by_name; - mutable std::unordered_map wire_by_name; - mutable std::unordered_map pip_by_name; + mutable std::unordered_map pip_by_name; + + // fast access to X and Y IdStrings for building object names + std::vector x_ids, y_ids; + // inverse of the above for name->object mapping + std::unordered_map id_to_x, id_to_y; // Helpers template const TileTypePOD *tileInfo(Id &id) const @@ -439,15 +442,17 @@ struct Arch : BaseArch // tiles can complicate this? int getTilePipDimZ(int x, int y) const override { return 2; } + char getNameDelimiter() const override { return '/'; } + // Bels BelId getBelByName(IdStringList name) const override; IdStringList getBelName(BelId bel) const override { NPNR_ASSERT(bel != BelId()); - std::stringstream name; - name << "X" << bel.location.x << "/Y" << bel.location.y << "/" << tileInfo(bel)->bel_data[bel.index].name.get(); - return IdStringList(id(name.str())); + std::array ids{x_ids.at(bel.location.x), y_ids.at(bel.location.y), + id(tileInfo(bel)->bel_data[bel.index].name.get())}; + return IdStringList(ids); } Loc getBelLocation(BelId bel) const override @@ -498,10 +503,9 @@ struct Arch : BaseArch IdStringList getWireName(WireId wire) const override { NPNR_ASSERT(wire != WireId()); - std::stringstream name; - name << "X" << wire.location.x << "/Y" << wire.location.y << "/" - << tileInfo(wire)->wire_data[wire.index].name.get(); - return IdStringList(id(name.str())); + std::array ids{x_ids.at(wire.location.x), y_ids.at(wire.location.y), + id(tileInfo(wire)->wire_data[wire.index].name.get())}; + return IdStringList(ids); } DelayInfo getWireDelay(WireId wire) const override { return DelayInfo(); } -- cgit v1.2.3 From 8f5133d8111d83137195b8cdae5d80747f8ee315 Mon Sep 17 00:00:00 2001 From: gatecat Date: Thu, 11 Feb 2021 13:46:29 +0000 Subject: machxo2: Use snake_case for non-ArchAPI functions Signed-off-by: gatecat --- machxo2/arch.cc | 34 +++++++++++++++++----------------- machxo2/arch.h | 52 ++++++++++++++++++++++++++-------------------------- machxo2/bitstream.cc | 28 ++++++++++++++-------------- machxo2/main.cc | 12 ++++++------ 4 files changed, 63 insertions(+), 63 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index c2b2e0ad..21129f07 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -109,7 +109,7 @@ Arch::Arch(ArchArgs args) : args(args) } } -bool Arch::isAvailable(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip) != nullptr; } +bool Arch::is_available(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip) != nullptr; } std::string Arch::getChipName() const { @@ -130,7 +130,7 @@ std::string Arch::getChipName() const } } -std::string Arch::getFullChipName() const +std::string Arch::get_full_chip_name() const { std::string name = getChipName(); name += "-"; @@ -187,7 +187,7 @@ BelId Arch::getBelByName(IdStringList name) const loc.x = id_to_x.at(name[0]); loc.y = id_to_y.at(name[1]); ret.location = loc; - const TileTypePOD *loci = tileInfo(ret); + const TileTypePOD *loci = tile_info(ret); for (int i = 0; i < loci->num_bels; i++) { if (std::strcmp(loci->bel_data[i].name.get(), name[2].c_str(this)) == 0) { ret.index = i; @@ -207,7 +207,7 @@ BelId Arch::getBelByLocation(Loc loc) const ret.location.x = loc.x; ret.location.y = loc.y; - const TileTypePOD *tilei = tileInfo(ret); + const TileTypePOD *tilei = tile_info(ret); for (int i = 0; i < tilei->num_bels; i++) { if (tilei->bel_data[i].z == loc.z) { ret.index = i; @@ -241,8 +241,8 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const { NPNR_ASSERT(bel != BelId()); - int num_bel_wires = tileInfo(bel)->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = &*tileInfo(bel)->bel_data[bel.index].bel_wires; + int num_bel_wires = tile_info(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = &*tile_info(bel)->bel_data[bel.index].bel_wires; for (int i = 0; i < num_bel_wires; i++) if (bel_wires[i].port == pin.index) { @@ -262,8 +262,8 @@ PortType Arch::getBelPinType(BelId bel, IdString pin) const { NPNR_ASSERT(bel != BelId()); - int num_bel_wires = tileInfo(bel)->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = &*tileInfo(bel)->bel_data[bel.index].bel_wires; + int num_bel_wires = tile_info(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = &*tile_info(bel)->bel_data[bel.index].bel_wires; for (int i = 0; i < num_bel_wires; i++) if (bel_wires[i].port == pin.index) @@ -277,8 +277,8 @@ std::vector Arch::getBelPins(BelId bel) const std::vector ret; NPNR_ASSERT(bel != BelId()); - int num_bel_wires = tileInfo(bel)->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = &*tileInfo(bel)->bel_data[bel.index].bel_wires; + int num_bel_wires = tile_info(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = &*tile_info(bel)->bel_data[bel.index].bel_wires; for (int i = 0; i < num_bel_wires; i++) { IdString id(bel_wires[i].port); @@ -314,7 +314,7 @@ WireId Arch::getWireByName(IdStringList name) const loc.x = id_to_x.at(name[0]); loc.y = id_to_y.at(name[1]); ret.location = loc; - const TileTypePOD *loci = tileInfo(ret); + const TileTypePOD *loci = tile_info(ret); for (int i = 0; i < loci->num_wires; i++) { if (std::strcmp(loci->wire_data[i].name.get(), name[2].c_str(this)) == 0) { ret.index = i; @@ -340,7 +340,7 @@ PipId Arch::getPipByName(IdStringList name) const loc.x = id_to_x.at(name[0]); loc.y = id_to_y.at(name[1]); ret.location = loc; - const TileTypePOD *loci = tileInfo(ret); + const TileTypePOD *loci = tile_info(ret); for (int i = 0; i < loci->num_pips; i++) { PipId curr; curr.location = loc; @@ -354,10 +354,10 @@ PipId Arch::getPipByName(IdStringList name) const IdStringList Arch::getPipName(PipId pip) const { - auto &pip_data = tileInfo(pip)->pips_data[pip.index]; + auto &pip_data = tile_info(pip)->pips_data[pip.index]; WireId src = getPipSrcWire(pip), dst = getPipDstWire(pip); - const char *src_name = tileInfo(src)->wire_data[src.index].name.get(); - const char *dst_name = tileInfo(dst)->wire_data[dst.index].name.get(); + const char *src_name = tile_info(src)->wire_data[src.index].name.get(); + const char *dst_name = tile_info(dst)->wire_data[dst.index].name.get(); std::string pip_name = stringf("%d_%d_%s->%d_%d_%s", pip_data.src.x - pip.location.x, pip_data.src.y - pip.location.y, src_name, pip_data.dst.x - pip.location.x, pip_data.dst.y - pip.location.y, dst_name); @@ -465,9 +465,9 @@ const std::vector Arch::availablePlacers = {"sa", const std::string Arch::defaultRouter = "router1"; const std::vector Arch::availableRouters = {"router1", "router2"}; -bool Arch::cellsCompatible(const CellInfo **cells, int count) const { return false; } +bool Arch::cells_compatible(const CellInfo **cells, int count) const { return false; } -std::vector> Arch::getTilesAtLocation(int row, int col) +std::vector> Arch::get_tiles_at_location(int row, int col) { std::vector> ret; auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; diff --git a/machxo2/arch.h b/machxo2/arch.h index fae7523e..937157f3 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -406,12 +406,12 @@ struct Arch : BaseArch std::unordered_map id_to_x, id_to_y; // Helpers - template const TileTypePOD *tileInfo(Id &id) const + template const TileTypePOD *tile_info(Id &id) const { return &(chip_info->tiles[id.location.y * chip_info->width + id.location.x]); } - int getBelFlatIndex(BelId bel) const + int get_bel_flat_index(BelId bel) const { return (bel.location.y * chip_info->width + bel.location.x) * max_loc_bels + bel.index; } @@ -423,11 +423,11 @@ struct Arch : BaseArch ArchArgs args; Arch(ArchArgs args); - static bool isAvailable(ArchArgs::ArchArgsTypes chip); + static bool is_available(ArchArgs::ArchArgsTypes chip); std::string getChipName() const override; // Extra helper - std::string getFullChipName() const; + std::string get_full_chip_name() const; IdString archId() const override { return id("machxo2"); } ArchArgs archArgs() const override { return args; } @@ -451,7 +451,7 @@ struct Arch : BaseArch { NPNR_ASSERT(bel != BelId()); std::array ids{x_ids.at(bel.location.x), y_ids.at(bel.location.y), - id(tileInfo(bel)->bel_data[bel.index].name.get())}; + id(tile_info(bel)->bel_data[bel.index].name.get())}; return IdStringList(ids); } @@ -461,7 +461,7 @@ struct Arch : BaseArch Loc loc; loc.x = bel.location.x; loc.y = bel.location.y; - loc.z = tileInfo(bel)->bel_data[bel.index].z; + loc.z = tile_info(bel)->bel_data[bel.index].z; return loc; } @@ -486,7 +486,7 @@ struct Arch : BaseArch { NPNR_ASSERT(bel != BelId()); IdString id; - id.index = tileInfo(bel)->bel_data[bel.index].type; + id.index = tile_info(bel)->bel_data[bel.index].type; return id; } @@ -504,7 +504,7 @@ struct Arch : BaseArch { NPNR_ASSERT(wire != WireId()); std::array ids{x_ids.at(wire.location.x), y_ids.at(wire.location.y), - id(tileInfo(wire)->wire_data[wire.index].name.get())}; + id(tile_info(wire)->wire_data[wire.index].name.get())}; return IdStringList(ids); } @@ -527,9 +527,9 @@ struct Arch : BaseArch { BelPinRange range; NPNR_ASSERT(wire != WireId()); - range.b.ptr = tileInfo(wire)->wire_data[wire.index].bel_pins.get(); + range.b.ptr = tile_info(wire)->wire_data[wire.index].bel_pins.get(); range.b.wire_loc = wire.location; - range.e.ptr = range.b.ptr + tileInfo(wire)->wire_data[wire.index].num_bel_pins; + range.e.ptr = range.b.ptr + tile_info(wire)->wire_data[wire.index].num_bel_pins; range.e.wire_loc = wire.location; return range; } @@ -567,8 +567,8 @@ struct Arch : BaseArch { WireId wire; NPNR_ASSERT(pip != PipId()); - wire.index = tileInfo(pip)->pips_data[pip.index].src_idx; - wire.location = tileInfo(pip)->pips_data[pip.index].src; + wire.index = tile_info(pip)->pips_data[pip.index].src_idx; + wire.location = tile_info(pip)->pips_data[pip.index].src; return wire; } @@ -576,8 +576,8 @@ struct Arch : BaseArch { WireId wire; NPNR_ASSERT(pip != PipId()); - wire.index = tileInfo(pip)->pips_data[pip.index].dst_idx; - wire.location = tileInfo(pip)->pips_data[pip.index].dst; + wire.index = tile_info(pip)->pips_data[pip.index].dst_idx; + wire.location = tile_info(pip)->pips_data[pip.index].dst; return wire; } @@ -594,9 +594,9 @@ struct Arch : BaseArch { PipRange range; NPNR_ASSERT(wire != WireId()); - range.b.cursor = tileInfo(wire)->wire_data[wire.index].pips_downhill.get(); + range.b.cursor = tile_info(wire)->wire_data[wire.index].pips_downhill.get(); range.b.wire_loc = wire.location; - range.e.cursor = range.b.cursor + tileInfo(wire)->wire_data[wire.index].num_downhill; + range.e.cursor = range.b.cursor + tile_info(wire)->wire_data[wire.index].num_downhill; range.e.wire_loc = wire.location; return range; } @@ -605,21 +605,21 @@ struct Arch : BaseArch { PipRange range; NPNR_ASSERT(wire != WireId()); - range.b.cursor = tileInfo(wire)->wire_data[wire.index].pips_uphill.get(); + range.b.cursor = tile_info(wire)->wire_data[wire.index].pips_uphill.get(); range.b.wire_loc = wire.location; - range.e.cursor = range.b.cursor + tileInfo(wire)->wire_data[wire.index].num_uphill; + range.e.cursor = range.b.cursor + tile_info(wire)->wire_data[wire.index].num_uphill; range.e.wire_loc = wire.location; return range; } // Extra Pip helpers. - int8_t getPipClass(PipId pip) const { return tileInfo(pip)->pips_data[pip.index].pip_type; } + int8_t get_pip_class(PipId pip) const { return tile_info(pip)->pips_data[pip.index].pip_type; } - std::string getPipTilename(PipId pip) const + std::string get_pip_tilename(PipId pip) const { auto &tileloc = chip_info->tile_info[pip.location.y * chip_info->width + pip.location.x]; for (int i = 0; i < tileloc.num_tiles; i++) { - if (tileloc.tile_names[i].type_idx == tileInfo(pip)->pips_data[pip.index].tile_type) + if (tileloc.tile_names[i].type_idx == tile_info(pip)->pips_data[pip.index].tile_type) return tileloc.tile_names[i].name.get(); } NPNR_ASSERT_FALSE("failed to find Pip tile"); @@ -659,10 +659,10 @@ struct Arch : BaseArch // --------------------------------------------------------------- // Internal usage - bool cellsCompatible(const CellInfo **cells, int count) const; + bool cells_compatible(const CellInfo **cells, int count) const; - std::vector> getTilesAtLocation(int row, int col); - std::string getTileByTypeAndLocation(int row, int col, std::string type) const + std::vector> get_tiles_at_location(int row, int col); + std::string get_tile_by_type_and_loc(int row, int col, std::string type) const { auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; for (int i = 0; i < tileloc.num_tiles; i++) { @@ -673,7 +673,7 @@ struct Arch : BaseArch type); } - std::string getTileByTypeAndLocation(int row, int col, const std::set &type) const + std::string get_tile_by_type_and_loc(int row, int col, const std::set &type) const { auto &tileloc = chip_info->tile_info[row * chip_info->width + col]; for (int i = 0; i < tileloc.num_tiles; i++) { @@ -683,7 +683,7 @@ struct Arch : BaseArch NPNR_ASSERT_FALSE_STR("no tile at (" + std::to_string(col) + ", " + std::to_string(row) + ") with type in set"); } - std::string getTileByType(std::string type) const + std::string get_tile_by_type(std::string type) const { for (int i = 0; i < chip_info->height * chip_info->width; i++) { auto &tileloc = chip_info->tile_info[i]; diff --git a/machxo2/bitstream.cc b/machxo2/bitstream.cc index 1711326f..37363b09 100644 --- a/machxo2/bitstream.cc +++ b/machxo2/bitstream.cc @@ -52,7 +52,7 @@ void config_empty_lcmxo2_1200hc(ChipConfig &cc) // Convert an absolute wire name to a relative Trellis one static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) { - std::string basename = ctx->tileInfo(wire)->wire_data[wire.index].name.get(); + std::string basename = ctx->tile_info(wire)->wire_data[wire.index].name.get(); std::string prefix2 = basename.substr(0, 2); std::string prefix7 = basename.substr(0, 7); int max_col = ctx->chip_info->width - 1; @@ -99,7 +99,7 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire) static void set_pip(Context *ctx, ChipConfig &cc, PipId pip) { - std::string tile = ctx->getPipTilename(pip); + std::string tile = ctx->get_pip_tilename(pip); std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip)); std::string sink = get_trellis_wirename(ctx, pip.location, ctx->getPipDstWire(pip)); cc.tiles[tile].add_arc(sink, source); @@ -148,15 +148,15 @@ static std::string get_pic_tile(Context *ctx, BelId bel) static const std::set pio_l = {"PIC_L0", "PIC_LS0", "PIC_L0_VREF3"}; static const std::set pio_r = {"PIC_R0", "PIC_RS0"}; - std::string pio_name = ctx->tileInfo(bel)->bel_data[bel.index].name.get(); + std::string pio_name = ctx->tile_info(bel)->bel_data[bel.index].name.get(); if (bel.location.y == 0) { - return ctx->getTileByTypeAndLocation(0, bel.location.x, "PIC_T0"); + return ctx->get_tile_by_type_and_loc(0, bel.location.x, "PIC_T0"); } else if (bel.location.y == ctx->chip_info->height - 1) { - return ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, "PIC_B0"); + return ctx->get_tile_by_type_and_loc(bel.location.y, bel.location.x, "PIC_B0"); } else if (bel.location.x == 0) { - return ctx->getTileByTypeAndLocation(bel.location.y, 0, pio_l); + return ctx->get_tile_by_type_and_loc(bel.location.y, 0, pio_l); } else if (bel.location.x == ctx->chip_info->width - 1) { - return ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, pio_r); + return ctx->get_tile_by_type_and_loc(bel.location.y, bel.location.x, pio_r); } else { NPNR_ASSERT_FALSE("bad PIO location"); } @@ -174,12 +174,12 @@ void write_bitstream(Context *ctx, std::string text_config_file) NPNR_ASSERT_FALSE("Unsupported device type"); } - cc.metadata.push_back("Part: " + ctx->getFullChipName()); + cc.metadata.push_back("Part: " + ctx->get_full_chip_name()); // Add all set, configurable pips to the config for (auto pip : ctx->getPips()) { if (ctx->getBoundPipNet(pip) != nullptr) { - if (ctx->getPipClass(pip) == 0) { // ignore fixed pips + if (ctx->get_pip_class(pip) == 0) { // ignore fixed pips set_pip(ctx, cc, pip); } } @@ -197,8 +197,8 @@ void write_bitstream(Context *ctx, std::string text_config_file) } BelId bel = ci->bel; if (ci->type == id_FACADE_SLICE) { - std::string tname = ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, "PLC"); - std::string slice = ctx->tileInfo(bel)->bel_data[bel.index].name.get(); + std::string tname = ctx->get_tile_by_type_and_loc(bel.location.y, bel.location.x, "PLC"); + std::string slice = ctx->tile_info(bel)->bel_data[bel.index].name.get(); NPNR_ASSERT(slice.substr(0, 5) == "SLICE"); int int_index = slice[5] - 'A'; @@ -227,15 +227,15 @@ void write_bitstream(Context *ctx, std::string text_config_file) cc.tiles[tname].add_enum(slice + ".REG1.REGSET", str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET")); } else if (ci->type == ctx->id("FACADE_IO")) { - std::string pio = ctx->tileInfo(bel)->bel_data[bel.index].name.get(); + std::string pio = ctx->tile_info(bel)->bel_data[bel.index].name.get(); std::string iotype = str_or_default(ci->attrs, ctx->id("IO_TYPE"), "LVCMOS33"); std::string dir = str_or_default(ci->params, ctx->id("DIR"), "INPUT"); std::string pic_tile = get_pic_tile(ctx, bel); cc.tiles[pic_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype); } else if (ci->type == ctx->id("OSCH")) { std::string freq = str_or_default(ci->params, ctx->id("NOM_FREQ"), "2.08"); - cc.tiles[ctx->getTileByType("CFG1")].add_enum("OSCH.MODE", "OSCH"); - cc.tiles[ctx->getTileByType("CFG1")].add_enum("OSCH.NOM_FREQ", freq); + cc.tiles[ctx->get_tile_by_type("CFG1")].add_enum("OSCH.MODE", "OSCH"); + cc.tiles[ctx->get_tile_by_type("CFG1")].add_enum("OSCH.NOM_FREQ", freq); } } diff --git a/machxo2/main.cc b/machxo2/main.cc index 3d0884bf..961fe9ae 100644 --- a/machxo2/main.cc +++ b/machxo2/main.cc @@ -47,17 +47,17 @@ MachXO2CommandHandler::MachXO2CommandHandler(int argc, char **argv) : CommandHan po::options_description MachXO2CommandHandler::getArchOptions() { po::options_description specific("Architecture specific options"); - if (Arch::isAvailable(ArchArgs::LCMXO2_256HC)) + if (Arch::is_available(ArchArgs::LCMXO2_256HC)) specific.add_options()("256", "set device type to LCMXO2-256HC"); - if (Arch::isAvailable(ArchArgs::LCMXO2_640HC)) + if (Arch::is_available(ArchArgs::LCMXO2_640HC)) specific.add_options()("640", "set device type to LCMXO2-640HC"); - if (Arch::isAvailable(ArchArgs::LCMXO2_1200HC)) + if (Arch::is_available(ArchArgs::LCMXO2_1200HC)) specific.add_options()("1200", "set device type to LCMXO2-1200HC"); - if (Arch::isAvailable(ArchArgs::LCMXO2_2000HC)) + if (Arch::is_available(ArchArgs::LCMXO2_2000HC)) specific.add_options()("2000", "set device type to LCMXO2-2000HC"); - if (Arch::isAvailable(ArchArgs::LCMXO2_4000HC)) + if (Arch::is_available(ArchArgs::LCMXO2_4000HC)) specific.add_options()("4000", "set device type to LCMXO2-4000HC"); - if (Arch::isAvailable(ArchArgs::LCMXO2_7000HC)) + if (Arch::is_available(ArchArgs::LCMXO2_7000HC)) specific.add_options()("7000", "set device type to LCMXO2-7000HC"); specific.add_options()("package", po::value(), "select device package"); -- cgit v1.2.3 From 33eca9a3d2569f51c24204ea103672a72f63795d Mon Sep 17 00:00:00 2001 From: gatecat Date: Fri, 12 Feb 2021 10:40:03 +0000 Subject: machxo2: Python bindings and stub GUI Signed-off-by: gatecat --- machxo2/arch.cc | 10 +++++ machxo2/arch.h | 1 + machxo2/arch_pybindings.cc | 79 +++++++++++++++++++++++++++++++++++++ machxo2/arch_pybindings.h | 98 ++++++++++++++++++++++++++++++++++++++++++++++ machxo2/family.cmake | 6 --- 5 files changed, 188 insertions(+), 6 deletions(-) create mode 100644 machxo2/arch_pybindings.cc create mode 100644 machxo2/arch_pybindings.h (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index 21129f07..df9b7efc 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -111,6 +111,16 @@ Arch::Arch(ArchArgs args) : args(args) bool Arch::is_available(ArchArgs::ArchArgsTypes chip) { return get_chip_info(chip) != nullptr; } +std::vector Arch::get_supported_packages(ArchArgs::ArchArgsTypes chip) +{ + const ChipInfoPOD *chip_info = get_chip_info(chip); + std::vector pkgs; + for (int i = 0; i < chip_info->num_packages; i++) { + pkgs.push_back(chip_info->package_info[i].name.get()); + } + return pkgs; +} + std::string Arch::getChipName() const { if (args.type == ArchArgs::LCMXO2_256HC) { diff --git a/machxo2/arch.h b/machxo2/arch.h index 937157f3..f1642490 100644 --- a/machxo2/arch.h +++ b/machxo2/arch.h @@ -424,6 +424,7 @@ struct Arch : BaseArch Arch(ArchArgs args); static bool is_available(ArchArgs::ArchArgsTypes chip); + static std::vector get_supported_packages(ArchArgs::ArchArgsTypes chip); std::string getChipName() const override; // Extra helper diff --git a/machxo2/arch_pybindings.cc b/machxo2/arch_pybindings.cc new file mode 100644 index 00000000..fa0f9535 --- /dev/null +++ b/machxo2/arch_pybindings.cc @@ -0,0 +1,79 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Claire Xen + * Copyright (C) 2018 David Shah + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef NO_PYTHON + +#include "arch_pybindings.h" +#include "nextpnr.h" +#include "pybindings.h" + +NEXTPNR_NAMESPACE_BEGIN + +void arch_wrap_python(py::module &m) +{ + using namespace PythonConversion; + py::class_(m, "ArchArgs").def_readwrite("type", &ArchArgs::type); + + py::class_(m, "BelId").def_readwrite("index", &BelId::index); + + py::class_(m, "WireId").def_readwrite("index", &WireId::index); + + py::class_(m, "PipId").def_readwrite("index", &PipId::index); + + auto arch_cls = py::class_(m, "Arch").def(py::init()); + auto ctx_cls = py::class_(m, "Context") + .def("checksum", &Context::checksum) + .def("pack", &Context::pack) + .def("place", &Context::place) + .def("route", &Context::route); + + fn_wrapper_2a, + addr_and_unwrap, conv_from_str>::def_wrap(ctx_cls, "isValidBelForCell"); + + typedef std::unordered_map> CellMap; + typedef std::unordered_map> NetMap; + typedef std::unordered_map AliasMap; + typedef std::unordered_map HierarchyMap; + + auto belpin_cls = py::class_>(m, "BelPin"); + readonly_wrapper>::def_wrap(belpin_cls, "bel"); + readonly_wrapper>::def_wrap(belpin_cls, "pin"); + + typedef const PipRange UphillPipRange; + typedef const PipRange DownhillPipRange; + + typedef const std::vector &BelBucketRange; + typedef const std::vector &BelRangeForBelBucket; +#include "arch_pybindings_shared.h" + + WRAP_RANGE(m, Bel, conv_to_str); + WRAP_RANGE(m, Wire, conv_to_str); + WRAP_RANGE(m, AllPip, conv_to_str); + WRAP_RANGE(m, Pip, conv_to_str); + WRAP_RANGE(m, BelPin, wrap_context); + + WRAP_MAP_UPTR(m, CellMap, "IdCellMap"); + WRAP_MAP_UPTR(m, NetMap, "IdNetMap"); + WRAP_MAP(m, HierarchyMap, wrap_context, "HierarchyMap"); +} + +NEXTPNR_NAMESPACE_END + +#endif // NO_PYTHON diff --git a/machxo2/arch_pybindings.h b/machxo2/arch_pybindings.h new file mode 100644 index 00000000..62f66406 --- /dev/null +++ b/machxo2/arch_pybindings.h @@ -0,0 +1,98 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Claire Xen + * Copyright (C) 2018 David Shah + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ +#ifndef ARCH_PYBINDINGS_H +#define ARCH_PYBINDINGS_H +#ifndef NO_PYTHON + +#include "nextpnr.h" +#include "pybindings.h" + +NEXTPNR_NAMESPACE_BEGIN + +namespace PythonConversion { + +template <> struct string_converter +{ + BelId from_str(Context *ctx, std::string name) { return ctx->getBelByNameStr(name); } + + std::string to_str(Context *ctx, BelId id) + { + if (id == BelId()) + throw bad_wrap(); + return ctx->getBelName(id).str(ctx); + } +}; + +template <> struct string_converter +{ + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByNameStr(name); } + + std::string to_str(Context *ctx, WireId id) + { + if (id == WireId()) + throw bad_wrap(); + return ctx->getWireName(id).str(ctx); + } +}; + +template <> struct string_converter +{ + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByNameStr(name); } + + std::string to_str(Context *ctx, WireId id) + { + if (id == WireId()) + throw bad_wrap(); + return ctx->getWireName(id).str(ctx); + } +}; + +template <> struct string_converter +{ + PipId from_str(Context *ctx, std::string name) { return ctx->getPipByNameStr(name); } + + std::string to_str(Context *ctx, PipId id) + { + if (id == PipId()) + throw bad_wrap(); + return ctx->getPipName(id).str(ctx); + } +}; + +template <> struct string_converter +{ + BelPin from_str(Context *ctx, std::string name) + { + NPNR_ASSERT_FALSE("string_converter::from_str not implemented"); + } + + std::string to_str(Context *ctx, BelPin pin) + { + if (pin.bel == BelId()) + throw bad_wrap(); + return ctx->getBelName(pin.bel).str(ctx) + "/" + pin.pin.str(ctx); + } +}; + +} // namespace PythonConversion + +NEXTPNR_NAMESPACE_END +#endif +#endif diff --git a/machxo2/family.cmake b/machxo2/family.cmake index b898e396..76c5df93 100644 --- a/machxo2/family.cmake +++ b/machxo2/family.cmake @@ -1,9 +1,3 @@ -if (BUILD_GUI) - message(FATAL_ERROR "GUI support is not implemented for MachXO2. Build with -DBUILD_GUI=OFF.") -endif() -if (BUILD_PYTHON) - message(FATAL_ERROR "Python support is not implemented for MachXO2. Build with -DBUILD_PYTHON=OFF.") -endif() add_subdirectory(${family}) message(STATUS "Using MachXO2 chipdb: ${MACHXO2_CHIPDB}") -- cgit v1.2.3 From 6de733b38c049bf794975551418c5b4fb592cc8c Mon Sep 17 00:00:00 2001 From: gatecat Date: Fri, 12 Feb 2021 10:43:15 +0000 Subject: machxo2: Misc tidying up Signed-off-by: gatecat --- machxo2/arch.cc | 5 ++++- machxo2/archdefs.h | 7 ------- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'machxo2') diff --git a/machxo2/arch.cc b/machxo2/arch.cc index df9b7efc..2938f1ba 100644 --- a/machxo2/arch.cc +++ b/machxo2/arch.cc @@ -401,7 +401,10 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const { ArcBounds bb; - + bb.x0 = std::min(src.location.x, dst.location.x); + bb.y0 = std::min(src.location.y, dst.location.y); + bb.x1 = std::max(src.location.x, dst.location.x); + bb.y1 = std::max(src.location.y, dst.location.y); return bb; } diff --git a/machxo2/archdefs.h b/machxo2/archdefs.h index caa15ece..844a87b6 100644 --- a/machxo2/archdefs.h +++ b/machxo2/archdefs.h @@ -129,13 +129,6 @@ struct NetInfo; struct ArchCellInfo { - // Custom grouping set via "PACK_GROUP" attribute. All cells with the same group - // value may share a tile (-1 = don't care, default if not set) - int user_group; - // Is a slice type primitive - bool is_slice; - // Only packing rule for slice type primitives is a single clock per tile - const NetInfo *slice_clk; }; NEXTPNR_NAMESPACE_END -- cgit v1.2.3