1 /*
2  *  nextpnr -- Next Generation Place and Route
3  *
4  *  Copyright (C) 2018  Clifford Wolf <clifford@symbioticeda.com>
5  *
6  *  Permission to use, copy, modify, and/or distribute this software for any
7  *  purpose with or without fee is hereby granted, provided that the above
8  *  copyright notice and this permission notice appear in all copies.
9  *
10  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  */
19 
20 #include <iostream>
21 #include <math.h>
22 #include "nextpnr.h"
23 #include "placer1.h"
24 #include "placer_heap.h"
25 #include "router1.h"
26 #include "router2.h"
27 #include "util.h"
28 
29 NEXTPNR_NAMESPACE_BEGIN
30 
wire_info(IdString wire)31 WireInfo &Arch::wire_info(IdString wire)
32 {
33     auto w = wires.find(wire);
34     if (w == wires.end())
35         NPNR_ASSERT_FALSE_STR("no wire named " + wire.str(this));
36     return w->second;
37 }
38 
pip_info(IdString pip)39 PipInfo &Arch::pip_info(IdString pip)
40 {
41     auto p = pips.find(pip);
42     if (p == pips.end())
43         NPNR_ASSERT_FALSE_STR("no pip named " + pip.str(this));
44     return p->second;
45 }
46 
bel_info(IdString bel)47 BelInfo &Arch::bel_info(IdString bel)
48 {
49     auto b = bels.find(bel);
50     if (b == bels.end())
51         NPNR_ASSERT_FALSE_STR("no bel named " + bel.str(this));
52     return b->second;
53 }
54 
addWire(IdString name,IdString type,int x,int y)55 void Arch::addWire(IdString name, IdString type, int x, int y)
56 {
57     NPNR_ASSERT(wires.count(name) == 0);
58     WireInfo &wi = wires[name];
59     wi.name = name;
60     wi.type = type;
61     wi.x = x;
62     wi.y = y;
63 
64     wire_ids.push_back(name);
65 }
66 
addPip(IdString name,IdString type,IdString srcWire,IdString dstWire,DelayInfo delay,Loc loc)67 void Arch::addPip(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay, Loc loc)
68 {
69     NPNR_ASSERT(pips.count(name) == 0);
70     PipInfo &pi = pips[name];
71     pi.name = name;
72     pi.type = type;
73     pi.srcWire = srcWire;
74     pi.dstWire = dstWire;
75     pi.delay = delay;
76     pi.loc = loc;
77 
78     wire_info(srcWire).downhill.push_back(name);
79     wire_info(dstWire).uphill.push_back(name);
80     pip_ids.push_back(name);
81 
82     if (int(tilePipDimZ.size()) <= loc.x)
83         tilePipDimZ.resize(loc.x + 1);
84 
85     if (int(tilePipDimZ[loc.x].size()) <= loc.y)
86         tilePipDimZ[loc.x].resize(loc.y + 1);
87 
88     gridDimX = std::max(gridDimX, loc.x + 1);
89     gridDimY = std::max(gridDimY, loc.x + 1);
90     tilePipDimZ[loc.x][loc.y] = std::max(tilePipDimZ[loc.x][loc.y], loc.z + 1);
91 }
92 
addAlias(IdString name,IdString type,IdString srcWire,IdString dstWire,DelayInfo delay)93 void Arch::addAlias(IdString name, IdString type, IdString srcWire, IdString dstWire, DelayInfo delay)
94 {
95     NPNR_ASSERT(pips.count(name) == 0);
96     PipInfo &pi = pips[name];
97     pi.name = name;
98     pi.type = type;
99     pi.srcWire = srcWire;
100     pi.dstWire = dstWire;
101     pi.delay = delay;
102 
103     wire_info(srcWire).aliases.push_back(name);
104     pip_ids.push_back(name);
105 }
106 
addBel(IdString name,IdString type,Loc loc,bool gb)107 void Arch::addBel(IdString name, IdString type, Loc loc, bool gb)
108 {
109     NPNR_ASSERT(bels.count(name) == 0);
110     NPNR_ASSERT(bel_by_loc.count(loc) == 0);
111     BelInfo &bi = bels[name];
112     bi.name = name;
113     bi.type = type;
114     bi.x = loc.x;
115     bi.y = loc.y;
116     bi.z = loc.z;
117     bi.gb = gb;
118 
119     bel_ids.push_back(name);
120     bel_by_loc[loc] = name;
121 
122     if (int(bels_by_tile.size()) <= loc.x)
123         bels_by_tile.resize(loc.x + 1);
124 
125     if (int(bels_by_tile[loc.x].size()) <= loc.y)
126         bels_by_tile[loc.x].resize(loc.y + 1);
127 
128     bels_by_tile[loc.x][loc.y].push_back(name);
129 
130     if (int(tileBelDimZ.size()) <= loc.x)
131         tileBelDimZ.resize(loc.x + 1);
132 
133     if (int(tileBelDimZ[loc.x].size()) <= loc.y)
134         tileBelDimZ[loc.x].resize(loc.y + 1);
135 
136     gridDimX = std::max(gridDimX, loc.x + 1);
137     gridDimY = std::max(gridDimY, loc.x + 1);
138     tileBelDimZ[loc.x][loc.y] = std::max(tileBelDimZ[loc.x][loc.y], loc.z + 1);
139 }
140 
addBelInput(IdString bel,IdString name,IdString wire)141 void Arch::addBelInput(IdString bel, IdString name, IdString wire)
142 {
143     NPNR_ASSERT(bel_info(bel).pins.count(name) == 0);
144     PinInfo &pi = bel_info(bel).pins[name];
145     pi.name = name;
146     pi.wire = wire;
147     pi.type = PORT_IN;
148 
149     wire_info(wire).downhill_bel_pins.push_back(BelPin{bel, name});
150     wire_info(wire).bel_pins.push_back(BelPin{bel, name});
151 }
152 
addBelOutput(IdString bel,IdString name,IdString wire)153 void Arch::addBelOutput(IdString bel, IdString name, IdString wire)
154 {
155     NPNR_ASSERT(bel_info(bel).pins.count(name) == 0);
156     PinInfo &pi = bel_info(bel).pins[name];
157     pi.name = name;
158     pi.wire = wire;
159     pi.type = PORT_OUT;
160 
161     wire_info(wire).uphill_bel_pin = BelPin{bel, name};
162     wire_info(wire).bel_pins.push_back(BelPin{bel, name});
163 }
164 
addBelInout(IdString bel,IdString name,IdString wire)165 void Arch::addBelInout(IdString bel, IdString name, IdString wire)
166 {
167     NPNR_ASSERT(bel_info(bel).pins.count(name) == 0);
168     PinInfo &pi = bel_info(bel).pins[name];
169     pi.name = name;
170     pi.wire = wire;
171     pi.type = PORT_INOUT;
172 
173     wire_info(wire).downhill_bel_pins.push_back(BelPin{bel, name});
174     wire_info(wire).bel_pins.push_back(BelPin{bel, name});
175 }
176 
addGroupBel(IdString group,IdString bel)177 void Arch::addGroupBel(IdString group, IdString bel) { groups[group].bels.push_back(bel); }
178 
addGroupWire(IdString group,IdString wire)179 void Arch::addGroupWire(IdString group, IdString wire) { groups[group].wires.push_back(wire); }
180 
addGroupPip(IdString group,IdString pip)181 void Arch::addGroupPip(IdString group, IdString pip) { groups[group].pips.push_back(pip); }
182 
addGroupGroup(IdString group,IdString grp)183 void Arch::addGroupGroup(IdString group, IdString grp) { groups[group].groups.push_back(grp); }
184 
addDecalGraphic(DecalId decal,const GraphicElement & graphic)185 void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic)
186 {
187     decal_graphics[decal].push_back(graphic);
188     refreshUi();
189 }
190 
setWireDecal(WireId wire,DecalXY decalxy)191 void Arch::setWireDecal(WireId wire, DecalXY decalxy)
192 {
193     wire_info(wire).decalxy = decalxy;
194     refreshUiWire(wire);
195 }
196 
setPipDecal(PipId pip,DecalXY decalxy)197 void Arch::setPipDecal(PipId pip, DecalXY decalxy)
198 {
199     pip_info(pip).decalxy = decalxy;
200     refreshUiPip(pip);
201 }
202 
setBelDecal(BelId bel,DecalXY decalxy)203 void Arch::setBelDecal(BelId bel, DecalXY decalxy)
204 {
205     bel_info(bel).decalxy = decalxy;
206     refreshUiBel(bel);
207 }
208 
setGroupDecal(GroupId group,DecalXY decalxy)209 void Arch::setGroupDecal(GroupId group, DecalXY decalxy)
210 {
211     groups[group].decalxy = decalxy;
212     refreshUiGroup(group);
213 }
214 
setWireAttr(IdString wire,IdString key,const std::string & value)215 void Arch::setWireAttr(IdString wire, IdString key, const std::string &value) { wire_info(wire).attrs[key] = value; }
216 
setPipAttr(IdString pip,IdString key,const std::string & value)217 void Arch::setPipAttr(IdString pip, IdString key, const std::string &value) { pip_info(pip).attrs[key] = value; }
218 
setBelAttr(IdString bel,IdString key,const std::string & value)219 void Arch::setBelAttr(IdString bel, IdString key, const std::string &value) { bel_info(bel).attrs[key] = value; }
220 
setLutK(int K)221 void Arch::setLutK(int K) { args.K = K; }
222 
setDelayScaling(double scale,double offset)223 void Arch::setDelayScaling(double scale, double offset)
224 {
225     args.delayScale = scale;
226     args.delayOffset = offset;
227 }
228 
addCellTimingClock(IdString cell,IdString port)229 void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; }
230 
addCellTimingDelay(IdString cell,IdString fromPort,IdString toPort,DelayInfo delay)231 void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayInfo delay)
232 {
233     if (get_or_default(cellTiming[cell].portClasses, fromPort, TMG_IGNORE) == TMG_IGNORE)
234         cellTiming[cell].portClasses[fromPort] = TMG_COMB_INPUT;
235     if (get_or_default(cellTiming[cell].portClasses, toPort, TMG_IGNORE) == TMG_IGNORE)
236         cellTiming[cell].portClasses[toPort] = TMG_COMB_OUTPUT;
237     cellTiming[cell].combDelays[CellDelayKey{fromPort, toPort}] = delay;
238 }
239 
addCellTimingSetupHold(IdString cell,IdString port,IdString clock,DelayInfo setup,DelayInfo hold)240 void Arch::addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayInfo setup, DelayInfo hold)
241 {
242     TimingClockingInfo ci;
243     ci.clock_port = clock;
244     ci.edge = RISING_EDGE;
245     ci.setup = setup;
246     ci.hold = hold;
247     cellTiming[cell].clockingInfo[port].push_back(ci);
248     cellTiming[cell].portClasses[port] = TMG_REGISTER_INPUT;
249 }
250 
addCellTimingClockToOut(IdString cell,IdString port,IdString clock,DelayInfo clktoq)251 void Arch::addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq)
252 {
253     TimingClockingInfo ci;
254     ci.clock_port = clock;
255     ci.edge = RISING_EDGE;
256     ci.clockToQ = clktoq;
257     cellTiming[cell].clockingInfo[port].push_back(ci);
258     cellTiming[cell].portClasses[port] = TMG_REGISTER_OUTPUT;
259 }
260 
261 // ---------------------------------------------------------------
262 
Arch(ArchArgs args)263 Arch::Arch(ArchArgs args) : chipName("generic"), args(args)
264 {
265     // Dummy for empty decals
266     decal_graphics[IdString()];
267 }
268 
initialize_arch(const BaseCtx * ctx)269 void IdString::initialize_arch(const BaseCtx *ctx) {}
270 
271 // ---------------------------------------------------------------
272 
getBelByName(IdString name) const273 BelId Arch::getBelByName(IdString name) const
274 {
275     if (bels.count(name))
276         return name;
277     return BelId();
278 }
279 
getBelName(BelId bel) const280 IdString Arch::getBelName(BelId bel) const { return bel; }
281 
getBelLocation(BelId bel) const282 Loc Arch::getBelLocation(BelId bel) const
283 {
284     auto &info = bels.at(bel);
285     return Loc(info.x, info.y, info.z);
286 }
287 
getBelByLocation(Loc loc) const288 BelId Arch::getBelByLocation(Loc loc) const
289 {
290     auto it = bel_by_loc.find(loc);
291     if (it != bel_by_loc.end())
292         return it->second;
293     return BelId();
294 }
295 
getBelsByTile(int x,int y) const296 const std::vector<BelId> &Arch::getBelsByTile(int x, int y) const { return bels_by_tile.at(x).at(y); }
297 
getBelGlobalBuf(BelId bel) const298 bool Arch::getBelGlobalBuf(BelId bel) const { return bels.at(bel).gb; }
299 
getBelChecksum(BelId bel) const300 uint32_t Arch::getBelChecksum(BelId bel) const
301 {
302     // FIXME
303     return 0;
304 }
305 
bindBel(BelId bel,CellInfo * cell,PlaceStrength strength)306 void Arch::bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
307 {
308     bels.at(bel).bound_cell = cell;
309     cell->bel = bel;
310     cell->belStrength = strength;
311     refreshUiBel(bel);
312 }
313 
unbindBel(BelId bel)314 void Arch::unbindBel(BelId bel)
315 {
316     bels.at(bel).bound_cell->bel = BelId();
317     bels.at(bel).bound_cell->belStrength = STRENGTH_NONE;
318     bels.at(bel).bound_cell = nullptr;
319     refreshUiBel(bel);
320 }
321 
checkBelAvail(BelId bel) const322 bool Arch::checkBelAvail(BelId bel) const { return bels.at(bel).bound_cell == nullptr; }
323 
getBoundBelCell(BelId bel) const324 CellInfo *Arch::getBoundBelCell(BelId bel) const { return bels.at(bel).bound_cell; }
325 
getConflictingBelCell(BelId bel) const326 CellInfo *Arch::getConflictingBelCell(BelId bel) const { return bels.at(bel).bound_cell; }
327 
getBels() const328 const std::vector<BelId> &Arch::getBels() const { return bel_ids; }
329 
getBelType(BelId bel) const330 IdString Arch::getBelType(BelId bel) const { return bels.at(bel).type; }
331 
getBelAttrs(BelId bel) const332 const std::map<IdString, std::string> &Arch::getBelAttrs(BelId bel) const { return bels.at(bel).attrs; }
333 
getBelPinWire(BelId bel,IdString pin) const334 WireId Arch::getBelPinWire(BelId bel, IdString pin) const
335 {
336     const auto &bdata = bels.at(bel);
337     if (!bdata.pins.count(pin))
338         log_error("bel '%s' has no pin '%s'\n", bel.c_str(this), pin.c_str(this));
339     return bdata.pins.at(pin).wire;
340 }
341 
getBelPinType(BelId bel,IdString pin) const342 PortType Arch::getBelPinType(BelId bel, IdString pin) const { return bels.at(bel).pins.at(pin).type; }
343 
getBelPins(BelId bel) const344 std::vector<IdString> Arch::getBelPins(BelId bel) const
345 {
346     std::vector<IdString> ret;
347     for (auto &it : bels.at(bel).pins)
348         ret.push_back(it.first);
349     return ret;
350 }
351 
352 // ---------------------------------------------------------------
353 
getWireByName(IdString name) const354 WireId Arch::getWireByName(IdString name) const
355 {
356     if (wires.count(name))
357         return name;
358     return WireId();
359 }
360 
getWireName(WireId wire) const361 IdString Arch::getWireName(WireId wire) const { return wire; }
362 
getWireType(WireId wire) const363 IdString Arch::getWireType(WireId wire) const { return wires.at(wire).type; }
364 
getWireAttrs(WireId wire) const365 const std::map<IdString, std::string> &Arch::getWireAttrs(WireId wire) const { return wires.at(wire).attrs; }
366 
getWireChecksum(WireId wire) const367 uint32_t Arch::getWireChecksum(WireId wire) const
368 {
369     // FIXME
370     return 0;
371 }
372 
bindWire(WireId wire,NetInfo * net,PlaceStrength strength)373 void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
374 {
375     wires.at(wire).bound_net = net;
376     net->wires[wire].pip = PipId();
377     net->wires[wire].strength = strength;
378     refreshUiWire(wire);
379 }
380 
unbindWire(WireId wire)381 void Arch::unbindWire(WireId wire)
382 {
383     auto &net_wires = wires.at(wire).bound_net->wires;
384 
385     auto pip = net_wires.at(wire).pip;
386     if (pip != PipId()) {
387         pips.at(pip).bound_net = nullptr;
388         refreshUiPip(pip);
389     }
390 
391     net_wires.erase(wire);
392     wires.at(wire).bound_net = nullptr;
393     refreshUiWire(wire);
394 }
395 
checkWireAvail(WireId wire) const396 bool Arch::checkWireAvail(WireId wire) const { return wires.at(wire).bound_net == nullptr; }
397 
getBoundWireNet(WireId wire) const398 NetInfo *Arch::getBoundWireNet(WireId wire) const { return wires.at(wire).bound_net; }
399 
getConflictingWireNet(WireId wire) const400 NetInfo *Arch::getConflictingWireNet(WireId wire) const { return wires.at(wire).bound_net; }
401 
getWireBelPins(WireId wire) const402 const std::vector<BelPin> &Arch::getWireBelPins(WireId wire) const { return wires.at(wire).bel_pins; }
403 
getWires() const404 const std::vector<WireId> &Arch::getWires() const { return wire_ids; }
405 
406 // ---------------------------------------------------------------
407 
getPipByName(IdString name) const408 PipId Arch::getPipByName(IdString name) const
409 {
410     if (pips.count(name))
411         return name;
412     return PipId();
413 }
414 
getPipName(PipId pip) const415 IdString Arch::getPipName(PipId pip) const { return pip; }
416 
getPipType(PipId pip) const417 IdString Arch::getPipType(PipId pip) const { return pips.at(pip).type; }
418 
getPipAttrs(PipId pip) const419 const std::map<IdString, std::string> &Arch::getPipAttrs(PipId pip) const { return pips.at(pip).attrs; }
420 
getPipChecksum(PipId wire) const421 uint32_t Arch::getPipChecksum(PipId wire) const
422 {
423     // FIXME
424     return 0;
425 }
426 
bindPip(PipId pip,NetInfo * net,PlaceStrength strength)427 void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
428 {
429     WireId wire = pips.at(pip).dstWire;
430     pips.at(pip).bound_net = net;
431     wires.at(wire).bound_net = net;
432     net->wires[wire].pip = pip;
433     net->wires[wire].strength = strength;
434     refreshUiPip(pip);
435     refreshUiWire(wire);
436 }
437 
unbindPip(PipId pip)438 void Arch::unbindPip(PipId pip)
439 {
440     WireId wire = pips.at(pip).dstWire;
441     wires.at(wire).bound_net->wires.erase(wire);
442     pips.at(pip).bound_net = nullptr;
443     wires.at(wire).bound_net = nullptr;
444     refreshUiPip(pip);
445     refreshUiWire(wire);
446 }
447 
checkPipAvail(PipId pip) const448 bool Arch::checkPipAvail(PipId pip) const { return pips.at(pip).bound_net == nullptr; }
449 
getBoundPipNet(PipId pip) const450 NetInfo *Arch::getBoundPipNet(PipId pip) const { return pips.at(pip).bound_net; }
451 
getConflictingPipNet(PipId pip) const452 NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; }
453 
getConflictingPipWire(PipId pip) const454 WireId Arch::getConflictingPipWire(PipId pip) const { return pips.at(pip).bound_net ? pips.at(pip).dstWire : WireId(); }
455 
getPips() const456 const std::vector<PipId> &Arch::getPips() const { return pip_ids; }
457 
getPipLocation(PipId pip) const458 Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; }
459 
getPipSrcWire(PipId pip) const460 WireId Arch::getPipSrcWire(PipId pip) const { return pips.at(pip).srcWire; }
461 
getPipDstWire(PipId pip) const462 WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; }
463 
getPipDelay(PipId pip) const464 DelayInfo Arch::getPipDelay(PipId pip) const { return pips.at(pip).delay; }
465 
getPipsDownhill(WireId wire) const466 const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; }
467 
getPipsUphill(WireId wire) const468 const std::vector<PipId> &Arch::getPipsUphill(WireId wire) const { return wires.at(wire).uphill; }
469 
getWireAliases(WireId wire) const470 const std::vector<PipId> &Arch::getWireAliases(WireId wire) const { return wires.at(wire).aliases; }
471 
472 // ---------------------------------------------------------------
473 
getGroupByName(IdString name) const474 GroupId Arch::getGroupByName(IdString name) const { return name; }
475 
getGroupName(GroupId group) const476 IdString Arch::getGroupName(GroupId group) const { return group; }
477 
getGroups() const478 std::vector<GroupId> Arch::getGroups() const
479 {
480     std::vector<GroupId> ret;
481     for (auto &it : groups)
482         ret.push_back(it.first);
483     return ret;
484 }
485 
getGroupBels(GroupId group) const486 const std::vector<BelId> &Arch::getGroupBels(GroupId group) const { return groups.at(group).bels; }
487 
getGroupWires(GroupId group) const488 const std::vector<WireId> &Arch::getGroupWires(GroupId group) const { return groups.at(group).wires; }
489 
getGroupPips(GroupId group) const490 const std::vector<PipId> &Arch::getGroupPips(GroupId group) const { return groups.at(group).pips; }
491 
getGroupGroups(GroupId group) const492 const std::vector<GroupId> &Arch::getGroupGroups(GroupId group) const { return groups.at(group).groups; }
493 
494 // ---------------------------------------------------------------
495 
estimateDelay(WireId src,WireId dst) const496 delay_t Arch::estimateDelay(WireId src, WireId dst) const
497 {
498     const WireInfo &s = wires.at(src);
499     const WireInfo &d = wires.at(dst);
500     int dx = abs(s.x - d.x);
501     int dy = abs(s.y - d.y);
502     return (dx + dy) * args.delayScale + args.delayOffset;
503 }
504 
predictDelay(const NetInfo * net_info,const PortRef & sink) const505 delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
506 {
507     const auto &driver = net_info->driver;
508     auto driver_loc = getBelLocation(driver.cell->bel);
509     auto sink_loc = getBelLocation(sink.cell->bel);
510 
511     int dx = abs(sink_loc.x - driver_loc.x);
512     int dy = abs(sink_loc.y - driver_loc.y);
513     return (dx + dy) * args.delayScale + args.delayOffset;
514 }
515 
getBudgetOverride(const NetInfo * net_info,const PortRef & sink,delay_t & budget) const516 bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; }
517 
getRouteBoundingBox(WireId src,WireId dst) const518 ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const
519 {
520     ArcBounds bb;
521 
522     int src_x = wires.at(src).x;
523     int src_y = wires.at(src).y;
524     int dst_x = wires.at(dst).x;
525     int dst_y = wires.at(dst).y;
526 
527     bb.x0 = src_x;
528     bb.y0 = src_y;
529     bb.x1 = src_x;
530     bb.y1 = src_y;
531 
532     auto extend = [&](int x, int y) {
533         bb.x0 = std::min(bb.x0, x);
534         bb.x1 = std::max(bb.x1, x);
535         bb.y0 = std::min(bb.y0, y);
536         bb.y1 = std::max(bb.y1, y);
537     };
538     extend(dst_x, dst_y);
539     return bb;
540 }
541 
542 // ---------------------------------------------------------------
543 
place()544 bool Arch::place()
545 {
546     std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
547     if (placer == "heap") {
548         bool have_iobuf_or_constr = false;
549         for (auto cell : sorted(cells)) {
550             CellInfo *ci = cell.second;
551             if (ci->type == id("GENERIC_IOB") || ci->bel != BelId() || ci->attrs.count(id("BEL"))) {
552                 have_iobuf_or_constr = true;
553                 break;
554             }
555         }
556         bool retVal;
557         if (!have_iobuf_or_constr) {
558             log_warning("Unable to use HeAP due to a lack of IO buffers or constrained cells as anchors; reverting to "
559                         "SA.\n");
560             retVal = placer1(getCtx(), Placer1Cfg(getCtx()));
561         } else {
562             PlacerHeapCfg cfg(getCtx());
563             cfg.ioBufTypes.insert(id("GENERIC_IOB"));
564             retVal = placer_heap(getCtx(), cfg);
565         }
566         getCtx()->settings[getCtx()->id("place")] = 1;
567         archInfoToAttributes();
568         return retVal;
569     } else if (placer == "sa") {
570         bool retVal = placer1(getCtx(), Placer1Cfg(getCtx()));
571         getCtx()->settings[getCtx()->id("place")] = 1;
572         archInfoToAttributes();
573         return retVal;
574     } else {
575         log_error("Generic architecture does not support placer '%s'\n", placer.c_str());
576     }
577 }
578 
route()579 bool Arch::route()
580 {
581     std::string router = str_or_default(settings, id("router"), defaultRouter);
582     bool result;
583     if (router == "router1") {
584         result = router1(getCtx(), Router1Cfg(getCtx()));
585     } else if (router == "router2") {
586         router2(getCtx(), Router2Cfg(getCtx()));
587         result = true;
588     } else {
589         log_error("iCE40 architecture does not support router '%s'\n", router.c_str());
590     }
591     getCtx()->settings[getCtx()->id("route")] = 1;
592     archInfoToAttributes();
593     return result;
594 }
595 
596 // ---------------------------------------------------------------
597 
getDecalGraphics(DecalId decal) const598 const std::vector<GraphicElement> &Arch::getDecalGraphics(DecalId decal) const
599 {
600     if (!decal_graphics.count(decal)) {
601         std::cerr << "No decal named " << decal.str(this) << std::endl;
602         log_error("No decal named %s!\n", decal.c_str(this));
603     }
604     return decal_graphics.at(decal);
605 }
606 
getBelDecal(BelId bel) const607 DecalXY Arch::getBelDecal(BelId bel) const { return bels.at(bel).decalxy; }
608 
getWireDecal(WireId wire) const609 DecalXY Arch::getWireDecal(WireId wire) const { return wires.at(wire).decalxy; }
610 
getPipDecal(PipId pip) const611 DecalXY Arch::getPipDecal(PipId pip) const { return pips.at(pip).decalxy; }
612 
getGroupDecal(GroupId group) const613 DecalXY Arch::getGroupDecal(GroupId group) const { return groups.at(group).decalxy; }
614 
615 // ---------------------------------------------------------------
616 
getCellDelay(const CellInfo * cell,IdString fromPort,IdString toPort,DelayInfo & delay) const617 bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
618 {
619     if (!cellTiming.count(cell->name))
620         return false;
621     const auto &tmg = cellTiming.at(cell->name);
622     auto fnd = tmg.combDelays.find(CellDelayKey{fromPort, toPort});
623     if (fnd != tmg.combDelays.end()) {
624         delay = fnd->second;
625         return true;
626     } else {
627         return false;
628     }
629 }
630 
631 // Get the port class, also setting clockPort if applicable
getPortTimingClass(const CellInfo * cell,IdString port,int & clockInfoCount) const632 TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const
633 {
634     if (!cellTiming.count(cell->name))
635         return TMG_IGNORE;
636     const auto &tmg = cellTiming.at(cell->name);
637     if (tmg.clockingInfo.count(port))
638         clockInfoCount = int(tmg.clockingInfo.at(port).size());
639     else
640         clockInfoCount = 0;
641     return get_or_default(tmg.portClasses, port, TMG_IGNORE);
642 }
643 
getPortClockingInfo(const CellInfo * cell,IdString port,int index) const644 TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const
645 {
646     NPNR_ASSERT(cellTiming.count(cell->name));
647     const auto &tmg = cellTiming.at(cell->name);
648     NPNR_ASSERT(tmg.clockingInfo.count(port));
649     return tmg.clockingInfo.at(port).at(index);
650 }
651 
isValidBelForCell(CellInfo * cell,BelId bel) const652 bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
653 {
654     std::vector<const CellInfo *> cells;
655     cells.push_back(cell);
656     Loc loc = getBelLocation(bel);
657     for (auto tbel : getBelsByTile(loc.x, loc.y)) {
658         if (tbel == bel)
659             continue;
660         CellInfo *bound = getBoundBelCell(tbel);
661         if (bound != nullptr)
662             cells.push_back(bound);
663     }
664     return cellsCompatible(cells.data(), int(cells.size()));
665 }
666 
isBelLocationValid(BelId bel) const667 bool Arch::isBelLocationValid(BelId bel) const
668 {
669     std::vector<const CellInfo *> cells;
670     Loc loc = getBelLocation(bel);
671     for (auto tbel : getBelsByTile(loc.x, loc.y)) {
672         CellInfo *bound = getBoundBelCell(tbel);
673         if (bound != nullptr)
674             cells.push_back(bound);
675     }
676     return cellsCompatible(cells.data(), int(cells.size()));
677 }
678 
679 #ifdef WITH_HEAP
680 const std::string Arch::defaultPlacer = "heap";
681 #else
682 const std::string Arch::defaultPlacer = "sa";
683 #endif
684 
685 const std::vector<std::string> Arch::availablePlacers = {"sa",
686 #ifdef WITH_HEAP
687                                                          "heap"
688 #endif
689 };
690 
691 const std::string Arch::defaultRouter = "router1";
692 const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};
693 
assignArchInfo()694 void Arch::assignArchInfo()
695 {
696     for (auto &cell : getCtx()->cells) {
697         CellInfo *ci = cell.second.get();
698         if (ci->type == id("GENERIC_SLICE")) {
699             ci->is_slice = true;
700             ci->slice_clk = get_net_or_empty(ci, id("CLK"));
701         } else {
702             ci->is_slice = false;
703         }
704         ci->user_group = int_or_default(ci->attrs, id("PACK_GROUP"), -1);
705     }
706 }
707 
cellsCompatible(const CellInfo ** cells,int count) const708 bool Arch::cellsCompatible(const CellInfo **cells, int count) const
709 {
710     const NetInfo *clk = nullptr;
711     int group = -1;
712     for (int i = 0; i < count; i++) {
713         const CellInfo *ci = cells[i];
714         if (ci->is_slice && ci->slice_clk != nullptr) {
715             if (clk == nullptr)
716                 clk = ci->slice_clk;
717             else if (clk != ci->slice_clk)
718                 return false;
719         }
720         if (ci->user_group != -1) {
721             if (group == -1)
722                 group = ci->user_group;
723             else if (group != ci->user_group)
724                 return false;
725         }
726     }
727     return true;
728 }
729 
730 NEXTPNR_NAMESPACE_END
731