diff --git a/himbaechel/uarch/gatemate/ccf.cc b/himbaechel/uarch/gatemate/ccf.cc index 071025c3..ab513161 100644 --- a/himbaechel/uarch/gatemate/ccf.cc +++ b/himbaechel/uarch/gatemate/ccf.cc @@ -154,6 +154,44 @@ struct GateMateCCFReader } } + std::regex pattern_to_regex(const std::string &pat) + { + std::string expr; + expr.reserve(pat.size() * 2); + expr += '^'; + for (char c : pat) { + switch (c) { + case '*': + expr += ".*"; + break; + case '?': + expr += "."; + break; + // Escape regex metacharacters + case '.': + case '+': + case '(': + case ')': + case '{': + case '}': + case '^': + case '$': + case '|': + case '\\': + case '[': + case ']': + expr += '\\'; + expr += c; + break; + + default: + expr += c; + } + } + expr += '$'; + return std::regex(expr); + } + void run() { log_info("Parsing CCF file..\n"); @@ -167,6 +205,7 @@ struct GateMateCCFReader }; lineno = 0; count = std::vector(uarch->dies, 0); + bool floorplanning = false; while (std::getline(in, line)) { ++lineno; // Both // and # are considered start of comment @@ -180,6 +219,125 @@ struct GateMateCCFReader continue; linebuf += line; + boost::algorithm::to_lower(line); + if (line.find("start floorplanning") != std::string::npos) { + floorplanning = true; + linebuf = ""; + continue; + } else if (line.find("end floorplanning") != std::string::npos) { + floorplanning = false; + linebuf = ""; + continue; + } + if (floorplanning) { + // int size = -1; + std::string src_location; + + std::string s = linebuf; + boost::trim(s); + + // split input into segments by ';' + std::vector segments; + boost::split(segments, s, boost::is_any_of(";")); + for (auto &seg : segments) + boost::trim(seg); + + if (!segments.empty()) { + std::vector parts; + boost::split(parts, segments[0], boost::is_any_of(":")); + for (auto &p : parts) + boost::trim(p); + + // index is numeric token + // int index = -1; + if (!parts.empty() && !parts[0].empty() && + std::all_of(parts[0].begin(), parts[0].end(), ::isdigit)) { + // index = std::stoi(parts[0]); + parts.erase(parts.begin()); + } + + // find size + // size = -1; + for (size_t i = 0; i + 1 < parts.size(); ++i) { + if (boost::iequals(parts[i], "size")) { + if (!parts[i + 1].empty() && + std::all_of(parts[i + 1].begin(), parts[i + 1].end(), ::isdigit)) { + // size = std::stoi(parts[i + 1]); + } + break; + } + } + + // always the last piece of the main segment + if (!parts.empty()) { + src_location = parts.back(); + boost::trim(src_location); + } + } + + if (segments.size() > 1) { + std::string &tmp = segments[1]; + boost::trim(tmp); + + if (!tmp.empty()) { + std::vector subparts; + boost::split(subparts, tmp, boost::is_any_of(":")); + for (auto &p : subparts) + boost::trim(p); + + if (!subparts.empty() && boost::iequals(subparts[0], "pb")) { + if (subparts.size() == 2) { + std::string pb_position = subparts[1]; + + std::regex pb_regex(R"(x(-?\d+)y(-?\d+)x(-?\d+)y(-?\d+))"); + std::smatch match; + if (std::regex_match(pb_position, match, pb_regex)) { + int x1 = std::stoi(match[1]) + 2; + int y1 = std::stoi(match[2]) + 2; + int x2 = std::stoi(match[3]) + 2; + int y2 = std::stoi(match[4]) + 2; + + if (x1 < 0 || x1 >= ctx->getGridDimX() || x2 < 0 || x2 >= ctx->getGridDimX() || + y1 < 0 || y1 >= ctx->getGridDimY() || y2 < 0 || y2 >= ctx->getGridDimY()) + log_error("Placebox coordinates out of range '%s' in line %d.\n", + pb_position.c_str(), lineno); + + IdString scopename(ctx, src_location.c_str()); + std::regex expr = pattern_to_regex(src_location); + bool matched_any = false; + + for (const IdString &name : uarch->scopenames) { + if (std::regex_match(name.str(ctx), expr)) { + matched_any = true; + + ctx->createRectangularRegion(name, x1, y1, x2, y2); + uarch->scopenames_used.emplace(name); + + log_info(" Constraining region '%s' to '%s'\n", name.c_str(ctx), + pb_position.c_str()); + } + } + + if (!matched_any) { + log_error("Unknown scope name or pattern: '%s' in line %d.\n", + src_location.c_str(), lineno); + } + } else { + log_error("Placebox format invalid: %s in line %d.\n", pb_position.c_str(), lineno); + } + } else { + log_error("Missing data for pB (in line %d).\n", lineno); + } + } else { + log_error("Unexpected content in last segment (in line %d).\n", lineno); + } + } + } + + linebuf = ""; + continue; + } + size_t pos = linebuf.find(';'); // Need to concatenate lines until there is closing ; sign while (pos != std::string::npos) { @@ -222,6 +380,14 @@ struct GateMateCCFReader parse_params(params, false, &cell->params); } else log_warning("Pad with name '%s' not found in netlist.\n", pin_name.c_str()); + } else if (type == "start" || type == "end") { + std::string word2 = words.at(1); + boost::algorithm::to_lower(word2); + if (word2 == "floorplanning") { + log("Found floor planning\n"); + } else + log_error("Unknown command '%s' in line %d.\n", word2.c_str(), lineno); + } else { log_error("Unknown type '%s' in line %d.\n", type.c_str(), lineno); } diff --git a/himbaechel/uarch/gatemate/gatemate.h b/himbaechel/uarch/gatemate/gatemate.h index e6b65050..bdc17cb2 100644 --- a/himbaechel/uarch/gatemate/gatemate.h +++ b/himbaechel/uarch/gatemate/gatemate.h @@ -115,6 +115,8 @@ struct GateMateImpl : HimbaechelAPI dict index_to_die; dict die_to_index; dict> pass_backtrace; + pool scopenames; + pool scopenames_used; private: bool getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc, diff --git a/himbaechel/uarch/gatemate/pack.cc b/himbaechel/uarch/gatemate/pack.cc index 5e03e717..11167ae2 100644 --- a/himbaechel/uarch/gatemate/pack.cc +++ b/himbaechel/uarch/gatemate/pack.cc @@ -512,11 +512,42 @@ void GateMatePacker::assign_clocks() } } +static IdString get_scopename(Context *ctx, CellInfo &ci) +{ + std::string scope = "top"; + if (ci.attrs.count(ctx->id("scopename"))) { + scope = str_or_default(ci.attrs, ctx->id("scopename"), ""); + scope = "top " + scope; + } else if (ci.attrs.count(ctx->id("hdlname"))) { + scope = str_or_default(ci.attrs, ctx->id("hdlname"), ""); + scope = "top " + scope; + } + return IdString(ctx, scope.c_str()); +} + +void GateMatePacker::find_regions() +{ + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + IdString name = get_scopename(ctx, ci); + uarch->scopenames.emplace(name); + } + if (uarch->scopenames.size() > 1) { + log_info("Detected regions..\n"); + for (auto &scope : uarch->scopenames) { + log_info(" %s\n", scope.c_str(ctx)); + } + } +} + void GateMatePacker::assign_regions() { log_info("Assign cell region based on attributes..\n"); for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; + IdString name = get_scopename(ctx, ci); + if (uarch->scopenames_used.count(name)) + ctx->constrainCellToRegion(ci.name, name); if (ci.attrs.count(id_GATEMATE_DIE) != 0) { std::string die_name = str_or_default(ci.attrs, id_GATEMATE_DIE, ""); IdString die = ctx->id(die_name); @@ -566,6 +597,8 @@ void GateMatePacker::fix_regions() void GateMateImpl::pack() { const ArchArgs &args = ctx->args; + GateMatePacker packer(ctx, this); + packer.find_regions(); if (args.options.count("ccf")) { parse_ccf(args.options["ccf"].as()); } @@ -600,7 +633,6 @@ void GateMateImpl::pack() if (strategy == MultiDieStrategy::REUSE_CLK1 || strategy == MultiDieStrategy::FULL_USE) preferred_die = 0; - GateMatePacker packer(ctx, this); if (forced_die == IdString()) packer.assign_regions(); packer.pack_constants(); diff --git a/himbaechel/uarch/gatemate/pack.h b/himbaechel/uarch/gatemate/pack.h index 533fa7bb..dbf24801 100644 --- a/himbaechel/uarch/gatemate/pack.h +++ b/himbaechel/uarch/gatemate/pack.h @@ -72,6 +72,7 @@ struct GateMatePacker void reassign_clocks(); void copy_clocks(); void assign_clocks(); + void find_regions(); void assign_regions(); void fix_regions();