From 1839a3a770a71c928b92bf876e04728d2649e425 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 1 Aug 2019 14:28:21 +0100 Subject: [PATCH 1/7] Major Property improvements for common and iCE40 Signed-off-by: David Shah --- bba/main.cc | 2 +- common/command.cc | 20 +++--- common/nextpnr.cc | 100 +++++++++++++++++++++------ common/nextpnr.h | 119 +++++++++++++++++++++++++-------- common/placer1.cc | 2 +- common/placer_heap.cc | 2 +- common/pybindings.cc | 9 ++- common/util.h | 24 +++++++ ecp5/main.cc | 12 ++-- gui/designwidget.cc | 9 ++- ice40/arch.cc | 4 +- ice40/bitstream.cc | 62 +++++++++-------- ice40/cells.cc | 152 +++++++++++++++++++++--------------------- ice40/cells.h | 12 ++-- ice40/chains.cc | 10 +-- ice40/main.cc | 14 ++-- ice40/pack.cc | 60 +++++++++-------- ice40/pcf.cc | 8 +-- json/jsonparse.cc | 58 ++++++++-------- json/jsonwrite.cc | 16 +++-- 20 files changed, 430 insertions(+), 265 deletions(-) diff --git a/bba/main.cc b/bba/main.cc index d3c81445..32a68c63 100644 --- a/bba/main.cc +++ b/bba/main.cc @@ -191,7 +191,7 @@ int main(int argc, char **argv) assert(end != nullptr); *end = 0; value += 1; - const char *comment = skipWhitespace(strtok(end+1, "\r\n")); + const char *comment = skipWhitespace(strtok(end + 1, "\r\n")); std::string label = std::string("str:") + value; Stream &s = streams.at(streamStack.back()); if (labelIndex.count(label) == 0) { diff --git a/common/command.cc b/common/command.cc index 8acbafd2..ad5b6c54 100644 --- a/common/command.cc +++ b/common/command.cc @@ -184,9 +184,9 @@ void CommandHandler::setupContext(Context *ctx) } if (vm.count("slack_redist_iter")) { - ctx->settings[ctx->id("slack_redist_iter")] = vm["slack_redist_iter"].as(); + ctx->settings[ctx->id("slack_redist_iter")] = vm["slack_redist_iter"].as(); if (vm.count("freq") && vm["freq"].as() == 0) { - ctx->settings[ctx->id("auto_freq")] = std::to_string(true); + ctx->settings[ctx->id("auto_freq")] = true; #ifndef NO_GUI if (!vm.count("gui")) #endif @@ -195,11 +195,11 @@ void CommandHandler::setupContext(Context *ctx) } if (vm.count("ignore-loops")) { - ctx->settings[ctx->id("timing/ignoreLoops")] = std::to_string(true); + ctx->settings[ctx->id("timing/ignoreLoops")] = true; } if (vm.count("timing-allow-fail")) { - ctx->settings[ctx->id("timing/allowFail")] = std::to_string(true); + ctx->settings[ctx->id("timing/allowFail")] = true; } if (vm.count("placer")) { @@ -219,7 +219,7 @@ void CommandHandler::setupContext(Context *ctx) } if (vm.count("placer-budgets")) { - ctx->settings[ctx->id("placer1/budgetBased")] = std::to_string(true); + ctx->settings[ctx->id("placer1/budgetBased")] = true; } if (vm.count("freq")) { auto freq = vm["freq"].as(); @@ -228,23 +228,23 @@ void CommandHandler::setupContext(Context *ctx) } if (vm.count("no-tmdriv")) - ctx->settings[ctx->id("timing_driven")] = std::to_string(false); + ctx->settings[ctx->id("timing_driven")] = false; // Setting default values if (ctx->settings.find(ctx->id("target_freq")) == ctx->settings.end()) ctx->settings[ctx->id("target_freq")] = std::to_string(12e6); if (ctx->settings.find(ctx->id("timing_driven")) == ctx->settings.end()) - ctx->settings[ctx->id("timing_driven")] = std::to_string(true); + ctx->settings[ctx->id("timing_driven")] = true; if (ctx->settings.find(ctx->id("slack_redist_iter")) == ctx->settings.end()) - ctx->settings[ctx->id("slack_redist_iter")] = "0"; + ctx->settings[ctx->id("slack_redist_iter")] = 0; if (ctx->settings.find(ctx->id("auto_freq")) == ctx->settings.end()) - ctx->settings[ctx->id("auto_freq")] = std::to_string(false); + ctx->settings[ctx->id("auto_freq")] = false; if (ctx->settings.find(ctx->id("placer")) == ctx->settings.end()) ctx->settings[ctx->id("placer")] = Arch::defaultPlacer; ctx->settings[ctx->id("arch.name")] = std::string(ctx->archId().c_str(ctx)); ctx->settings[ctx->id("arch.type")] = std::string(ctx->archArgsToId(ctx->archArgs()).c_str(ctx)); - ctx->settings[ctx->id("seed")] = std::to_string(ctx->rngstate); + ctx->settings[ctx->id("seed")] = ctx->rngstate; } int CommandHandler::executeMain(std::unique_ptr ctx) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index d4cc4917..8f172422 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -131,6 +131,60 @@ TimingConstrObjectId BaseCtx::timingPortObject(CellInfo *cell, IdString port) } } +Property::Property() : is_string(false), str(""), intval(0) {} + +Property::Property(int64_t intval, int width) : is_string(false), intval(intval) +{ + str.resize(width); + for (int i = 0; i < width; i++) + str.push_back((intval & (1ULL << i)) ? S1 : S0); +} + +Property::Property(const std::string &strval) : is_string(true), str(strval), intval(0xDEADBEEF) {} + +Property::Property(State bit) : is_string(false), str(std::string("") + char(bit)), intval(bit == S1) {} + +std::string Property::to_string() const +{ + if (is_string) { + std::string result = str; + int state = 0; + for (char c : str) { + if (state == 0) { + if (c == '0' || c == '1' || c == 'x' || c == 'z') + state = 0; + else if (c == ' ') + state = 1; + else + state = 2; + } else if (state == 1 && c != ' ') + state = 2; + } + if (state < 2) + result += " "; + return result; + } else { + return std::string(str.rbegin(), str.rend()); + } +} + +Property Property::from_string(const std::string &s) +{ + Property p; + + size_t cursor = s.find_first_not_of("01xz"); + if (cursor == std::string::npos) { + p.str = std::string(s.rbegin(), s.rend()); + p.is_string = false; + p.update_intval(); + } else if (s.find_first_not_of(' ', cursor) == std::string::npos) { + p = Property(s.substr(0, s.size() - 1)); + } else { + p = Property(s); + } + return p; +} + void BaseCtx::addConstraint(std::unique_ptr constr) { for (auto fromObj : constr->from) @@ -285,8 +339,8 @@ uint32_t Context::checksum() const for (auto &a : ni.attrs) { uint32_t attr_x = 123456789; attr_x = xorshift32(attr_x + xorshift32(a.first.index)); - for (uint8_t ch : a.second) - attr_x = xorshift32(attr_x + xorshift32(ch)); + for (char ch : a.second.str) + attr_x = xorshift32(attr_x + xorshift32((int)ch)); attr_x_sum += attr_x; } x = xorshift32(x + xorshift32(attr_x_sum)); @@ -329,8 +383,8 @@ uint32_t Context::checksum() const for (auto &a : ci.attrs) { uint32_t attr_x = 123456789; attr_x = xorshift32(attr_x + xorshift32(a.first.index)); - for (uint8_t ch : a.second) - attr_x = xorshift32(attr_x + xorshift32(ch)); + for (char ch : a.second.str) + attr_x = xorshift32(attr_x + xorshift32((int)ch)); attr_x_sum += attr_x; } x = xorshift32(x + xorshift32(attr_x_sum)); @@ -339,8 +393,8 @@ uint32_t Context::checksum() const for (auto &p : ci.params) { uint32_t param_x = 123456789; param_x = xorshift32(param_x + xorshift32(p.first.index)); - for (uint8_t ch : p.second) - param_x = xorshift32(param_x + xorshift32(ch)); + for (char ch : p.second.str) + param_x = xorshift32(param_x + xorshift32((int)ch)); param_x_sum += param_x; } x = xorshift32(x + xorshift32(param_x_sum)); @@ -462,19 +516,19 @@ void BaseCtx::archInfoToAttributes() if (ci->attrs.find(id("BEL")) != ci->attrs.end()) { ci->attrs.erase(ci->attrs.find(id("BEL"))); } - ci->attrs[id("NEXTPNR_BEL")] = getCtx()->getBelName(ci->bel).c_str(this); - ci->attrs[id("BEL_STRENGTH")] = std::to_string((int)ci->belStrength); + ci->attrs[id("NEXTPNR_BEL")] = getCtx()->getBelName(ci->bel).str(this); + ci->attrs[id("BEL_STRENGTH")] = (int)ci->belStrength; } if (ci->constr_x != ci->UNCONSTR) - ci->attrs[id("CONSTR_X")] = std::to_string(ci->constr_x); + ci->attrs[id("CONSTR_X")] = ci->constr_x; if (ci->constr_y != ci->UNCONSTR) - ci->attrs[id("CONSTR_Y")] = std::to_string(ci->constr_y); + ci->attrs[id("CONSTR_Y")] = ci->constr_y; if (ci->constr_z != ci->UNCONSTR) { - ci->attrs[id("CONSTR_Z")] = std::to_string(ci->constr_z); - ci->attrs[id("CONSTR_ABS_Z")] = std::to_string(ci->constr_abs_z ? 1 : 0); + ci->attrs[id("CONSTR_Z")] = ci->constr_z; + ci->attrs[id("CONSTR_ABS_Z")] = ci->constr_abs_z ? 1 : 0; } if (ci->constr_parent != nullptr) - ci->attrs[id("CONSTR_PARENT")] = ci->constr_parent->name.c_str(this); + ci->attrs[id("CONSTR_PARENT")] = ci->constr_parent->name.str(this); if (!ci->constr_children.empty()) { std::string constr = ""; for (auto &item : ci->constr_children) { @@ -512,37 +566,38 @@ void BaseCtx::attributesToArchInfo() auto str = ci->attrs.find(id("BEL_STRENGTH")); PlaceStrength strength = PlaceStrength::STRENGTH_USER; if (str != ci->attrs.end()) - strength = (PlaceStrength)std::stoi(str->second.str); + strength = (PlaceStrength)str->second.as_int64(); - BelId b = getCtx()->getBelByName(id(val->second.str)); + BelId b = getCtx()->getBelByName(id(val->second.as_string())); getCtx()->bindBel(b, ci, strength); } val = ci->attrs.find(id("CONSTR_X")); if (val != ci->attrs.end()) - ci->constr_x = std::stoi(val->second.str); + ci->constr_x = val->second.as_int64(); val = ci->attrs.find(id("CONSTR_Y")); if (val != ci->attrs.end()) - ci->constr_y = std::stoi(val->second.str); + ci->constr_y = val->second.as_int64(); val = ci->attrs.find(id("CONSTR_Z")); if (val != ci->attrs.end()) - ci->constr_z = std::stoi(val->second.str); + ci->constr_z = val->second.as_int64(); val = ci->attrs.find(id("CONSTR_ABS_Z")); if (val != ci->attrs.end()) - ci->constr_abs_z = std::stoi(val->second.str) == 1; + ci->constr_abs_z = val->second.as_int64() == 1; val = ci->attrs.find(id("CONSTR_PARENT")); if (val != ci->attrs.end()) { - auto parent = cells.find(id(val->second.str)); + auto parent = cells.find(id(val->second.as_string())); if (parent != cells.end()) ci->constr_parent = parent->second.get(); } val = ci->attrs.find(id("CONSTR_CHILDREN")); if (val != ci->attrs.end()) { std::vector strs; - boost::split(strs, val->second.str, boost::is_any_of(";")); + auto children = val->second.as_string(); + boost::split(strs, children, boost::is_any_of(";")); for (auto val : strs) { ci->constr_children.push_back(cells.find(id(val.c_str()))->second.get()); } @@ -553,7 +608,8 @@ void BaseCtx::attributesToArchInfo() auto val = ni->attrs.find(id("ROUTING")); if (val != ni->attrs.end()) { std::vector strs; - boost::split(strs, val->second.str, boost::is_any_of(";")); + auto routing = val->second.as_string(); + boost::split(strs, routing, boost::is_any_of(";")); for (size_t i = 0; i < strs.size() / 3; i++) { std::string wire = strs[i * 3]; std::string pip = strs[i * 3 + 1]; diff --git a/common/nextpnr.h b/common/nextpnr.h index 1f22e65a..efa326c0 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -32,6 +32,7 @@ #include #include +#include #include #ifndef NEXTPNR_H @@ -289,42 +290,98 @@ struct PipMap struct Property { + enum State : char + { + S0 = '0', + S1 = '1', + Sx = 'x', + Sz = 'z' + }; + + Property(); + Property(int64_t intval, int width = 32); + Property(const std::string &strval); + Property(State bit); + Property &operator=(const Property &other) = default; + bool is_string; + // The string literal (for string values), or a string of [01xz] (for numeric values) std::string str; - int num; + // The lower 64 bits (for numeric values), unused for string values + int64_t intval; - std::string::iterator begin() { return str.begin(); } - std::string::iterator end() { return str.end(); } - - bool isString() const { return is_string; } - - void setNumber(int val) + void update_intval() { - is_string = false; - num = val; - str = std::to_string(val); - } - void setString(std::string val) - { - is_string = true; - str = val; + intval = 0; + for (int i = 0; i < int(str.size()); i++) { + NPNR_ASSERT(str[i] == S0 || str[i] == S1 || str[i] == Sx || str[i] == Sz); + if ((str[i] == S1) && i < 64) + intval |= (1ULL << i); + } } - const char *c_str() const { return str.c_str(); } - operator std::string() const { return str; } - - bool operator==(const std::string other) const { return str == other; } - bool operator!=(const std::string other) const { return str != other; } - - Property &operator=(std::string other) + int64_t as_int64() const { - is_string = true; - str = other; - return *this; + NPNR_ASSERT(!is_string); + return intval; } + std::vector as_bits() const + { + std::vector result; + result.reserve(str.size()); + NPNR_ASSERT(!is_string); + for (auto c : str) + result.push_back(c == S1); + } + std::string as_string() const + { + NPNR_ASSERT(is_string); + return str; + } + const char *c_str() const + { + NPNR_ASSERT(is_string); + return str.c_str(); + } + size_t size() const { return is_string ? 8 * str.size() : str.size(); } + double as_double() const + { + NPNR_ASSERT(is_string); + return std::stod(str); + } + bool as_bool() const + { + if (int(str.size()) <= 64) + return intval != 0; + else + return std::any_of(str.begin(), str.end(), [](char c) { return c == S1; }); + } + bool is_fully_def() const + { + return !is_string && std::all_of(str.begin(), str.end(), [](char c) { return c == S0 || c == S1; }); + } + Property extract(int offset, int len, State padding = State::S0) const + { + Property ret; + ret.is_string = false; + ret.str.reserve(len); + for (int i = offset; i < offset + len; i++) + ret.str.push_back(i < int(str.size()) ? str[i] : padding); + ret.update_intval(); + return ret; + } + // Convert to a string representation, escaping literal strings matching /^[01xz]* *$/ by adding a space at the end, + // to disambiguate from binary strings + std::string to_string() const; + // Convert a string of four-value binary [01xz], or a literal string escaped according to the above rule + // to a Property + static Property from_string(const std::string &s); }; +inline bool operator==(const Property &a, const Property &b) { return a.is_string == b.is_string && a.str == b.str; } +inline bool operator!=(const Property &a, const Property &b) { return a.is_string != b.is_string || a.str != b.str; } + struct ClockConstraint; struct NetInfo : ArchNetInfo @@ -731,8 +788,10 @@ struct Context : Arch, DeterministicRNG template T setting(const char *name, T defaultValue) { IdString new_id = id(name); - if (settings.find(new_id) != settings.end()) - return boost::lexical_cast(settings.find(new_id)->second.str); + auto found = settings.find(new_id); + if (found != settings.end()) + return boost::lexical_cast(found->second.is_string ? found->second.as_string() + : std::to_string(found->second.as_int64())); else settings[id(name)] = std::to_string(defaultValue); @@ -742,8 +801,10 @@ struct Context : Arch, DeterministicRNG template T setting(const char *name) const { IdString new_id = id(name); - if (settings.find(new_id) != settings.end()) - return boost::lexical_cast(settings.find(new_id)->second.str); + auto found = settings.find(new_id); + if (found != settings.end()) + return boost::lexical_cast(found->second.is_string ? found->second.as_string() + : std::to_string(found->second.as_int64())); else throw std::runtime_error("settings does not exists"); } diff --git a/common/placer1.cc b/common/placer1.cc index cb7ae847..6683ddf7 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -159,7 +159,7 @@ class SAPlacer CellInfo *cell = cell_entry.second.get(); auto loc = cell->attrs.find(ctx->id("BEL")); if (loc != cell->attrs.end()) { - std::string loc_name = loc->second; + std::string loc_name = loc->second.as_string(); BelId bel = ctx->getBelByName(ctx->id(loc_name)); if (bel == BelId()) { log_error("No Bel named \'%s\' located for " diff --git a/common/placer_heap.cc b/common/placer_heap.cc index d1f5a974..e9fc2fb2 100644 --- a/common/placer_heap.cc +++ b/common/placer_heap.cc @@ -348,7 +348,7 @@ class HeAPPlacer CellInfo *cell = cell_entry.second.get(); auto loc = cell->attrs.find(ctx->id("BEL")); if (loc != cell->attrs.end()) { - std::string loc_name = loc->second; + std::string loc_name = loc->second.as_string(); BelId bel = ctx->getBelByName(ctx->id(loc_name)); if (bel == BelId()) { log_error("No Bel named \'%s\' located for " diff --git a/common/pybindings.cc b/common/pybindings.cc index 52dd9717..3f2cb811 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -81,6 +81,13 @@ template <> struct string_converter } }; +template <> struct string_converter +{ + inline Property from_str(Context *ctx, std::string s) { return Property::from_string(s); } + + inline std::string to_str(Context *ctx, Property p) { return p.to_string(); } +}; + } // namespace PythonConversion BOOST_PYTHON_MODULE(MODULE_NAME) @@ -207,7 +214,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME) readonly_wrapper>::def_wrap(region_cls, "wires"); - WRAP_MAP(AttrMap, pass_through, "AttrMap"); + WRAP_MAP(AttrMap, conv_to_str, "AttrMap"); WRAP_MAP(PortMap, wrap_context, "PortMap"); WRAP_MAP(PinMap, conv_to_str, "PinMap"); WRAP_MAP(WireMap, wrap_context, "WireMap"); diff --git a/common/util.h b/common/util.h index 8f361dc8..81d7e47d 100644 --- a/common/util.h +++ b/common/util.h @@ -51,6 +51,16 @@ std::string str_or_default(const Container &ct, const KeyType &key, std::string return found->second; }; +template +std::string str_or_default(const std::unordered_map &ct, const KeyType &key, std::string def = "") +{ + auto found = ct.find(key); + if (found == ct.end()) + return def; + else + return found->second.as_string(); +}; + // Get a value from a map-style container, converting to int, and returning // default if value is not found template int int_or_default(const Container &ct, const KeyType &key, int def = 0) @@ -62,6 +72,20 @@ template int int_or_default(const Contain return std::stoi(found->second); }; +template +int int_or_default(const std::unordered_map &ct, const KeyType &key, int def = 0) +{ + auto found = ct.find(key); + if (found == ct.end()) + return def; + else { + if (found->second.is_string) + return std::stoi(found->second.as_string()); + else + return found->second.as_int64(); + } +}; + // As above, but convert to bool template bool bool_or_default(const Container &ct, const KeyType &key, bool def = false) diff --git a/ecp5/main.cc b/ecp5/main.cc index 75126cea..ed2501a9 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -34,7 +34,7 @@ class ECP5CommandHandler : public CommandHandler public: ECP5CommandHandler(int argc, char **argv); virtual ~ECP5CommandHandler(){}; - std::unique_ptr createContext(std::unordered_map &values) override; + std::unique_ptr createContext(std::unordered_map &values) override; void setupArchContext(Context *ctx) override{}; void customAfterLoad(Context *ctx) override; void validate() override; @@ -113,7 +113,7 @@ static std::string speedString(ArchArgs::SpeedGrade speed) return ""; } -std::unique_ptr ECP5CommandHandler::createContext(std::unordered_map &values) +std::unique_ptr ECP5CommandHandler::createContext(std::unordered_map &values) { ArchArgs chipArgs; chipArgs.type = ArchArgs::NONE; @@ -162,12 +162,12 @@ std::unique_ptr ECP5CommandHandler::createContext(std::unordered_map ECP5CommandHandler::createContext(std::unordered_mapattrs) { - addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str()); + addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), + item.second.is_string ? item.second.to_string().c_str() : item.second.as_string().c_str()); } QtProperty *wiresItem = addSubGroup(topItem, "Wires"); @@ -813,12 +814,14 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt QtProperty *cellAttrItem = addSubGroup(topItem, "Attributes"); for (auto &item : cell->attrs) { - addProperty(cellAttrItem, QVariant::String, item.first.c_str(ctx), item.second.c_str()); + addProperty(cellAttrItem, QVariant::String, item.first.c_str(ctx), + item.second.is_string ? item.second.as_string().c_str() : item.second.to_string().c_str()); } QtProperty *cellParamsItem = addSubGroup(topItem, "Parameters"); for (auto &item : cell->params) { - addProperty(cellParamsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str()); + addProperty(cellParamsItem, QVariant::String, item.first.c_str(ctx), + item.second.is_string ? item.second.as_string().c_str() : item.second.to_string().c_str()); } QtProperty *cellPinsItem = groupManager->addProperty("Pins"); diff --git a/ice40/arch.cc b/ice40/arch.cc index 0b1d280c..cc50cb68 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -689,7 +689,7 @@ bool Arch::place() tocfg.cellTypes.insert(id_ICESTORM_LC); retVal = timing_opt(getCtx(), tocfg); } - getCtx()->settings[getCtx()->id("place")] = "1"; + getCtx()->settings[getCtx()->id("place")] = 1; archInfoToAttributes(); return retVal; } @@ -697,7 +697,7 @@ bool Arch::place() bool Arch::route() { bool retVal = router1(getCtx(), Router1Cfg(getCtx())); - getCtx()->settings[getCtx()->id("route")] = "1"; + getCtx()->settings[getCtx()->id("route")] = 1; archInfoToAttributes(); return retVal; } diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 7632b443..7149f127 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -23,6 +23,7 @@ #include #include "cells.h" #include "log.h" +#include "util.h" NEXTPNR_NAMESPACE_BEGIN @@ -98,12 +99,15 @@ void set_ie_bit_logical(const Context *ctx, const TileInfoPOD &ti, std::vectorparams.find(param); - if (found != cell->params.end()) - return std::stoi(found->second); - else + if (found != cell->params.end()) { + if (found->second.is_string) + log_error("expected numeric value for parameter '%s' on cell '%s'\n", param.c_str(ctx), + cell->name.c_str(ctx)); + return found->second.as_int64(); + } else return defval; } @@ -111,7 +115,7 @@ std::string get_param_str_or_def(const CellInfo *cell, const IdString param, std { auto found = cell->params.find(param); if (found != cell->params.end()) - return found->second; + return found->second.as_string(); else return defval; } @@ -172,8 +176,8 @@ void configure_extra_cell(chipconfig_t &config, const Context *ctx, CellInfo *ce } else { int ival; try { - ival = get_param_or_def(cell, ctx->id(p.first), 0); - } catch (std::invalid_argument &e) { + ival = get_param_or_def(ctx, cell, ctx->id(p.first), 0); + } catch (std::exception &e) { log_error("expected numeric value for parameter '%s' on cell '%s'\n", p.first.c_str(), cell->name.c_str(ctx)); } @@ -419,12 +423,12 @@ void write_asc(const Context *ctx, std::ostream &out) const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC]; - unsigned lut_init = get_param_or_def(cell.second.get(), ctx->id("LUT_INIT")); - bool neg_clk = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK")); - bool dff_enable = get_param_or_def(cell.second.get(), ctx->id("DFF_ENABLE")); - bool async_sr = get_param_or_def(cell.second.get(), ctx->id("ASYNC_SR")); - bool set_noreset = get_param_or_def(cell.second.get(), ctx->id("SET_NORESET")); - bool carry_enable = get_param_or_def(cell.second.get(), ctx->id("CARRY_ENABLE")); + unsigned lut_init = get_param_or_def(ctx, cell.second.get(), ctx->id("LUT_INIT")); + bool neg_clk = get_param_or_def(ctx, cell.second.get(), ctx->id("NEG_CLK")); + bool dff_enable = get_param_or_def(ctx, cell.second.get(), ctx->id("DFF_ENABLE")); + bool async_sr = get_param_or_def(ctx, cell.second.get(), ctx->id("ASYNC_SR")); + bool set_noreset = get_param_or_def(ctx, cell.second.get(), ctx->id("SET_NORESET")); + bool carry_enable = get_param_or_def(ctx, cell.second.get(), ctx->id("CARRY_ENABLE")); std::vector lc(20, false); // Discover permutation @@ -483,8 +487,8 @@ void write_asc(const Context *ctx, std::ostream &out) if (dff_enable) set_config(ti, config.at(y).at(x), "NegClk", neg_clk); - bool carry_const = get_param_or_def(cell.second.get(), ctx->id("CIN_CONST")); - bool carry_set = get_param_or_def(cell.second.get(), ctx->id("CIN_SET")); + bool carry_const = get_param_or_def(ctx, cell.second.get(), ctx->id("CIN_CONST")); + bool carry_set = get_param_or_def(ctx, cell.second.get(), ctx->id("CIN_SET")); if (carry_const) { if (!ctx->force) NPNR_ASSERT(z == 0); @@ -494,9 +498,9 @@ void write_asc(const Context *ctx, std::ostream &out) const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; - unsigned pin_type = get_param_or_def(cell.second.get(), ctx->id("PIN_TYPE")); - bool neg_trigger = get_param_or_def(cell.second.get(), ctx->id("NEG_TRIGGER")); - bool pullup = get_param_or_def(cell.second.get(), ctx->id("PULLUP")); + unsigned pin_type = get_param_or_def(ctx, cell.second.get(), ctx->id("PIN_TYPE")); + bool neg_trigger = get_param_or_def(ctx, cell.second.get(), ctx->id("NEG_TRIGGER")); + bool pullup = get_param_or_def(ctx, cell.second.get(), ctx->id("PULLUP")); bool lvds = cell.second->ioInfo.lvds; bool used_by_pll_out = sb_io_used_by_pll_out.count(Loc(x, y, z)) > 0; bool used_by_pll_pad = sb_io_used_by_pll_pad.count(Loc(x, y, z)) > 0; @@ -532,7 +536,7 @@ void write_asc(const Context *ctx, std::ostream &out) if (ctx->args.type == ArchArgs::UP5K) { std::string pullup_resistor = "100K"; if (cell.second->attrs.count(ctx->id("PULLUP_RESISTOR"))) - pullup_resistor = cell.second->attrs.at(ctx->id("PULLUP_RESISTOR")); + pullup_resistor = cell.second->attrs.at(ctx->id("PULLUP_RESISTOR")).as_string(); NPNR_ASSERT(pullup_resistor == "100K" || pullup_resistor == "10K" || pullup_resistor == "6P8K" || pullup_resistor == "3P3K"); if (iez == 0) { @@ -599,10 +603,10 @@ void write_asc(const Context *ctx, std::ostream &out) if (!(ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K)) { set_config(ti_ramb, config.at(y).at(x), "RamConfig.PowerUp", true); } - bool negclk_r = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK_R")); - bool negclk_w = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK_W")); - int write_mode = get_param_or_def(cell.second.get(), ctx->id("WRITE_MODE")); - int read_mode = get_param_or_def(cell.second.get(), ctx->id("READ_MODE")); + bool negclk_r = get_param_or_def(ctx, cell.second.get(), ctx->id("NEG_CLK_R")); + bool negclk_w = get_param_or_def(ctx, cell.second.get(), ctx->id("NEG_CLK_W")); + int write_mode = get_param_or_def(ctx, cell.second.get(), ctx->id("WRITE_MODE")); + int read_mode = get_param_or_def(ctx, cell.second.get(), ctx->id("READ_MODE")); set_config(ti_ramb, config.at(y).at(x), "NegClk", negclk_w); set_config(ti_ramt, config.at(y + 1).at(x), "NegClk", negclk_r); @@ -628,9 +632,9 @@ void write_asc(const Context *ctx, std::ostream &out) // No config needed } else if (cell.second->type == ctx->id("SB_I2C")) { bool sda_in_dly = !cell.second->attrs.count(ctx->id("SDA_INPUT_DELAYED")) || - std::stoi(cell.second->attrs[ctx->id("SDA_INPUT_DELAYED")]); + cell.second->attrs[ctx->id("SDA_INPUT_DELAYED")].as_bool(); bool sda_out_dly = !cell.second->attrs.count(ctx->id("SDA_OUTPUT_DELAYED")) || - std::stoi(cell.second->attrs[ctx->id("SDA_OUTPUT_DELAYED")]); + cell.second->attrs[ctx->id("SDA_OUTPUT_DELAYED")].as_bool(); set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "SDA_INPUT_DELAYED", sda_in_dly, "IpConfig."); set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "SDA_OUTPUT_DELAYED", sda_out_dly, @@ -861,10 +865,10 @@ void write_asc(const Context *ctx, std::ostream &out) out << ".ram_data " << x << " " << y << std::endl; for (int w = 0; w < 16; w++) { std::vector bits(256); - std::string init = - get_param_str_or_def(cell.second.get(), ctx->id(std::string("INIT_") + get_hexdigit(w))); - for (size_t i = 0; i < init.size(); i++) { - bool val = (init.at((init.size() - 1) - i) == '1'); + Property init = get_or_default(cell.second->params, ctx->id(std::string("INIT_") + get_hexdigit(w)), + Property(0, 256)); + for (size_t i = 0; i < init.str.size(); i++) { + bool val = (init.str.at(i) == Property::State::S1); bits.at(i) = val; } for (int i = bits.size() - 4; i >= 0; i -= 4) { diff --git a/ice40/cells.cc b/ice40/cells.cc index a2abcea4..c4e93d5b 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -43,14 +43,14 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri } new_cell->type = type; if (type == ctx->id("ICESTORM_LC")) { - new_cell->params[ctx->id("LUT_INIT")] = "0"; - new_cell->params[ctx->id("NEG_CLK")] = "0"; - new_cell->params[ctx->id("CARRY_ENABLE")] = "0"; - new_cell->params[ctx->id("DFF_ENABLE")] = "0"; - new_cell->params[ctx->id("SET_NORESET")] = "0"; - new_cell->params[ctx->id("ASYNC_SR")] = "0"; - new_cell->params[ctx->id("CIN_CONST")] = "0"; - new_cell->params[ctx->id("CIN_SET")] = "0"; + new_cell->params[ctx->id("LUT_INIT")] = Property(0, 16); + new_cell->params[ctx->id("NEG_CLK")] = Property::State::S0; + new_cell->params[ctx->id("CARRY_ENABLE")] = Property::State::S0; + new_cell->params[ctx->id("DFF_ENABLE")] = Property::State::S0; + new_cell->params[ctx->id("SET_NORESET")] = Property::State::S0; + new_cell->params[ctx->id("ASYNC_SR")] = Property::State::S0; + new_cell->params[ctx->id("CIN_CONST")] = Property::State::S0; + new_cell->params[ctx->id("CIN_SET")] = Property::State::S0; add_port(ctx, new_cell.get(), "I0", PORT_IN); add_port(ctx, new_cell.get(), "I1", PORT_IN); @@ -66,10 +66,10 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "O", PORT_OUT); add_port(ctx, new_cell.get(), "COUT", PORT_OUT); } else if (type == ctx->id("SB_IO")) { - new_cell->params[ctx->id("PIN_TYPE")] = "0"; - new_cell->params[ctx->id("PULLUP")] = "0"; - new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; - new_cell->params[ctx->id("IOSTANDARD")] = "SB_LVCMOS"; + new_cell->params[ctx->id("PIN_TYPE")] = Property(0, 6); + new_cell->params[ctx->id("PULLUP")] = Property::State::S0; + new_cell->params[ctx->id("NEG_TRIGGER")] = Property::State::S0; + new_cell->params[ctx->id("IOSTANDARD")] = Property("SB_LVCMOS"); add_port(ctx, new_cell.get(), "PACKAGE_PIN", PORT_INOUT); @@ -85,10 +85,10 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "D_IN_0", PORT_OUT); add_port(ctx, new_cell.get(), "D_IN_1", PORT_OUT); } else if (type == ctx->id("ICESTORM_RAM")) { - new_cell->params[ctx->id("NEG_CLK_W")] = "0"; - new_cell->params[ctx->id("NEG_CLK_R")] = "0"; - new_cell->params[ctx->id("WRITE_MODE")] = "0"; - new_cell->params[ctx->id("READ_MODE")] = "0"; + new_cell->params[ctx->id("NEG_CLK_W")] = Property::State::S0; + new_cell->params[ctx->id("NEG_CLK_R")] = Property::State::S0; + new_cell->params[ctx->id("WRITE_MODE")] = Property::State::S0; + new_cell->params[ctx->id("READ_MODE")] = Property::State::S0; add_port(ctx, new_cell.get(), "RCLK", PORT_IN); add_port(ctx, new_cell.get(), "RCLKE", PORT_IN); @@ -114,8 +114,8 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "CLKLF", PORT_OUT); add_port(ctx, new_cell.get(), "CLKLF_FABRIC", PORT_OUT); } else if (type == ctx->id("ICESTORM_HFOSC")) { - new_cell->params[ctx->id("CLKHF_DIV")] = "0b00"; - new_cell->params[ctx->id("TRIM_EN")] = "0b0"; + new_cell->params[ctx->id("CLKHF_DIV")] = Property("0b00"); + new_cell->params[ctx->id("TRIM_EN")] = Property("0b0"); add_port(ctx, new_cell.get(), "CLKHFEN", PORT_IN); add_port(ctx, new_cell.get(), "CLKHFPU", PORT_IN); @@ -145,30 +145,30 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "MASKWREN_" + std::to_string(i), PORT_IN); } } else if (type == ctx->id("ICESTORM_DSP")) { - new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; + new_cell->params[ctx->id("NEG_TRIGGER")] = Property::State::S0; - new_cell->params[ctx->id("C_REG")] = "0"; - new_cell->params[ctx->id("A_REG")] = "0"; - new_cell->params[ctx->id("B_REG")] = "0"; - new_cell->params[ctx->id("D_REG")] = "0"; - new_cell->params[ctx->id("TOP_8x8_MULT_REG")] = "0"; - new_cell->params[ctx->id("BOT_8x8_MULT_REG")] = "0"; - new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG1")] = "0"; - new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG2")] = "0"; + new_cell->params[ctx->id("C_REG")] = Property::State::S0; + new_cell->params[ctx->id("A_REG")] = Property::State::S0; + new_cell->params[ctx->id("B_REG")] = Property::State::S0; + new_cell->params[ctx->id("D_REG")] = Property::State::S0; + new_cell->params[ctx->id("TOP_8x8_MULT_REG")] = Property::State::S0; + new_cell->params[ctx->id("BOT_8x8_MULT_REG")] = Property::State::S0; + new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG1")] = Property::State::S0; + new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG2")] = Property::State::S0; - new_cell->params[ctx->id("TOPOUTPUT_SELECT")] = "0"; - new_cell->params[ctx->id("TOPADDSUB_LOWERINPUT")] = "0"; - new_cell->params[ctx->id("TOPADDSUB_UPPERINPUT")] = "0"; - new_cell->params[ctx->id("TOPADDSUB_CARRYSELECT")] = "0"; + new_cell->params[ctx->id("TOPOUTPUT_SELECT")] = Property(0, 2); + new_cell->params[ctx->id("TOPADDSUB_LOWERINPUT")] = Property(0, 2); + new_cell->params[ctx->id("TOPADDSUB_UPPERINPUT")] = Property::State::S0; + new_cell->params[ctx->id("TOPADDSUB_CARRYSELECT")] = Property(0, 2); - new_cell->params[ctx->id("BOTOUTPUT_SELECT")] = "0"; - new_cell->params[ctx->id("BOTADDSUB_LOWERINPUT")] = "0"; - new_cell->params[ctx->id("BOTADDSUB_UPPERINPUT")] = "0"; - new_cell->params[ctx->id("BOTADDSUB_CARRYSELECT")] = "0"; + new_cell->params[ctx->id("BOTOUTPUT_SELECT")] = Property(0, 2); + new_cell->params[ctx->id("BOTADDSUB_LOWERINPUT")] = Property(0, 2); + new_cell->params[ctx->id("BOTADDSUB_UPPERINPUT")] = Property::State::S0; + new_cell->params[ctx->id("BOTADDSUB_CARRYSELECT")] = Property(0, 2); - new_cell->params[ctx->id("MODE_8x8")] = "0"; - new_cell->params[ctx->id("A_SIGNED")] = "0"; - new_cell->params[ctx->id("B_SIGNED")] = "0"; + new_cell->params[ctx->id("MODE_8x8")] = Property::State::S0; + new_cell->params[ctx->id("A_SIGNED")] = Property::State::S0; + new_cell->params[ctx->id("B_SIGNED")] = Property::State::S0; add_port(ctx, new_cell.get(), "CLK", PORT_IN); add_port(ctx, new_cell.get(), "CE", PORT_IN); @@ -210,24 +210,24 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "SIGNEXTOUT", PORT_OUT); } else if (type == ctx->id("ICESTORM_PLL")) { - new_cell->params[ctx->id("DELAY_ADJMODE_FB")] = "0"; - new_cell->params[ctx->id("DELAY_ADJMODE_REL")] = "0"; + new_cell->params[ctx->id("DELAY_ADJMODE_FB")] = Property::State::S0; + new_cell->params[ctx->id("DELAY_ADJMODE_REL")] = Property::State::S0; - new_cell->params[ctx->id("DIVF")] = "0"; - new_cell->params[ctx->id("DIVQ")] = "0"; - new_cell->params[ctx->id("DIVR")] = "0"; + new_cell->params[ctx->id("DIVF")] = Property(0, 7); + new_cell->params[ctx->id("DIVQ")] = Property(0, 3); + new_cell->params[ctx->id("DIVR")] = Property(0, 4); - new_cell->params[ctx->id("FDA_FEEDBACK")] = "0"; - new_cell->params[ctx->id("FDA_RELATIVE")] = "0"; - new_cell->params[ctx->id("FEEDBACK_PATH")] = "1"; - new_cell->params[ctx->id("FILTER_RANGE")] = "0"; + new_cell->params[ctx->id("FDA_FEEDBACK")] = Property(0, 4); + new_cell->params[ctx->id("FDA_RELATIVE")] = Property(0, 4); + new_cell->params[ctx->id("FEEDBACK_PATH")] = Property(1, 3); + new_cell->params[ctx->id("FILTER_RANGE")] = Property(0, 3); - new_cell->params[ctx->id("PLLOUT_SELECT_A")] = "0"; - new_cell->params[ctx->id("PLLOUT_SELECT_B")] = "0"; + new_cell->params[ctx->id("PLLOUT_SELECT_A")] = Property(0, 2); + new_cell->params[ctx->id("PLLOUT_SELECT_B")] = Property(0, 2); - new_cell->params[ctx->id("PLLTYPE")] = "0"; - new_cell->params[ctx->id("SHIFTREG_DIVMODE")] = "0"; - new_cell->params[ctx->id("TEST_MODE")] = "0"; + new_cell->params[ctx->id("PLLTYPE")] = Property(0, 3); + new_cell->params[ctx->id("SHIFTREG_DIVMODE")] = Property::State::S0; + new_cell->params[ctx->id("TEST_MODE")] = Property::State::S0; add_port(ctx, new_cell.get(), "BYPASS", PORT_IN); for (int i = 0; i < 8; i++) @@ -247,10 +247,10 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "PLLOUT_A_GLOBAL", PORT_OUT); add_port(ctx, new_cell.get(), "PLLOUT_B_GLOBAL", PORT_OUT); } else if (type == ctx->id("SB_RGBA_DRV")) { - new_cell->params[ctx->id("CURRENT_MODE")] = "0b0"; - new_cell->params[ctx->id("RGB0_CURRENT")] = "0b000000"; - new_cell->params[ctx->id("RGB1_CURRENT")] = "0b000000"; - new_cell->params[ctx->id("RGB2_CURRENT")] = "0b000000"; + new_cell->params[ctx->id("CURRENT_MODE")] = std::string("0b0"); + new_cell->params[ctx->id("RGB0_CURRENT")] = std::string("0b000000"); + new_cell->params[ctx->id("RGB1_CURRENT")] = std::string("0b000000"); + new_cell->params[ctx->id("RGB2_CURRENT")] = std::string("0b000000"); add_port(ctx, new_cell.get(), "CURREN", PORT_IN); add_port(ctx, new_cell.get(), "RGBLEDEN", PORT_IN); @@ -264,9 +264,9 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "EN", PORT_IN); add_port(ctx, new_cell.get(), "LEDPU", PORT_OUT); } else if (type == ctx->id("SB_RGB_DRV")) { - new_cell->params[ctx->id("RGB0_CURRENT")] = "0b000000"; - new_cell->params[ctx->id("RGB1_CURRENT")] = "0b000000"; - new_cell->params[ctx->id("RGB2_CURRENT")] = "0b000000"; + new_cell->params[ctx->id("RGB0_CURRENT")] = std::string("0b000000"); + new_cell->params[ctx->id("RGB1_CURRENT")] = std::string("0b000000"); + new_cell->params[ctx->id("RGB2_CURRENT")] = std::string("0b000000"); add_port(ctx, new_cell.get(), "RGBPU", PORT_IN); add_port(ctx, new_cell.get(), "RGBLEDEN", PORT_IN); @@ -292,8 +292,8 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "PWMOUT2", PORT_OUT); add_port(ctx, new_cell.get(), "LEDDON", PORT_OUT); } else if (type == ctx->id("SB_I2C")) { - new_cell->params[ctx->id("I2C_SLAVE_INIT_ADDR")] = "0b1111100001"; - new_cell->params[ctx->id("BUS_ADDR74")] = "0b0001"; + new_cell->params[ctx->id("I2C_SLAVE_INIT_ADDR")] = std::string("0b1111100001"); + new_cell->params[ctx->id("BUS_ADDR74")] = std::string("0b0001"); for (int i = 0; i < 8; i++) { add_port(ctx, new_cell.get(), "SBADRI" + std::to_string(i), PORT_IN); add_port(ctx, new_cell.get(), "SBDATI" + std::to_string(i), PORT_IN); @@ -312,7 +312,7 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "SDAO", PORT_OUT); add_port(ctx, new_cell.get(), "SDAOE", PORT_OUT); } else if (type == ctx->id("SB_SPI")) { - new_cell->params[ctx->id("BUS_ADDR74")] = "0b0000"; + new_cell->params[ctx->id("BUS_ADDR74")] = std::string("0b0000"); for (int i = 0; i < 8; i++) { add_port(ctx, new_cell.get(), "SBADRI" + std::to_string(i), PORT_IN); add_port(ctx, new_cell.get(), "SBDATI" + std::to_string(i), PORT_IN); @@ -346,29 +346,29 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { - lc->params[ctx->id("LUT_INIT")] = lut->params[ctx->id("LUT_INIT")]; + lc->params[ctx->id("LUT_INIT")] = lut->params[ctx->id("LUT_INIT")].extract(0, 16, Property::State::S0); replace_port(lut, ctx->id("I0"), lc, ctx->id("I0")); replace_port(lut, ctx->id("I1"), lc, ctx->id("I1")); replace_port(lut, ctx->id("I2"), lc, ctx->id("I2")); replace_port(lut, ctx->id("I3"), lc, ctx->id("I3")); if (no_dff) { replace_port(lut, ctx->id("O"), lc, ctx->id("O")); - lc->params[ctx->id("DFF_ENABLE")] = "0"; + lc->params[ctx->id("DFF_ENABLE")] = Property::State::S0; } } void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) { - lc->params[ctx->id("DFF_ENABLE")] = "1"; + lc->params[ctx->id("DFF_ENABLE")] = Property::State::S1; std::string config = dff->type.str(ctx).substr(6); auto citer = config.begin(); replace_port(dff, ctx->id("C"), lc, ctx->id("CLK")); if (citer != config.end() && *citer == 'N') { - lc->params[ctx->id("NEG_CLK")] = "1"; + lc->params[ctx->id("NEG_CLK")] = Property::State::S1; ++citer; } else { - lc->params[ctx->id("NEG_CLK")] = "0"; + lc->params[ctx->id("NEG_CLK")] = Property::State::S0; } if (citer != config.end() && *citer == 'E') { @@ -380,27 +380,27 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l if ((config.end() - citer) >= 2) { char c = *(citer++); NPNR_ASSERT(c == 'S'); - lc->params[ctx->id("ASYNC_SR")] = "0"; + lc->params[ctx->id("ASYNC_SR")] = Property::State::S0; } else { - lc->params[ctx->id("ASYNC_SR")] = "1"; + lc->params[ctx->id("ASYNC_SR")] = Property::State::S1; } if (*citer == 'S') { citer++; replace_port(dff, ctx->id("S"), lc, ctx->id("SR")); - lc->params[ctx->id("SET_NORESET")] = "1"; + lc->params[ctx->id("SET_NORESET")] = Property::State::S1; } else { NPNR_ASSERT(*citer == 'R'); citer++; replace_port(dff, ctx->id("R"), lc, ctx->id("SR")); - lc->params[ctx->id("SET_NORESET")] = "0"; + lc->params[ctx->id("SET_NORESET")] = Property::State::S0; } } NPNR_ASSERT(citer == config.end()); if (pass_thru_lut) { - lc->params[ctx->id("LUT_INIT")] = "2"; + lc->params[ctx->id("LUT_INIT")] = Property(2, 16); replace_port(dff, ctx->id("D"), lc, ctx->id("I0")); } @@ -410,17 +410,17 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set &todelete_cells) { if (nxio->type == ctx->id("$nextpnr_ibuf")) { - sbio->params[ctx->id("PIN_TYPE")] = "1"; + sbio->params[ctx->id("PIN_TYPE")] = 1; auto pu_attr = nxio->attrs.find(ctx->id("PULLUP")); if (pu_attr != nxio->attrs.end()) sbio->params[ctx->id("PULLUP")] = pu_attr->second; replace_port(nxio, ctx->id("O"), sbio, ctx->id("D_IN_0")); } else if (nxio->type == ctx->id("$nextpnr_obuf")) { - sbio->params[ctx->id("PIN_TYPE")] = "25"; + sbio->params[ctx->id("PIN_TYPE")] = 25; replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0")); } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { // N.B. tristate will be dealt with below - sbio->params[ctx->id("PIN_TYPE")] = "25"; + sbio->params[ctx->id("PIN_TYPE")] = 25; replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0")); replace_port(nxio, ctx->id("O"), sbio, ctx->id("D_IN_0")); } else { @@ -431,7 +431,7 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, std::unordered_set ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); }, ctx->id("Y")); if (tbuf) { - sbio->params[ctx->id("PIN_TYPE")] = "41"; + sbio->params[ctx->id("PIN_TYPE")] = 41; replace_port(tbuf, ctx->id("A"), sbio, ctx->id("D_OUT_0")); replace_port(tbuf, ctx->id("E"), sbio, ctx->id("OUTPUT_ENABLE")); diff --git a/ice40/cells.h b/ice40/cells.h index 3d9358da..777ca3e2 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -101,17 +101,19 @@ inline bool is_sb_pll40_pad(const BaseCtx *ctx, const CellInfo *cell) return cell->type == ctx->id("SB_PLL40_PAD") || cell->type == ctx->id("SB_PLL40_2_PAD") || cell->type == ctx->id("SB_PLL40_2F_PAD") || (cell->type == ctx->id("ICESTORM_PLL") && - (cell->attrs.at(ctx->id("TYPE")) == "SB_PLL40_PAD" || cell->attrs.at(ctx->id("TYPE")) == "SB_PLL40_2_PAD" || - cell->attrs.at(ctx->id("TYPE")) == "SB_PLL40_2F_PAD")); + (cell->attrs.at(ctx->id("TYPE")).as_string() == "SB_PLL40_PAD" || + cell->attrs.at(ctx->id("TYPE")).as_string() == "SB_PLL40_2_PAD" || + cell->attrs.at(ctx->id("TYPE")).as_string() == "SB_PLL40_2F_PAD")); } inline bool is_sb_pll40_dual(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_PLL40_2_PAD") || cell->type == ctx->id("SB_PLL40_2F_PAD") || cell->type == ctx->id("SB_PLL40_2F_CORE") || - (cell->type == ctx->id("ICESTORM_PLL") && (cell->attrs.at(ctx->id("TYPE")) == "SB_PLL40_2_PAD" || - cell->attrs.at(ctx->id("TYPE")) == "SB_PLL40_2F_PAD" || - cell->attrs.at(ctx->id("TYPE")) == "SB_PLL40_2F_CORE")); + (cell->type == ctx->id("ICESTORM_PLL") && + (cell->attrs.at(ctx->id("TYPE")).as_string() == "SB_PLL40_2_PAD" || + cell->attrs.at(ctx->id("TYPE")).as_string() == "SB_PLL40_2F_PAD" || + cell->attrs.at(ctx->id("TYPE")).as_string() == "SB_PLL40_2F_CORE")); } uint8_t sb_pll40_type(const BaseCtx *ctx, const CellInfo *cell); diff --git a/ice40/chains.cc b/ice40/chains.cc index b3b54d6b..1b556f65 100644 --- a/ice40/chains.cc +++ b/ice40/chains.cc @@ -91,8 +91,8 @@ class ChainConstrainer { NPNR_ASSERT(cout_port.net != nullptr); std::unique_ptr lc = create_ice_cell(ctx, ctx->id("ICESTORM_LC")); - lc->params[ctx->id("LUT_INIT")] = "65280"; // 0xff00: O = I3 - lc->params[ctx->id("CARRY_ENABLE")] = "1"; + lc->params[ctx->id("LUT_INIT")] = Property(65280, 16); // 0xff00: O = I3 + lc->params[ctx->id("CARRY_ENABLE")] = Property::State::S1; lc->ports.at(id_O).net = cout_port.net; std::unique_ptr co_i3_net(new NetInfo()); co_i3_net->name = ctx->id(lc->name.str(ctx) + "$I3"); @@ -167,9 +167,9 @@ class ChainConstrainer { NPNR_ASSERT(cin_port.net != nullptr); std::unique_ptr lc = create_ice_cell(ctx, ctx->id("ICESTORM_LC")); - lc->params[ctx->id("CARRY_ENABLE")] = "1"; - lc->params[ctx->id("CIN_CONST")] = "1"; - lc->params[ctx->id("CIN_SET")] = "1"; + lc->params[ctx->id("CARRY_ENABLE")] = Property::State::S1; + lc->params[ctx->id("CIN_CONST")] = Property::State::S1; + lc->params[ctx->id("CIN_SET")] = Property::State::S1; lc->ports.at(ctx->id("I1")).net = cin_port.net; cin_port.net->users.erase(std::remove_if(cin_port.net->users.begin(), cin_port.net->users.end(), [cin_cell, cin_port](const PortRef &usr) { diff --git a/ice40/main.cc b/ice40/main.cc index 83cb04b0..b656f932 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -159,12 +159,12 @@ std::unique_ptr Ice40CommandHandler::createContext(std::unordered_map(); if (values.find("arch.name") != values.end()) { - std::string arch_name = values["arch.name"].str; + std::string arch_name = values["arch.name"].as_string(); if (arch_name != "ice40") log_error("Unsuported architecture '%s'.\n", arch_name.c_str()); } if (values.find("arch.type") != values.end()) { - std::string arch_type = values["arch.type"].str; + std::string arch_type = values["arch.type"].as_string(); if (chipArgs.type != ArchArgs::NONE) log_error("Overriding architecture is unsuported.\n"); @@ -195,7 +195,7 @@ std::unique_ptr Ice40CommandHandler::createContext(std::unordered_map Ice40CommandHandler::createContext(std::unordered_mapsettings[ctx->id("arch.package")] = ctx->archArgs().package; if (vm.count("promote-logic")) - ctx->settings[ctx->id("promote_logic")] = "1"; + ctx->settings[ctx->id("promote_logic")] = Property::State::S1; if (vm.count("no-promote-globals")) - ctx->settings[ctx->id("no_promote_globals")] = "1"; + ctx->settings[ctx->id("no_promote_globals")] = Property::State::S1; if (vm.count("opt-timing")) - ctx->settings[ctx->id("opt_timing")] = "1"; + ctx->settings[ctx->id("opt_timing")] = Property::State::S1; if (vm.count("pcf-allow-unconstrained")) - ctx->settings[ctx->id("pcf_allow_unconstrained")] = "1"; + ctx->settings[ctx->id("pcf_allow_unconstrained")] = Property::State::S1; return ctx; } diff --git a/ice40/pack.cc b/ice40/pack.cc index d1366c9c..462310cd 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -210,7 +210,7 @@ static void pack_carries(Context *ctx) } new_cells.push_back(std::move(created_lc)); } - carry_lc->params[ctx->id("CARRY_ENABLE")] = "1"; + carry_lc->params[ctx->id("CARRY_ENABLE")] = Property::State::S1; replace_port(ci, ctx->id("CI"), carry_lc, ctx->id("CIN")); replace_port(ci, ctx->id("CO"), carry_lc, ctx->id("COUT")); if (i0_net) { @@ -230,8 +230,9 @@ static void pack_carries(Context *ctx) if (carry_lc->ports.at(ctx->id("CIN")).net != nullptr) { IdString cin_net = carry_lc->ports.at(ctx->id("CIN")).net->name; if (cin_net == ctx->id("$PACKER_GND_NET") || cin_net == ctx->id("$PACKER_VCC_NET")) { - carry_lc->params[ctx->id("CIN_CONST")] = "1"; - carry_lc->params[ctx->id("CIN_SET")] = cin_net == ctx->id("$PACKER_VCC_NET") ? "1" : "0"; + carry_lc->params[ctx->id("CIN_CONST")] = Property::State::S1; + carry_lc->params[ctx->id("CIN_SET")] = + cin_net == ctx->id("$PACKER_VCC_NET") ? Property::State::S1 : Property::State::S0; carry_lc->ports.at(ctx->id("CIN")).net = nullptr; auto &cin_users = ctx->nets.at(cin_net)->users; cin_users.erase( @@ -270,9 +271,9 @@ static void pack_ram(Context *ctx) for (auto param : ci->params) packed->params[param.first] = param.second; packed->params[ctx->id("NEG_CLK_W")] = - std::to_string(ci->type == ctx->id("SB_RAM40_4KNW") || ci->type == ctx->id("SB_RAM40_4KNRNW")); + Property(ci->type == ctx->id("SB_RAM40_4KNW") || ci->type == ctx->id("SB_RAM40_4KNRNW"), 1); packed->params[ctx->id("NEG_CLK_R")] = - std::to_string(ci->type == ctx->id("SB_RAM40_4KNR") || ci->type == ctx->id("SB_RAM40_4KNRNW")); + Property(ci->type == ctx->id("SB_RAM40_4KNR") || ci->type == ctx->id("SB_RAM40_4KNRNW"), 1); packed->type = ctx->id("ICESTORM_RAM"); for (auto port : ci->ports) { PortInfo &pi = port.second; @@ -334,7 +335,7 @@ static void pack_constants(Context *ctx) log_info("Packing constants..\n"); std::unique_ptr gnd_cell = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_GND"); - gnd_cell->params[ctx->id("LUT_INIT")] = "0"; + gnd_cell->params[ctx->id("LUT_INIT")] = Property(0, 16); 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(); @@ -347,7 +348,7 @@ static void pack_constants(Context *ctx) } std::unique_ptr vcc_cell = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_VCC"); - vcc_cell->params[ctx->id("LUT_INIT")] = "1"; + vcc_cell->params[ctx->id("LUT_INIT")] = Property(1, 16); 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(); @@ -417,13 +418,13 @@ static std::unique_ptr create_padin_gbuf(Context *ctx, CellInfo *cell, std::string gbuf_name) { // Find the matching SB_GB BEL connected to the same global network - BelId bel = ctx->getBelByName(ctx->id(cell->attrs[ctx->id("BEL")])); + BelId bel = ctx->getBelByName(ctx->id(cell->attrs[ctx->id("BEL")].as_string())); BelId gb_bel = find_padin_gbuf(ctx, bel, port_name); NPNR_ASSERT(gb_bel != BelId()); // Create a SB_GB Cell and lock it there std::unique_ptr gb = create_ice_cell(ctx, ctx->id("SB_GB"), gbuf_name); - gb->attrs[ctx->id("FOR_PAD_IN")] = "1"; + gb->attrs[ctx->id("FOR_PAD_IN")] = Property::State::S1; gb->attrs[ctx->id("BEL")] = ctx->getBelName(gb_bel).str(ctx); // Reconnect the net to that port for easier identification it's a global net @@ -521,7 +522,7 @@ static void pack_io(Context *ctx) // Make it a normal SB_IO with global marker ci->type = ctx->id("SB_IO"); - ci->attrs[ctx->id("GLOBAL")] = "1"; + ci->attrs[ctx->id("GLOBAL")] = Property::State::S1; } else if (is_sb_io(ctx, ci)) { // Disconnect unused inputs NetInfo *net_in0 = ci->ports.count(id_D_IN_0) ? ci->ports[id_D_IN_0].net : nullptr; @@ -636,7 +637,7 @@ static void promote_globals(Context *ctx) /* And possibly limits what we can promote */ if (cell.second->attrs.find(ctx->id("BEL")) != cell.second->attrs.end()) { /* If the SB_GB is locked, doesn't matter what it drives */ - BelId bel = ctx->getBelByName(ctx->id(cell.second->attrs[ctx->id("BEL")])); + BelId bel = ctx->getBelByName(ctx->id(cell.second->attrs[ctx->id("BEL")].as_string())); int glb_id = ctx->getDrivenGlobalNetwork(bel); if ((glb_id % 2) == 0) resets_available--; @@ -755,10 +756,10 @@ static void place_plls(Context *ctx) // If it's constrained already, add to already used list if (ci->attrs.count(ctx->id("BEL"))) { - BelId bel_constrain = ctx->getBelByName(ctx->id(ci->attrs[ctx->id("BEL")])); + BelId bel_constrain = ctx->getBelByName(ctx->id(ci->attrs[ctx->id("BEL")].as_string())); if (pll_all_bels.count(bel_constrain) == 0) log_error("PLL '%s' is constrained to invalid BEL '%s'\n", ci->name.c_str(ctx), - ci->attrs[ctx->id("BEL")].c_str()); + ci->attrs[ctx->id("BEL")].as_string().c_str()); pll_used_bels[bel_constrain] = ci; } @@ -790,7 +791,7 @@ static void place_plls(Context *ctx) log_error("PLL '%s' PACKAGEPIN SB_IO '%s' is unconstrained\n", ci->name.c_str(ctx), io_cell->name.c_str(ctx)); - BelId io_bel = ctx->getBelByName(ctx->id(io_cell->attrs.at(ctx->id("BEL")))); + BelId io_bel = ctx->getBelByName(ctx->id(io_cell->attrs.at(ctx->id("BEL")).as_string())); BelId found_bel; // Find the PLL BEL that would suit that connection @@ -815,7 +816,7 @@ static void place_plls(Context *ctx) // Is it user constrained ? if (ci->attrs.count(ctx->id("BEL"))) { // Yes. Check it actually matches ! - BelId bel_constrain = ctx->getBelByName(ctx->id(ci->attrs[ctx->id("BEL")])); + BelId bel_constrain = ctx->getBelByName(ctx->id(ci->attrs[ctx->id("BEL")].as_string())); if (bel_constrain != found_bel) log_error("PLL '%s' is user constrained to %s but can only be placed in %s based on its PACKAGEPIN " "connection\n", @@ -845,7 +846,7 @@ static void place_plls(Context *ctx) continue; // Check all placed PLL (either forced by user, or forced by PACKAGEPIN) - BelId io_bel = ctx->getBelByName(ctx->id(io_ci->attrs[ctx->id("BEL")])); + BelId io_bel = ctx->getBelByName(ctx->id(io_ci->attrs[ctx->id("BEL")].as_string())); for (auto placed_pll : pll_used_bels) { BelPin pll_io_a, pll_io_b; @@ -879,7 +880,7 @@ static void place_plls(Context *ctx) continue; // Check all placed PLL (either forced by user, or forced by PACKAGEPIN) - BelId gb_bel = ctx->getBelByName(ctx->id(gb_ci->attrs[ctx->id("BEL")])); + BelId gb_bel = ctx->getBelByName(ctx->id(gb_ci->attrs[ctx->id("BEL")].as_string())); for (auto placed_pll : pll_used_bels) { CellInfo *ci = placed_pll.second; @@ -938,7 +939,7 @@ static void place_plls(Context *ctx) bool could_be_pad = false; BelId pad_bel; if (ni->users.size() == 1 && is_sb_io(ctx, ni->driver.cell) && ni->driver.cell->attrs.count(ctx->id("BEL"))) - pad_bel = ctx->getBelByName(ctx->id(ni->driver.cell->attrs[ctx->id("BEL")])); + pad_bel = ctx->getBelByName(ctx->id(ni->driver.cell->attrs[ctx->id("BEL")].as_string())); // Find a BEL for it BelId found_bel; @@ -989,7 +990,7 @@ static std::unique_ptr spliceLUT(Context *ctx, CellInfo *ci, IdString // Create pass-through LUT. std::unique_ptr pt = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "$nextpnr_" + portId.str(ctx) + "_lut_through"); - pt->params[ctx->id("LUT_INIT")] = "65280"; // output is always I3 + pt->params[ctx->id("LUT_INIT")] = Property(65280, 16); // output is always I3 // Create LUT output net. std::unique_ptr out_net = std::unique_ptr(new NetInfo); @@ -1187,10 +1188,11 @@ static void pack_special(Context *ctx) {std::make_tuple(id_SB_SPI, "0b0010"), Loc(25, 0, 1)}, {std::make_tuple(id_SB_I2C, "0b0011"), Loc(25, 31, 0)}, }; - if (map_ba74.find(std::make_tuple(ci->type, ci->params[ctx->id("BUS_ADDR74")])) == map_ba74.end()) + if (map_ba74.find(std::make_tuple(ci->type, ci->params[ctx->id("BUS_ADDR74")].as_string())) == + map_ba74.end()) log_error("Invalid value for BUS_ADDR74 for cell '%s' of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx)); - Loc bel_loc = map_ba74.at(std::make_tuple(ci->type, ci->params[ctx->id("BUS_ADDR74")])); + Loc bel_loc = map_ba74.at(std::make_tuple(ci->type, ci->params[ctx->id("BUS_ADDR74")].as_string())); BelId bel = ctx->getBelByLocation(bel_loc); if (bel == BelId() || ctx->getBelType(bel) != ci->type) log_error("Unable to find placement for cell '%s' of type '%s'\n", ci->name.c_str(ctx), @@ -1230,12 +1232,12 @@ static void pack_special(Context *ctx) }; for (auto param : ci->params) if (pos_map_name.find(param.first) != pos_map_name.end()) { - if (pos_map_val.find(param.second) == pos_map_val.end()) - log_error("Invalid PLL output selection '%s'\n", param.second.c_str()); - packed->params[pos_map_name.at(param.first)] = std::to_string(pos_map_val.at(param.second)); + if (pos_map_val.find(param.second.as_string()) == pos_map_val.end()) + log_error("Invalid PLL output selection '%s'\n", param.second.as_string().c_str()); + packed->params[pos_map_name.at(param.first)] = pos_map_val.at(param.second.as_string()); } - auto feedback_path = packed->params[ctx->id("FEEDBACK_PATH")]; + auto feedback_path = packed->params[ctx->id("FEEDBACK_PATH")].as_string(); std::string fbp_value = feedback_path == "DELAY" ? "0" @@ -1247,8 +1249,8 @@ static void pack_special(Context *ctx) if (!std::all_of(fbp_value.begin(), fbp_value.end(), isdigit)) log_error("PLL '%s' has unsupported FEEDBACK_PATH value '%s'\n", ci->name.c_str(ctx), feedback_path.c_str()); - packed->params[ctx->id("FEEDBACK_PATH")] = fbp_value; - packed->params[ctx->id("PLLTYPE")] = std::to_string(sb_pll40_type(ctx, ci)); + packed->params[ctx->id("FEEDBACK_PATH")] = Property(std::stoi(fbp_value), 3); + packed->params[ctx->id("PLLTYPE")] = sb_pll40_type(ctx, ci); NetInfo *pad_packagepin_net = nullptr; @@ -1304,7 +1306,7 @@ static void pack_special(Context *ctx) } // PLL must have been placed already in place_plls() - BelId pll_bel = ctx->getBelByName(ctx->id(packed->attrs[ctx->id("BEL")])); + BelId pll_bel = ctx->getBelByName(ctx->id(packed->attrs[ctx->id("BEL")].as_string())); NPNR_ASSERT(pll_bel != BelId()); // Deal with PAD PLL peculiarities @@ -1448,7 +1450,7 @@ bool Arch::pack() ctx->assignArchInfo(); constrain_chains(ctx); ctx->assignArchInfo(); - ctx->settings[ctx->id("pack")] = "1"; + ctx->settings[ctx->id("pack")] = 1; archInfoToAttributes(); log_info("Checksum: 0x%08x\n", ctx->checksum()); return true; diff --git a/ice40/pcf.cc b/ice40/pcf.cc index a854a780..8c61eb23 100644 --- a/ice40/pcf.cc +++ b/ice40/pcf.cc @@ -51,15 +51,15 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in) bool nowarn = false; if (cmd == "set_io") { size_t args_end = 1; - std::vector> extra_attrs; + std::vector> extra_attrs; while (args_end < words.size() && words.at(args_end).at(0) == '-') { const auto &setting = words.at(args_end); if (setting == "-pullup") { const auto &value = words.at(++args_end); if (value == "yes" || value == "1") - extra_attrs.emplace_back(std::make_pair(ctx->id("PULLUP"), "1")); + extra_attrs.emplace_back(std::make_pair(ctx->id("PULLUP"), Property::State::S1)); else if (value == "no" || value == "0") - extra_attrs.emplace_back(std::make_pair(ctx->id("PULLUP"), "0")); + extra_attrs.emplace_back(std::make_pair(ctx->id("PULLUP"), Property::State::S0)); else log_error("Invalid value '%s' for -pullup (on line %d)\n", value.c_str(), lineno); } else if (setting == "-pullup_resistor") { @@ -96,7 +96,7 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in) log_error("duplicate pin constraint on '%s' (on line %d)\n", cell.c_str(), lineno); fnd_cell->second->attrs[ctx->id("BEL")] = ctx->getBelName(pin_bel).str(ctx); log_info("constrained '%s' to bel '%s'\n", cell.c_str(), - fnd_cell->second->attrs[ctx->id("BEL")].c_str()); + fnd_cell->second->attrs[ctx->id("BEL")].as_string().c_str()); for (const auto &attr : extra_attrs) fnd_cell->second->attrs[attr.first] = attr.second; } diff --git a/json/jsonparse.cc b/json/jsonparse.cc index caedbb5b..b3bb491b 100644 --- a/json/jsonparse.cc +++ b/json/jsonparse.cc @@ -230,6 +230,25 @@ struct JsonNode } }; +inline Property json_parse_attr_param_value(JsonNode *node) +{ + Property value; + + if (node->type == 'S') { + value = Property::from_string(node->data_string); + } else if (node->type == 'N') { + value = Property(node->data_number, 32); + } else if (node->type == 'A') { + log_error("JSON attribute or parameter value is an array.\n"); + } else if (node->type == 'D') { + log_error("JSON attribute or parameter value is a dict.\n"); + } else { + log_abort(); + } + + return value; +} + void ground_net(Context *ctx, NetInfo *net) { std::unique_ptr cell = std::unique_ptr(new CellInfo); @@ -323,18 +342,12 @@ void json_import_cell_params(Context *ctx, string &modname, CellInfo *cell, Json param = param_node->data_dict.at(param_node->data_dict_keys[param_id]); pId = ctx->id(param_node->data_dict_keys[param_id]); - if (param->type == 'N') { - (*dest)[pId].setNumber(param->data_number); - } else if (param->type == 'S') - (*dest)[pId].setString(param->data_string); - else - log_error("JSON parameter type of \"%s\' of cell \'%s\' not supported\n", pId.c_str(ctx), - cell->name.c_str(ctx)); + (*dest)[pId] = json_parse_attr_param_value(param); if (json_debug) log_info(" Added parameter \'%s\'=%s to cell \'%s\' " "of module \'%s\'\n", - pId.c_str(ctx), cell->params[pId].c_str(), cell->name.c_str(ctx), modname.c_str()); + pId.c_str(ctx), cell->params[pId].as_string().c_str(), cell->name.c_str(ctx), modname.c_str()); } void json_import_net_attrib(Context *ctx, string &modname, NetInfo *net, JsonNode *param_node, @@ -347,16 +360,12 @@ void json_import_net_attrib(Context *ctx, string &modname, NetInfo *net, JsonNod param = param_node->data_dict.at(param_node->data_dict_keys[param_id]); pId = ctx->id(param_node->data_dict_keys[param_id]); - if (param->type == 'N') { - (*dest)[pId].setNumber(param->data_number); - } else if (param->type == 'S') - (*dest)[pId].setString(param->data_string); - else - log_error("JSON parameter type of \"%s\' of net \'%s\' not supported\n", pId.c_str(ctx), net->name.c_str(ctx)); + (*dest)[pId] = json_parse_attr_param_value(param); + if (json_debug) log_info(" Added parameter \'%s\'=%s to net \'%s\' " "of module \'%s\'\n", - pId.c_str(ctx), net->attrs[pId].c_str(), net->name.c_str(ctx), modname.c_str()); + pId.c_str(ctx), net->attrs[pId].as_string().c_str(), net->name.c_str(ctx), modname.c_str()); } void json_import_top_attrib(Context *ctx, string &modname, JsonNode *param_node, @@ -369,14 +378,10 @@ void json_import_top_attrib(Context *ctx, string &modname, JsonNode *param_node, param = param_node->data_dict.at(param_node->data_dict_keys[param_id]); pId = ctx->id(param_node->data_dict_keys[param_id]); - if (param->type == 'N') { - (*dest)[pId].setNumber(param->data_number); - } else if (param->type == 'S') - (*dest)[pId].setString(param->data_string); - else - log_error("JSON parameter type of \"%s\' of module not supported\n", pId.c_str(ctx)); + (*dest)[pId] = json_parse_attr_param_value(param); + if (json_debug) - log_info(" Added parameter \'%s\'=%s module \'%s\'\n", pId.c_str(ctx), (*dest)[pId].c_str(), + log_info(" Added parameter \'%s\'=%s module \'%s\'\n", pId.c_str(ctx), (*dest)[pId].as_string().c_str(), modname.c_str()); } @@ -917,7 +922,7 @@ void json_import(Context *ctx, string modname, JsonNode *node) } } check_all_nets_driven(ctx); - ctx->settings[ctx->id("synth")] = "1"; + ctx->settings[ctx->id("synth")] = 1; } }; // End Namespace JsonParser @@ -986,12 +991,7 @@ bool load_json_settings(std::istream &f, std::string &filename, std::unordered_m for (int attrid = 0; attrid < GetSize(attr_node->data_dict_keys); attrid++) { JsonNode *param = attr_node->data_dict.at(attr_node->data_dict_keys[attrid]); std::string pId = attr_node->data_dict_keys[attrid]; - if (param->type == 'N') { - values[pId].setNumber(param->data_number); - } else if (param->type == 'S') - values[pId].setString(param->data_string); - else - log_error("JSON parameter type of \"%s\' of module not supported\n", pId.c_str()); + values[pId] = json_parse_attr_param_value(param); } } } diff --git a/json/jsonwrite.cc b/json/jsonwrite.cc index 0b7a5b25..30bee107 100644 --- a/json/jsonwrite.cc +++ b/json/jsonwrite.cc @@ -45,6 +45,15 @@ std::string get_string(std::string str) std::string get_name(IdString name, Context *ctx) { return get_string(name.c_str(ctx)); } +void write_parameter_value(std::ostream &f, const Property &value) +{ + if (value.size() == 32 && value.is_fully_def()) { + f << stringf("%d", value.as_int64()); + } else { + f << get_string(value.as_string()); + } +} + void write_parameters(std::ostream &f, Context *ctx, const std::unordered_map ¶meters, bool for_module = false) { @@ -52,10 +61,7 @@ void write_parameters(std::ostream &f, Context *ctx, const std::unordered_mapattrs.find(ctx->id("module")); if (val != ctx->attrs.end()) - f << stringf(" %s: {\n", get_string(val->second.str).c_str()); + f << stringf(" %s: {\n", get_string(val->second.as_string()).c_str()); else f << stringf(" %s: {\n", get_string("top").c_str()); f << stringf(" \"settings\": {"); From ec48f8f464a63dece47e9af903098387088c68c5 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 5 Aug 2019 16:31:35 +0100 Subject: [PATCH 2/7] ecp5: New Property interface Signed-off-by: David Shah --- common/nextpnr.cc | 2 +- common/nextpnr.h | 1 + ecp5/arch.cc | 4 +- ecp5/arch_place.cc | 4 +- ecp5/bitstream.cc | 131 +++++----- ecp5/cells.cc | 120 ++++----- ecp5/dcu_bitstream.h | 588 ++++++++++++++++++++++++------------------- ecp5/globals.cc | 4 +- ecp5/main.cc | 12 +- ecp5/pack.cc | 128 +++++----- 10 files changed, 550 insertions(+), 444 deletions(-) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 8f172422..0d89b55a 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -135,7 +135,7 @@ Property::Property() : is_string(false), str(""), intval(0) {} Property::Property(int64_t intval, int width) : is_string(false), intval(intval) { - str.resize(width); + str.reserve(width); for (int i = 0; i < width; i++) str.push_back((intval & (1ULL << i)) ? S1 : S0); } diff --git a/common/nextpnr.h b/common/nextpnr.h index efa326c0..177048bf 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -333,6 +333,7 @@ struct Property NPNR_ASSERT(!is_string); for (auto c : str) result.push_back(c == S1); + return result; } std::string as_string() const { diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 5b3cc660..4be9833e 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -526,7 +526,7 @@ bool Arch::place() } permute_luts(); - getCtx()->settings[getCtx()->id("place")] = "1"; + getCtx()->settings[getCtx()->id("place")] = 1; archInfoToAttributes(); return true; } @@ -563,7 +563,7 @@ bool Arch::route() log_info(" base %d adder %d\n", speed_grade->pip_classes[locInfo(slowest_pip)->pip_data[slowest_pip.index].timing_class].max_base_delay, speed_grade->pip_classes[locInfo(slowest_pip)->pip_data[slowest_pip.index].timing_class].max_fanout_adder); #endif - getCtx()->settings[getCtx()->id("route")] = "1"; + getCtx()->settings[getCtx()->id("route")] = 1; archInfoToAttributes(); return result; } diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index e5c9b31f..b5c11851 100644 --- a/ecp5/arch_place.cc +++ b/ecp5/arch_place.cc @@ -162,7 +162,7 @@ void Arch::permute_luts() connect_port(getCtx(), orig_nets.at(inputs.at(i).second), ci, p); ci->params[id(p.str(this) + "MUX")] = p.str(this); } else { - ci->params[id(p.str(this) + "MUX")] = "1"; + ci->params[id(p.str(this) + "MUX")] = std::string("1"); } } // Rewrite function @@ -177,7 +177,7 @@ void Arch::permute_luts() if (old_init & (1 << old_index)) new_init |= (1 << i); } - ci->params[id("LUT" + std::to_string(lut) + "_INITVAL")] = std::to_string(new_init); + ci->params[id("LUT" + std::to_string(lut) + "_INITVAL")] = Property(new_init, 16); }; for (auto cell : sorted(cells)) { diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index d549a727..a4b345e6 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -134,12 +134,14 @@ inline int chtohex(char c) return hex.find(c); } -std::vector parse_init_str(const std::string &str, int length, const char *cellname) +std::vector parse_init_str(const Property &p, int length, const char *cellname) { // Parse a string that may be binary or hex std::vector result; result.resize(length, false); - if (str.substr(0, 2) == "0x") { + if (p.is_string) { + std::string str = p.as_string(); + NPNR_ASSERT(str.substr(0, 2) == "0x"); // Lattice style hex string if (int(str.length()) > (2 + ((length + 3) / 4))) log_error("hex string value too long, expected up to %d chars and found %d.\n", (2 + ((length + 3) / 4)), @@ -156,15 +158,8 @@ std::vector parse_init_str(const std::string &str, int length, const char result.at(i * 4 + 3) = nibble & 0x8; } } else { - // Yosys style binary string - if (int(str.length()) > length) - log_error("hex string value too long, expected up to %d bits and found %d.\n", length, int(str.length())); - for (int i = 0; i < int(str.length()); i++) { - char c = str.at((str.size() - i) - 1); - if (c != '0' && c != '1' && c != 'X' && c != 'x') - log_error("Found illegal character '%c' while processing parameters for cell '%s'\n", c, cellname); - result.at(i) = (c == '1'); - } + result = p.as_bits(); + result.resize(length, false); } return result; } @@ -498,46 +493,67 @@ static void set_pip(Context *ctx, ChipConfig &cc, PipId pip) cc.tiles[tile].add_arc(sink, source); } -static std::vector parse_config_str(std::string str, int length) +static std::vector parse_config_str(const Property &p, int length) { - // For DCU config which might be bin, hex or dec using prefices accordingly - std::string base = str.substr(0, 2); std::vector word; - word.resize(length, false); - if (base == "0b") { - for (int i = 0; i < int(str.length()) - 2; i++) { - char c = str.at((str.size() - 1) - i); - NPNR_ASSERT(c == '0' || c == '1'); - word.at(i) = (c == '1'); + if (p.is_string) { + std::string str = p.as_string(); + // For DCU config which might be bin, hex or dec using prefices accordingly + std::string base = str.substr(0, 2); + word.resize(length, false); + if (base == "0b") { + for (int i = 0; i < int(str.length()) - 2; i++) { + char c = str.at((str.size() - 1) - i); + NPNR_ASSERT(c == '0' || c == '1'); + word.at(i) = (c == '1'); + } + } else if (base == "0x") { + for (int i = 0; i < int(str.length()) - 2; i++) { + char c = str.at((str.size() - i) - 1); + int nibble = chtohex(c); + word.at(i * 4) = nibble & 0x1; + if (i * 4 + 1 < length) + word.at(i * 4 + 1) = nibble & 0x2; + if (i * 4 + 2 < length) + word.at(i * 4 + 2) = nibble & 0x4; + if (i * 4 + 3 < length) + word.at(i * 4 + 3) = nibble & 0x8; + } + } else if (base == "0d") { + NPNR_ASSERT(length < 64); + unsigned long long value = std::stoull(str.substr(2)); + for (int i = 0; i < length; i++) + if (value & (1 << i)) + word.at(i) = true; + } else { + NPNR_ASSERT(length < 64); + unsigned long long value = std::stoull(str); + for (int i = 0; i < length; i++) + if (value & (1 << i)) + word.at(i) = true; } - } else if (base == "0x") { - for (int i = 0; i < int(str.length()) - 2; i++) { - char c = str.at((str.size() - i) - 1); - int nibble = chtohex(c); - word.at(i * 4) = nibble & 0x1; - if (i * 4 + 1 < length) - word.at(i * 4 + 1) = nibble & 0x2; - if (i * 4 + 2 < length) - word.at(i * 4 + 2) = nibble & 0x4; - if (i * 4 + 3 < length) - word.at(i * 4 + 3) = nibble & 0x8; - } - } else if (base == "0d") { - NPNR_ASSERT(length < 64); - unsigned long long value = std::stoull(str.substr(2)); - for (int i = 0; i < length; i++) - if (value & (1 << i)) - word.at(i) = true; } else { - NPNR_ASSERT(length < 64); - unsigned long long value = std::stoull(str); - for (int i = 0; i < length; i++) - if (value & (1 << i)) - word.at(i) = true; + word = p.as_bits(); + word.resize(length, 0); } + return word; } +std::string intstr_or_default(const std::unordered_map &ct, const IdString &key, + std::string def = "0") +{ + auto found = ct.find(key); + if (found == ct.end()) + return def; + else { + if (found->second.is_string) + return found->second.as_string(); + else + return std::to_string(found->second.as_int64()); + } +}; + void write_bitstream(Context *ctx, std::string base_config_file, std::string text_config_file) { ChipConfig cc; @@ -735,8 +751,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex cc.tiles[tname].add_word(slice + ".K1.INIT", int_to_bitvector(lut1_init, 16)); cc.tiles[tname].add_enum(slice + ".MODE", str_or_default(ci->params, ctx->id("MODE"), "LOGIC")); cc.tiles[tname].add_enum(slice + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "ENABLED")); - cc.tiles[tname].add_enum(slice + ".REG0.SD", str_or_default(ci->params, ctx->id("REG0_SD"), "0")); - cc.tiles[tname].add_enum(slice + ".REG1.SD", str_or_default(ci->params, ctx->id("REG1_SD"), "0")); + cc.tiles[tname].add_enum(slice + ".REG0.SD", intstr_or_default(ci->params, ctx->id("REG0_SD"), "0")); + cc.tiles[tname].add_enum(slice + ".REG1.SD", intstr_or_default(ci->params, ctx->id("REG1_SD"), "0")); cc.tiles[tname].add_enum(slice + ".REG0.REGSET", str_or_default(ci->params, ctx->id("REG0_REGSET"), "RESET")); cc.tiles[tname].add_enum(slice + ".REG1.REGSET", @@ -888,8 +904,10 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex auto csd_a = str_to_bitvector(str_or_default(ci->params, ctx->id("CSDECODE_A"), "0b000"), 3), csd_b = str_to_bitvector(str_or_default(ci->params, ctx->id("CSDECODE_B"), "0b000"), 3); - tg.config.add_enum(ebr + ".DP16KD.DATA_WIDTH_A", str_or_default(ci->params, ctx->id("DATA_WIDTH_A"), "18")); - tg.config.add_enum(ebr + ".DP16KD.DATA_WIDTH_B", str_or_default(ci->params, ctx->id("DATA_WIDTH_B"), "18")); + tg.config.add_enum(ebr + ".DP16KD.DATA_WIDTH_A", + intstr_or_default(ci->params, ctx->id("DATA_WIDTH_A"), "18")); + tg.config.add_enum(ebr + ".DP16KD.DATA_WIDTH_B", + intstr_or_default(ci->params, ctx->id("DATA_WIDTH_B"), "18")); tg.config.add_enum(ebr + ".DP16KD.WRITEMODE_A", str_or_default(ci->params, ctx->id("WRITEMODE_A"), "NORMAL")); @@ -916,7 +934,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex // If MUX doesn't exist, set to INV to emulate default 0 tie_cib_signal(ctx, cc, ctx->getBelPinWire(ci->bel, port.first), true); if (!ci->params.count(ctx->id(port.first.str(ctx) + "MUX"))) - ci->params[ctx->id(port.first.str(ctx) + "MUX")] = "INV"; + ci->params[ctx->id(port.first.str(ctx) + "MUX")] = std::string("INV"); } else if (port.first == id_CEA || port.first == id_CEB || port.first == id_OCEA || port.first == id_OCEB) { // CIB CE. Tie to "1" in CIB @@ -930,7 +948,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex // If MUX doesn't exist, set to INV to emulate default 0 tie_cib_signal(ctx, cc, ctx->getBelPinWire(ci->bel, port.first), true); if (!ci->params.count(ctx->id(port.first.str(ctx) + "MUX"))) - ci->params[ctx->id(port.first.str(ctx) + "MUX")] = "INV"; + ci->params[ctx->id(port.first.str(ctx) + "MUX")] = std::string("INV"); } else { // CIB ABCD signal // Tie signals low unless explicit MUX param specified @@ -971,7 +989,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex for (int i = 0; i <= 0x3F; i++) { IdString param = ctx->id("INITVAL_" + fmt_str(std::hex << std::uppercase << std::setw(2) << std::setfill('0') << i)); - auto value = parse_init_str(str_or_default(ci->params, param, "0"), 320, ci->name.c_str(ctx)); + auto value = parse_init_str(get_or_default(ci->params, param, Property(0)), 320, ci->name.c_str(ctx)); for (int j = 0; j < 16; j++) { // INIT parameter consists of 16 18-bit words with 2-bit padding int ofs = 20 * j; @@ -1220,9 +1238,9 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex for (auto ¶m : ci->params) { if (param.first == ctx->id("DELAY.DEL_VALUE")) cc.tiles[pic_tile].add_word(prim + "." + param.first.str(ctx), - int_to_bitvector(std::stoi(param.second), 7)); + int_to_bitvector(param.second.as_int64(), 7)); else - cc.tiles[pic_tile].add_enum(prim + "." + param.first.str(ctx), param.second); + cc.tiles[pic_tile].add_enum(prim + "." + param.first.str(ctx), param.second.as_string()); } } else if (ci->type == id_DCUA) { TileGroup tg; @@ -1234,12 +1252,13 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex } else if (ci->type == id_EXTREFB) { TileGroup tg; tg.tiles = get_dcu_tiles(ctx, ci->bel); - tg.config.add_word("EXTREF.REFCK_DCBIAS_EN", - parse_config_str(str_or_default(ci->params, ctx->id("REFCK_DCBIAS_EN"), "0"), 1)); + tg.config.add_word( + "EXTREF.REFCK_DCBIAS_EN", + parse_config_str(get_or_default(ci->params, ctx->id("REFCK_DCBIAS_EN"), Property(0)), 1)); tg.config.add_word("EXTREF.REFCK_RTERM", - parse_config_str(str_or_default(ci->params, ctx->id("REFCK_RTERM"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("REFCK_RTERM"), Property(0)), 1)); tg.config.add_word("EXTREF.REFCK_PWDNB", - parse_config_str(str_or_default(ci->params, ctx->id("REFCK_PWDNB"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("REFCK_PWDNB"), Property(0)), 1)); cc.tilegroups.push_back(tg); } else if (ci->type == id_PCSCLKDIV) { Loc loc = ctx->getBelLocation(ci->bel); diff --git a/ecp5/cells.cc b/ecp5/cells.cc index 38bcc17c..46f84d97 100644 --- a/ecp5/cells.cc +++ b/ecp5/cells.cc @@ -58,21 +58,21 @@ std::unique_ptr create_ecp5_cell(Context *ctx, IdString type, std::str }; if (type == ctx->id("TRELLIS_SLICE")) { - new_cell->params[ctx->id("MODE")] = "LOGIC"; - new_cell->params[ctx->id("GSR")] = "DISABLED"; - new_cell->params[ctx->id("SRMODE")] = "LSR_OVER_CE"; - new_cell->params[ctx->id("CEMUX")] = "1"; - new_cell->params[ctx->id("CLKMUX")] = "CLK"; - new_cell->params[ctx->id("LSRMUX")] = "LSR"; - new_cell->params[ctx->id("LUT0_INITVAL")] = "0"; - new_cell->params[ctx->id("LUT1_INITVAL")] = "0"; - new_cell->params[ctx->id("REG0_SD")] = "0"; - new_cell->params[ctx->id("REG1_SD")] = "0"; - new_cell->params[ctx->id("REG0_REGSET")] = "RESET"; - new_cell->params[ctx->id("REG1_REGSET")] = "RESET"; - new_cell->params[ctx->id("CCU2_INJECT1_0")] = "NO"; - new_cell->params[ctx->id("CCU2_INJECT1_1")] = "NO"; - new_cell->params[ctx->id("WREMUX")] = "WRE"; + new_cell->params[ctx->id("MODE")] = std::string("LOGIC"); + new_cell->params[ctx->id("GSR")] = std::string("DISABLED"); + new_cell->params[ctx->id("SRMODE")] = std::string("LSR_OVER_CE"); + new_cell->params[ctx->id("CEMUX")] = std::string("1"); + new_cell->params[ctx->id("CLKMUX")] = std::string("CLK"); + new_cell->params[ctx->id("LSRMUX")] = std::string("LSR"); + new_cell->params[ctx->id("LUT0_INITVAL")] = Property(0, 16); + new_cell->params[ctx->id("LUT1_INITVAL")] = Property(0, 16); + new_cell->params[ctx->id("REG0_SD")] = std::string("0"); + new_cell->params[ctx->id("REG1_SD")] = std::string("0"); + new_cell->params[ctx->id("REG0_REGSET")] = std::string("RESET"); + new_cell->params[ctx->id("REG1_REGSET")] = std::string("RESET"); + new_cell->params[ctx->id("CCU2_INJECT1_0")] = std::string("NO"); + new_cell->params[ctx->id("CCU2_INJECT1_1")] = std::string("NO"); + new_cell->params[ctx->id("WREMUX")] = std::string("WRE"); add_port(ctx, new_cell.get(), "A0", PORT_IN); add_port(ctx, new_cell.get(), "B0", PORT_IN); @@ -125,10 +125,10 @@ std::unique_ptr create_ecp5_cell(Context *ctx, IdString type, std::str add_port(ctx, new_cell.get(), "WADO2", PORT_OUT); add_port(ctx, new_cell.get(), "WADO3", PORT_OUT); } else if (type == ctx->id("TRELLIS_IO")) { - new_cell->params[ctx->id("DIR")] = "INPUT"; - new_cell->attrs[ctx->id("IO_TYPE")] = "LVCMOS33"; - new_cell->params[ctx->id("DATAMUX_ODDR")] = "PADDO"; - new_cell->params[ctx->id("DATAMUX_MDDR")] = "PADDO"; + new_cell->params[ctx->id("DIR")] = std::string("INPUT"); + new_cell->attrs[ctx->id("IO_TYPE")] = std::string("LVCMOS33"); + new_cell->params[ctx->id("DATAMUX_ODDR")] = std::string("PADDO"); + new_cell->params[ctx->id("DATAMUX_MDDR")] = std::string("PADDO"); add_port(ctx, new_cell.get(), "B", PORT_INOUT); add_port(ctx, new_cell.get(), "I", PORT_IN); @@ -139,7 +139,7 @@ std::unique_ptr create_ecp5_cell(Context *ctx, IdString type, std::str add_port(ctx, new_cell.get(), "IOLTO", PORT_IN); } else if (type == ctx->id("LUT4")) { - new_cell->params[ctx->id("INIT")] = "0"; + new_cell->params[ctx->id("INIT")] = Property(0, 16); add_port(ctx, new_cell.get(), "A", PORT_IN); add_port(ctx, new_cell.get(), "B", PORT_IN); @@ -147,10 +147,10 @@ std::unique_ptr create_ecp5_cell(Context *ctx, IdString type, std::str add_port(ctx, new_cell.get(), "D", PORT_IN); add_port(ctx, new_cell.get(), "Z", PORT_OUT); } else if (type == ctx->id("CCU2C")) { - new_cell->params[ctx->id("INIT0")] = "0"; - new_cell->params[ctx->id("INIT1")] = "0"; - new_cell->params[ctx->id("INJECT1_0")] = "YES"; - new_cell->params[ctx->id("INJECT1_1")] = "YES"; + new_cell->params[ctx->id("INIT0")] = Property(0, 16); + new_cell->params[ctx->id("INIT1")] = Property(0, 16); + new_cell->params[ctx->id("INJECT1_0")] = std::string("YES"); + new_cell->params[ctx->id("INJECT1_1")] = std::string("YES"); add_port(ctx, new_cell.get(), "CIN", PORT_IN); @@ -173,31 +173,31 @@ std::unique_ptr create_ecp5_cell(Context *ctx, IdString type, std::str add_port(ctx, new_cell.get(), "CLKO", PORT_OUT); add_port(ctx, new_cell.get(), "CE", PORT_IN); } else if (type == id_IOLOGIC || type == id_SIOLOGIC) { - new_cell->params[ctx->id("MODE")] = "NONE"; - new_cell->params[ctx->id("GSR")] = "DISABLED"; - new_cell->params[ctx->id("CLKIMUX")] = "CLK"; - new_cell->params[ctx->id("CLKOMUX")] = "CLK"; - new_cell->params[ctx->id("LSRIMUX")] = "0"; - new_cell->params[ctx->id("LSROMUX")] = "0"; - new_cell->params[ctx->id("LSRMUX")] = "LSR"; + new_cell->params[ctx->id("MODE")] = std::string("NONE"); + new_cell->params[ctx->id("GSR")] = std::string("DISABLED"); + new_cell->params[ctx->id("CLKIMUX")] = std::string("CLK"); + new_cell->params[ctx->id("CLKOMUX")] = std::string("CLK"); + new_cell->params[ctx->id("LSRIMUX")] = std::string("0"); + new_cell->params[ctx->id("LSROMUX")] = std::string("0"); + new_cell->params[ctx->id("LSRMUX")] = std::string("LSR"); - new_cell->params[ctx->id("DELAY.OUTDEL")] = "DISABLED"; - new_cell->params[ctx->id("DELAY.DEL_VALUE")] = "0"; - new_cell->params[ctx->id("DELAY.WAIT_FOR_EDGE")] = "DISABLED"; + new_cell->params[ctx->id("DELAY.OUTDEL")] = std::string("DISABLED"); + new_cell->params[ctx->id("DELAY.DEL_VALUE")] = Property(0, 7); + new_cell->params[ctx->id("DELAY.WAIT_FOR_EDGE")] = std::string("DISABLED"); if (type == id_IOLOGIC) { - new_cell->params[ctx->id("IDDRXN.MODE")] = "NONE"; - new_cell->params[ctx->id("ODDRXN.MODE")] = "NONE"; + new_cell->params[ctx->id("IDDRXN.MODE")] = std::string("NONE"); + new_cell->params[ctx->id("ODDRXN.MODE")] = std::string("NONE"); - new_cell->params[ctx->id("MIDDRX.MODE")] = "NONE"; - new_cell->params[ctx->id("MODDRX.MODE")] = "NONE"; - new_cell->params[ctx->id("MTDDRX.MODE")] = "NONE"; + new_cell->params[ctx->id("MIDDRX.MODE")] = std::string("NONE"); + new_cell->params[ctx->id("MODDRX.MODE")] = std::string("NONE"); + new_cell->params[ctx->id("MTDDRX.MODE")] = std::string("NONE"); - new_cell->params[ctx->id("IOLTOMUX")] = "NONE"; - new_cell->params[ctx->id("MTDDRX.DQSW_INVERT")] = "DISABLED"; - new_cell->params[ctx->id("MTDDRX.REGSET")] = "RESET"; + new_cell->params[ctx->id("IOLTOMUX")] = std::string("NONE"); + new_cell->params[ctx->id("MTDDRX.DQSW_INVERT")] = std::string("DISABLED"); + new_cell->params[ctx->id("MTDDRX.REGSET")] = std::string("RESET"); - new_cell->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = "NONE"; + new_cell->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = std::string("NONE"); } // Just copy ports from the Bel copy_bel_ports(); @@ -241,7 +241,7 @@ void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool drive set_param_safe(has_ff, lc, ctx->id("LSRMUX"), str_or_default(ff->params, ctx->id("LSRMUX"), "LSR")); set_param_safe(has_ff, lc, ctx->id("CLKMUX"), str_or_default(ff->params, ctx->id("CLKMUX"), "CLK")); - lc->params[ctx->id(reg + "_SD")] = driven_by_lut ? "1" : "0"; + lc->params[ctx->id(reg + "_SD")] = std::string(driven_by_lut ? "1" : "0"); lc->params[ctx->id(reg + "_REGSET")] = str_or_default(ff->params, ctx->id("REGSET"), "RESET"); replace_port_safe(has_ff, ff, ctx->id("CLK"), lc, ctx->id("CLK")); if (ff->ports.find(ctx->id("LSR")) != ff->ports.end()) @@ -259,7 +259,8 @@ void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool drive void lut_to_slice(Context *ctx, CellInfo *lut, CellInfo *lc, int index) { - lc->params[ctx->id("LUT" + std::to_string(index) + "_INITVAL")] = str_or_default(lut->params, ctx->id("INIT"), "0"); + lc->params[ctx->id("LUT" + std::to_string(index) + "_INITVAL")] = + get_or_default(lut->params, ctx->id("INIT"), Property(0, 16)); replace_port(lut, ctx->id("A"), lc, ctx->id("A" + std::to_string(index))); replace_port(lut, ctx->id("B"), lc, ctx->id("B" + std::to_string(index))); replace_port(lut, ctx->id("C"), lc, ctx->id("C" + std::to_string(index))); @@ -269,9 +270,9 @@ void lut_to_slice(Context *ctx, CellInfo *lut, CellInfo *lc, int index) void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc) { - lc->params[ctx->id("MODE")] = "CCU2"; - lc->params[ctx->id("LUT0_INITVAL")] = str_or_default(ccu->params, ctx->id("INIT0"), "0"); - lc->params[ctx->id("LUT1_INITVAL")] = str_or_default(ccu->params, ctx->id("INIT1"), "0"); + lc->params[ctx->id("MODE")] = std::string("CCU2"); + lc->params[ctx->id("LUT0_INITVAL")] = get_or_default(ccu->params, ctx->id("INIT0"), Property(0, 16)); + lc->params[ctx->id("LUT1_INITVAL")] = get_or_default(ccu->params, ctx->id("INIT1"), Property(0, 16)); lc->params[ctx->id("INJECT1_0")] = str_or_default(ccu->params, ctx->id("INJECT1_0"), "YES"); lc->params[ctx->id("INJECT1_1")] = str_or_default(ccu->params, ctx->id("INJECT1_1"), "YES"); @@ -296,7 +297,7 @@ void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc) void dram_to_ramw(Context *ctx, CellInfo *ram, CellInfo *lc) { - lc->params[ctx->id("MODE")] = "RAMW"; + lc->params[ctx->id("MODE")] = std::string("RAMW"); replace_port(ram, ctx->id("WAD[0]"), lc, ctx->id("D0")); replace_port(ram, ctx->id("WAD[1]"), lc, ctx->id("B0")); replace_port(ram, ctx->id("WAD[2]"), lc, ctx->id("C0")); @@ -310,12 +311,13 @@ void dram_to_ramw(Context *ctx, CellInfo *ram, CellInfo *lc) static unsigned get_dram_init(const Context *ctx, const CellInfo *ram, int bit) { - const std::string &idata = str_or_default(ram->params, ctx->id("INITVAL"), - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + auto init_prop = get_or_default(ram->params, ctx->id("INITVAL"), Property(0, 64)); + NPNR_ASSERT(!init_prop.is_string); + const std::string &idata = init_prop.str; NPNR_ASSERT(idata.length() == 64); unsigned value = 0; for (int i = 0; i < 16; i++) { - char c = idata.at(63 - (4 * i + bit)); + char c = idata.at(4 * i + bit); if (c == '1') value |= (1 << i); else @@ -326,7 +328,7 @@ static unsigned get_dram_init(const Context *ctx, const CellInfo *ram, int bit) void dram_to_ram_slice(Context *ctx, CellInfo *ram, CellInfo *lc, CellInfo *ramw, int index) { - lc->params[ctx->id("MODE")] = "DPRAM"; + lc->params[ctx->id("MODE")] = std::string("DPRAM"); lc->params[ctx->id("WREMUX")] = str_or_default(ram->params, ctx->id("WREMUX"), "WRE"); lc->params[ctx->id("WCKMUX")] = str_or_default(ram->params, ctx->id("WCKMUX"), "WCK"); @@ -349,8 +351,8 @@ void dram_to_ram_slice(Context *ctx, CellInfo *ram, CellInfo *lc, CellInfo *ramw permuted_init1 |= (1 << i); } - lc->params[ctx->id("LUT0_INITVAL")] = std::to_string(permuted_init0); - lc->params[ctx->id("LUT1_INITVAL")] = std::to_string(permuted_init1); + lc->params[ctx->id("LUT0_INITVAL")] = Property(permuted_init0, 16); + lc->params[ctx->id("LUT1_INITVAL")] = Property(permuted_init1, 16); if (ram->ports.count(ctx->id("RAD[0]"))) { connect_port(ctx, ram->ports.at(ctx->id("RAD[0]")).net, lc, ctx->id("D0")); @@ -401,14 +403,14 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector &todelete_cells) { if (nxio->type == ctx->id("$nextpnr_ibuf")) { - trio->params[ctx->id("DIR")] = "INPUT"; + trio->params[ctx->id("DIR")] = std::string("INPUT"); replace_port(nxio, ctx->id("O"), trio, ctx->id("O")); } else if (nxio->type == ctx->id("$nextpnr_obuf")) { - trio->params[ctx->id("DIR")] = "OUTPUT"; + trio->params[ctx->id("DIR")] = std::string("OUTPUT"); replace_port(nxio, ctx->id("I"), trio, ctx->id("I")); } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { // N.B. tristate will be dealt with below - trio->params[ctx->id("DIR")] = "BIDIR"; + trio->params[ctx->id("DIR")] = std::string("BIDIR"); replace_port(nxio, ctx->id("I"), trio, ctx->id("I")); replace_port(nxio, ctx->id("O"), trio, ctx->id("O")); } else { @@ -423,7 +425,7 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector inv_lut = create_ecp5_cell(ctx, ctx->id("LUT4"), trio->name.str(ctx) + "$invert_T"); replace_port(tbuf, ctx->id("E"), inv_lut.get(), ctx->id("A")); - inv_lut->params[ctx->id("INIT")] = "21845"; + inv_lut->params[ctx->id("INIT")] = Property(21845, 16); connect_ports(ctx, inv_lut.get(), ctx->id("Z"), trio, ctx->id("T")); created_cells.push_back(std::move(inv_lut)); diff --git a/ecp5/dcu_bitstream.h b/ecp5/dcu_bitstream.h index 93c1f9f2..0c461a6b 100644 --- a/ecp5/dcu_bitstream.h +++ b/ecp5/dcu_bitstream.h @@ -1,424 +1,504 @@ tg.config.add_word("DCU.CH0_AUTO_CALIB_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_AUTO_CALIB_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_AUTO_CALIB_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_AUTO_FACQ_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_AUTO_FACQ_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_AUTO_FACQ_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_BAND_THRESHOLD", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_BAND_THRESHOLD"), "0"), 6)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_BAND_THRESHOLD"), Property(0)), 6)); tg.config.add_word("DCU.CH0_CALIB_CK_MODE", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_CALIB_CK_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_CALIB_CK_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH0_CC_MATCH_1", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_CC_MATCH_1"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_CC_MATCH_1"), Property(0)), 10)); tg.config.add_word("DCU.CH0_CC_MATCH_2", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_CC_MATCH_2"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_CC_MATCH_2"), Property(0)), 10)); tg.config.add_word("DCU.CH0_CC_MATCH_3", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_CC_MATCH_3"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_CC_MATCH_3"), Property(0)), 10)); tg.config.add_word("DCU.CH0_CC_MATCH_4", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_CC_MATCH_4"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_CC_MATCH_4"), Property(0)), 10)); tg.config.add_word("DCU.CH0_CDR_CNT4SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_CDR_CNT4SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_CDR_CNT4SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH0_CDR_CNT8SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_CDR_CNT8SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_CDR_CNT8SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH0_CTC_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_CTC_BYPASS"), "0"), 1)); -tg.config.add_word("DCU.CH0_DCOATDCFG", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOATDCFG"), "0"), 2)); -tg.config.add_word("DCU.CH0_DCOATDDLY", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOATDDLY"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_CTC_BYPASS"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_DCOATDCFG", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOATDCFG"), Property(0)), 2)); +tg.config.add_word("DCU.CH0_DCOATDDLY", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOATDDLY"), Property(0)), 2)); tg.config.add_word("DCU.CH0_DCOBYPSATD", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOBYPSATD"), "0"), 1)); -tg.config.add_word("DCU.CH0_DCOCALDIV", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOCALDIV"), "0"), 3)); -tg.config.add_word("DCU.CH0_DCOCTLGI", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOCTLGI"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOBYPSATD"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_DCOCALDIV", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOCALDIV"), Property(0)), 3)); +tg.config.add_word("DCU.CH0_DCOCTLGI", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOCTLGI"), Property(0)), 3)); tg.config.add_word("DCU.CH0_DCODISBDAVOID", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCODISBDAVOID"), "0"), 1)); -tg.config.add_word("DCU.CH0_DCOFLTDAC", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOFLTDAC"), "0"), 2)); -tg.config.add_word("DCU.CH0_DCOFTNRG", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOFTNRG"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCODISBDAVOID"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_DCOFLTDAC", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOFLTDAC"), Property(0)), 2)); +tg.config.add_word("DCU.CH0_DCOFTNRG", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOFTNRG"), Property(0)), 3)); tg.config.add_word("DCU.CH0_DCOIOSTUNE", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOIOSTUNE"), "0"), 3)); -tg.config.add_word("DCU.CH0_DCOITUNE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOITUNE"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOIOSTUNE"), Property(0)), 3)); +tg.config.add_word("DCU.CH0_DCOITUNE", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOITUNE"), Property(0)), 2)); tg.config.add_word("DCU.CH0_DCOITUNE4LSB", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOITUNE4LSB"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOITUNE4LSB"), Property(0)), 3)); tg.config.add_word("DCU.CH0_DCOIUPDNX2", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOIUPDNX2"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOIUPDNX2"), Property(0)), 1)); tg.config.add_word("DCU.CH0_DCONUOFLSB", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCONUOFLSB"), "0"), 3)); -tg.config.add_word("DCU.CH0_DCOSCALEI", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOSCALEI"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCONUOFLSB"), Property(0)), 3)); +tg.config.add_word("DCU.CH0_DCOSCALEI", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOSCALEI"), Property(0)), 2)); tg.config.add_word("DCU.CH0_DCOSTARTVAL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOSTARTVAL"), "0"), 3)); -tg.config.add_word("DCU.CH0_DCOSTEP", parse_config_str(str_or_default(ci->params, ctx->id("CH0_DCOSTEP"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOSTARTVAL"), Property(0)), 3)); +tg.config.add_word("DCU.CH0_DCOSTEP", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DCOSTEP"), Property(0)), 2)); tg.config.add_word("DCU.CH0_DEC_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_DEC_BYPASS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_DEC_BYPASS"), Property(0)), 1)); tg.config.add_word("DCU.CH0_ENABLE_CG_ALIGN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_ENABLE_CG_ALIGN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_ENABLE_CG_ALIGN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_ENC_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_ENC_BYPASS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_ENC_BYPASS"), Property(0)), 1)); tg.config.add_word("DCU.CH0_FF_RX_F_CLK_DIS", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_FF_RX_F_CLK_DIS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_FF_RX_F_CLK_DIS"), Property(0)), 1)); tg.config.add_word("DCU.CH0_FF_RX_H_CLK_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_FF_RX_H_CLK_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_FF_RX_H_CLK_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_FF_TX_F_CLK_DIS", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_FF_TX_F_CLK_DIS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_FF_TX_F_CLK_DIS"), Property(0)), 1)); tg.config.add_word("DCU.CH0_FF_TX_H_CLK_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_FF_TX_H_CLK_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_FF_TX_H_CLK_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_GE_AN_ENABLE", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_GE_AN_ENABLE"), "0"), 1)); -tg.config.add_word("DCU.CH0_INVERT_RX", parse_config_str(str_or_default(ci->params, ctx->id("CH0_INVERT_RX"), "0"), 1)); -tg.config.add_word("DCU.CH0_INVERT_TX", parse_config_str(str_or_default(ci->params, ctx->id("CH0_INVERT_TX"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_GE_AN_ENABLE"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_INVERT_RX", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_INVERT_RX"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_INVERT_TX", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_INVERT_TX"), Property(0)), 1)); tg.config.add_word("DCU.CH0_LDR_CORE2TX_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_LDR_CORE2TX_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_LDR_CORE2TX_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH0_LDR_RX2CORE_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_LDR_RX2CORE_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_LDR_RX2CORE_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH0_LEQ_OFFSET_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_LEQ_OFFSET_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_LEQ_OFFSET_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH0_LEQ_OFFSET_TRIM", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_LEQ_OFFSET_TRIM"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_LEQ_OFFSET_TRIM"), Property(0)), 3)); tg.config.add_word("DCU.CH0_LSM_DISABLE", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_LSM_DISABLE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_LSM_DISABLE"), Property(0)), 1)); tg.config.add_word("DCU.CH0_MATCH_2_ENABLE", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_MATCH_2_ENABLE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_MATCH_2_ENABLE"), Property(0)), 1)); tg.config.add_word("DCU.CH0_MATCH_4_ENABLE", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_MATCH_4_ENABLE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_MATCH_4_ENABLE"), Property(0)), 1)); tg.config.add_word("DCU.CH0_MIN_IPG_CNT", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_MIN_IPG_CNT"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_MIN_IPG_CNT"), Property(0)), 2)); tg.config.add_word("DCU.CH0_PCIE_EI_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_PCIE_EI_EN"), "0"), 1)); -tg.config.add_word("DCU.CH0_PCIE_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_PCIE_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_PCIE_EI_EN"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_PCIE_MODE", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_PCIE_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH0_PCS_DET_TIME_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_PCS_DET_TIME_SEL"), "0"), 2)); -tg.config.add_word("DCU.CH0_PDEN_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_PDEN_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_PCS_DET_TIME_SEL"), Property(0)), 2)); +tg.config.add_word("DCU.CH0_PDEN_SEL", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_PDEN_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH0_PRBS_ENABLE", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_PRBS_ENABLE"), "0"), 1)); -tg.config.add_word("DCU.CH0_PRBS_LOCK", parse_config_str(str_or_default(ci->params, ctx->id("CH0_PRBS_LOCK"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_PRBS_ENABLE"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_PRBS_LOCK", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_PRBS_LOCK"), Property(0)), 1)); tg.config.add_word("DCU.CH0_PRBS_SELECTION", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_PRBS_SELECTION"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_PRBS_SELECTION"), Property(0)), 1)); tg.config.add_word("DCU.CH0_RATE_MODE_RX", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RATE_MODE_RX"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RATE_MODE_RX"), Property(0)), 1)); tg.config.add_word("DCU.CH0_RATE_MODE_TX", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RATE_MODE_TX"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RATE_MODE_TX"), Property(0)), 1)); tg.config.add_word("DCU.CH0_RCV_DCC_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RCV_DCC_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RCV_DCC_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_REG_BAND_OFFSET", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_REG_BAND_OFFSET"), "0"), 4)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_REG_BAND_OFFSET"), Property(0)), 4)); tg.config.add_word("DCU.CH0_REG_BAND_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_REG_BAND_SEL"), "0"), 6)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_REG_BAND_SEL"), Property(0)), 6)); tg.config.add_word("DCU.CH0_REG_IDAC_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_REG_IDAC_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_REG_IDAC_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_REG_IDAC_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_REG_IDAC_SEL"), "0"), 10)); -tg.config.add_word("DCU.CH0_REQ_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_REQ_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_REG_IDAC_SEL"), Property(0)), 10)); +tg.config.add_word("DCU.CH0_REQ_EN", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_REQ_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_REQ_LVL_SET", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_REQ_LVL_SET"), "0"), 2)); -tg.config.add_word("DCU.CH0_RIO_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RIO_MODE"), "0"), 1)); -tg.config.add_word("DCU.CH0_RLOS_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RLOS_SEL"), "0"), 1)); -tg.config.add_word("DCU.CH0_RPWDNB", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RPWDNB"), "0"), 1)); -tg.config.add_word("DCU.CH0_RTERM_RX", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RTERM_RX"), "0"), 5)); -tg.config.add_word("DCU.CH0_RTERM_TX", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RTERM_TX"), "0"), 5)); -tg.config.add_word("DCU.CH0_RXIN_CM", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RXIN_CM"), "0"), 2)); -tg.config.add_word("DCU.CH0_RXTERM_CM", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RXTERM_CM"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_REQ_LVL_SET"), Property(0)), 2)); +tg.config.add_word("DCU.CH0_RIO_MODE", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RIO_MODE"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_RLOS_SEL", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RLOS_SEL"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_RPWDNB", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RPWDNB"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_RTERM_RX", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RTERM_RX"), Property(0)), 5)); +tg.config.add_word("DCU.CH0_RTERM_TX", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RTERM_TX"), Property(0)), 5)); +tg.config.add_word("DCU.CH0_RXIN_CM", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RXIN_CM"), Property(0)), 2)); +tg.config.add_word("DCU.CH0_RXTERM_CM", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RXTERM_CM"), Property(0)), 2)); tg.config.add_word("DCU.CH0_RX_DCO_CK_DIV", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_DCO_CK_DIV"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RX_DCO_CK_DIV"), Property(0)), 3)); tg.config.add_word("DCU.CH0_RX_DIV11_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_DIV11_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RX_DIV11_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH0_RX_GEAR_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_GEAR_BYPASS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RX_GEAR_BYPASS"), Property(0)), 1)); tg.config.add_word("DCU.CH0_RX_GEAR_MODE", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_GEAR_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RX_GEAR_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH0_RX_LOS_CEQ", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_LOS_CEQ"), "0"), 2)); -tg.config.add_word("DCU.CH0_RX_LOS_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_LOS_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RX_LOS_CEQ"), Property(0)), 2)); +tg.config.add_word("DCU.CH0_RX_LOS_EN", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RX_LOS_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_RX_LOS_HYST_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_LOS_HYST_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RX_LOS_HYST_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_RX_LOS_LVL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_LOS_LVL"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RX_LOS_LVL"), Property(0)), 3)); tg.config.add_word("DCU.CH0_RX_RATE_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_RATE_SEL"), "0"), 4)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RX_RATE_SEL"), Property(0)), 4)); tg.config.add_word("DCU.CH0_RX_SB_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_RX_SB_BYPASS"), "0"), 1)); -tg.config.add_word("DCU.CH0_SB_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_SB_BYPASS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_RX_SB_BYPASS"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_SB_BYPASS", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_SB_BYPASS"), Property(0)), 1)); tg.config.add_word("DCU.CH0_SEL_SD_RX_CLK", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_SEL_SD_RX_CLK"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_SEL_SD_RX_CLK"), Property(0)), 1)); tg.config.add_word("DCU.CH0_TDRV_DAT_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_DAT_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_DAT_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TDRV_POST_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_POST_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_POST_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_TDRV_PRE_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_PRE_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_PRE_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_TDRV_SLICE0_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE0_CUR"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE0_CUR"), Property(0)), 3)); tg.config.add_word("DCU.CH0_TDRV_SLICE0_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE0_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE0_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TDRV_SLICE1_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE1_CUR"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE1_CUR"), Property(0)), 3)); tg.config.add_word("DCU.CH0_TDRV_SLICE1_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE1_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE1_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TDRV_SLICE2_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE2_CUR"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE2_CUR"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TDRV_SLICE2_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE2_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE2_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TDRV_SLICE3_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE3_CUR"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE3_CUR"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TDRV_SLICE3_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE3_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE3_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TDRV_SLICE4_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE4_CUR"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE4_CUR"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TDRV_SLICE4_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE4_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE4_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TDRV_SLICE5_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE5_CUR"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE5_CUR"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TDRV_SLICE5_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TDRV_SLICE5_SEL"), "0"), 2)); -tg.config.add_word("DCU.CH0_TPWDNB", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TPWDNB"), "0"), 1)); -tg.config.add_word("DCU.CH0_TX_CM_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_CM_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TDRV_SLICE5_SEL"), Property(0)), 2)); +tg.config.add_word("DCU.CH0_TPWDNB", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TPWDNB"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_TX_CM_SEL", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TX_CM_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH0_TX_DIV11_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_DIV11_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TX_DIV11_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH0_TX_GEAR_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_GEAR_BYPASS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TX_GEAR_BYPASS"), Property(0)), 1)); tg.config.add_word("DCU.CH0_TX_GEAR_MODE", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_GEAR_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TX_GEAR_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH0_TX_POST_SIGN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_POST_SIGN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TX_POST_SIGN"), Property(0)), 1)); tg.config.add_word("DCU.CH0_TX_PRE_SIGN", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_TX_PRE_SIGN"), "0"), 1)); -tg.config.add_word("DCU.CH0_UC_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_UC_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_TX_PRE_SIGN"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_UC_MODE", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_UC_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH0_UDF_COMMA_A", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_UDF_COMMA_A"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_UDF_COMMA_A"), Property(0)), 10)); tg.config.add_word("DCU.CH0_UDF_COMMA_B", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_UDF_COMMA_B"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_UDF_COMMA_B"), Property(0)), 10)); tg.config.add_word("DCU.CH0_UDF_COMMA_MASK", - parse_config_str(str_or_default(ci->params, ctx->id("CH0_UDF_COMMA_MASK"), "0"), 10)); -tg.config.add_word("DCU.CH0_WA_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH0_WA_BYPASS"), "0"), 1)); -tg.config.add_word("DCU.CH0_WA_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH0_WA_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH0_UDF_COMMA_MASK"), Property(0)), 10)); +tg.config.add_word("DCU.CH0_WA_BYPASS", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_WA_BYPASS"), Property(0)), 1)); +tg.config.add_word("DCU.CH0_WA_MODE", + parse_config_str(get_or_default(ci->params, ctx->id("CH0_WA_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH1_AUTO_CALIB_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_AUTO_CALIB_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_AUTO_CALIB_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_AUTO_FACQ_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_AUTO_FACQ_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_AUTO_FACQ_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_BAND_THRESHOLD", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_BAND_THRESHOLD"), "0"), 6)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_BAND_THRESHOLD"), Property(0)), 6)); tg.config.add_word("DCU.CH1_CALIB_CK_MODE", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_CALIB_CK_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_CALIB_CK_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH1_CC_MATCH_1", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_CC_MATCH_1"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_CC_MATCH_1"), Property(0)), 10)); tg.config.add_word("DCU.CH1_CC_MATCH_2", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_CC_MATCH_2"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_CC_MATCH_2"), Property(0)), 10)); tg.config.add_word("DCU.CH1_CC_MATCH_3", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_CC_MATCH_3"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_CC_MATCH_3"), Property(0)), 10)); tg.config.add_word("DCU.CH1_CC_MATCH_4", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_CC_MATCH_4"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_CC_MATCH_4"), Property(0)), 10)); tg.config.add_word("DCU.CH1_CDR_CNT4SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_CDR_CNT4SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_CDR_CNT4SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH1_CDR_CNT8SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_CDR_CNT8SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_CDR_CNT8SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH1_CTC_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_CTC_BYPASS"), "0"), 1)); -tg.config.add_word("DCU.CH1_DCOATDCFG", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOATDCFG"), "0"), 2)); -tg.config.add_word("DCU.CH1_DCOATDDLY", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOATDDLY"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_CTC_BYPASS"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_DCOATDCFG", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOATDCFG"), Property(0)), 2)); +tg.config.add_word("DCU.CH1_DCOATDDLY", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOATDDLY"), Property(0)), 2)); tg.config.add_word("DCU.CH1_DCOBYPSATD", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOBYPSATD"), "0"), 1)); -tg.config.add_word("DCU.CH1_DCOCALDIV", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOCALDIV"), "0"), 3)); -tg.config.add_word("DCU.CH1_DCOCTLGI", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOCTLGI"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOBYPSATD"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_DCOCALDIV", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOCALDIV"), Property(0)), 3)); +tg.config.add_word("DCU.CH1_DCOCTLGI", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOCTLGI"), Property(0)), 3)); tg.config.add_word("DCU.CH1_DCODISBDAVOID", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCODISBDAVOID"), "0"), 1)); -tg.config.add_word("DCU.CH1_DCOFLTDAC", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOFLTDAC"), "0"), 2)); -tg.config.add_word("DCU.CH1_DCOFTNRG", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOFTNRG"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCODISBDAVOID"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_DCOFLTDAC", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOFLTDAC"), Property(0)), 2)); +tg.config.add_word("DCU.CH1_DCOFTNRG", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOFTNRG"), Property(0)), 3)); tg.config.add_word("DCU.CH1_DCOIOSTUNE", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOIOSTUNE"), "0"), 3)); -tg.config.add_word("DCU.CH1_DCOITUNE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOITUNE"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOIOSTUNE"), Property(0)), 3)); +tg.config.add_word("DCU.CH1_DCOITUNE", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOITUNE"), Property(0)), 2)); tg.config.add_word("DCU.CH1_DCOITUNE4LSB", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOITUNE4LSB"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOITUNE4LSB"), Property(0)), 3)); tg.config.add_word("DCU.CH1_DCOIUPDNX2", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOIUPDNX2"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOIUPDNX2"), Property(0)), 1)); tg.config.add_word("DCU.CH1_DCONUOFLSB", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCONUOFLSB"), "0"), 3)); -tg.config.add_word("DCU.CH1_DCOSCALEI", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOSCALEI"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCONUOFLSB"), Property(0)), 3)); +tg.config.add_word("DCU.CH1_DCOSCALEI", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOSCALEI"), Property(0)), 2)); tg.config.add_word("DCU.CH1_DCOSTARTVAL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOSTARTVAL"), "0"), 3)); -tg.config.add_word("DCU.CH1_DCOSTEP", parse_config_str(str_or_default(ci->params, ctx->id("CH1_DCOSTEP"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOSTARTVAL"), Property(0)), 3)); +tg.config.add_word("DCU.CH1_DCOSTEP", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DCOSTEP"), Property(0)), 2)); tg.config.add_word("DCU.CH1_DEC_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_DEC_BYPASS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_DEC_BYPASS"), Property(0)), 1)); tg.config.add_word("DCU.CH1_ENABLE_CG_ALIGN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_ENABLE_CG_ALIGN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_ENABLE_CG_ALIGN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_ENC_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_ENC_BYPASS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_ENC_BYPASS"), Property(0)), 1)); tg.config.add_word("DCU.CH1_FF_RX_F_CLK_DIS", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_FF_RX_F_CLK_DIS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_FF_RX_F_CLK_DIS"), Property(0)), 1)); tg.config.add_word("DCU.CH1_FF_RX_H_CLK_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_FF_RX_H_CLK_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_FF_RX_H_CLK_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_FF_TX_F_CLK_DIS", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_FF_TX_F_CLK_DIS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_FF_TX_F_CLK_DIS"), Property(0)), 1)); tg.config.add_word("DCU.CH1_FF_TX_H_CLK_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_FF_TX_H_CLK_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_FF_TX_H_CLK_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_GE_AN_ENABLE", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_GE_AN_ENABLE"), "0"), 1)); -tg.config.add_word("DCU.CH1_INVERT_RX", parse_config_str(str_or_default(ci->params, ctx->id("CH1_INVERT_RX"), "0"), 1)); -tg.config.add_word("DCU.CH1_INVERT_TX", parse_config_str(str_or_default(ci->params, ctx->id("CH1_INVERT_TX"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_GE_AN_ENABLE"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_INVERT_RX", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_INVERT_RX"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_INVERT_TX", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_INVERT_TX"), Property(0)), 1)); tg.config.add_word("DCU.CH1_LDR_CORE2TX_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_LDR_CORE2TX_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_LDR_CORE2TX_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH1_LDR_RX2CORE_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_LDR_RX2CORE_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_LDR_RX2CORE_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH1_LEQ_OFFSET_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_LEQ_OFFSET_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_LEQ_OFFSET_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH1_LEQ_OFFSET_TRIM", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_LEQ_OFFSET_TRIM"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_LEQ_OFFSET_TRIM"), Property(0)), 3)); tg.config.add_word("DCU.CH1_LSM_DISABLE", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_LSM_DISABLE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_LSM_DISABLE"), Property(0)), 1)); tg.config.add_word("DCU.CH1_MATCH_2_ENABLE", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_MATCH_2_ENABLE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_MATCH_2_ENABLE"), Property(0)), 1)); tg.config.add_word("DCU.CH1_MATCH_4_ENABLE", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_MATCH_4_ENABLE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_MATCH_4_ENABLE"), Property(0)), 1)); tg.config.add_word("DCU.CH1_MIN_IPG_CNT", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_MIN_IPG_CNT"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_MIN_IPG_CNT"), Property(0)), 2)); tg.config.add_word("DCU.CH1_PCIE_EI_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_PCIE_EI_EN"), "0"), 1)); -tg.config.add_word("DCU.CH1_PCIE_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_PCIE_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_PCIE_EI_EN"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_PCIE_MODE", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_PCIE_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH1_PCS_DET_TIME_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_PCS_DET_TIME_SEL"), "0"), 2)); -tg.config.add_word("DCU.CH1_PDEN_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_PDEN_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_PCS_DET_TIME_SEL"), Property(0)), 2)); +tg.config.add_word("DCU.CH1_PDEN_SEL", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_PDEN_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH1_PRBS_ENABLE", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_PRBS_ENABLE"), "0"), 1)); -tg.config.add_word("DCU.CH1_PRBS_LOCK", parse_config_str(str_or_default(ci->params, ctx->id("CH1_PRBS_LOCK"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_PRBS_ENABLE"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_PRBS_LOCK", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_PRBS_LOCK"), Property(0)), 1)); tg.config.add_word("DCU.CH1_PRBS_SELECTION", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_PRBS_SELECTION"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_PRBS_SELECTION"), Property(0)), 1)); tg.config.add_word("DCU.CH1_RATE_MODE_RX", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RATE_MODE_RX"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RATE_MODE_RX"), Property(0)), 1)); tg.config.add_word("DCU.CH1_RATE_MODE_TX", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RATE_MODE_TX"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RATE_MODE_TX"), Property(0)), 1)); tg.config.add_word("DCU.CH1_RCV_DCC_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RCV_DCC_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RCV_DCC_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_REG_BAND_OFFSET", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_REG_BAND_OFFSET"), "0"), 4)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_REG_BAND_OFFSET"), Property(0)), 4)); tg.config.add_word("DCU.CH1_REG_BAND_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_REG_BAND_SEL"), "0"), 6)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_REG_BAND_SEL"), Property(0)), 6)); tg.config.add_word("DCU.CH1_REG_IDAC_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_REG_IDAC_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_REG_IDAC_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_REG_IDAC_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_REG_IDAC_SEL"), "0"), 10)); -tg.config.add_word("DCU.CH1_REQ_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_REQ_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_REG_IDAC_SEL"), Property(0)), 10)); +tg.config.add_word("DCU.CH1_REQ_EN", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_REQ_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_REQ_LVL_SET", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_REQ_LVL_SET"), "0"), 2)); -tg.config.add_word("DCU.CH1_RIO_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RIO_MODE"), "0"), 1)); -tg.config.add_word("DCU.CH1_RLOS_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RLOS_SEL"), "0"), 1)); -tg.config.add_word("DCU.CH1_RPWDNB", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RPWDNB"), "0"), 1)); -tg.config.add_word("DCU.CH1_RTERM_RX", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RTERM_RX"), "0"), 5)); -tg.config.add_word("DCU.CH1_RTERM_TX", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RTERM_TX"), "0"), 5)); -tg.config.add_word("DCU.CH1_RXIN_CM", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RXIN_CM"), "0"), 2)); -tg.config.add_word("DCU.CH1_RXTERM_CM", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RXTERM_CM"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_REQ_LVL_SET"), Property(0)), 2)); +tg.config.add_word("DCU.CH1_RIO_MODE", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RIO_MODE"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_RLOS_SEL", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RLOS_SEL"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_RPWDNB", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RPWDNB"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_RTERM_RX", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RTERM_RX"), Property(0)), 5)); +tg.config.add_word("DCU.CH1_RTERM_TX", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RTERM_TX"), Property(0)), 5)); +tg.config.add_word("DCU.CH1_RXIN_CM", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RXIN_CM"), Property(0)), 2)); +tg.config.add_word("DCU.CH1_RXTERM_CM", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RXTERM_CM"), Property(0)), 2)); tg.config.add_word("DCU.CH1_RX_DCO_CK_DIV", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_DCO_CK_DIV"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RX_DCO_CK_DIV"), Property(0)), 3)); tg.config.add_word("DCU.CH1_RX_DIV11_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_DIV11_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RX_DIV11_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH1_RX_GEAR_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_GEAR_BYPASS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RX_GEAR_BYPASS"), Property(0)), 1)); tg.config.add_word("DCU.CH1_RX_GEAR_MODE", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_GEAR_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RX_GEAR_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH1_RX_LOS_CEQ", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_LOS_CEQ"), "0"), 2)); -tg.config.add_word("DCU.CH1_RX_LOS_EN", parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_LOS_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RX_LOS_CEQ"), Property(0)), 2)); +tg.config.add_word("DCU.CH1_RX_LOS_EN", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RX_LOS_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_RX_LOS_HYST_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_LOS_HYST_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RX_LOS_HYST_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_RX_LOS_LVL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_LOS_LVL"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RX_LOS_LVL"), Property(0)), 3)); tg.config.add_word("DCU.CH1_RX_RATE_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_RATE_SEL"), "0"), 4)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RX_RATE_SEL"), Property(0)), 4)); tg.config.add_word("DCU.CH1_RX_SB_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_RX_SB_BYPASS"), "0"), 1)); -tg.config.add_word("DCU.CH1_SB_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_SB_BYPASS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_RX_SB_BYPASS"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_SB_BYPASS", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_SB_BYPASS"), Property(0)), 1)); tg.config.add_word("DCU.CH1_SEL_SD_RX_CLK", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_SEL_SD_RX_CLK"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_SEL_SD_RX_CLK"), Property(0)), 1)); tg.config.add_word("DCU.CH1_TDRV_DAT_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_DAT_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_DAT_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TDRV_POST_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_POST_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_POST_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_TDRV_PRE_EN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_PRE_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_PRE_EN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_TDRV_SLICE0_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE0_CUR"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE0_CUR"), Property(0)), 3)); tg.config.add_word("DCU.CH1_TDRV_SLICE0_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE0_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE0_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TDRV_SLICE1_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE1_CUR"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE1_CUR"), Property(0)), 3)); tg.config.add_word("DCU.CH1_TDRV_SLICE1_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE1_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE1_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TDRV_SLICE2_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE2_CUR"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE2_CUR"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TDRV_SLICE2_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE2_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE2_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TDRV_SLICE3_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE3_CUR"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE3_CUR"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TDRV_SLICE3_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE3_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE3_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TDRV_SLICE4_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE4_CUR"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE4_CUR"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TDRV_SLICE4_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE4_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE4_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TDRV_SLICE5_CUR", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE5_CUR"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE5_CUR"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TDRV_SLICE5_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TDRV_SLICE5_SEL"), "0"), 2)); -tg.config.add_word("DCU.CH1_TPWDNB", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TPWDNB"), "0"), 1)); -tg.config.add_word("DCU.CH1_TX_CM_SEL", parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_CM_SEL"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TDRV_SLICE5_SEL"), Property(0)), 2)); +tg.config.add_word("DCU.CH1_TPWDNB", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TPWDNB"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_TX_CM_SEL", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TX_CM_SEL"), Property(0)), 2)); tg.config.add_word("DCU.CH1_TX_DIV11_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_DIV11_SEL"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TX_DIV11_SEL"), Property(0)), 1)); tg.config.add_word("DCU.CH1_TX_GEAR_BYPASS", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_GEAR_BYPASS"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TX_GEAR_BYPASS"), Property(0)), 1)); tg.config.add_word("DCU.CH1_TX_GEAR_MODE", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_GEAR_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TX_GEAR_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH1_TX_POST_SIGN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_POST_SIGN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TX_POST_SIGN"), Property(0)), 1)); tg.config.add_word("DCU.CH1_TX_PRE_SIGN", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_TX_PRE_SIGN"), "0"), 1)); -tg.config.add_word("DCU.CH1_UC_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_UC_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_TX_PRE_SIGN"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_UC_MODE", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_UC_MODE"), Property(0)), 1)); tg.config.add_word("DCU.CH1_UDF_COMMA_A", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_UDF_COMMA_A"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_UDF_COMMA_A"), Property(0)), 10)); tg.config.add_word("DCU.CH1_UDF_COMMA_B", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_UDF_COMMA_B"), "0"), 10)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_UDF_COMMA_B"), Property(0)), 10)); tg.config.add_word("DCU.CH1_UDF_COMMA_MASK", - parse_config_str(str_or_default(ci->params, ctx->id("CH1_UDF_COMMA_MASK"), "0"), 10)); -tg.config.add_word("DCU.CH1_WA_BYPASS", parse_config_str(str_or_default(ci->params, ctx->id("CH1_WA_BYPASS"), "0"), 1)); -tg.config.add_word("DCU.CH1_WA_MODE", parse_config_str(str_or_default(ci->params, ctx->id("CH1_WA_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("CH1_UDF_COMMA_MASK"), Property(0)), 10)); +tg.config.add_word("DCU.CH1_WA_BYPASS", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_WA_BYPASS"), Property(0)), 1)); +tg.config.add_word("DCU.CH1_WA_MODE", + parse_config_str(get_or_default(ci->params, ctx->id("CH1_WA_MODE"), Property(0)), 1)); tg.config.add_word("DCU.D_BITCLK_FROM_ND_EN", - parse_config_str(str_or_default(ci->params, ctx->id("D_BITCLK_FROM_ND_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("D_BITCLK_FROM_ND_EN"), Property(0)), 1)); tg.config.add_word("DCU.D_BITCLK_LOCAL_EN", - parse_config_str(str_or_default(ci->params, ctx->id("D_BITCLK_LOCAL_EN"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("D_BITCLK_LOCAL_EN"), Property(0)), 1)); tg.config.add_word("DCU.D_BITCLK_ND_EN", - parse_config_str(str_or_default(ci->params, ctx->id("D_BITCLK_ND_EN"), "0"), 1)); -tg.config.add_word("DCU.D_BUS8BIT_SEL", parse_config_str(str_or_default(ci->params, ctx->id("D_BUS8BIT_SEL"), "0"), 1)); -tg.config.add_word("DCU.D_CDR_LOL_SET", parse_config_str(str_or_default(ci->params, ctx->id("D_CDR_LOL_SET"), "0"), 2)); -tg.config.add_word("DCU.D_CMUSETBIASI", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETBIASI"), "0"), 2)); -tg.config.add_word("DCU.D_CMUSETI4CPP", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETI4CPP"), "0"), 4)); -tg.config.add_word("DCU.D_CMUSETI4CPZ", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETI4CPZ"), "0"), 4)); -tg.config.add_word("DCU.D_CMUSETI4VCO", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETI4VCO"), "0"), 2)); -tg.config.add_word("DCU.D_CMUSETICP4P", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETICP4P"), "0"), 2)); -tg.config.add_word("DCU.D_CMUSETICP4Z", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETICP4Z"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("D_BITCLK_ND_EN"), Property(0)), 1)); +tg.config.add_word("DCU.D_BUS8BIT_SEL", + parse_config_str(get_or_default(ci->params, ctx->id("D_BUS8BIT_SEL"), Property(0)), 1)); +tg.config.add_word("DCU.D_CDR_LOL_SET", + parse_config_str(get_or_default(ci->params, ctx->id("D_CDR_LOL_SET"), Property(0)), 2)); +tg.config.add_word("DCU.D_CMUSETBIASI", + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETBIASI"), Property(0)), 2)); +tg.config.add_word("DCU.D_CMUSETI4CPP", + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETI4CPP"), Property(0)), 4)); +tg.config.add_word("DCU.D_CMUSETI4CPZ", + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETI4CPZ"), Property(0)), 4)); +tg.config.add_word("DCU.D_CMUSETI4VCO", + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETI4VCO"), Property(0)), 2)); +tg.config.add_word("DCU.D_CMUSETICP4P", + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETICP4P"), Property(0)), 2)); +tg.config.add_word("DCU.D_CMUSETICP4Z", + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETICP4Z"), Property(0)), 3)); tg.config.add_word("DCU.D_CMUSETINITVCT", - parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETINITVCT"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETINITVCT"), Property(0)), 2)); tg.config.add_word("DCU.D_CMUSETISCL4VCO", - parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETISCL4VCO"), "0"), 3)); -tg.config.add_word("DCU.D_CMUSETP1GM", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETP1GM"), "0"), 3)); -tg.config.add_word("DCU.D_CMUSETP2AGM", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETP2AGM"), "0"), 3)); -tg.config.add_word("DCU.D_CMUSETZGM", parse_config_str(str_or_default(ci->params, ctx->id("D_CMUSETZGM"), "0"), 3)); + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETISCL4VCO"), Property(0)), 3)); +tg.config.add_word("DCU.D_CMUSETP1GM", + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETP1GM"), Property(0)), 3)); +tg.config.add_word("DCU.D_CMUSETP2AGM", + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETP2AGM"), Property(0)), 3)); +tg.config.add_word("DCU.D_CMUSETZGM", + parse_config_str(get_or_default(ci->params, ctx->id("D_CMUSETZGM"), Property(0)), 3)); tg.config.add_word("DCU.D_DCO_CALIB_TIME_SEL", - parse_config_str(str_or_default(ci->params, ctx->id("D_DCO_CALIB_TIME_SEL"), "0"), 2)); -tg.config.add_word("DCU.D_HIGH_MARK", parse_config_str(str_or_default(ci->params, ctx->id("D_HIGH_MARK"), "0"), 4)); -tg.config.add_word("DCU.D_IB_PWDNB", parse_config_str(str_or_default(ci->params, ctx->id("D_IB_PWDNB"), "0"), 1)); -tg.config.add_word("DCU.D_ISETLOS", parse_config_str(str_or_default(ci->params, ctx->id("D_ISETLOS"), "0"), 8)); -tg.config.add_word("DCU.D_LOW_MARK", parse_config_str(str_or_default(ci->params, ctx->id("D_LOW_MARK"), "0"), 4)); -tg.config.add_word("DCU.D_MACROPDB", parse_config_str(str_or_default(ci->params, ctx->id("D_MACROPDB"), "0"), 1)); -tg.config.add_word("DCU.D_PD_ISET", parse_config_str(str_or_default(ci->params, ctx->id("D_PD_ISET"), "0"), 2)); -tg.config.add_word("DCU.D_PLL_LOL_SET", parse_config_str(str_or_default(ci->params, ctx->id("D_PLL_LOL_SET"), "0"), 2)); -tg.config.add_word("DCU.D_REFCK_MODE", parse_config_str(str_or_default(ci->params, ctx->id("D_REFCK_MODE"), "0"), 3)); -tg.config.add_word("DCU.D_REQ_ISET", parse_config_str(str_or_default(ci->params, ctx->id("D_REQ_ISET"), "0"), 3)); -tg.config.add_word("DCU.D_RG_EN", parse_config_str(str_or_default(ci->params, ctx->id("D_RG_EN"), "0"), 1)); -tg.config.add_word("DCU.D_RG_SET", parse_config_str(str_or_default(ci->params, ctx->id("D_RG_SET"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("D_DCO_CALIB_TIME_SEL"), Property(0)), 2)); +tg.config.add_word("DCU.D_HIGH_MARK", + parse_config_str(get_or_default(ci->params, ctx->id("D_HIGH_MARK"), Property(0)), 4)); +tg.config.add_word("DCU.D_IB_PWDNB", + parse_config_str(get_or_default(ci->params, ctx->id("D_IB_PWDNB"), Property(0)), 1)); +tg.config.add_word("DCU.D_ISETLOS", parse_config_str(get_or_default(ci->params, ctx->id("D_ISETLOS"), Property(0)), 8)); +tg.config.add_word("DCU.D_LOW_MARK", + parse_config_str(get_or_default(ci->params, ctx->id("D_LOW_MARK"), Property(0)), 4)); +tg.config.add_word("DCU.D_MACROPDB", + parse_config_str(get_or_default(ci->params, ctx->id("D_MACROPDB"), Property(0)), 1)); +tg.config.add_word("DCU.D_PD_ISET", parse_config_str(get_or_default(ci->params, ctx->id("D_PD_ISET"), Property(0)), 2)); +tg.config.add_word("DCU.D_PLL_LOL_SET", + parse_config_str(get_or_default(ci->params, ctx->id("D_PLL_LOL_SET"), Property(0)), 2)); +tg.config.add_word("DCU.D_REFCK_MODE", + parse_config_str(get_or_default(ci->params, ctx->id("D_REFCK_MODE"), Property(0)), 3)); +tg.config.add_word("DCU.D_REQ_ISET", + parse_config_str(get_or_default(ci->params, ctx->id("D_REQ_ISET"), Property(0)), 3)); +tg.config.add_word("DCU.D_RG_EN", parse_config_str(get_or_default(ci->params, ctx->id("D_RG_EN"), Property(0)), 1)); +tg.config.add_word("DCU.D_RG_SET", parse_config_str(get_or_default(ci->params, ctx->id("D_RG_SET"), Property(0)), 2)); tg.config.add_word("DCU.D_SETICONST_AUX", - parse_config_str(str_or_default(ci->params, ctx->id("D_SETICONST_AUX"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("D_SETICONST_AUX"), Property(0)), 2)); tg.config.add_word("DCU.D_SETICONST_CH", - parse_config_str(str_or_default(ci->params, ctx->id("D_SETICONST_CH"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("D_SETICONST_CH"), Property(0)), 2)); tg.config.add_word("DCU.D_SETIRPOLY_AUX", - parse_config_str(str_or_default(ci->params, ctx->id("D_SETIRPOLY_AUX"), "0"), 2)); + parse_config_str(get_or_default(ci->params, ctx->id("D_SETIRPOLY_AUX"), Property(0)), 2)); tg.config.add_word("DCU.D_SETIRPOLY_CH", - parse_config_str(str_or_default(ci->params, ctx->id("D_SETIRPOLY_CH"), "0"), 2)); -tg.config.add_word("DCU.D_SETPLLRC", parse_config_str(str_or_default(ci->params, ctx->id("D_SETPLLRC"), "0"), 6)); + parse_config_str(get_or_default(ci->params, ctx->id("D_SETIRPOLY_CH"), Property(0)), 2)); +tg.config.add_word("DCU.D_SETPLLRC", + parse_config_str(get_or_default(ci->params, ctx->id("D_SETPLLRC"), Property(0)), 6)); tg.config.add_word("DCU.D_SYNC_LOCAL_EN", - parse_config_str(str_or_default(ci->params, ctx->id("D_SYNC_LOCAL_EN"), "0"), 1)); -tg.config.add_word("DCU.D_SYNC_ND_EN", parse_config_str(str_or_default(ci->params, ctx->id("D_SYNC_ND_EN"), "0"), 1)); -tg.config.add_word("DCU.D_TXPLL_PWDNB", parse_config_str(str_or_default(ci->params, ctx->id("D_TXPLL_PWDNB"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("D_SYNC_LOCAL_EN"), Property(0)), 1)); +tg.config.add_word("DCU.D_SYNC_ND_EN", + parse_config_str(get_or_default(ci->params, ctx->id("D_SYNC_ND_EN"), Property(0)), 1)); +tg.config.add_word("DCU.D_TXPLL_PWDNB", + parse_config_str(get_or_default(ci->params, ctx->id("D_TXPLL_PWDNB"), Property(0)), 1)); tg.config.add_word("DCU.D_TX_VCO_CK_DIV", - parse_config_str(str_or_default(ci->params, ctx->id("D_TX_VCO_CK_DIV"), "0"), 3)); -tg.config.add_word("DCU.D_XGE_MODE", parse_config_str(str_or_default(ci->params, ctx->id("D_XGE_MODE"), "0"), 1)); + parse_config_str(get_or_default(ci->params, ctx->id("D_TX_VCO_CK_DIV"), Property(0)), 3)); +tg.config.add_word("DCU.D_XGE_MODE", + parse_config_str(get_or_default(ci->params, ctx->id("D_XGE_MODE"), Property(0)), 1)); diff --git a/ecp5/globals.cc b/ecp5/globals.cc index 026f3a85..5fb348e7 100644 --- a/ecp5/globals.cc +++ b/ecp5/globals.cc @@ -275,7 +275,7 @@ class Ecp5GlobalRouter if (drv.cell == nullptr) { return 0; } else if (drv.cell->attrs.count(ctx->id("BEL"))) { - drv_bel = ctx->getBelByName(ctx->id(drv.cell->attrs.at(ctx->id("BEL")))); + drv_bel = ctx->getBelByName(ctx->id(drv.cell->attrs.at(ctx->id("BEL")).as_string())); } else { // Check if driver is a singleton BelId last_bel; @@ -382,7 +382,7 @@ class Ecp5GlobalRouter glbnet->name = ctx->id("$glbnet$" + net->name.str(ctx)); glbnet->driver.cell = dcc.get(); glbnet->driver.port = id_CLKO; - glbnet->attrs[ctx->id("ECP5_IS_GLOBAL")] = "1"; + glbnet->attrs[ctx->id("ECP5_IS_GLOBAL")] = 1; dcc->ports[id_CLKO].net = glbnet.get(); std::vector keep_users; diff --git a/ecp5/main.cc b/ecp5/main.cc index ed2501a9..5544c55f 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -34,7 +34,7 @@ class ECP5CommandHandler : public CommandHandler public: ECP5CommandHandler(int argc, char **argv); virtual ~ECP5CommandHandler(){}; - std::unique_ptr createContext(std::unordered_map &values) override; + std::unique_ptr createContext(std::unordered_map &values) override; void setupArchContext(Context *ctx) override{}; void customAfterLoad(Context *ctx) override; void validate() override; @@ -113,7 +113,7 @@ static std::string speedString(ArchArgs::SpeedGrade speed) return ""; } -std::unique_ptr ECP5CommandHandler::createContext(std::unordered_map &values) +std::unique_ptr ECP5CommandHandler::createContext(std::unordered_map &values) { ArchArgs chipArgs; chipArgs.type = ArchArgs::NONE; @@ -162,12 +162,12 @@ std::unique_ptr ECP5CommandHandler::createContext(std::unordered_map ECP5CommandHandler::createContext(std::unordered_mapattrs.find(ctx->id("LOC")); if (loc_attr != trio->attrs.end()) { - std::string pin = loc_attr->second; + std::string pin = loc_attr->second.as_string(); BelId pinBel = ctx->getPackagePinBel(pin); if (pinBel == BelId()) { log_error("IO pin '%s' constrained to pin '%s', which does not exist for package '%s'.\n", @@ -460,8 +460,10 @@ class Ecp5Packer replace_port(lut1, ctx->id("D"), packed.get(), ctx->id("D1")); replace_port(ci, ctx->id("C0"), packed.get(), ctx->id("M0")); replace_port(ci, ctx->id("Z"), packed.get(), ctx->id("OFX0")); - packed->params[ctx->id("LUT0_INITVAL")] = str_or_default(lut0->params, ctx->id("INIT"), "0"); - packed->params[ctx->id("LUT1_INITVAL")] = str_or_default(lut1->params, ctx->id("INIT"), "0"); + packed->params[ctx->id("LUT0_INITVAL")] = + get_or_default(lut0->params, ctx->id("INIT"), Property(0, 16)); + packed->params[ctx->id("LUT1_INITVAL")] = + get_or_default(lut1->params, ctx->id("INIT"), Property(0, 16)); ctx->nets.erase(f0->name); ctx->nets.erase(f1->name); @@ -641,10 +643,10 @@ class Ecp5Packer { std::unique_ptr feedin = create_ecp5_cell(ctx, ctx->id("CCU2C")); - feedin->params[ctx->id("INIT0")] = "10"; // LUT4 = 0; LUT2 = A - feedin->params[ctx->id("INIT1")] = "65535"; - feedin->params[ctx->id("INJECT1_0")] = "NO"; - feedin->params[ctx->id("INJECT1_1")] = "YES"; + feedin->params[ctx->id("INIT0")] = Property(10, 16); // LUT4 = 0; LUT2 = A + feedin->params[ctx->id("INIT1")] = Property(65535, 16); + feedin->params[ctx->id("INJECT1_0")] = std::string("NO"); + feedin->params[ctx->id("INJECT1_1")] = std::string("YES"); carry->users.erase(std::remove_if(carry->users.begin(), carry->users.end(), [chain_in](const PortRef &user) { @@ -671,10 +673,10 @@ class Ecp5Packer CellInfo *make_carry_feed_out(NetInfo *carry, boost::optional chain_next = boost::optional()) { std::unique_ptr feedout = create_ecp5_cell(ctx, ctx->id("CCU2C")); - feedout->params[ctx->id("INIT0")] = "0"; - feedout->params[ctx->id("INIT1")] = "10"; // LUT4 = 0; LUT2 = A - feedout->params[ctx->id("INJECT1_0")] = "NO"; - feedout->params[ctx->id("INJECT1_1")] = "NO"; + feedout->params[ctx->id("INIT0")] = Property(0, 16); + feedout->params[ctx->id("INIT1")] = Property(10, 16); // LUT4 = 0; LUT2 = A + feedout->params[ctx->id("INJECT1_0")] = std::string("NO"); + feedout->params[ctx->id("INJECT1_1")] = std::string("NO"); PortRef carry_drv = carry->driver; carry->driver.cell = nullptr; @@ -1056,7 +1058,7 @@ class Ecp5Packer int index = std::string("ABCD").find(input.str(ctx)); int init = int_or_default(cell->params, ctx->id("INIT")); int new_init = make_init_with_const_input(init, index, value); - cell->params[ctx->id("INIT")] = std::to_string(new_init); + cell->params[ctx->id("INIT")] = Property(new_init, 16); cell->ports.at(input).net = nullptr; } @@ -1067,7 +1069,7 @@ class Ecp5Packer int index = std::string("ABCD").find(input_str[0]); int init = int_or_default(cell->params, ctx->id("INIT" + std::to_string(lut))); int new_init = make_init_with_const_input(init, index, value); - cell->params[ctx->id("INIT" + std::to_string(lut))] = std::to_string(new_init); + cell->params[ctx->id("INIT" + std::to_string(lut))] = Property(new_init, 16); cell->ports.at(input).net = nullptr; } @@ -1095,7 +1097,7 @@ class Ecp5Packer if (is_lut(ctx, uc)) { set_lut_input_constant(uc, user.port, constval); } else if (is_ff(ctx, uc) && user.port == ctx->id("CE")) { - uc->params[ctx->id("CEMUX")] = constval ? "1" : "0"; + uc->params[ctx->id("CEMUX")] = std::string(constval ? "1" : "0"); uc->ports[user.port].net = nullptr; } else if (is_carry(ctx, uc)) { if (constval && @@ -1141,7 +1143,7 @@ class Ecp5Packer uc->params[ctx->id(user.port.str(ctx) + "MUX")] = constval ? user.port.str(ctx) : "INV"; } else { // Connected to CIB ABCD. Default state is bitstream configurable - uc->params[ctx->id(user.port.str(ctx) + "MUX")] = constval ? "1" : "0"; + uc->params[ctx->id(user.port.str(ctx) + "MUX")] = std::string(constval ? "1" : "0"); } uc->ports[user.port].net = nullptr; } else if (uc->type == id_ALU54B || uc->type == id_MULT18X18D) { @@ -1156,7 +1158,7 @@ class Ecp5Packer constnet->users.push_back(user); } else { // Connected to CIB ABCD. Default state is bitstream configurable - uc->params[ctx->id(user.port.str(ctx) + "MUX")] = constval ? "1" : "0"; + uc->params[ctx->id(user.port.str(ctx) + "MUX")] = std::string(constval ? "1" : "0"); uc->ports[user.port].net = nullptr; } } else { @@ -1174,7 +1176,7 @@ class Ecp5Packer log_info("Packing constants..\n"); std::unique_ptr gnd_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_GND"); - gnd_cell->params[ctx->id("INIT")] = "0"; + gnd_cell->params[ctx->id("INIT")] = Property(0, 16); 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(); @@ -1182,7 +1184,7 @@ class Ecp5Packer gnd_cell->ports.at(ctx->id("Z")).net = gnd_net.get(); std::unique_ptr vcc_cell = create_ecp5_cell(ctx, ctx->id("LUT4"), "$PACKER_VCC"); - vcc_cell->params[ctx->id("INIT")] = "65535"; + vcc_cell->params[ctx->id("INIT")] = Property(65535, 16); 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(); @@ -1271,7 +1273,7 @@ class Ecp5Packer autocreate_empty_port(ci, id_WEB); autocreate_empty_port(ci, id_RSTB); - ci->attrs[ctx->id("WID")] = std::to_string(wid++); + ci->attrs[ctx->id("WID")] = wid++; } } } @@ -1321,22 +1323,22 @@ class Ecp5Packer CellInfo *ci = cell.second; if (ci->type == id_DCUA) { if (ci->attrs.count(ctx->id("LOC"))) { - std::string loc = ci->attrs.at(ctx->id("LOC")); + std::string loc = ci->attrs.at(ctx->id("LOC")).as_string(); if (loc == "DCU0" && (ctx->args.type == ArchArgs::LFE5UM_25F || ctx->args.type == ArchArgs::LFE5UM5G_25F)) - ci->attrs[ctx->id("BEL")] = "X42/Y50/DCU"; + ci->attrs[ctx->id("BEL")] = std::string("X42/Y50/DCU"); else if (loc == "DCU0" && (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F)) - ci->attrs[ctx->id("BEL")] = "X42/Y71/DCU"; + ci->attrs[ctx->id("BEL")] = std::string("X42/Y71/DCU"); else if (loc == "DCU1" && (ctx->args.type == ArchArgs::LFE5UM_45F || ctx->args.type == ArchArgs::LFE5UM5G_45F)) - ci->attrs[ctx->id("BEL")] = "X69/Y71/DCU"; + ci->attrs[ctx->id("BEL")] = std::string("X69/Y71/DCU"); else if (loc == "DCU0" && (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F)) - ci->attrs[ctx->id("BEL")] = "X46/Y95/DCU"; + ci->attrs[ctx->id("BEL")] = std::string("X46/Y95/DCU"); else if (loc == "DCU1" && (ctx->args.type == ArchArgs::LFE5UM_85F || ctx->args.type == ArchArgs::LFE5UM5G_85F)) - ci->attrs[ctx->id("BEL")] = "X71/Y95/DCU"; + ci->attrs[ctx->id("BEL")] = std::string("X71/Y95/DCU"); else log_error("no DCU location '%s' in device '%s'\n", loc.c_str(), ctx->getChipName().c_str()); } @@ -1372,7 +1374,7 @@ class Ecp5Packer } if (!dcu->attrs.count(ctx->id("BEL"))) log_error("DCU must be constrained to a Bel!\n"); - std::string bel = dcu->attrs.at(ctx->id("BEL")); + std::string bel = dcu->attrs.at(ctx->id("BEL")).as_string(); NPNR_ASSERT(bel.substr(bel.length() - 3) == "DCU"); bel.replace(bel.length() - 3, 3, "EXTREF"); ci->attrs[ctx->id("BEL")] = bel; @@ -1382,7 +1384,7 @@ class Ecp5Packer CellInfo *dcu = clki->driver.cell; if (!dcu->attrs.count(ctx->id("BEL"))) log_error("DCU must be constrained to a Bel!\n"); - BelId bel = ctx->getBelByName(ctx->id(dcu->attrs.at(ctx->id("BEL")))); + BelId bel = ctx->getBelByName(ctx->id(dcu->attrs.at(ctx->id("BEL")).as_string())); if (bel == BelId()) log_error("Invalid DCU bel '%s'\n", dcu->attrs.at(ctx->id("BEL")).c_str()); Loc loc = ctx->getBelLocation(bel); @@ -1418,7 +1420,7 @@ class Ecp5Packer for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (ci->type == id_EHXPLLL && ci->attrs.count(ctx->id("BEL"))) - available_plls.erase(ctx->getBelByName(ctx->id(ci->attrs.at(ctx->id("BEL"))))); + available_plls.erase(ctx->getBelByName(ctx->id(ci->attrs.at(ctx->id("BEL")).as_string()))); } // Place PLL connected to fixed drivers such as IO close to their source for (auto cell : sorted(ctx->cells)) { @@ -1430,7 +1432,7 @@ class Ecp5Packer const CellInfo *drivercell = drivernet->driver.cell; if (!drivercell->attrs.count(ctx->id("BEL"))) continue; - BelId drvbel = ctx->getBelByName(ctx->id(drivercell->attrs.at(ctx->id("BEL")))); + BelId drvbel = ctx->getBelByName(ctx->id(drivercell->attrs.at(ctx->id("BEL")).as_string())); Loc drvloc = ctx->getBelLocation(drvbel); BelId closest_pll; int closest_distance = std::numeric_limits::max(); @@ -1512,8 +1514,7 @@ class Ecp5Packer std::unique_ptr promoted_ecknet(new NetInfo); promoted_ecknet->name = eckname; - promoted_ecknet->attrs[ctx->id("ECP5_IS_GLOBAL")] = - "1"; // Prevents router etc touching this special net + promoted_ecknet->attrs[ctx->id("ECP5_IS_GLOBAL")] = 1; // Prevents router etc touching this special net eclk.buf = promoted_ecknet.get(); NPNR_ASSERT(!ctx->nets.count(eckname)); ctx->nets[eckname] = std::move(promoted_ecknet); @@ -1625,7 +1626,7 @@ class Ecp5Packer log_error("DQSBUFM can only be used with a pin-constrained PIO connected to its DQSI input" "(while processing '%s').\n", ci->name.c_str(ctx)); - BelId pio_bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")))); + BelId pio_bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string())); NPNR_ASSERT(pio_bel != BelId()); Loc pio_loc = ctx->getBelLocation(pio_bel); if (pio_loc.z != 0) @@ -1659,7 +1660,7 @@ class Ecp5Packer port.c_str(ctx), ci->name.c_str(ctx), usr.port.c_str(ctx), usr.cell->name.c_str(ctx)); } - pn->attrs[ctx->id("ECP5_IS_GLOBAL")] = "1"; + pn->attrs[ctx->id("ECP5_IS_GLOBAL")] = 1; } for (auto zport : @@ -1709,9 +1710,9 @@ class Ecp5Packer if (prim->ports.count(port)) sclk = prim->ports[port].net; if (sclk == nullptr) { - iol->params[input ? ctx->id("CLKIMUX") : ctx->id("CLKOMUX")] = "0"; + iol->params[input ? ctx->id("CLKIMUX") : ctx->id("CLKOMUX")] = std::string("0"); } else { - iol->params[input ? ctx->id("CLKIMUX") : ctx->id("CLKOMUX")] = "CLK"; + iol->params[input ? ctx->id("CLKIMUX") : ctx->id("CLKOMUX")] = std::string("CLK"); if (iol->ports[id_CLK].net != nullptr) { if (iol->ports[id_CLK].net != sclk && !equal_constant(iol->ports[id_CLK].net, sclk)) log_error("IOLOGIC '%s' has conflicting clocks '%s' and '%s'\n", iol->name.c_str(ctx), @@ -1747,9 +1748,9 @@ class Ecp5Packer if (prim->ports.count(port)) lsr = prim->ports[port].net; if (lsr == nullptr) { - iol->params[input ? ctx->id("LSRIMUX") : ctx->id("LSROMUX")] = "0"; + iol->params[input ? ctx->id("LSRIMUX") : ctx->id("LSROMUX")] = std::string("0"); } else { - iol->params[input ? ctx->id("LSRIMUX") : ctx->id("LSROMUX")] = "LSRMUX"; + iol->params[input ? ctx->id("LSRIMUX") : ctx->id("LSROMUX")] = std::string("LSRMUX"); if (iol->ports[id_LSR].net != nullptr && !equal_constant(iol->ports[id_LSR].net, lsr)) { if (iol->ports[id_LSR].net != lsr) log_error("IOLOGIC '%s' has conflicting LSR signals '%s' and '%s'\n", iol->name.c_str(ctx), @@ -1763,7 +1764,7 @@ class Ecp5Packer }; auto set_iologic_mode = [&](CellInfo *iol, std::string mode) { - auto &curr_mode = iol->params[ctx->id("MODE")]; + auto &curr_mode = iol->params[ctx->id("MODE")].str; if (curr_mode != "NONE" && curr_mode != "IREG_OREG" && curr_mode != mode) log_error("IOLOGIC '%s' has conflicting modes '%s' and '%s'\n", iol->name.c_str(ctx), curr_mode.c_str(), mode.c_str()); @@ -1778,7 +1779,7 @@ class Ecp5Packer log_error("IOLOGIC functionality (DDR, DELAY, DQS, etc) can only be used with pin-constrained PIO " "(while processing '%s').\n", curr->name.c_str(ctx)); - BelId bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")))); + BelId bel = ctx->getBelByName(ctx->id(pio->attrs.at(ctx->id("BEL")).as_string())); NPNR_ASSERT(bel != BelId()); return bel; }; @@ -1869,7 +1870,7 @@ class Ecp5Packer packed_cells.insert(cell.first); } else if (o_pio != nullptr) { iol = create_pio_iologic(o_pio, ci); - iol->params[ctx->id("DELAY.OUTDEL")] = "ENABLED"; + iol->params[ctx->id("DELAY.OUTDEL")] = std::string("ENABLED"); bool driven_by_iol = false; NetInfo *input_net = ci->ports.at(ctx->id("A")).net, *dly_net = ci->ports.at(ctx->id("Z")).net; if (input_net->driver.cell != nullptr && is_iologic_output_cell(ctx, input_net->driver.cell) && @@ -1899,9 +1900,9 @@ class Ecp5Packer ci->name.c_str(ctx)); } iol->params[ctx->id("DELAY.DEL_VALUE")] = - std::to_string(lookup_delay(str_or_default(ci->params, ctx->id("DEL_MODE"), "USER_DEFINED"))); + lookup_delay(str_or_default(ci->params, ctx->id("DEL_MODE"), "USER_DEFINED")); if (ci->params.count(ctx->id("DEL_VALUE")) && - std::string(ci->params.at(ctx->id("DEL_VALUE"))).substr(0, 5) != "DELAY") + std::string(ci->params.at(ctx->id("DEL_VALUE")).as_string()).substr(0, 5) != "DELAY") iol->params[ctx->id("DELAY.DEL_VALUE")] = ci->params.at(ctx->id("DEL_VALUE")); if (ci->ports.count(id_LOADN)) replace_port(ci, id_LOADN, iol, id_LOADN); @@ -1957,7 +1958,7 @@ class Ecp5Packer pio->ports[id_IOLDO].type = PORT_IN; } replace_port(pio, id_I, pio, id_IOLDO); - pio->params[ctx->id("DATAMUX_ODDR")] = "IOLDO"; + pio->params[ctx->id("DATAMUX_ODDR")] = std::string("IOLDO"); set_iologic_sclk(iol, ci, ctx->id("SCLK"), false); set_iologic_lsr(iol, ci, ctx->id("RST"), false); replace_port(ci, ctx->id("D0"), iol, id_TXDATA0); @@ -1991,8 +1992,8 @@ class Ecp5Packer replace_port(ci, ctx->id("D2"), iol, id_TXDATA2); replace_port(ci, ctx->id("D3"), iol, id_TXDATA3); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("ODDRXN.MODE")] = "ODDRX2"; - pio->params[ctx->id("DATAMUX_ODDR")] = "IOLDO"; + iol->params[ctx->id("ODDRXN.MODE")] = std::string("ODDRX2"); + pio->params[ctx->id("DATAMUX_ODDR")] = std::string("IOLDO"); packed_cells.insert(cell.first); } else if (ci->type == ctx->id("IDDRX2F")) { CellInfo *pio = net_driven_by(ctx, ci->ports.at(ctx->id("D")).net, is_trellis_io, id_O); @@ -2014,7 +2015,7 @@ class Ecp5Packer replace_port(ci, ctx->id("Q2"), iol, id_RXDATA2); replace_port(ci, ctx->id("Q3"), iol, id_RXDATA3); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("IDDRXN.MODE")] = "IDDRX2"; + iol->params[ctx->id("IDDRXN.MODE")] = std::string("IDDRX2"); packed_cells.insert(cell.first); } else if (ci->type == ctx->id("OSHX2A")) { CellInfo *pio = net_only_drives(ctx, ci->ports.at(ctx->id("Q")).net, is_trellis_io, id_I, true); @@ -2040,8 +2041,8 @@ class Ecp5Packer replace_port(ci, ctx->id("D0"), iol, id_TXDATA0); replace_port(ci, ctx->id("D1"), iol, id_TXDATA2); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("MODDRX.MODE")] = "MOSHX2"; - pio->params[ctx->id("DATAMUX_MDDR")] = "IOLDO"; + iol->params[ctx->id("MODDRX.MODE")] = std::string("MOSHX2"); + pio->params[ctx->id("DATAMUX_MDDR")] = std::string("IOLDO"); packed_cells.insert(cell.first); } else if (ci->type == ctx->id("ODDRX2DQA") || ci->type == ctx->id("ODDRX2DQSB")) { CellInfo *pio = net_only_drives(ctx, ci->ports.at(ctx->id("Q")).net, is_trellis_io, id_I, true); @@ -2069,10 +2070,11 @@ class Ecp5Packer replace_port(ci, ctx->id("D2"), iol, id_TXDATA2); replace_port(ci, ctx->id("D3"), iol, id_TXDATA3); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("MODDRX.MODE")] = "MODDRX2"; - iol->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = ci->type == ctx->id("ODDRX2DQSB") ? "DQSW" : "DQSW270"; + iol->params[ctx->id("MODDRX.MODE")] = std::string("MODDRX2"); + iol->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = + std::string(ci->type == ctx->id("ODDRX2DQSB") ? "DQSW" : "DQSW270"); process_dqs_port(ci, pio, iol, ci->type == ctx->id("ODDRX2DQSB") ? id_DQSW : id_DQSW270); - pio->params[ctx->id("DATAMUX_MDDR")] = "IOLDO"; + pio->params[ctx->id("DATAMUX_MDDR")] = std::string("IOLDO"); packed_cells.insert(cell.first); } else if (ci->type == ctx->id("IDDRX2DQA")) { CellInfo *pio = net_driven_by(ctx, ci->ports.at(ctx->id("D")).net, is_trellis_io, id_O); @@ -2095,7 +2097,7 @@ class Ecp5Packer replace_port(ci, ctx->id("Q3"), iol, id_RXDATA3); replace_port(ci, ctx->id("QWL"), iol, id_INFF); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("MIDDRX.MODE")] = "MIDDRX2"; + iol->params[ctx->id("MIDDRX.MODE")] = std::string("MIDDRX2"); process_dqs_port(ci, pio, iol, id_DQSR90); process_dqs_port(ci, pio, iol, id_RDPNTR2); process_dqs_port(ci, pio, iol, id_RDPNTR1); @@ -2128,11 +2130,13 @@ class Ecp5Packer replace_port(ci, ctx->id("T1"), iol, id_TSDATA1); process_dqs_port(ci, pio, iol, ci->type == ctx->id("TSHX2DQSA") ? id_DQSW : id_DQSW270); iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED"); - iol->params[ctx->id("MTDDRX.MODE")] = "MTSHX2"; - iol->params[ctx->id("MTDDRX.REGSET")] = "SET"; - iol->params[ctx->id("MTDDRX.DQSW_INVERT")] = ci->type == ctx->id("TSHX2DQSA") ? "ENABLED" : "DISABLED"; - iol->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = ci->type == ctx->id("TSHX2DQSA") ? "DQSW" : "DQSW270"; - iol->params[ctx->id("IOLTOMUX")] = "TDDR"; + iol->params[ctx->id("MTDDRX.MODE")] = std::string("MTSHX2"); + iol->params[ctx->id("MTDDRX.REGSET")] = std::string("SET"); + iol->params[ctx->id("MTDDRX.DQSW_INVERT")] = + std::string(ci->type == ctx->id("TSHX2DQSA") ? "ENABLED" : "DISABLED"); + iol->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = + std::string(ci->type == ctx->id("TSHX2DQSA") ? "DQSW" : "DQSW270"); + iol->params[ctx->id("IOLTOMUX")] = std::string("TDDR"); packed_cells.insert(cell.first); } } @@ -2188,8 +2192,8 @@ class Ecp5Packer log_error("ECLKSYNCB '%s' has disconnected port ECLKO\n", ci->name.c_str(ctx)); for (auto user : eclko->users) { if (user.cell->type == id_TRELLIS_ECLKBUF) { - Loc eckbuf_loc = - ctx->getBelLocation(ctx->getBelByName(ctx->id(user.cell->attrs.at(ctx->id("BEL"))))); + Loc eckbuf_loc = ctx->getBelLocation( + ctx->getBelByName(ctx->id(user.cell->attrs.at(ctx->id("BEL")).as_string()))); for (auto bel : ctx->getBels()) { if (ctx->getBelType(bel) != id_ECLKSYNCB) continue; @@ -2433,7 +2437,7 @@ bool Arch::pack() Ecp5Packer(ctx).pack(); log_info("Checksum: 0x%08x\n", ctx->checksum()); assignArchInfo(); - ctx->settings[ctx->id("pack")] = "1"; + ctx->settings[ctx->id("pack")] = 1; archInfoToAttributes(); return true; } catch (log_execution_error_exception) { @@ -2468,8 +2472,8 @@ void Arch::assignArchInfo() ci->sliceInfo.lsrmux = id(str_or_default(ci->params, id_LSRMUX, "LSR")); ci->sliceInfo.srmode = id(str_or_default(ci->params, id_SRMODE, "LSR_OVER_CE")); ci->sliceInfo.is_carry = str_or_default(ci->params, id("MODE"), "LOGIC") == "CCU2"; - ci->sliceInfo.sd0 = int_or_default(ci->params, id("REG0_SD"), 0); - ci->sliceInfo.sd1 = int_or_default(ci->params, id("REG1_SD"), 0); + ci->sliceInfo.sd0 = std::stoi(str_or_default(ci->params, id("REG0_SD"), "0")); + ci->sliceInfo.sd1 = std::stoi(str_or_default(ci->params, id("REG1_SD"), "0")); ci->sliceInfo.has_l6mux = false; if (ci->ports.count(id_FXA) && ci->ports[id_FXA].net != nullptr && ci->ports[id_FXA].net->driver.port == id_OFX0) From ebcdfc1ae83eaef8e4a4d7586385eafdf8443386 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 5 Aug 2019 17:28:54 +0100 Subject: [PATCH 3/7] generic: New Property interface Signed-off-by: David Shah --- generic/arch.cc | 4 ++-- generic/cells.cc | 26 +++++++++++++------------- generic/examples/simple_timing.py | 2 +- generic/examples/write_fasm.py | 3 +-- generic/main.cc | 2 +- generic/pack.cc | 6 +++--- 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/generic/arch.cc b/generic/arch.cc index fa3c825d..9e59540e 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -497,7 +497,7 @@ bool Arch::place() // FIXME: No HeAP because it needs a list of IO buffers if (placer == "sa") { bool retVal = placer1(getCtx(), Placer1Cfg(getCtx())); - getCtx()->settings[getCtx()->id("place")] = "1"; + getCtx()->settings[getCtx()->id("place")] = 1; archInfoToAttributes(); return retVal; } else { @@ -508,7 +508,7 @@ bool Arch::place() bool Arch::route() { bool retVal = router1(getCtx(), Router1Cfg(getCtx())); - getCtx()->settings[getCtx()->id("route")] = "1"; + getCtx()->settings[getCtx()->id("route")] = 1; archInfoToAttributes(); return retVal; } diff --git a/generic/cells.cc b/generic/cells.cc index 14b368b2..53886e33 100644 --- a/generic/cells.cc +++ b/generic/cells.cc @@ -43,8 +43,8 @@ std::unique_ptr create_generic_cell(Context *ctx, IdString type, std:: new_cell->type = type; if (type == ctx->id("GENERIC_SLICE")) { new_cell->params[ctx->id("K")] = std::to_string(ctx->args.K); - new_cell->params[ctx->id("INIT")] = "0"; - new_cell->params[ctx->id("FF_USED")] = "0"; + new_cell->params[ctx->id("INIT")] = 0; + new_cell->params[ctx->id("FF_USED")] = 0; for (int i = 0; i < ctx->args.K; i++) add_port(ctx, new_cell.get(), "I[" + std::to_string(i) + "]", PORT_IN); @@ -53,9 +53,9 @@ std::unique_ptr create_generic_cell(Context *ctx, IdString type, std:: add_port(ctx, new_cell.get(), "Q", PORT_OUT); } else if (type == ctx->id("GENERIC_IOB")) { - new_cell->params[ctx->id("INPUT_USED")] = "0"; - new_cell->params[ctx->id("OUTPUT_USED")] = "0"; - new_cell->params[ctx->id("ENABLE_USED")] = "0"; + new_cell->params[ctx->id("INPUT_USED")] = 0; + new_cell->params[ctx->id("OUTPUT_USED")] = 0; + new_cell->params[ctx->id("ENABLE_USED")] = 0; add_port(ctx, new_cell.get(), "PAD", PORT_INOUT); add_port(ctx, new_cell.get(), "I", PORT_IN); @@ -81,17 +81,17 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) if (no_dff) { replace_port(lut, ctx->id("Q"), lc, ctx->id("Q")); - lc->params[ctx->id("FF_USED")] = "0"; + lc->params[ctx->id("FF_USED")] = 0; } } void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) { - lc->params[ctx->id("FF_USED")] = "1"; + lc->params[ctx->id("FF_USED")] = 1; replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK")); if (pass_thru_lut) { - lc->params[ctx->id("INIT")] = "2"; + lc->params[ctx->id("INIT")] = 2; replace_port(dff, ctx->id("D"), lc, ctx->id("I[0]")); } @@ -101,15 +101,15 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set &todelete_cells) { if (nxio->type == ctx->id("$nextpnr_ibuf")) { - iob->params[ctx->id("INPUT_USED")] = "1"; + iob->params[ctx->id("INPUT_USED")] = 1; replace_port(nxio, ctx->id("O"), iob, ctx->id("O")); } else if (nxio->type == ctx->id("$nextpnr_obuf")) { - iob->params[ctx->id("OUTPUT_USED")] = "1"; + iob->params[ctx->id("OUTPUT_USED")] = 1; replace_port(nxio, ctx->id("I"), iob, ctx->id("I")); } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { // N.B. tristate will be dealt with below - iob->params[ctx->id("INPUT_USED")] = "1"; - iob->params[ctx->id("OUTPUT_USED")] = "1"; + iob->params[ctx->id("INPUT_USED")] = 1; + iob->params[ctx->id("OUTPUT_USED")] = 1; replace_port(nxio, ctx->id("I"), iob, ctx->id("I")); replace_port(nxio, ctx->id("O"), iob, ctx->id("O")); } else { @@ -120,7 +120,7 @@ void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, std::unordered_set ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); }, ctx->id("Y")); if (tbuf) { - iob->params[ctx->id("ENABLE_USED")] = "1"; + iob->params[ctx->id("ENABLE_USED")] = 1; replace_port(tbuf, ctx->id("A"), iob, ctx->id("I")); replace_port(tbuf, ctx->id("E"), iob, ctx->id("EN")); diff --git a/generic/examples/simple_timing.py b/generic/examples/simple_timing.py index a955c8d7..2ccb197e 100644 --- a/generic/examples/simple_timing.py +++ b/generic/examples/simple_timing.py @@ -4,7 +4,7 @@ for cname, cell in ctx.cells: if cname in ("$PACKER_GND", "$PACKER_VCC"): continue K = int(cell.params["K"]) - if cell.params["FF_USED"] == "1": + if int(cell.params["FF_USED"], 2) == 1: ctx.addCellTimingClock(cell=cname, port="CLK") for i in range(K): ctx.addCellTimingSetupHold(cell=cname, port="I[%d]" % i, clock="CLK", diff --git a/generic/examples/write_fasm.py b/generic/examples/write_fasm.py index 1f279b63..ede8f16b 100644 --- a/generic/examples/write_fasm.py +++ b/generic/examples/write_fasm.py @@ -45,8 +45,7 @@ def write_fasm(ctx, paramCfg, f): print("%s.%s" % (cell.bel, fasm_name), file=f) else: # Parameters with width >32 are direct binary, otherwise denary - binval = val if cfg.width > 32 else "{:0{}b}".format(int(val), cfg.width) - print("%s.%s[%d:0] = %d'b%s" % (cell.bel, fasm_name, cfg.width-1, cfg.width, binval), file=f) + print("%s.%s[%d:0] = %d'b%s" % (cell.bel, fasm_name, cfg.width-1, cfg.width, val), file=f) else: print("%s.%s.%s" % (cell.bel, fasm_name, val), file=f) print("", file=f) \ No newline at end of file diff --git a/generic/main.cc b/generic/main.cc index ce1a51c7..7dfc6aa7 100644 --- a/generic/main.cc +++ b/generic/main.cc @@ -55,7 +55,7 @@ std::unique_ptr GenericCommandHandler::createContext(std::unordered_map { ArchArgs chipArgs; if (values.find("arch.name") != values.end()) { - std::string arch_name = values["arch.name"].str; + std::string arch_name = values["arch.name"].as_string(); if (arch_name != "generic") log_error("Unsuported architecture '%s'.\n", arch_name.c_str()); } diff --git a/generic/pack.cc b/generic/pack.cc index 558eca7c..3dc12bc1 100644 --- a/generic/pack.cc +++ b/generic/pack.cc @@ -150,7 +150,7 @@ static void pack_constants(Context *ctx) log_info("Packing constants..\n"); std::unique_ptr gnd_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_GND"); - gnd_cell->params[ctx->id("INIT")] = "0"; + gnd_cell->params[ctx->id("INIT")] = 0; 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(); @@ -158,7 +158,7 @@ static void pack_constants(Context *ctx) gnd_cell->ports.at(ctx->id("Q")).net = gnd_net.get(); std::unique_ptr vcc_cell = create_generic_cell(ctx, ctx->id("GENERIC_SLICE"), "$PACKER_VCC"); - vcc_cell->params[ctx->id("INIT")] = "1"; + vcc_cell->params[ctx->id("INIT")] = 1; 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(); @@ -282,7 +282,7 @@ bool Arch::pack() pack_io(ctx); pack_lut_lutffs(ctx); pack_nonlut_ffs(ctx); - ctx->settings[ctx->id("pack")] = "1"; + ctx->settings[ctx->id("pack")] = 1; ctx->assignArchInfo(); log_info("Checksum: 0x%08x\n", ctx->checksum()); return true; From 7b5b5524c43bf84bb9b74e0af9b8fdf2c43d2e25 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 5 Aug 2019 17:30:11 +0100 Subject: [PATCH 4/7] ci: Update Yosys version Signed-off-by: David Shah --- .cirrus/Dockerfile.ubuntu16.04 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.cirrus/Dockerfile.ubuntu16.04 b/.cirrus/Dockerfile.ubuntu16.04 index 4b149b7b..1e540af9 100644 --- a/.cirrus/Dockerfile.ubuntu16.04 +++ b/.cirrus/Dockerfile.ubuntu16.04 @@ -8,7 +8,8 @@ RUN set -e -x ;\ apt-get -y install \ build-essential autoconf cmake clang bison wget flex gperf \ libreadline-dev gawk tcl-dev libffi-dev graphviz xdot python3-dev \ - libboost-all-dev qt5-default git libftdi-dev pkg-config libeigen3-dev + libboost-all-dev qt5-default git libftdi-dev pkg-config libeigen3-dev \ + zlib1g-dev RUN set -e -x ;\ mkdir -p /usr/local/src ;\ @@ -36,7 +37,7 @@ RUN set -e -x ;\ cd /usr/local/src ;\ git clone --recursive https://github.com/YosysHQ/yosys.git ;\ cd yosys ;\ - git reset --hard ea8ac0aaad3a1f89ead8eb44b2fef5927f29a099 ;\ + git reset --hard 292f03355a425ede48051c79d5bf619591531080 ;\ make -j $(nproc) ;\ make install ;\ rm -rf /usr/local/src/yosys From c9ba81ab50c79de43526436d4d6fda496dffa7b6 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 5 Aug 2019 19:10:00 +0100 Subject: [PATCH 5/7] ice40: Fix regression Signed-off-by: David Shah --- ice40/pack.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ice40/pack.cc b/ice40/pack.cc index 462310cd..4386d2a1 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -1237,7 +1237,9 @@ static void pack_special(Context *ctx) packed->params[pos_map_name.at(param.first)] = pos_map_val.at(param.second.as_string()); } - auto feedback_path = packed->params[ctx->id("FEEDBACK_PATH")].as_string(); + auto feedback_path = packed->params[ctx->id("FEEDBACK_PATH")].is_string + ? packed->params[ctx->id("FEEDBACK_PATH")].as_string() + : std::to_string(packed->params[ctx->id("FEEDBACK_PATH")].as_int64()); std::string fbp_value = feedback_path == "DELAY" ? "0" From 7126dacccd5f1f57c1ff937247e0c9b10f4588e2 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 6 Aug 2019 09:53:33 +0100 Subject: [PATCH 6/7] ecp5: Add a check for legacy parameter values Signed-off-by: David Shah --- ecp5/pack.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ecp5/pack.cc b/ecp5/pack.cc index c21a5e3c..a9416f32 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -2384,9 +2384,21 @@ class Ecp5Packer } } + void prepack_checks() + { + // Check for legacy-style JSON (use CEMUX as a clue) and error out, avoiding a confusing assertion failure + // later + for (auto cell : sorted(ctx->cells)) { + if (is_ff(ctx, cell.second) && cell.second->params.count(ctx->id("CEMUX")) && + !cell.second->params[ctx->id("CEMUX")].is_string) + log_error("Found netlist using legacy-style JSON parameter values, please update your Yosys.\n"); + } + } + public: void pack() { + prepack_checks(); pack_io(); pack_dqsbuf(); pack_iologic(); From 8eef6ac55e48aa181d1e268fcec004a58f9d8db4 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 6 Aug 2019 09:58:28 +0100 Subject: [PATCH 7/7] Bump tests submodule Signed-off-by: David Shah --- tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests b/tests index 5182fd4b..6f93d3ed 160000 --- a/tests +++ b/tests @@ -1 +1 @@ -Subproject commit 5182fd4bec49a568cc3fa37d62d9f9a82f280917 +Subproject commit 6f93d3edb3cb3adab142a8d00eec0a7377faa864