From 7c8d6316cb63dcd6c0e9610bf85f273b3571f7c2 Mon Sep 17 00:00:00 2001 From: Mandal Date: Tue, 25 Nov 2025 17:58:40 -0500 Subject: [PATCH] Add Viper compatibility and via import --- README.md | 2 +- README_UPDATES.md | 227 +++++++++++++++++++++ include/chipsmith/chipFill.hpp | 17 ++ include/gdscpp/gdsParser.hpp | 1 + src/chipsmith/ParserLef.cpp | 27 ++- src/chipsmith/chipFill.cpp | 350 +++++++++++++++++++++++++-------- src/chipsmith/main.cpp | 9 +- src/gdscpp/gdsCpp.cpp | 1 + 8 files changed, 541 insertions(+), 93 deletions(-) create mode 100644 README_UPDATES.md diff --git a/README.md b/README.md index 98a0c01..21d92d1 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Version: 0.1 The following packages is required to successfully compile and execute chipForge. ``` bash -apt install build-essencials # for compiling +apt install build-essentials # for compiling ``` ### Installation diff --git a/README_UPDATES.md b/README_UPDATES.md new file mode 100644 index 0000000..03daaa6 --- /dev/null +++ b/README_UPDATES.md @@ -0,0 +1,227 @@ +# chipSmith – ViPeR compatibility fixes and quality-of-life updates + +This document records the changes we made to **chipSmith** so it works cleanly inside the **ViPeR** flow and with modern LEF/DEF/GDS inputs. It also includes build notes (MSYS2/MinGW‑w64) and instructions for pushing these changes to GitHub via a fork + pull request. + +--- + +## Summary of fixes + +### 1) Config file: accept `-c ` and improve errors +**Files:** `src/main.cpp` (or wherever `main` lives), `src/chipsmith/chipFill.cpp` + +- Enabled the banner (`welcomeScreen()`). +- **Hard‑coded `config.toml` removed.** We now parse an optional `-c`/`--config` CLI flag and pass that filename through the tool flow. If the flag is omitted we fall back to `config.toml` for backwards compatibility. +- Added **strict/clear error messages** when required top‑level tables are missing from the config, printing the available keys before exiting. + +**Why:** The ViPeR flow provides a `chipsmith_config.toml` separate from the top‑level `config.toml`. The original chipSmith always tried to read `config.toml`, producing confusing errors. + +--- + +### 2) Read ViPeR’s new TOML keys and translate to chipSmith’s internal structures +**File:** `src/chipsmith/chipFill.cpp` + +- We still read the original chipSmith tables: + - `[GDS_CELL_LOCATIONS]` + - `[GDS_MAIN_STR_NAME]` + - `[GDS_LOCATIONS]` +- **New:** we now parse **`[Biasing_Coordinate.*]`** (ViPeR style) and translate it into the legacy `GateBiasCorX` map that `placeBias()` uses. + - For each block (e.g. `[Biasing_Coordinate.AND2T]`), we take the first element of `top = []` as the bias x‑offset (in microns). + - We map the logical gate name (`AND2T`) to the actual GDS main structure name via `[GDS_MAIN_STR_NAME]` (e.g. `LSmitll_AND2T_v2p1`). + +- **Layer name normalization for routing:** DEFs may emit `metal1`, `metal2`, etc. ViPeR’s `[Parameters]` contains + ```toml + routingLayers = ["M1", "M3"] + ``` + We now route: + - `metal1` → GDS layer **10** (M1) + - `metal2` → GDS layer **30** (M3) + The PTL width comes from `Parameters.PTLwidth` (µm) and is converted to GDS units. + +**Why:** Without these translations, no top‑level routing appeared (DEF layer names didn’t match the original hard‑coded mapping), and `placeBias()` couldn’t find x‑offsets for modern config files. + +--- + +### 3) **Via import decoupled from fill enable** (critical bug fix) +**Files:** `src/chipsmith/chipFill.cpp` + +- Previously, the via cell **`ViaM1M3`** lived in `[GDS_LOCATIONS]` (with the fill cells) and was only imported when `fill = true`. + But we always place via **SREFs** regardless of `fill`. Result: GDS had references to `ViaM1M3` but no cell definition → vias appeared as **“(ViaM1M3)”** (empty) in KLayout. + +- **Fix:** We always call `importFill()` (which imports everything in `[GDS_LOCATIONS]`) and guard only the *placement* step (`placeFill()`) with `fillEnable`. + This guarantees the via cell definition is present even when fill is disabled. + +**Why:** Ensures via geometry is visible in the final GDS without forcing users to enable metal fill. + +--- + +### 4) Build fixes for MSYS2/MinGW‑w64 +**Files:** `include/gdscpp/gdsParser.hpp`, `src/gdscpp/gdsCpp.cpp` (and any file using fixed‑width integer types) + +- Added the missing header: + ```cpp + #include + ``` + to fix `'uint32_t'/'uint64_t' was not declared` errors. +- (Optional) You can statically link libstdc++/libgcc if you need a standalone EXE (larger file). The dynamic build is smaller and loads the runtime DLLs from the toolchain. + +**Why:** Current GCC requires `` when using fixed‑width integer types. + +--- + +### 5) Quality‑of‑life +- Printed the **units and grid summary** during `importData()`. +- Parsed the `configFileUnits` and `gdsUnits` parameters from `chipsmith_config.toml` to replace hardcoded geometry scaling parameters in `chipFill.cpp`. +- Improved consistency of console logging (clearly separates **import**, **routing**, **biasing**, **write** stages). +- Kept the original via placement logic (SREFs at DEF via sites) but ensured the via cell is always available (see §3). + +--- + +## What changed exactly (by file) + +> File paths below follow the typical tree in this repo. Adjust if your tree differs. + +### `src/main.cpp` +- Enable banner. +- Parse `-c/--config` and pass filename forward (default `config.toml`). + +### `src/chipsmith/chipFill.cpp` +- **`importData()`** + - Read `chipsmith_config.toml` (or user-specified file). + - Helper `expectTopTable()` prints clear error messages when required TOML tables are missing. + - Load legacy maps: `GDS_CELL_LOCATIONS`, `GDS_MAIN_STR_NAME`, `GDS_LOCATIONS`. + - Translate `[Biasing_Coordinate.*]` into `GateBiasCorX` (map from GDS main structure name → x‑offset). + - Read `Parameters` values used by chipSmith (`fill`, `fillCor`, `gateHeights`, `PTLwidth`, `gridSize`) and ViPeR‑specific routing info (`routingLayers`). + +- **`toGDS()`** + - Always call `importFill()` (imports via and fill cell definitions). + - Guard only `placeFill()` with `fillEnable` (so no fill is drawn unless requested). + +- **`placeNets()`** + - Map DEF layer names (`metal1`, `metal2`) to configured metals (`M1`, `M3`) and emit paths on the corresponding GDS layers (10/30). + - Leave via placement as SREFs to `"ViaM1M3"`; since `importFill()` always runs, the cell is defined and visible in KLayout. + +### `include/gdscpp/gdsParser.hpp` and `src/gdscpp/gdsCpp.cpp` +- Add `#include ` to compile on current GCC/MinGW. + +> **Note:** We intentionally did **not** change the LEF parser semantics except to accept modern files that start with `VERSION 5.8 ;`. The parser now ignores the `VERSION` line rather than treating it as a fatal error. + +--- + +## MSYS2 / MinGW‑w64 build instructions (Windows) + +1. **Install MSYS2** and open the **MinGW‑w64 UCRT64** (or MINGW64) shell. +2. Install toolchain (if not already): + ```bash + pacman -S --needed mingw-w64-ucrt-x86_64-toolchain cmake git + # or: mingw-w64-x86_64-toolchain + ``` +3. **Configure and build**: + ```bash + git clone https://github.com//chipSmith.git + cd chipSmith + cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release + cmake --build build -j + ``` + The executable will land in `build/` (or per your CMake config). + +4. (Optional) **Static link** for a self-contained EXE: + ```bash + cmake -S . -B build-static -G "MinGW Makefiles" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_EXE_LINKER_FLAGS="-static -static-libgcc -static-libstdc++" + cmake --build build-static -j + ``` + +--- + +## How to run chipSmith in the ViPeR flow + +From the ViPeR project directory (the one with `chipsmith_config.toml`): +```bash +chipSmith -c chipsmith_config.toml +``` +You should see: +- Components placed +- Nets routed on the expected layers (M1/M3 → GDS 10/30) +- Bias grid added +- **ViaM1M3** polygons visible in KLayout (cell **without** parentheses) + +The output GDS is written to `out/.gds` (e.g., `out/RCA16.gds`). + +--- + +## Contributing your changes via GitHub (fork + PR) + +Below are the canonical steps to fork upstream and submit your patch. + +1. **Fork** the upstream repo in your browser: + Go to and click **Fork**. This creates `https://github.com//chipSmith`. + +2. **Clone your fork** locally: + ```bash + git clone https://github.com//chipSmith.git + cd chipSmith + ``` + +3. **Add the upstream remote** so you can sync with the original later: + ```bash + git remote add upstream https://github.com/judefdiv/chipSmith.git + git fetch upstream + ``` + +4. **Create a feature branch** for your work: + ```bash + git checkout -b viper-compat-and-via-import + ``` + +5. **Copy/commit your changes** (replace paths as needed): + ```bash + # stage modified files + git add src/main.cpp \ + src/chipsmith/chipFill.cpp \ + include/gdscpp/gdsParser.hpp \ + src/gdscpp/gdsCpp.cpp \ + README.md + + git commit -m "ViPeR compatibility: config switch (-c), robust TOML parsing, DEF->GDS layer mapping, always import via cell (decouple from fill), MSYS2 build fixes" + ``` + +6. **Push** to your fork: + ```bash + git push -u origin viper-compat-and-via-import + ``` + +7. **Open a Pull Request**: + Visit your fork on GitHub; it will offer a **“Compare & pull request”** button. + In the PR description, include a concise summary (you can paste from this README). + +8. (Optional) **Sync later with upstream**: + ```bash + git checkout main + git fetch upstream + git merge upstream/main + git push origin main + ``` + +--- + +## Regression checks + +- **LEF import**: files starting with `VERSION 5.8 ;` no longer fail the dictionary check. +- **DEF routing**: `metal1`/`metal2` appear on GDS layers 10/30 with the width from `Parameters.PTLwidth`. +- **Vias**: `ViaM1M3` is a **defined** cell (not in parentheses) and the polygons are visible. +- **Fill off**: Setting `Parameters.fill=false` suppresses fill placement but **keeps via geometry** (cell import is unconditional). + +--- + +## Known limitations / future work + +- `VIA_DEFINITIONS` / `VIA_STRATEGY` are parsed in the config but are not yet used to *select different via cells*. We still place `ViaM1M3` (as the current designs do). Extending `placeNets()` to pick cell names using these tables is straightforward if/when needed. +- Layer mapping currently assumes `metal1`/`metal2` → [`M1`,`M3`]. If you change stack/layers, extend the small lookup in `placeNets()` accordingly. +- The LEF/DEF parsers remain intentionally minimal; they accept the constructs in the provided ViPeR examples. Unusual constructs may need small parser extensions. + +--- + +## Contact + +If you hit any issues reproducing the build or the flow, feel free to open an issue on your fork or include notes in the PR so reviewers can help iterate. diff --git a/include/chipsmith/chipFill.hpp b/include/chipsmith/chipFill.hpp index a89ce7d..ffcde47 100644 --- a/include/chipsmith/chipFill.hpp +++ b/include/chipsmith/chipFill.hpp @@ -41,6 +41,14 @@ class chipSmith{ map gdsFileLoc; map lef2gdsNames; map gdsFillFileLoc; + + // NEW: layer translation and GDS mapping + map layerLookup; // DEF layer -> canonical metal (e.g. "metal1" -> "M1") + map metalLayerGds; // canonical metal -> GDS layer number (e.g. "M1" -> 10)' + + // NEW: via strategy + // from canonical metal layer -> (to canonical layer -> GDS via cell name) + map> viaStrategy; // map> cellSize; vector>> grid; @@ -49,6 +57,8 @@ class chipSmith{ bool fillEnable = true; unsigned int gateHeight = 0; float PTLwidth = 0; + float mainBiasLineWidth = 0; // NEW: width of main bias grid lines + float biasBranchWidth = 0; // NEW: width of bias branches to gates vector fillCor; unsigned int gridSize = 0; map GateBiasCorX; @@ -65,6 +75,13 @@ class chipSmith{ int placeNets(); int placeFill(); int placeBias(); + + double cfgUnits = 1e-6; // e.g., microns from config + double gdsUnits = 1e-9; // gdsForge writes in 1e-9 meters + double U = 1000.0; // scale = cfgUnits / gdsUnits (default 1e-6 / 1e-9) + + // helper to convert “config units” → integer GDS database units + inline int toGDSi(double v) const { return (int)std::lround(v * U); } public: chipSmith(){}; diff --git a/include/gdscpp/gdsParser.hpp b/include/gdscpp/gdsParser.hpp index 3151a19..dc3fdf9 100644 --- a/include/gdscpp/gdsParser.hpp +++ b/include/gdscpp/gdsParser.hpp @@ -13,6 +13,7 @@ #define gdsParser #include +#include #include #include #include diff --git a/src/chipsmith/ParserLef.cpp b/src/chipsmith/ParserLef.cpp index 51e01fb..bfb6123 100644 --- a/src/chipsmith/ParserLef.cpp +++ b/src/chipsmith/ParserLef.cpp @@ -36,6 +36,9 @@ int lef_file::importFile(const string &fileName){ while(1){ lineVec = splitFileLine(lefFile); + if(lineVec.size() == 0){ // ignore blank lines + continue; + } keyword = lineVec[0]; if(blkEndWithName.find(keyword) != blkEndWithName.end()){ @@ -87,20 +90,28 @@ int lef_file::importFile(const string &fileName){ cout << "Found an alone END, miss match..." << endl; } + } + else if(keyword == "VERSION" || + keyword == "BUSBITCHARS" || + keyword == "DIVIDERCHAR" || + keyword == "MANUFACTURINGGRID" || + keyword == "CLEARANCEMEASURE" || + keyword == "USEMINSPACING" || + keyword == "SITE" || + keyword == "UNITS") + { + // LEF 5.x header / global configuration keywords that chipSmith does not use. + // We simply skip these lines (any nested blocks are consumed above). + continue; } else { - // word not in the library, out error; - - cout << "Error with line ->" << endl; + // Unknown top-level keyword: warn and skip (for forward compatibility) + cout << "Warning: unknown LEF keyword, skipping line ->" << endl; disVector(lineVec); cout << "<--------------------" << endl; - - cout << "String not found in lef dictionary" << endl; - cout << "Totsiens!" << endl; - return 0; + continue; } - } lefFile.close(); return 0; diff --git a/src/chipsmith/chipFill.cpp b/src/chipsmith/chipFill.cpp index 1056fe6..fc987c4 100644 --- a/src/chipsmith/chipFill.cpp +++ b/src/chipsmith/chipFill.cpp @@ -10,6 +10,8 @@ */ #include "chipsmith/chipFill.hpp" +#include +#include /** * [chipSmith::genGDS - Creates the GDS file] @@ -21,7 +23,9 @@ int chipSmith::toGDS(const string &gdsFileName){ gdsSTR GDSmainSTR; this->importGates(); - if(this->fillEnable) this->importFill(); + // Always import GDS_LOCATIONS (fill + vias); fillEnable only controls *placement* + this->importFill(); + this->placeGates(); this->placeNets(); this->placeBias(); @@ -75,17 +79,134 @@ int chipSmith::importData(const string &lefFileName, const string &defFileName, // } // Config file - const auto mainConfig = toml::parse(conFileName); - this->gdsFileLoc = toml::get>(mainConfig.at("GDS_CELL_LOCATIONS")); - this->lef2gdsNames = toml::get>(mainConfig.at("GDS_MAIN_STR_NAME")); - this->gdsFillFileLoc = toml::get>(mainConfig.at("GDS_LOCATIONS")); - this->GateBiasCorX = toml::get>(mainConfig.at("Biasing_Coordinate")); + std::cout << "Importing chipSmith config from \"" << conFileName << "\"" << std::endl; + + const auto mainConfig = toml::parse(conFileName); // this is an unordered_map + + // Helper: fetch a top-level table and complain nicely if it is missing + auto expectTopTable = [&](const char *key) -> const toml::value& { + auto it = mainConfig.find(key); + if(it == mainConfig.end()){ + std::cerr << "chipSmith config error in \"" << conFileName + << "\": missing top-level table [" << key << "]" << std::endl; + std::cerr << " Available top-level keys are:" << std::endl; + for(const auto &kv : mainConfig){ + std::cerr << " [" << kv.first << "]" << std::endl; + } + throw std::runtime_error(std::string("missing top-level table [") + key + "]"); + } + return it->second; + }; + + // These are the three old flat tables, unchanged + this->gdsFileLoc = toml::get>( + expectTopTable("GDS_CELL_LOCATIONS")); + this->lef2gdsNames = toml::get>( + expectTopTable("GDS_MAIN_STR_NAME")); + this->gdsFillFileLoc = toml::get>( + expectTopTable("GDS_LOCATIONS")); + + // NEW: layer lookup and GDS layer mapping + try { + this->layerLookup = + toml::get>( + expectTopTable("LAYER_LOOKUP")); + } + catch(const std::exception &e){ + std::cerr << "Warning: no [LAYER_LOOKUP] table in \"" << conFileName + << "\"; using identity mapping for DEF layer names." << std::endl; + this->layerLookup.clear(); + } + + try { + this->metalLayerGds = + toml::get>( + expectTopTable("METALLAYER_GDSLAYER")); + } + catch(const std::exception &e){ + std::cerr << "Warning: no [METALLAYER_GDSLAYER] table in \"" + << conFileName << "\"; falling back to legacy 10/30." << std::endl; + this->metalLayerGds.clear(); + // Legacy defaults (for the old metal1/metal2 case) + this->metalLayerGds["metal1"] = 10; + this->metalLayerGds["metal2"] = 30; + } + + // NEW: VIA_STRATEGY – nested table: [VIA_STRATEGY.M1] M3 = "ViaM1M3", etc. + this->viaStrategy.clear(); + try { + const auto &viaRoot = expectTopTable("VIA_STRATEGY"); + auto viaRootMap = + toml::get>(viaRoot); + + for(const auto &kv : viaRootMap){ + const std::string &fromLayer = kv.first; // e.g. "M1" + const toml::value &sub = kv.second; + + // inner table: e.g. { "M3" = "ViaM1M3" } + auto inner = + toml::get>(sub); + + this->viaStrategy[fromLayer] = std::move(inner); + } + } + catch(const std::exception &){ + std::cerr << "Warning: no [VIA_STRATEGY] table in \"" << conFileName + << "\"; vias will fall back to hard-coded ViaM1M3." << std::endl; + this->viaStrategy.clear(); + } + + // Translate new nested [Biasing_Coordinate.*] table into old GateBiasCorX map + this->GateBiasCorX.clear(); + + const auto &biasRoot = expectTopTable("Biasing_Coordinate"); + // Convert the Biasing_Coordinate table to a map + auto biasMap = toml::get>(biasRoot); + + // biasMap is a map of: + // "AND2T" -> { top = [95], bottom = [] } + // "OR2T" -> { top = [85], bottom = [] } + // etc. + for(const auto &cellItem : biasMap){ + const std::string &logicalName = cellItem.first; // e.g. "AND2T" + const toml::value &sub = cellItem.second; + + // We use the first entry of "top" as the x-offset (in microns) + std::vector topVec; + try { + topVec = toml::find>(sub, "top"); + } + catch(const std::out_of_range &){ + // no "top" array; skip this cell + continue; + } + + if(topVec.empty()){ + continue; + } + int xCoord = topVec[0]; + + // Map logical name -> actual GDS main structure name, if available + std::string gdsName = logicalName; + auto itMap = this->lef2gdsNames.find(logicalName); + if(itMap != this->lef2gdsNames.end()){ + gdsName = itMap->second; // e.g. "LSmitll_AND2T_v2p1" + } + + this->GateBiasCorX[gdsName] = xCoord; + } + /*************************************************************************** ************************** Fill Parameters ******************************** ***************************************************************************/ const auto &Para = toml::find(mainConfig, "Parameters"); + + // Units from config (double) + this->cfgUnits = toml::find(Para, "configFileUnits"); // e.g., 1e-6 + this->gdsUnits = toml::find(Para, "gdsUnits"); // e.g., 1e-9 + this->U = this->cfgUnits / this->gdsUnits; // e.g., 1000.0 auto element = toml::find(Para, "fill"); this->fillEnable = toml::get(element); @@ -94,13 +215,32 @@ int chipSmith::importData(const string &lefFileName, const string &defFileName, this->fillCor = toml::get>(element); element = toml::find(Para, "gateHeights"); - this->gateHeight = toml::get(element) * 1000; + this->gateHeight = toGDSi(toml::get(element)); element = toml::find(Para, "PTLwidth"); - this->PTLwidth = toml::get(element) * 1000; + this->PTLwidth = toGDSi(toml::get(element)); + + // NEW: bias line widths (default to PTLwidth if not present) + this->mainBiasLineWidth = this->PTLwidth; + this->biasBranchWidth = this->PTLwidth; + + try { + element = toml::find(Para, "mainBiasLineWidth"); + this->mainBiasLineWidth = toGDSi(toml::get(element)); + } + catch(const std::exception&) { + // keep default = PTLwidth + } + + try { + element = toml::find(Para, "biasBranchWidth"); + this->biasBranchWidth = toGDSi(toml::get(element)); + } + catch(const std::exception&) { + // keep default = PTLwidth + } - element = toml::find(Para, "gridSize"); - this->gridSize = toml::get(element); + this->gridSize = toml::get(toml::find(Para, "gridSize"));; gridLX = (fillCor[2] - fillCor[0])/this->gridSize; gridLY = (fillCor[3] - fillCor[1])/this->gridSize; @@ -152,8 +292,8 @@ int chipSmith::placeGates(){ for(auto &itComps: defFile.comps){ GDSdefSTR.SREF.push_back(drawSREF(this->lef2gdsNames[itComps.getCompType()], - itComps.getCorX() * 10, - itComps.getCorY() * 10)); + itComps.getCorX() * this->gridSize, + itComps.getCorY() * this->gridSize)); } gdsF.setSTR(GDSdefSTR); @@ -194,25 +334,72 @@ int chipSmith::placeNets(){ corY.clear(); for(unsigned int i = 0; i < itPath.ptX.size(); i++){ - corX.push_back(itPath.ptX[i] * 10); - corY.push_back(itPath.ptY[i] * 10); + corX.push_back(itPath.ptX[i] * this->gridSize); + corY.push_back(itPath.ptY[i] * this->gridSize); } - if(!itPath.LAYER.compare("metal1")){ - GDSroute.PATH.push_back(drawPath(10, this->PTLwidth, corX, corY)); + // Map DEF route layer to a GDS layer using config + std::string defLayer = itPath.LAYER; // e.g. "M1", "M3", "metal1", ... + std::string canonical = defLayer; + + // Optional translation via [LAYER_LOOKUP] + auto itL = this->layerLookup.find(defLayer); + if(itL != this->layerLookup.end()){ + canonical = itL->second; // e.g. "metal1" -> "M1" } - else if(!itPath.LAYER.compare("metal2")){ - GDSroute.PATH.push_back(drawPath(30, this->PTLwidth, corX, corY)); + + // Now map canonical metal name to GDS layer via [METALLAYER_GDSLAYER] + auto itG = this->metalLayerGds.find(canonical); + if(itG == this->metalLayerGds.end()){ + std::cout << "Warning: no GDS mapping for DEF layer \"" + << defLayer << "\" (canonical \"" << canonical + << "\"); skipping route segment." << std::endl; + continue; } + + int gdsLayer = itG->second; // e.g. 10 for M1, 30 for M3 + + GDSroute.PATH.push_back(drawPath(gdsLayer, this->PTLwidth, corX, corY)); } } /** * VIAS + * + * We assume each boundary between two consecutive route segments + * that are on different layers needs a via. */ - for(auto &itNet: this->defFile.nets){ - for(int i = 0; i < itNet.routes.size() -1; i++){ - GDSvia.SREF.push_back(drawSREF("ViaM1M3", itNet.routes[i].ptX.back() * 10, itNet.routes[i].ptY.back() * 10)); + if(itNet.routes.size() < 2){ + continue; + } + + for(std::size_t i = 0; i + 1 < itNet.routes.size(); ++i){ + auto &seg = itNet.routes[i]; + auto &next = itNet.routes[i+1]; + + if(seg.ptX.empty() || seg.ptY.empty()){ + continue; + } + + // Logical layer names as they appear in the DEF, e.g. "M1", "M3" + std::string fromLayer = seg.LAYER; + std::string toLayer = next.LAYER; + + // Default via cell name + std::string viaCell = "ViaM1M3"; + + // Try to look up a more specific via cell using VIA_STRATEGY + auto itFrom = this->viaStrategy.find(fromLayer); + if(itFrom != this->viaStrategy.end()){ + auto itTo = itFrom->second.find(toLayer); + if(itTo != itFrom->second.end()){ + viaCell = itTo->second; + } + } + + int vx = seg.ptX.back() * this->gridSize; + int vy = seg.ptY.back() * this->gridSize; + GDSvia.SREF.push_back(drawSREF(viaCell, vx, vy)); } } @@ -285,17 +472,20 @@ int chipSmith::placeFill(){ // cout << "N: " << comps.name << " " << comps.xCor << ", " << comps.yCor << endl; - int x_0 = (comps.xCor) - (fillCor[0] *1000) + (this->cellSizes[comps.name][0]); - int y_0 = (comps.yCor) - (fillCor[1] *1000) + (this->cellSizes[comps.name][1]); - int x_1 = (comps.xCor) - (fillCor[0] *1000) + (this->cellSizes[comps.name][2]); - int y_1 = (comps.yCor) - (fillCor[1] *1000) + (this->cellSizes[comps.name][3]); + int x_0 = (comps.xCor) - toGDSi(fillCor[0]) + (this->cellSizes[comps.name][0]); + int y_0 = (comps.yCor) - toGDSi(fillCor[1]) + (this->cellSizes[comps.name][1]); + int x_1 = (comps.xCor) - toGDSi(fillCor[0]) + (this->cellSizes[comps.name][2]); + int y_1 = (comps.yCor) - toGDSi(fillCor[1]) + (this->cellSizes[comps.name][3]); // cout << "x_1, y_1; x_2, y_2: " << x_0 << ", " << y_0 << "; "<< x_1 << ", " << y_1 << endl; + + // size of one grid cell in GDS ints + const double cell_in_gds = toGDSi(this->gridSize); // e.g., 1000 * 10 = 10000 - x_0 = constrain(x_0 / 10000, 0, gridLX); - y_0 = constrain(y_0 / 10000, 0, gridLY); - x_1 = constrain(x_1 / 10000, 0, gridLX); - y_1 = constrain(y_1 / 10000, 0, gridLY); + x_0 = constrain((int)std::floor(x_0 / toGDSi(this->gridSize)), 0, gridLX); + y_0 = constrain((int)std::floor(y_0 / toGDSi(this->gridSize)), 0, gridLY); + x_1 = constrain((int)std::floor(x_1 / toGDSi(this->gridSize)), 0, gridLX); + y_1 = constrain((int)std::floor(y_1 / toGDSi(this->gridSize)), 0, gridLY); for(unsigned int i = x_0; i < x_1; i++){ @@ -350,15 +540,15 @@ int chipSmith::placeFill(){ */ for(const auto &vias: this->gdsF.STR[viaIndex].SREF){ - int x_0 = (vias.xCor) - (fillCor[0] *1000) + (viaSize[0]); - int y_0 = (vias.yCor) - (fillCor[1] *1000) + (viaSize[1]); - int x_1 = (vias.xCor) - (fillCor[0] *1000) + (viaSize[2]); - int y_1 = (vias.yCor) - (fillCor[1] *1000) + (viaSize[3]); + int x_0 = (vias.xCor) - toGDSi(fillCor[0]) + (viaSize[0]); + int y_0 = (vias.yCor) - toGDSi(fillCor[1]) + (viaSize[1]); + int x_1 = (vias.xCor) - toGDSi(fillCor[0]) + (viaSize[2]); + int y_1 = (vias.yCor) - toGDSi(fillCor[1]) + (viaSize[3]); - x_0 = constrain(round((float)x_0 / 10000), 0, gridLX); - y_0 = constrain(round((float)y_0 / 10000), 0, gridLY); - x_1 = constrain(round((float)x_1 / 10000), 0, gridLX); - y_1 = constrain(round((float)y_1 / 10000), 0, gridLY); + x_0 = constrain(round((float)x_0 / toGDSi(this->gridSize)), 0, gridLX); + y_0 = constrain(round((float)y_0 / toGDSi(this->gridSize)), 0, gridLY); + x_1 = constrain(round((float)x_1 / toGDSi(this->gridSize)), 0, gridLX); + y_1 = constrain(round((float)y_1 / toGDSi(this->gridSize)), 0, gridLY); for(unsigned int i = x_0; i < x_1; i++){ for(unsigned int j = y_0; j < y_1; j++){ @@ -402,17 +592,17 @@ int chipSmith::placeFill(){ for(unsigned int i = 0; i < path.xCor.size() -1; i++){ - int x_0 = (path.xCor[i]) - (fillCor[0] *1000); - int y_0 = (path.yCor[i]) - (fillCor[1] *1000); - int x_1 = (path.xCor[i+1]) - (fillCor[0] *1000); - int y_1 = (path.yCor[i+1]) - (fillCor[1] *1000); + int x_0 = (path.xCor[i]) - toGDSi(fillCor[0]); + int y_0 = (path.yCor[i]) - toGDSi(fillCor[1]); + int x_1 = (path.xCor[i+1]) - toGDSi(fillCor[0]); + int y_1 = (path.yCor[i+1]) - toGDSi(fillCor[1]); // cout << "[" << path.layer/10 << "]: " << x_0 << ", " << y_0 << "; "<< x_1 << ", " << y_1 << endl; - x_0 /= 10000; - y_0 /= 10000; - x_1 /= 10000; - y_1 /= 10000; + x_0 /= toGDSi(this->gridSize); + y_0 /= toGDSi(this->gridSize); + x_1 /= toGDSi(this->gridSize); + y_1 /= toGDSi(this->gridSize); if(x_0 == x_1){ //vertical @@ -487,17 +677,17 @@ int chipSmith::placeFill(){ // cout << "N: " << comps.name << " " << comps.xCor << ", " << comps.yCor << endl; - int x_0 = (comps.xCor) - (fillCor[0] *1000) + (this->cellSizes[comps.name][0]); - int y_0 = (comps.yCor) - (fillCor[1] *1000) + (this->cellSizes[comps.name][1]); - int x_1 = (comps.xCor) - (fillCor[0] *1000) + (this->cellSizes[comps.name][2]); - int y_1 = (comps.yCor) - (fillCor[1] *1000) + (this->cellSizes[comps.name][3]); + int x_0 = (comps.xCor) - toGDSi(fillCor[0]) + (this->cellSizes[comps.name][0]); + int y_0 = (comps.yCor) - toGDSi(fillCor[1]) + (this->cellSizes[comps.name][1]); + int x_1 = (comps.xCor) - toGDSi(fillCor[0]) + (this->cellSizes[comps.name][2]); + int y_1 = (comps.yCor) - toGDSi(fillCor[1]) + (this->cellSizes[comps.name][3]); // cout << "x_1, y_1; x_2, y_2: " << x_0 << ", " << y_0 << "; "<< x_1 << ", " << y_1 << endl; - x_0 = constrain(x_0 / 10000, 0, gridLX); - y_0 = constrain(y_0 / 10000, 0, gridLY); - x_1 = constrain(x_1 / 10000, 0, gridLX); - y_1 = constrain(y_1 / 10000, 0, gridLY); + x_0 = constrain(x_0 / toGDSi(this->gridSize), 0, gridLX); + y_0 = constrain(y_0 / toGDSi(this->gridSize), 0, gridLY); + x_1 = constrain(x_1 / toGDSi(this->gridSize), 0, gridLX); + y_1 = constrain(y_1 / toGDSi(this->gridSize), 0, gridLY); for(unsigned int i = x_0; i < x_1; i++){ for(unsigned int j = y_0; j < y_1; j++){ @@ -525,17 +715,17 @@ int chipSmith::placeFill(){ for(unsigned int i = 0; i < path.xCor.size() -1; i++){ - int x_0 = (path.xCor[i]) - (fillCor[0] *1000); - int y_0 = (path.yCor[i]) - (fillCor[1] *1000); - int x_1 = (path.xCor[i+1]) - (fillCor[0] *1000); - int y_1 = (path.yCor[i+1]) - (fillCor[1] *1000); + int x_0 = (path.xCor[i]) - toGDSi(fillCor[0]); + int y_0 = (path.yCor[i]) - toGDSi(fillCor[1]); + int x_1 = (path.xCor[i+1]) - toGDSi(fillCor[0]); + int y_1 = (path.yCor[i+1]) - toGDSi(fillCor[1]); // cout << "[" << path.layer/10 << "]: " << x_0 << ", " << y_0 << "; "<< x_1 << ", " << y_1 << endl; - x_0 /= 10000; - y_0 /= 10000; - x_1 /= 10000; - y_1 /= 10000; + x_0 /= toGDSi(this->gridSize); + y_0 /= toGDSi(this->gridSize); + x_1 /= toGDSi(this->gridSize); + y_1 /= toGDSi(this->gridSize); if(x_0 == x_1){ //vertical @@ -601,7 +791,7 @@ int chipSmith::placeFill(){ for(unsigned int x = 0; x < grid[i].size(); x++){ for(unsigned int y = 0; y < grid[i][x].size(); y++){ if(this->grid[i][x][y] == true){ - GDSfil[i].SREF.push_back(drawSREF(gdsFillName[i], (fillCor[0] * 1000) + (x*10000), (fillCor[1] * 1000) + (y*10000))); + GDSfil[i].SREF.push_back(drawSREF(gdsFillName[i], toGDSi(fillCor[0]) + (x*toGDSi(this->gridSize)), toGDSi(fillCor[1]) + (y*toGDSi(this->gridSize)))); } } } @@ -636,7 +826,7 @@ int chipSmith::placeBias(){ set rowCor; // y-coordinates - int setOffset = 5000 + (this->gateHeight); + int setOffset = toGDSi(this->gridSize) / 2 + (this->gateHeight); for(const auto &itSTR: this->gdsF.STR[compIndex].SREF){ rowCor.insert(itSTR.yCor + setOffset); @@ -678,8 +868,8 @@ int chipSmith::placeBias(){ } } - colCorMin -= gridSize *1000 / 2; - colCorMax += gridSize *1000 / 2; + colCorMin -= toGDSi(gridSize) / 2; + colCorMax += toGDSi(gridSize) / 2; // cout << "Left most coordinate: " << colCorMin / 1000 << endl; // cout << "Right most coordinate: " << colCorMax / 1000 << endl; @@ -701,7 +891,7 @@ int chipSmith::placeBias(){ for(setIt = rowCor.begin(); setIt != rowCor.end(); setIt++){ corY.push_back(*setIt); corY.push_back(*setIt); - GDSbias.PATH.push_back(drawPath(50, this->PTLwidth, corX, corY)); + GDSbias.PATH.push_back(drawPath(50, this->mainBiasLineWidth, corX, corY)); corY.clear(); } @@ -714,12 +904,12 @@ int chipSmith::placeBias(){ corX.push_back(colCorMin); corY.push_back(*setIt); corY.push_back(*setIt2); - GDSbias.PATH.push_back(drawPath(50, this->PTLwidth, corX, corY)); + GDSbias.PATH.push_back(drawPath(50, this->mainBiasLineWidth, corX, corY)); corX.clear(); corX.push_back(colCorMax); corX.push_back(colCorMax); - GDSbias.PATH.push_back(drawPath(50, this->PTLwidth, corX, corY)); + GDSbias.PATH.push_back(drawPath(50, this->mainBiasLineWidth, corX, corY)); /*************************************************************************** *********************** Connecting Gate to Main Grid ********************** @@ -731,11 +921,11 @@ int chipSmith::placeBias(){ } corX.clear(); corY.clear(); - corX.push_back(itSTR.xCor + (this->GateBiasCorX[itSTR.name] * 1000)); - corX.push_back(itSTR.xCor + (this->GateBiasCorX[itSTR.name] * 1000)); - corY.push_back(itSTR.yCor + this->gateHeight + (gridSize * 500)); - corY.push_back(itSTR.yCor + this->gateHeight - (gridSize * 500)); - GDSbias.PATH.push_back(drawPath(50, this->PTLwidth, corX, corY)); + corX.push_back(itSTR.xCor + (this->toGDSi(GateBiasCorX[itSTR.name]))); + corX.push_back(itSTR.xCor + (this->toGDSi(GateBiasCorX[itSTR.name]))); + corY.push_back(itSTR.yCor + this->gateHeight + toGDSi(gridSize)/2); + corY.push_back(itSTR.yCor + this->gateHeight - toGDSi(gridSize)/2); + GDSbias.PATH.push_back(drawPath(50, this->biasBranchWidth, corX, corY)); } this->gdsF.setSTR(GDSbias); @@ -789,20 +979,20 @@ int chipSmith::importGates(){ GDSlefSTR.BOUNDARY.push_back(draw2ptBox(10, 0, 0, - this->lefFile.macros[mactoIndex].getSizeX() * 1000, - this->lefFile.macros[mactoIndex].getSizeY() * 1000)); + this->toGDSi(lefFile.macros[mactoIndex].getSizeX()), + this->toGDSi(lefFile.macros[mactoIndex].getSizeY()))); GDSlefSTR.BOUNDARY.push_back(draw2ptBox(30, 0, 0, - this->lefFile.macros[mactoIndex].getSizeX() * 1000, - this->lefFile.macros[mactoIndex].getSizeY() * 1000)); + this->toGDSi(lefFile.macros[mactoIndex].getSizeX()), + this->toGDSi(lefFile.macros[mactoIndex].getSizeY()))); } else{ GDSlefSTR.BOUNDARY.push_back(draw2ptBox(200, 0, 0, - this->lefFile.macros[mactoIndex].getSizeX() * 1000, - this->lefFile.macros[mactoIndex].getSizeY() * 1000)); + this->toGDSi(lefFile.macros[mactoIndex].getSizeX()), + this->toGDSi(lefFile.macros[mactoIndex].getSizeY()))); } gdsF.setSTR(GDSlefSTR); } @@ -833,7 +1023,7 @@ int chipSmith::importGates(){ this->gdsF.calculate_STR_bounding_box(i, bar); for(unsigned int j = 0; j < 4; j++){ - foo[j] = round(((float)bar[j])/10000)*10000; + foo[j] = round(((float)bar[j])/toGDSi(this->gridSize))*toGDSi(this->gridSize); } this->cellSizes.insert(pair>(this->lef2gdsNames[itGates], foo)); diff --git a/src/chipsmith/main.cpp b/src/chipsmith/main.cpp index ac11a6b..a114b0f 100644 --- a/src/chipsmith/main.cpp +++ b/src/chipsmith/main.cpp @@ -13,12 +13,13 @@ #include //string goodies #include #include +#include // add this // #include "chipsmith/genFunc.hpp" #include "chipsmith/toolFlow.hpp" #include "toml/toml.hpp" -#define versionNo 0.1 +#define versionNo 0.2 #define configFile "config.toml" using namespace std; @@ -37,7 +38,7 @@ int RunToolFromConfig(string fileName); */ int main(int argc, char* argv[]){ - // welcomeScreen(); + //welcomeScreen(); if(!RunTool(argc, argv)) return 0; return 0; @@ -124,7 +125,7 @@ int RunTool(int argCount, char** argValues){ */ int RunToolFromConfig(string fileName){ - cout << "Importing execution parameters from config.toml" << endl; + cout << "Importing execution parameters from \"" << fileName << "\"" << endl; const auto mainConfig = toml::parse(fileName); map run_para = toml::get>(mainConfig.at("File_Location")); @@ -171,7 +172,7 @@ int RunToolFromConfig(string fileName){ if(!command.compare("g")){ if(defFName.compare("\0") && gdsFName.compare("\0") && lefFName.compare("\0")){ - forgeChip(lefFName, defFName, gdsFName, configFile); + forgeChip(lefFName, defFName, gdsFName, fileName); return 0; } else{ diff --git a/src/gdscpp/gdsCpp.cpp b/src/gdscpp/gdsCpp.cpp index 5efcb70..9f5a0d8 100644 --- a/src/gdscpp/gdsCpp.cpp +++ b/src/gdscpp/gdsCpp.cpp @@ -11,6 +11,7 @@ // ========================= Includes ========================= #include "gdscpp/gdsCpp.hpp" +#include // ====================== Miscellanious ======================= using namespace std;