Skip to content

Commit

Permalink
Viaduct API for a hybrid between generic and full-custom arch
Browse files Browse the repository at this point in the history
Signed-off-by: gatecat <[email protected]>
  • Loading branch information
gatecat committed Jan 4, 2022
1 parent 089ca82 commit e88bd34
Show file tree
Hide file tree
Showing 18 changed files with 1,055 additions and 28 deletions.
60 changes: 54 additions & 6 deletions generic/arch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "router1.h"
#include "router2.h"
#include "util.h"
#include "viaduct_api.h"

NEXTPNR_NAMESPACE_BEGIN

Expand Down Expand Up @@ -285,6 +286,8 @@ uint32_t Arch::getBelChecksum(BelId bel) const

void Arch::bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
{
if (uarch)
uarch->notifyBelChange(bel, cell);
bel_info(bel).bound_cell = cell;
cell->bel = bel;
cell->belStrength = strength;
Expand All @@ -293,14 +296,19 @@ void Arch::bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)

void Arch::unbindBel(BelId bel)
{
if (uarch)
uarch->notifyBelChange(bel, nullptr);
auto &bi = bel_info(bel);
bi.bound_cell->bel = BelId();
bi.bound_cell->belStrength = STRENGTH_NONE;
bi.bound_cell = nullptr;
refreshUiBel(bel);
}

bool Arch::checkBelAvail(BelId bel) const { return bel_info(bel).bound_cell == nullptr; }
bool Arch::checkBelAvail(BelId bel) const
{
return (!uarch || uarch->checkBelAvail(bel)) && (bel_info(bel).bound_cell == nullptr);
}

CellInfo *Arch::getBoundBelCell(BelId bel) const { return bel_info(bel).bound_cell; }

Expand Down Expand Up @@ -359,6 +367,8 @@ uint32_t Arch::getWireChecksum(WireId wire) const { return wire.index; }

void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
{
if (uarch)
uarch->notifyWireChange(wire, net);
wire_info(wire).bound_net = net;
net->wires[wire].pip = PipId();
net->wires[wire].strength = strength;
Expand All @@ -371,16 +381,22 @@ void Arch::unbindWire(WireId wire)

auto pip = net_wires.at(wire).pip;
if (pip != PipId()) {
if (uarch)
uarch->notifyPipChange(pip, nullptr);
pip_info(pip).bound_net = nullptr;
refreshUiPip(pip);
}

uarch->notifyWireChange(wire, nullptr);
net_wires.erase(wire);
wire_info(wire).bound_net = nullptr;
refreshUiWire(wire);
}

bool Arch::checkWireAvail(WireId wire) const { return wire_info(wire).bound_net == nullptr; }
bool Arch::checkWireAvail(WireId wire) const
{
return (!uarch || uarch->checkWireAvail(wire)) && (wire_info(wire).bound_net == nullptr);
}

NetInfo *Arch::getBoundWireNet(WireId wire) const { return wire_info(wire).bound_net; }

Expand Down Expand Up @@ -413,6 +429,10 @@ uint32_t Arch::getPipChecksum(PipId pip) const { return pip.index; }
void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
{
WireId wire = pip_info(pip).dstWire;
if (uarch) {
uarch->notifyPipChange(pip, net);
uarch->notifyWireChange(wire, net);
}
pip_info(pip).bound_net = net;
wire_info(wire).bound_net = net;
net->wires[wire].pip = pip;
Expand All @@ -424,17 +444,26 @@ void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
void Arch::unbindPip(PipId pip)
{
WireId wire = pip_info(pip).dstWire;
if (uarch) {
uarch->notifyPipChange(pip, nullptr);
uarch->notifyWireChange(wire, nullptr);
}
wire_info(wire).bound_net->wires.erase(wire);
pip_info(pip).bound_net = nullptr;
wire_info(wire).bound_net = nullptr;
refreshUiPip(pip);
refreshUiWire(wire);
}

bool Arch::checkPipAvail(PipId pip) const { return pip_info(pip).bound_net == nullptr; }
bool Arch::checkPipAvail(PipId pip) const
{
return (!uarch || uarch->checkPipAvail(pip)) && (pip_info(pip).bound_net == nullptr);
}

bool Arch::checkPipAvailForNet(PipId pip, NetInfo *net) const
{
if (uarch && !uarch->checkPipAvailForNet(pip, net))
return false;
NetInfo *bound_net = pip_info(pip).bound_net;
return bound_net == nullptr || bound_net == net;
}
Expand Down Expand Up @@ -488,6 +517,8 @@ const std::vector<GroupId> &Arch::getGroupGroups(GroupId group) const { return g

delay_t Arch::estimateDelay(WireId src, WireId dst) const
{
if (uarch)
return uarch->estimateDelay(src, dst);
const WireInfo &s = wire_info(src);
const WireInfo &d = wire_info(dst);
int dx = abs(s.x - d.x);
Expand All @@ -497,8 +528,8 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const

delay_t Arch::predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const
{
NPNR_UNUSED(src_pin);
NPNR_UNUSED(dst_pin);
if (uarch)
return uarch->predictDelay(src_bel, src_pin, dst_bel, dst_pin);
auto driver_loc = getBelLocation(src_bel);
auto sink_loc = getBelLocation(dst_bel);

Expand All @@ -511,6 +542,8 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay

ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const
{
if (uarch)
return uarch->getRouteBoundingBox(src, dst);
ArcBounds bb;

int src_x = wire_info(src).x;
Expand All @@ -537,6 +570,8 @@ ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const

bool Arch::place()
{
if (uarch)
uarch->prePlace();
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
if (placer == "heap") {
bool have_iobuf_or_constr = false;
Expand All @@ -548,7 +583,7 @@ bool Arch::place()
}
}
bool retVal;
if (!have_iobuf_or_constr) {
if (!have_iobuf_or_constr && !uarch) {
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()));
Expand All @@ -557,11 +592,15 @@ bool Arch::place()
cfg.ioBufTypes.insert(id("GENERIC_IOB"));
retVal = placer_heap(getCtx(), cfg);
}
if (uarch)
uarch->postPlace();
getCtx()->settings[getCtx()->id("place")] = 1;
archInfoToAttributes();
return retVal;
} else if (placer == "sa") {
bool retVal = placer1(getCtx(), Placer1Cfg(getCtx()));
if (uarch)
uarch->postPlace();
getCtx()->settings[getCtx()->id("place")] = 1;
archInfoToAttributes();
return retVal;
Expand All @@ -572,6 +611,8 @@ bool Arch::place()

bool Arch::route()
{
if (uarch)
uarch->preRoute();
std::string router = str_or_default(settings, id("router"), defaultRouter);
bool result;
if (router == "router1") {
Expand All @@ -582,6 +623,8 @@ bool Arch::route()
} else {
log_error("iCE40 architecture does not support router '%s'\n", router.c_str());
}
if (uarch)
uarch->postRoute();
getCtx()->settings[getCtx()->id("route")] = 1;
archInfoToAttributes();
return result;
Expand Down Expand Up @@ -644,6 +687,8 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port

bool Arch::isBelLocationValid(BelId bel) const
{
if (uarch)
return uarch->isBelLocationValid(bel);
std::vector<const CellInfo *> cells;
Loc loc = getBelLocation(bel);
for (auto tbel : getBelsByTile(loc.x, loc.y)) {
Expand Down Expand Up @@ -671,6 +716,7 @@ const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};

void Arch::assignArchInfo()
{
int index = 0;
for (auto &cell : getCtx()->cells) {
CellInfo *ci = cell.second.get();
if (ci->type == id("GENERIC_SLICE")) {
Expand All @@ -684,6 +730,8 @@ void Arch::assignArchInfo()
for (auto &p : ci->ports)
if (!ci->bel_pins.count(p.first))
ci->bel_pins.emplace(p.first, std::vector<IdString>{p.first});
ci->flat_index = index;
++index;
}
}

Expand Down
33 changes: 18 additions & 15 deletions generic/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
#include <map>

#include "arch_api.h"
#include "base_arch.h"
#include "idstring.h"
#include "idstringlist.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"
#include "viaduct_api.h"

NEXTPNR_NAMESPACE_BEGIN

Expand Down Expand Up @@ -126,7 +128,7 @@ template <typename TId> struct linear_range
iterator end() const { return iterator(size); }
};

struct ArchRanges
struct ArchRanges : BaseArchRanges
{
using ArchArgsT = ArchArgs;
// Bels
Expand Down Expand Up @@ -158,9 +160,10 @@ struct ArchRanges
using BucketBelRangeT = std::vector<BelId>;
};

struct Arch : ArchAPI<ArchRanges>
struct Arch : BaseArch<ArchRanges>
{
std::string chipName;
std::unique_ptr<ViaductAPI> uarch{};

std::vector<WireInfo> wires;
std::vector<PipInfo> pips;
Expand Down Expand Up @@ -325,6 +328,8 @@ struct Arch : ArchAPI<ArchRanges>

std::vector<IdString> getCellTypes() const override
{
if (uarch)
return uarch->getCellTypes();
pool<IdString> cell_types;
for (auto bel : bels) {
cell_types.insert(bel.type);
Expand All @@ -339,9 +344,15 @@ struct Arch : ArchAPI<ArchRanges>

BelBucketId getBelBucketByName(IdString bucket) const override { return bucket; }

BelBucketId getBelBucketForBel(BelId bel) const override { return getBelType(bel); }
BelBucketId getBelBucketForBel(BelId bel) const override
{
return uarch ? uarch->getBelBucketForBel(bel) : getBelType(bel);
}

BelBucketId getBelBucketForCellType(IdString cell_type) const override { return cell_type; }
BelBucketId getBelBucketForCellType(IdString cell_type) const override
{
return uarch ? uarch->getBelBucketForCellType(cell_type) : cell_type;
}

std::vector<BelId> getBelsInBucket(BelBucketId bucket) const override
{
Expand All @@ -366,19 +377,11 @@ struct Arch : ArchAPI<ArchRanges>
// Get the TimingClockingInfo of a port
TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const override;

bool isValidBelForCellType(IdString cell_type, BelId bel) const override { return cell_type == getBelType(bel); }
bool isBelLocationValid(BelId bel) const override;

// TODO
CellInfo *getClusterRootCell(ClusterId cluster) const override { NPNR_ASSERT_FALSE("unimplemented"); }
ArcBounds getClusterBounds(ClusterId cluster) const override { NPNR_ASSERT_FALSE("unimplemented"); }
Loc getClusterOffset(const CellInfo *cell) const override { NPNR_ASSERT_FALSE("unimplemented"); }
bool isClusterStrict(const CellInfo *cell) const override { NPNR_ASSERT_FALSE("unimplemented"); }
bool getClusterPlacement(ClusterId cluster, BelId root_bel,
std::vector<std::pair<CellInfo *, BelId>> &placement) const override
bool isValidBelForCellType(IdString cell_type, BelId bel) const override
{
NPNR_ASSERT_FALSE("unimplemented");
return uarch ? uarch->isValidBelForCellType(cell_type, bel) : cell_type == getBelType(bel);
}
bool isBelLocationValid(BelId bel) const override;

static const std::string defaultPlacer;
static const std::vector<std::string> availablePlacers;
Expand Down
5 changes: 4 additions & 1 deletion generic/archdefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#ifndef GENERIC_ARCHDEFS_H
#define GENERIC_ARCHDEFS_H

#include "base_clusterinfo.h"
#include "hashlib.h"
#include "idstringlist.h"

Expand Down Expand Up @@ -74,7 +75,7 @@ struct ArchNetInfo

struct NetInfo;

struct ArchCellInfo
struct ArchCellInfo : BaseClusterInfo
{
// 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)
Expand All @@ -83,6 +84,8 @@ struct ArchCellInfo
bool is_slice;
// Only packing rule for slice type primitives is a single clock per tile
const NetInfo *slice_clk;
// A flat index for cells; so viaduct uarches can have their own fast flat arrays of per-cell validity-related data
int flat_index;
// Cell to bel pin mapping
dict<IdString, std::vector<IdString>> bel_pins;
};
Expand Down
7 changes: 7 additions & 0 deletions generic/family.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
set(VIADUCT_UARCHES "example")
foreach(uarch ${VIADUCT_UARCHES})
aux_source_directory(${family}/viaduct/${uarch} UARCH_FILES)
foreach(target ${family_targets})
target_sources(${target} PRIVATE ${UARCH_FILES})
endforeach()
endforeach(uarch)
15 changes: 14 additions & 1 deletion generic/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ GenericCommandHandler::GenericCommandHandler(int argc, char **argv) : CommandHan

po::options_description GenericCommandHandler::getArchOptions()
{
std::string all_uarches = ViaductArch::list();
std::string uarch_help = stringf("viaduct micro-arch to use (available: %s)", all_uarches.c_str());
po::options_description specific("Architecture specific options");
specific.add_options()("generic", "set device type to generic");
specific.add_options()("uarch", po::value<std::string>(), uarch_help.c_str());
specific.add_options()("no-iobs", "disable automatic IO buffer insertion");
return specific;
}
Expand All @@ -63,6 +65,17 @@ std::unique_ptr<Context> GenericCommandHandler::createContext(dict<std::string,
auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
if (vm.count("no-iobs"))
ctx->settings[ctx->id("disable_iobs")] = Property::State::S1;
if (vm.count("uarch")) {
std::string uarch_name = vm["uarch"].as<std::string>();
dict<std::string, std::string> args; // TODO
auto uarch = ViaductArch::create(uarch_name, args);
if (!uarch) {
std::string all_uarches = ViaductArch::list();
log_error("Unknown viaduct uarch '%s'; available options: '%s'\n", uarch_name.c_str(), all_uarches.c_str());
}
ctx->uarch = std::move(uarch);
ctx->uarch->init(ctx.get());
}
return ctx;
}

Expand Down
14 changes: 9 additions & 5 deletions generic/pack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -276,12 +276,16 @@ 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;
if (uarch) {
uarch->pack();
} else {
pack_constants(ctx);
pack_io(ctx);
pack_lut_lutffs(ctx);
pack_nonlut_ffs(ctx);
}
ctx->assignArchInfo();
ctx->settings[ctx->id("pack")] = 1;
log_info("Checksum: 0x%08x\n", ctx->checksum());
return true;
} catch (log_execution_error_exception) {
Expand Down
1 change: 1 addition & 0 deletions generic/viaduct/example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.json
Loading

0 comments on commit e88bd34

Please sign in to comment.