diff --git a/README.md b/README.md index ef33a70..a435d53 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,29 @@ foundry via open PDKs and shuttle services like ## Devices +### Aegis Luna 1 + +A compact Aegis device targeting GF180MCU via [wafer.space](https://wafer.space) +(1x1 Full slot, 3.93 x 5.12mm die). + +| Resource | Count | +|-------------------|---------------| +| LUT4 | ~760 | +| BRAM (128x8) | 40 tiles | +| DSP18 (18x18 MAC) | 40 tiles | +| I/O pads | 118 | +| SerDes | 1 | +| Clock tiles | 1 (4 outputs) | +| Routing tracks | 1 per edge | + +```bash +nix build .#luna-1 # Generate IP (SV, JSON, chipdb, techmap) +nix build .#luna-1-tapeout # Full RTL-to-GDS for fab submission +``` + ### Aegis Terra 1 -The first Aegis device, targeting GF180MCU via [wafer.space](https://wafer.space). +A larger Aegis device targeting Sky130. | Resource | Count | |-------------------|---------------| diff --git a/devices.nix b/devices.nix new file mode 100644 index 0000000..0c9f8de --- /dev/null +++ b/devices.nix @@ -0,0 +1,42 @@ +{ + aegis-ip-tools, + gf180mcu-pdk, + sky130-pdk, +}: +{ + terra-1 = { + ip = aegis-ip-tools.mkIp { + deviceName = "terra_1"; + width = 48; + height = 64; + tracks = 4; + serdesCount = 4; + bramColumnInterval = 16; + dspColumnInterval = 24; + clockTileCount = 2; + }; + tapeout = { + pdk = sky130-pdk; + clockPeriodNs = 20; + }; + }; + luna-1 = { + ip = aegis-ip-tools.mkIp { + deviceName = "luna_1"; + width = 19; + height = 40; + tracks = 1; + serdesCount = 1; + bramColumnInterval = 9; + dspColumnInterval = 10; + clockTileCount = 1; + }; + tapeout = { + pdk = gf180mcu-pdk; + clockPeriodNs = 20; + dieWidthUm = 3930; + dieHeightUm = 5120; + tilePlacementDensities.SerDesTile = 0.5; + }; + }; +} diff --git a/flake.nix b/flake.nix index e34306f..72153b5 100644 --- a/flake.nix +++ b/flake.nix @@ -80,74 +80,99 @@ sky130-pdk = pkgs.callPackage ./pkgs/sky130-pdk { }; }; - packages = { - default = pkgs.aegis-ip-tools; - ip-tools = pkgs.aegis-ip-tools; - terra-1 = pkgs.aegis-ip-tools.mkIp { - deviceName = "terra_1"; - width = 48; - height = 64; - tracks = 4; - serdesCount = 4; - bramColumnInterval = 16; - dspColumnInterval = 24; - clockTileCount = 2; - }; - terra-1-tapeout = self.packages.${system}.terra-1.mkTapeout { - pdk = pkgs.gf180mcu-pdk; - clockPeriodNs = 20; - }; - terra-1-deb = self.packages.${system}.terra-1.deb; - terra-1-docker = self.packages.${system}.terra-1.docker; - }; + packages = + let + devices = import ./devices.nix { + inherit (pkgs) aegis-ip-tools gf180mcu-pdk sky130-pdk; + }; + + mkDevicePackages = name: cfg: { + "${name}" = cfg.ip; + "${name}-tapeout" = cfg.ip.mkTapeout cfg.tapeout; + "${name}-deb" = cfg.ip.deb; + "${name}-docker" = cfg.ip.docker; + }; + in + { + default = pkgs.aegis-ip-tools; + ip-tools = pkgs.aegis-ip-tools; + } + // lib.foldl' (acc: name: acc // mkDevicePackages name devices.${name}) { } ( + builtins.attrNames devices + ); checks = let - terra-1 = self.packages.${system}.terra-1; + devices = builtins.filter ( + name: + let + pkg = self.packages.${system}.${name}; + in + pkg ? deviceName && !(pkg ? tileMacros) + ) (builtins.attrNames self.packages.${system}); + mkDeviceChecks = + name: + let + ip = self.packages.${system}.${name}; + tapeout = self.packages.${system}."${name}-tapeout"; + in + { + "${name}-blinky" = pkgs.callPackage ./examples/blinky { + aegis-ip = ip; + }; + "${name}-blinky-sim" = pkgs.callPackage ./tests/blinky-sim { + aegis-ip = ip; + }; + "${name}-counter" = pkgs.callPackage ./tests/counter-verify { + aegis-ip = ip; + }; + "${name}-shift-register" = pkgs.callPackage ./tests/shift-register { + aegis-ip = ip; + }; + "${name}-logic-gates" = pkgs.callPackage ./tests/logic-gates { + aegis-ip = ip; + }; + "${name}-tile-bits" = pkgs.callPackage ./tests/tile-bits-consistency { + aegis-ip = ip; + }; + "${name}-synth-equiv-comb" = pkgs.callPackage ./tests/synth-equiv { + aegis-ip = ip; + design = "comb"; + }; + "${name}-synth-equiv-counter" = pkgs.callPackage ./tests/synth-equiv { + aegis-ip = ip; + design = "counter"; + }; + "${name}-formal-ip" = pkgs.callPackage ./tests/formal-ip { + aegis-ip = ip; + }; + "${name}-gds-verify" = pkgs.callPackage ./tests/gds-verify { + aegis-tapeout = tapeout; + }; + }; in - { - terra-1-blinky = pkgs.callPackage ./examples/blinky { - aegis-ip = terra-1; - }; - terra-1-blinky-sim = pkgs.callPackage ./tests/blinky-sim { - aegis-ip = terra-1; - }; - terra-1-counter = pkgs.callPackage ./tests/counter-verify { - aegis-ip = terra-1; - }; - terra-1-shift-register = pkgs.callPackage ./tests/shift-register { - aegis-ip = terra-1; - }; - terra-1-logic-gates = pkgs.callPackage ./tests/logic-gates { - aegis-ip = terra-1; - }; - # Formal verification checks - terra-1-tile-bits = pkgs.callPackage ./tests/tile-bits-consistency { - aegis-ip = terra-1; - }; - terra-1-synth-equiv-comb = pkgs.callPackage ./tests/synth-equiv { - aegis-ip = terra-1; - design = "comb"; - }; - terra-1-synth-equiv-counter = pkgs.callPackage ./tests/synth-equiv { - aegis-ip = terra-1; - design = "counter"; - }; - terra-1-formal-ip = pkgs.callPackage ./tests/formal-ip { - aegis-ip = terra-1; - }; - terra-1-gds-verify = pkgs.callPackage ./tests/gds-verify { - aegis-tapeout = self.packages.${system}.terra-1-tapeout; - }; - }; + lib.foldl' (acc: name: acc // mkDeviceChecks name) { } devices; - devShells = { - default = pkgs.aegis-ip-tools.shell; - ip-tools = pkgs.aegis-ip-tools.shell; - terra-1 = self.packages.${system}.terra-1.shell; - terra-1-tapeout = self.packages.${system}.terra-1-tapeout.shell; - terra-1-blinky = self.checks.${system}.terra-1-blinky.shell; - }; + devShells = + let + devices = builtins.filter ( + name: + let + pkg = self.packages.${system}.${name}; + in + pkg ? deviceName && !(pkg ? tileMacros) + ) (builtins.attrNames self.packages.${system}); + mkDeviceShells = name: { + "${name}" = self.packages.${system}.${name}.shell; + "${name}-tapeout" = self.packages.${system}."${name}-tapeout".shell; + "${name}-blinky" = self.checks.${system}."${name}-blinky".shell; + }; + in + { + default = pkgs.aegis-ip-tools.shell; + ip-tools = pkgs.aegis-ip-tools.shell; + } + // lib.foldl' (acc: name: acc // mkDeviceShells name) { } devices; }; }; } diff --git a/ip/lib/src/openroad/tcl_emitter.dart b/ip/lib/src/openroad/tcl_emitter.dart index 8a2ea27..0c590ed 100644 --- a/ip/lib/src/openroad/tcl_emitter.dart +++ b/ip/lib/src/openroad/tcl_emitter.dart @@ -592,7 +592,10 @@ class OpenroadTclEmitter { // Then place remaining standard cells (glue logic) buf.writeln('# Place remaining standard cells'); - buf.writeln('global_placement -density \$UTILIZATION'); + buf.writeln( + 'if {![info exists PLACEMENT_DENSITY]} { set PLACEMENT_DENSITY 0.1 }', + ); + buf.writeln('global_placement -density \$PLACEMENT_DENSITY'); buf.writeln('detailed_placement'); buf.writeln(); } @@ -642,7 +645,10 @@ class OpenroadTclEmitter { '# Detailed route may fail on offgrid pin shapes from place_pins.', ); buf.writeln('# If it fails, we still have the global-routed DEF.'); - buf.writeln('detailed_route'); + buf.writeln( + 'if {![info exists DROUTE_END_ITER]} { set DROUTE_END_ITER 8 }', + ); + buf.writeln('detailed_route -droute_end_iter \$DROUTE_END_ITER'); buf.writeln(); } diff --git a/ip/lib/src/openroad/tile_tcl_emitter.dart b/ip/lib/src/openroad/tile_tcl_emitter.dart index a75a934..30dea61 100644 --- a/ip/lib/src/openroad/tile_tcl_emitter.dart +++ b/ip/lib/src/openroad/tile_tcl_emitter.dart @@ -101,7 +101,11 @@ class OpenroadTileTclEmitter { buf.writeln(); // Placement - buf.writeln('global_placement -density \$TILE_UTIL'); + buf.writeln( + 'if {![info exists TILE_PLACEMENT_DENSITY]} ' + '{ set TILE_PLACEMENT_DENSITY \$TILE_UTIL }', + ); + buf.writeln('global_placement -density \$TILE_PLACEMENT_DENSITY'); buf.writeln('detailed_placement'); buf.writeln(); diff --git a/pkgs/aegis-tapeout/default.nix b/pkgs/aegis-tapeout/default.nix index e02bee4..afb94d5 100644 --- a/pkgs/aegis-tapeout/default.nix +++ b/pkgs/aegis-tapeout/default.nix @@ -26,6 +26,9 @@ lib.extendMkDerivation { "gridMarginUm" "tileUtilization" "tileDieSizes" + "tilePlacementDensities" + "topPlacementDensity" + "topDetailedRouteIter" ]; extendDrvArgs = @@ -42,6 +45,9 @@ lib.extendMkDerivation { gridMarginUm ? 20, tileUtilization ? 0.85, tileDieSizes ? { }, + tilePlacementDensities ? { }, + topPlacementDensity ? 0.1, + topDetailedRouteIter ? 8, ... }@args: @@ -186,6 +192,9 @@ lib.extendMkDerivation { set TILE_DIE_W ${toString effectiveTileDieSizes.${tileModule}.w} set TILE_DIE_H ${toString effectiveTileDieSizes.${tileModule}.h} ''} + ${lib.optionalString (builtins.hasAttr tileModule tilePlacementDensities) '' + set TILE_PLACEMENT_DENSITY ${toString tilePlacementDensities.${tileModule}} + ''} source ${aegis-ip}/${deviceName}-openroad-${tileModule}.tcl EOF openroad -threads $NIX_BUILD_CORES -exit pnr.tcl 2>&1 | tee openroad.log @@ -318,6 +327,8 @@ lib.extendMkDerivation { set CELL_LIB "${cellLib}" set MACRO_HALO ${toString macroHaloUm} set GRID_MARGIN ${toString gridMarginUm} + set PLACEMENT_DENSITY ${toString topPlacementDensity} + set DROUTE_END_ITER ${toString topDetailedRouteIter} ${lib.optionalString (dieWidthUm != null && dieHeightUm != null) '' set DIE_AREA "0 0 ${toString dieWidthUm} ${toString dieHeightUm}" ''} @@ -352,6 +363,9 @@ lib.extendMkDerivation { "gridMarginUm" "tileUtilization" "tileDieSizes" + "tilePlacementDensities" + "topPlacementDensity" + "topDetailedRouteIter" ] // { inherit name; @@ -461,6 +475,9 @@ lib.extendMkDerivation { gridMarginUm tileUtilization tileDieSizes + tilePlacementDensities + topPlacementDensity + topDetailedRouteIter tileMacros topSynth topPnr