add timing info

This commit is contained in:
Pepijn de Vos 2020-12-10 12:48:23 +01:00
parent c924ade85d
commit e14f5fccbd
7 changed files with 282 additions and 48 deletions

View File

@ -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<j.dest_id); }
bool aliasCompare (GlobalAliasPOD i, GlobalAliasPOD j) {
return (i.dest_row<j.dest_row) ||
(i.dest_row==j.dest_row && i.dest_col<j.dest_col) ||
(i.dest_row==j.dest_row && i.dest_col==j.dest_col && i.dest_id<j.dest_id);
}
bool timingCompare (TimingPOD i, TimingPOD j) {
return i.name_id < j.name_id;
}
const GlobalAliasPOD* aliasLookup(const GlobalAliasPOD *first, int len, const GlobalAliasPOD val)
template <class T, class C>
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; i<db->num_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);
}

View File

@ -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<TimingPOD> 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<TimingGroupsPOD> groups;
});
NPNR_PACKED_STRUCT(struct DatabasePOD {
RelPtr<char> family;
uint32_t version;
@ -85,6 +126,8 @@ NPNR_PACKED_STRUCT(struct DatabasePOD {
RelPtr<RelPtr<TilePOD>> grid;
uint32_t num_aliases;
RelPtr<GlobalAliasPOD> aliases;
uint32_t num_speeds;
RelPtr<TimingClassPOD> speeds;
uint16_t num_constids;
uint16_t num_ids;
RelPtr<RelPtr<char>> 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<IdString, WireInfo> wires;
std::unordered_map<IdString, PipInfo> 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;
}

View File

@ -205,8 +205,6 @@ void arch_wrap_python(py::module &m)
conv_from_str<IdString>, pass_through<std::string>>::def_wrap(ctx_cls, "setPipAttr", "pip"_a,
"key"_a, "value"_a);
fn_wrapper_1a_v<Context, decltype(&Context::setLutK), &Context::setLutK, pass_through<int>>::def_wrap(
ctx_cls, "setLutK", "K"_a);
fn_wrapper_2a_v<Context, decltype(&Context::setDelayScaling), &Context::setDelayScaling, pass_through<double>,
pass_through<double>>::def_wrap(ctx_cls, "setDelayScaling", "scale"_a, "offset"_a);

View File

@ -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;
}
};

View File

@ -407,4 +407,22 @@ X(I0)
X(I1)
X(I2)
X(I3)
X(OEN)
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)

View File

@ -49,7 +49,7 @@ po::options_description GowinCommandHandler::getArchOptions()
specific.add_options()("family", po::value<std::string>(), "device family");
specific.add_options()("package", po::value<std::string>(), "device package");
specific.add_options()("speed", po::value<std::string>(), "device speed grade");
specific.add_options()("pdc", po::value<std::string>(), "physical constraints file");
specific.add_options()("cst", po::value<std::string>(), "physical constraints file");
return specific;
}
@ -57,12 +57,15 @@ std::unique_ptr<Context> GowinCommandHandler::createContext(std::unordered_map<s
{
ArchArgs chipArgs;
chipArgs.device = vm["device"].as<std::string>();
chipArgs.family = vm["family"].as<std::string>();
chipArgs.speed = vm["speed"].as<std::string>();
chipArgs.package = vm["package"].as<std::string>();
return std::unique_ptr<Context>(new Context(chipArgs));
}
void GowinCommandHandler::customAfterLoad(Context *ctx)
{
// if (vm.count("pdc")) {
// if (vm.count("cst")) {
// std::string filename = vm["pdc"].as<std::string>();
// std::ifstream in(filename);
// if (!in)

View File

@ -139,7 +139,7 @@ static void pack_constants(Context *ctx)
log_info("Packing constants..\n");
std::unique_ptr<CellInfo> 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<NetInfo> gnd_net = std::unique_ptr<NetInfo>(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<CellInfo> 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<NetInfo> vcc_net = std::unique_ptr<NetInfo>(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)
{