From e14f5fccbd5edb656c09242386cb74697923138a Mon Sep 17 00:00:00 2001 From: Pepijn de Vos Date: Thu, 10 Dec 2020 12:48:23 +0100 Subject: [PATCH] add timing info --- gowin/arch.cc | 212 ++++++++++++++++++++++++++++++++++----- gowin/arch.h | 59 +++++++++-- gowin/arch_pybindings.cc | 2 - gowin/archdefs.h | 22 ++-- gowin/constids.inc | 20 +++- gowin/main.cc | 7 +- gowin/pack.cc | 8 +- 7 files changed, 282 insertions(+), 48 deletions(-) diff --git a/gowin/arch.cc b/gowin/arch.cc index 404205e0..49520e98 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -206,8 +206,6 @@ void Arch::setPipAttr(IdString pip, IdString key, const std::string &value) { pi 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; @@ -302,40 +300,191 @@ IdString Arch::wireToGlobal(int &row, int &col, const DatabasePOD *db, IdString return id(buf); } -const PairPOD* pairLookup(const PairPOD *list, const size_t len, const int src, const int dest) +const PairPOD* pairLookup(const PairPOD *list, const size_t len, const int dest) { for (size_t i = 0; i < len; i++) { const PairPOD *pair = &list[i]; - if ((src < 0 || pair->src_id == src) && (dest < 0 || pair->dest_id == dest)) { + if (pair->dest_id == dest) { return pair; } } return nullptr; } -bool destCompare (PairPOD i,PairPOD j) { return (i.dest_id +const T* genericLookup(const T *first, int len, const T val, C compare) { - auto res = std::lower_bound(first, first+len, val, aliasCompare); - if (res-first != len && !aliasCompare(val, *res)) { + auto res = std::lower_bound(first, first+len, val, compare); + if (res-first != len && !compare(val, *res)) { return res; } else { return nullptr; } } +DelayInfo delayLookup(const TimingPOD* first, int len, IdString name) { + TimingPOD needle; + needle.name_id = name.index; + const TimingPOD *timing = genericLookup(first, len, needle, timingCompare); + DelayInfo info; + if (timing != nullptr) { + info.maxFall = std::max(timing->ff, timing->rf)/1000; + info.minFall = std::min(timing->ff, timing->rf)/1000; + info.maxRaise = std::max(timing->rr, timing->fr)/1000; + info.minRaise = std::min(timing->rr, timing->fr)/1000; + } else { + info.maxFall = 0; + info.minFall = 0; + info.maxRaise = 0; + info.minRaise = 0; + } + return info; +} + +DelayInfo Arch::getWireTypeDelay(IdString wire) { + IdString len; + IdString glbsrc; + switch (wire.index) + { + case ID_X01: + case ID_X02: + case ID_X03: + case ID_X04: + case ID_X05: + case ID_X06: + case ID_X07: + case ID_X08: + len = id_X0; + break; + case ID_N100: + case ID_N130: + case ID_S100: + case ID_S130: + case ID_E100: + case ID_E130: + case ID_W100: + case ID_W130: + case ID_E110: + case ID_W110: + case ID_E120: + case ID_W120: + case ID_S110: + case ID_N110: + case ID_S120: + case ID_N120: + case ID_SN10: + case ID_SN20: + case ID_EW10: + case ID_EW20: + len = id_FX1; + break; + case ID_N200: + case ID_N210: + case ID_N220: + case ID_N230: + case ID_N240: + case ID_N250: + case ID_N260: + case ID_N270: + case ID_S200: + case ID_S210: + case ID_S220: + case ID_S230: + case ID_S240: + case ID_S250: + case ID_S260: + case ID_S270: + case ID_E200: + case ID_E210: + case ID_E220: + case ID_E230: + case ID_E240: + case ID_E250: + case ID_E260: + case ID_E270: + case ID_W200: + case ID_W210: + case ID_W220: + case ID_W230: + case ID_W240: + case ID_W250: + case ID_W260: + case ID_W270: + len = id_X2; + break; + case ID_N800: + case ID_N810: + case ID_N820: + case ID_N830: + case ID_S800: + case ID_S810: + case ID_S820: + case ID_S830: + case ID_E800: + case ID_E810: + case ID_E820: + case ID_E830: + case ID_W800: + case ID_W810: + case ID_W820: + case ID_W830: + len = id_X8; + break; + case ID_GT00: + case ID_GT10: + glbsrc = id_SPINE_TAP_PCLK; + break; + case ID_GBO0: + case ID_GBO1: + glbsrc = id_TAP_BRANCH_PCLK; + break; + case ID_GB00: + case ID_GB10: + case ID_GB20: + case ID_GB30: + case ID_GB40: + case ID_GB50: + case ID_GB60: + case ID_GB70: + glbsrc = id_BRANCH_PCLK; + break; + default: + if (wire.str(this).rfind("SPINE", 0) == 0){ + glbsrc = ID_CENT_SPINE_PCLK; + } else if (wire.str(this).rfind("UNK", 0) == 0) { + glbsrc = ID_PIO_CENT_PCLK; + } + break; + } + if (len != id("")) { + return delayLookup(speed->wire.timings.get(), speed->wire.num_timings, len); + } else if (glbsrc != id("")) { + return delayLookup(speed->glbsrc.timings.get(), speed->glbsrc.num_timings, glbsrc); + } else { + DelayInfo info; + info.maxFall = 0; + info.minFall = 0; + info.maxRaise = 0; + info.minRaise = 0; + return info; + } +} + + Arch::Arch(ArchArgs args) : args(args) { - family = "GW1N-1"; - device = "GW1N-1"; - speed = "C6/E5"; // or whatever - package = "QFN48"; // or something + family = args.family; + device = args.device; + package = args.package; // Load database std::string chipdb = stringf("gowin/chipdb-%s.bin", family.c_str()); @@ -350,6 +499,19 @@ Arch::Arch(ArchArgs args) : args(args) for (size_t i = 0; i < db->num_ids; i++) { IdString::initialize_add(this, db->id_strs[i].get(), uint32_t(i) + db->num_constids); } + // setup timing info + speed = nullptr; + for (unsigned int i=0; inum_speeds; i++) { + const TimingClassPOD *tc = &db->speeds[i]; + //std::cout << IdString(tc->name_id).str(this) << std::endl; + if (IdString(tc->name_id) == id(args.speed)) { + speed = tc->groups.get(); + break; + } + } + if (speed == nullptr) { + log_error("Unsuported speed grade '%s'.\n", args.speed.c_str()); + } // setup db char buf[32]; for (int i = 0; i < db->rows * db->cols; i++) { @@ -458,15 +620,15 @@ Arch::Arch(ArchArgs args) : args(args) snprintf(buf, 32, "R%dC%d_IOB%c", row + 1, col + 1, 'A' + z); belname = id(buf); addBel(belname, id_IOB, Loc(col, row, z), false); - portname = pairLookup(bel->ports.get(), bel->num_ports, -1, ID_O)->src_id; + portname = pairLookup(bel->ports.get(), bel->num_ports, ID_O)->src_id; snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); wirename = id(buf); addBelOutput(belname, id_O, wirename); - portname = pairLookup(bel->ports.get(), bel->num_ports, -1, ID_I)->src_id; + portname = pairLookup(bel->ports.get(), bel->num_ports, ID_I)->src_id; snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); wirename = id(buf); addBelInput(belname, id_I, wirename); - portname = pairLookup(bel->ports.get(), bel->num_ports, -1, ID_OE)->src_id; + portname = pairLookup(bel->ports.get(), bel->num_ports, ID_OE)->src_id; snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); wirename = id(buf); addBelInput(belname, id_OEN, wirename); @@ -499,10 +661,9 @@ Arch::Arch(ArchArgs args) : args(args) snprintf(buf, 32, "R%dC%d_%s_%s", row + 1, col + 1, IdString(pip.src_id).c_str(this), IdString(pip.dest_id).c_str(this)); IdString pipname = id(buf); - DelayInfo delay; - delay.delay = 0.1; // TODO + DelayInfo delay = getWireTypeDelay(pip.dest_id); // local alias - auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, -1, srcid.index); + auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, srcid.index); // std::cout << "srcid " << srcid.str(this) << std::endl; if(local_alias!=nullptr) { srcid = local_alias->src_id; @@ -514,7 +675,7 @@ Arch::Arch(ArchArgs args) : args(args) alias.dest_col = srccol; alias.dest_row = srcrow; alias.dest_id = srcid.index; - auto alias_src = aliasLookup(db->aliases.get(), db->num_aliases, alias); + auto alias_src = genericLookup(db->aliases.get(), db->num_aliases, alias, aliasCompare); if(alias_src!=nullptr) { srccol = alias_src->src_col; srcrow = alias_src->src_row; @@ -973,14 +1134,19 @@ void Arch::assignArchInfo() addCellTimingClock(cname, id_CLK); IdString ports[4] = {id_A, id_B, id_C, id_D}; for (int i=0; i<4; i++) { - DelayInfo setup = getDelayFromNS(0.1); - DelayInfo hold = getDelayFromNS(0.1); + DelayInfo setup = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clksetpos); + DelayInfo hold = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clkholdpos); + // DelayInfo setup = getDelayFromNS(0.1); + // DelayInfo hold = getDelayFromNS(0.1); addCellTimingSetupHold(cname, ports[i], id_CLK, setup, hold); } - DelayInfo clkout = getDelayFromNS(0.1); + DelayInfo clkout = delayLookup(speed->dff.timings.get(), speed->dff.num_timings, id_clk_qpos); + // DelayInfo clkout = getDelayFromNS(0.1); addCellTimingClockToOut(cname, id_Q, id_CLK, clkout); + IdString port_delay[4] = {id_a_f, id_b_f, id_c_f, id_d_f}; for (int i=0; i<4; i++) { - DelayInfo delay = getDelayFromNS(0.1); + DelayInfo delay = delayLookup(speed->lut.timings.get(), speed->lut.num_timings, port_delay[i]); + // DelayInfo delay = getDelayFromNS(0.1); addCellTimingDelay(cname, ports[i], id_F, delay); } diff --git a/gowin/arch.h b/gowin/arch.h index 842caa7f..3df0a9ed 100644 --- a/gowin/arch.h +++ b/gowin/arch.h @@ -77,6 +77,47 @@ NPNR_PACKED_STRUCT(struct GlobalAliasPOD { uint16_t src_id; }); +NPNR_PACKED_STRUCT(struct TimingPOD { + uint32_t name_id; + // input, output + uint32_t ff; + uint32_t fr; + uint32_t rf; + uint32_t rr; +}); + +NPNR_PACKED_STRUCT(struct TimingGroupPOD { + uint32_t name_id; + uint32_t num_timings; + RelPtr timings; +}); + +NPNR_PACKED_STRUCT(struct TimingGroupsPOD { + TimingGroupPOD lut; + TimingGroupPOD alu; + TimingGroupPOD sram; + TimingGroupPOD dff; + //TimingGroupPOD dl; + //TimingGroupPOD iddroddr; + //TimingGroupPOD pll; + //TimingGroupPOD dll; + TimingGroupPOD bram; + //TimingGroupPOD dsp; + TimingGroupPOD fanout; + TimingGroupPOD glbsrc; + TimingGroupPOD hclk; + TimingGroupPOD iodelay; + //TimingGroupPOD io; + //TimingGroupPOD iregoreg; + TimingGroupPOD wire; +}); + +NPNR_PACKED_STRUCT(struct TimingClassPOD { + uint32_t name_id; + uint32_t num_groups; + RelPtr groups; +}); + NPNR_PACKED_STRUCT(struct DatabasePOD { RelPtr family; uint32_t version; @@ -85,6 +126,8 @@ NPNR_PACKED_STRUCT(struct DatabasePOD { RelPtr> grid; uint32_t num_aliases; RelPtr aliases; + uint32_t num_speeds; + RelPtr speeds; uint16_t num_constids; uint16_t num_ids; RelPtr> id_strs; @@ -93,11 +136,12 @@ NPNR_PACKED_STRUCT(struct DatabasePOD { struct ArchArgs { std::string device; - // Number of LUT inputs - int K = 4; + std::string family; + std::string speed; + std::string package; // y = mx + c relationship between distance and delay for interconnect // delay estimates - double delayScale = 0.1, delayOffset = 0.1; + double delayScale = 0.1, delayOffset = 0.4; }; struct WireInfo; @@ -186,7 +230,7 @@ struct Arch : BaseCtx std::string family; std::string device; std::string package; - std::string speed; + const TimingGroupsPOD *speed; std::unordered_map wires; std::unordered_map pips; @@ -234,7 +278,6 @@ struct Arch : BaseCtx 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); @@ -243,6 +286,7 @@ struct Arch : BaseCtx void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayInfo clktoq); IdString wireToGlobal(int &row, int &col, const DatabasePOD* db, IdString &wire); + DelayInfo getWireTypeDelay(IdString wire); // --------------------------------------------------------------- // Common Arch API. Every arch must provide the following methods. @@ -331,7 +375,10 @@ struct Arch : BaseCtx DelayInfo getDelayFromNS(float ns) const { DelayInfo del; - del.delay = ns; + del.maxRaise = ns; + del.maxFall = ns; + del.minRaise = ns; + del.minFall = ns; return del; } diff --git a/gowin/arch_pybindings.cc b/gowin/arch_pybindings.cc index 7f7229fd..adb4b985 100644 --- a/gowin/arch_pybindings.cc +++ b/gowin/arch_pybindings.cc @@ -205,8 +205,6 @@ void arch_wrap_python(py::module &m) conv_from_str, pass_through>::def_wrap(ctx_cls, "setPipAttr", "pip"_a, "key"_a, "value"_a); - fn_wrapper_1a_v>::def_wrap( - ctx_cls, "setLutK", "K"_a); fn_wrapper_2a_v, pass_through>::def_wrap(ctx_cls, "setDelayScaling", "scale"_a, "offset"_a); diff --git a/gowin/archdefs.h b/gowin/archdefs.h index af317c2e..2430b906 100644 --- a/gowin/archdefs.h +++ b/gowin/archdefs.h @@ -27,21 +27,27 @@ typedef float delay_t; struct DelayInfo { - delay_t delay = 0; + delay_t minRaise = 0; + delay_t minFall = 0; + delay_t maxRaise = 0; + delay_t maxFall = 0; - delay_t minRaiseDelay() const { return delay; } - delay_t maxRaiseDelay() const { return delay; } + delay_t minRaiseDelay() const { return minRaise; } + delay_t maxRaiseDelay() const { return maxRaise; } - delay_t minFallDelay() const { return delay; } - delay_t maxFallDelay() const { return delay; } + delay_t minFallDelay() const { return minFall; } + delay_t maxFallDelay() const { return maxFall; } - delay_t minDelay() const { return delay; } - delay_t maxDelay() const { return delay; } + delay_t minDelay() const { return std::min(minFall, minRaise); } + delay_t maxDelay() const { return std::max(maxFall, maxRaise); } DelayInfo operator+(const DelayInfo &other) const { DelayInfo ret; - ret.delay = this->delay + other.delay; + ret.minRaise = this->minRaise + other.minRaise; + ret.maxRaise = this->maxRaise + other.maxRaise; + ret.minFall = this->minFall + other.minFall; + ret.maxFall = this->maxFall + other.maxFall; return ret; } }; diff --git a/gowin/constids.inc b/gowin/constids.inc index c24559a0..89a91164 100644 --- a/gowin/constids.inc +++ b/gowin/constids.inc @@ -407,4 +407,22 @@ X(I0) X(I1) X(I2) X(I3) -X(OEN) \ No newline at end of file +X(OEN) + +// timing +X(X0) +X(FX1) +X(X2) +X(X8) +X(PIO_CENT_PCLK) +X(CENT_SPINE_PCLK) +X(SPINE_TAP_PCLK) +X(TAP_BRANCH_PCLK) +X(BRANCH_PCLK) +X(clksetpos) +X(clkholdpos) +X(clk_qpos) +X(a_f) +X(b_f) +X(c_f) +X(d_f) \ No newline at end of file diff --git a/gowin/main.cc b/gowin/main.cc index 020d8882..a5f99247 100644 --- a/gowin/main.cc +++ b/gowin/main.cc @@ -49,7 +49,7 @@ po::options_description GowinCommandHandler::getArchOptions() specific.add_options()("family", po::value(), "device family"); specific.add_options()("package", po::value(), "device package"); specific.add_options()("speed", po::value(), "device speed grade"); - specific.add_options()("pdc", po::value(), "physical constraints file"); + specific.add_options()("cst", po::value(), "physical constraints file"); return specific; } @@ -57,12 +57,15 @@ std::unique_ptr GowinCommandHandler::createContext(std::unordered_map(); + chipArgs.family = vm["family"].as(); + chipArgs.speed = vm["speed"].as(); + chipArgs.package = vm["package"].as(); return std::unique_ptr(new Context(chipArgs)); } void GowinCommandHandler::customAfterLoad(Context *ctx) { - // if (vm.count("pdc")) { + // if (vm.count("cst")) { // std::string filename = vm["pdc"].as(); // std::ifstream in(filename); // if (!in) diff --git a/gowin/pack.cc b/gowin/pack.cc index 8267d3c6..4c880ee0 100644 --- a/gowin/pack.cc +++ b/gowin/pack.cc @@ -139,7 +139,7 @@ static void pack_constants(Context *ctx) log_info("Packing constants..\n"); std::unique_ptr gnd_cell = create_generic_cell(ctx, ctx->id("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(); @@ -148,7 +148,7 @@ static void pack_constants(Context *ctx) std::unique_ptr vcc_cell = create_generic_cell(ctx, ctx->id("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(); @@ -220,10 +220,6 @@ static void pack_io(Context *ctx) for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (is_gowin_iob(ctx, ci)) { - std::cout << ci->type.str(ctx) << std::endl; - for(auto p : ci->ports) { - std::cout << p.first.str(ctx) << std::endl; - } CellInfo *iob = nullptr; switch (ci->type.index) {