diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/archapi.md | 50 | ||||
-rw-r--r-- | docs/constraints.md | 37 | ||||
-rw-r--r-- | docs/faq.md | 89 |
3 files changed, 158 insertions, 18 deletions
diff --git a/docs/archapi.md b/docs/archapi.md index 73443c15..3c938865 100644 --- a/docs/archapi.md +++ b/docs/archapi.md @@ -30,15 +30,15 @@ delay_t maxDelay() const { return delay; } ### BelId -A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<BelId>`. +A type representing a bel name. `BelId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<BelId>`. ### WireId -A type representing a wire name. `WireId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<WireId>`. +A type representing a wire name. `WireId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<WireId>`. ### PipId -A type representing a pip name. `PipId()` must construct a unique null-value. Must provide `==` and `!=` operators and a specialization for `std::hash<PipId>`. +A type representing a pip name. `PipId()` must construct a unique null-value. Must provide `==`, `!=`, and `<` operators and a specialization for `std::hash<PipId>`. ### GroupId @@ -215,14 +215,15 @@ Return true if the wire is available, i.e. can be bound to a net. Return the net a wire is bound to. -### NetInfo \*getConflictingWireNet(WireId wire) const +### WireId getConflictingWireWire(WireId wire) const -If this returns a non-nullptr, then unbinding that net +If this returns a non-WireId(), then unbinding that wire will make the given wire available. -This returns nullptr if the wire is already available, -or if there is no single net that can be unbound to make this -wire available. +### NetInfo \*getConflictingWireNet(WireId wire) const + +If this returns a non-nullptr, then unbinding that entire net +will make the given wire available. ### DelayInfo getWireDelay(WireId wire) const @@ -282,18 +283,23 @@ This method must also update `NetInfo::wires`. Returns true if the given pip is available to be bound to a net. +Users must also check if the pip destination wire is available +with `checkWireAvail(getPipDstWire(pip))` before binding the +pip to a net. + ### NetInfo \*getBoundPipNet(PipId pip) const Return the net this pip is bound to. -### NetInfo \*getConflictingPipNet(PipId pip) const +### WireId getConflictingPipWire(PipId pip) const -Return the net that needs to be unbound in order to make this -pip available. +If this returns a non-WireId(), then unbinding that wire +will make the given pip available. -This does not need to (but may) return the conflicting wire if the conflict is -limited to the conflicting wire being bound to the destination wire for this -pip. +### NetInfo \*getConflictingPipNet(PipId pip) const + +If this returns a non-nullptr, then unbinding that entire net +will make the given pip available. ### const\_range\<PipId\> getPips() const @@ -398,6 +404,10 @@ actual penalty used is a multiple of this value (i.e. a weighted version of this Convert an `delay_t` to an actual real-world delay in nanoseconds. +### DelayInfo getDelayFromNS(float v) const + +Convert a real-world delay in nanoseconds to a DelayInfo with equal min/max rising/falling values. + ### uint32\_t getDelayChecksum(delay\_t v) const Convert a `delay_t` to an integer for checksum calculations. @@ -455,11 +465,17 @@ Cell Delay Methods Returns the delay for the specified path through a cell in the `&delay` argument. The method returns false if there is no timing relationship from `fromPort` to `toPort`. -### TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const +### TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const Return the _timing port class_ of a port. This can be a register or combinational input or output; clock input or -output; general startpoint or endpoint; or a port ignored for timing purposes. For register ports, clockPort is set -to the associated clock port. +output; general startpoint or endpoint; or a port ignored for timing purposes. For register ports, clockInfoCount is set +to the number of associated _clock edges_ that can be queried by getPortClockingInfo. + +### TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const + +Return the _clocking info_ (including port name of clock, clock polarity and setup/hold/clock-to-out times) of a +port. Where ports have more than one clock edge associated with them (such as DDR outputs), `index` can be used to obtain +information for all edges. `index` must be in [0, clockInfoCount), behaviour is undefined otherwise. Placer Methods -------------- diff --git a/docs/constraints.md b/docs/constraints.md new file mode 100644 index 00000000..263df7b6 --- /dev/null +++ b/docs/constraints.md @@ -0,0 +1,37 @@ +# Constraints + +There are three types of constraints available for end users of nextpnr. + +## Architecture-specific IO Cconstraints + +Architectures may provide support for their native (or any other) IO constraint format. +The iCE40 architecture supports PCF constraints thus: + + set_io led[0] 3 + +and the ECP5 architecture supports a subset of LPF constraints: + + LOCATE COMP "led[0]" SITE "E16"; + IOBUF PORT "led[0]" IO_TYPE=LVCMOS25; + + +## Absolute Placement Constraints + +nextpnr provides generic support for placement constraints by setting the Bel attribute on the cell to the name of +the Bel you wish it to be placed at. For example: + + (* BEL="X2/Y5/lc0" *) + +## Clock Constraints + +There are two ways to apply clock constraints in nextpnr. The `--clock {freq}` command line argument is used to +apply a default frequency (in MHz) to all clocks without a more specific constraint. + +The Python API can apply clock constraints to specific named clocks. This is done by passing a Python file +specifying these constraints to the `--pre-pack` command line argument. Inside the file, constraints are applied by +calling the function `ctx.addClock` with the name of the clock and its frequency in MHz, for example: + + ctx.addClock("csi_rx_i.dphy_clk", 96) + ctx.addClock("video_clk", 24) + ctx.addClock("uart_i.sys_clk_i", 12) + diff --git a/docs/faq.md b/docs/faq.md index d440bba6..7b358187 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -38,7 +38,94 @@ For nextpnr we are using the following terminology. Adding new architectures to nextpnr ----------------------------------- -TBD +### Implementing new architectures + +Each nextpnr architecture must implement the *nextpnr architecture API*. +See [archapi.md](archapi.md) for a complete reference of the architecture API. + +### Delay Estimates + +Each architecture must implement a `estimateDelay()` method that estimates the expected delay for a path from given `src` to `dst` wires. +*It is very important that this method slightly overestimates the expected delay.* Furthermore, it should overestimate the expected delay +by a slightly larger margin for longer paths than for shorter paths. Otherwise there will be performance issues with the router. + +The delays estimates returned by that method should also be as fine-grain as possible. It definitely pays off to spend some time improving the `estimateDelay()` +for your architecture once implementing small designs work. + +### Ripup Information + +The `getConflictingWireWire()`, `getConflictingWireNet()`, `getConflictingPipWire()`, and `getConflictingPipNet()` methods are used by the router +to determine which resources to rip up in order to make a given routing resource (wire or pip) available. + +The architecture must guanrantee that the following invariants hold. + +**Invariant 1:** + +``` + if (!ctx->checkWireAvail(wire)) { + WireId w = getConflictingWireWire(wire); + if (w != WireId()) { + ctx->unbindWire(w); + assert(ctx->checkWireAvail(wire)); + } + } +``` + +**Invariant 2:** + +``` + if (!ctx->checkWireAvail(wire)) { + NetInfo *n = getConflictingWireNet(wire); + if (n != nullptr) { + for (auto &it : n->wires) + ctx->unbindWire(it.first); + assert(ctx->checkWireAvail(wire)); + } + } +``` + +**Invariant 3:** + +``` + if (!ctx->checkPipAvail(pip)) { + WireId w = getConflictingPipWire(pip); + if (w != WireId()) { + ctx->unbindWire(w); + assert(ctx->checkPipAvail(pip)); + } + } +``` + +**Invariant 4:** + +``` + if (!ctx->checkPipAvail(pip)) { + NetInfo *n = getConflictingPipNet(pip); + if (n != nullptr) { + for (auto &it : n->wires) + ctx->unbindWire(it.first); + assert(ctx->checkPipAvail(pip)); + } + } +``` + +**Invariant 5:** + +``` + if (ctx->checkWireAvail(wire)) { + // bind is guaranteed to succeed + ctx->bindWire(wire, net, strength); + } +``` + +**Invariant 6:** + +``` + if (ctx->checkPipAvail(pip) && ctx->checkWireAvail(ctx->getPipDstWire(pip))) { + // bind is guaranteed to succeed + ctx->bindPip(pip, net, strength); + } +``` Nextpnr and other tools ----------------------- |