diff --git a/docs/user/AutoMemories.md b/docs/user/AutoMemories.md index 4fd8e4bb3a..33d5630eb6 100644 --- a/docs/user/AutoMemories.md +++ b/docs/user/AutoMemories.md @@ -22,22 +22,28 @@ into `$(RESULTS_DIR)/memories_inferred.json`, and | File | Content | | --- | --- | | `$(RESULTS_DIR)/memories.json` | Inventory of every detected memory: geometry, full pin list with pin functions, behavioral model, and whether it was converted (`idiomatic`) with a reason. | -| `$(RESULTS_DIR)/memories/.lib` | Generated Liberty view per converted memory. | -| `$(RESULTS_DIR)/memories/_pre_layout.lib` | Ideal-clock (zero clock-tree insertion) variant for pre-CTS consumers that select lib files themselves. The Makefile flow uses `.lib` throughout. | -| `$(RESULTS_DIR)/memories/.lef` | Abstract LEF per converted memory. | -| `$(RESULTS_DIR)/memories/blackboxes.txt` | ` ` per converted module — what synthesis blackboxes, and the area in um² its `.lib` states, which `SYNTH_MINIMUM_KEEP_SIZE` costs it by. | +| `$(AUTO_MEMORIES_DIR)/.lib` | Generated Liberty view per converted memory. | +| `$(AUTO_MEMORIES_DIR)/_pre_layout.lib` | Ideal-clock (zero clock-tree insertion) variant for pre-CTS consumers that select lib files themselves. The Makefile flow uses `.lib` throughout. | +| `$(AUTO_MEMORIES_DIR)/.lef` | Abstract LEF per converted memory. | +| `$(AUTO_MEMORIES_DIR)/blackboxes.txt` | ` ` per converted module — what synthesis blackboxes, and the area in um² its `.lib` states, which `SYNTH_MINIMUM_KEEP_SIZE` costs it by. | Synthesis (canonicalization) blackboxes the converted modules so the liberty view wins over their behavioral bodies; floorplan through final read the `.lib`/`.lef` of each module `blackboxes.txt` lists, alongside `ADDITIONAL_LIBS`/`ADDITIONAL_LEFS`. Everything downstream keys -off the files above, by the names the lists give: a file in `memories/` -that no list names is not read, and a list that is missing stops the +off the files above, by the names the lists give: a file in +`AUTO_MEMORIES_DIR` that no list names is not read, and a list that is missing stops the step that reads it. Nothing else passes between the generator and the flow. That file-based handoff is what lets build systems (e.g. bazel-orfs) declare the generated artifacts as ordinary stage outputs and transitive dependencies of the remaining stages. +`AUTO_MEMORIES_DIR` defaults to `$(RESULTS_DIR)/memories`. Synthesis +writes the views there and every later stage reads them from there, so a +variant whose stages run on another variant's synthesis, with +`FLOW_INPUT_VARIANT` naming it, reads that variant's memories by setting +`AUTO_MEMORIES_DIR` to its directory for every stage it runs. + Memories that are *not* converted stay in the netlist and synthesize to flip-flops, like any other RTL. diff --git a/docs/user/FlowVariables.md b/docs/user/FlowVariables.md index f26837bce4..9e826e44cf 100644 --- a/docs/user/FlowVariables.md +++ b/docs/user/FlowVariables.md @@ -103,9 +103,10 @@ configuration file. | ADDITIONAL_MEMORIES| Experimental. Space-separated list of user-supplied `.memories` files (the memories.json JSON schema) merged onto the set AUTO_MEMORIES detects — to force-convert a memory the idiomatic gate rejects, or to describe one the scanner cannot find. See docs/user/AutoMemories.md.| | | ADDITIONAL_SITES| Passed as -additional_sites to initialize_floorplan.| | | ASAP7_USE_VT| A space separated list of VT options to use with the ASAP7 standard cell library: RVT, LVT, SLVT.| RVT| -| AUTO_MEMORIES| Experimental. When set to 1, memories that yosys infers in the RTL (`$mem_v2` cells, module boundary only) are detected pre-synthesis, inventoried in `$(RESULTS_DIR)/memories.json`, and — when idiomatic as an SRAM macro — given generated .lib/.lef views under `$(RESULTS_DIR)/memories/`. Synthesis blackboxes those modules and all later stages read the generated views, so an existing design gets macro-based results without a memory compiler. Supported for the asap7 platform only. See docs/user/AutoMemories.md.| 0| +| AUTO_MEMORIES| Experimental. When set to 1, memories that yosys infers in the RTL (`$mem_v2` cells, module boundary only) are detected pre-synthesis, inventoried in `$(RESULTS_DIR)/memories.json`, and — when idiomatic as an SRAM macro — given generated .lib/.lef views under `$(AUTO_MEMORIES_DIR)`. Synthesis blackboxes those modules and all later stages read the generated views, so an existing design gets macro-based results without a memory compiler. Supported for the asap7 platform only. See docs/user/AutoMemories.md.| 0| +| AUTO_MEMORIES_DIR| Directory AUTO_MEMORIES writes its generated views and lists to in synthesis, and every later stage reads them from. Defaults to $(RESULTS_DIR)/memories. Set it to another variant's directory to run stages on that variant's synthesis without copying its memories, with FLOW_INPUT_VARIANT naming the variant the stage input is read from. Like AUTO_MEMORIES, not tied to stages: every step that reads the views needs it, the abstract among them.| | | AUTO_MEMORIES_MACRO_PLACE| Experimental. Space-separated list of module names of AUTO_MEMORIES_REGFILES register files to place as macros, blackboxed in synthesis and placed by the macro placer (and, in `mode netlist`, dissolved after macro placement). A register file not listed is inlined: its generated netlist of standard cells replaces the module's body in synthesis, and its cells are placed, sized and buffered with the rest of the design -- the better shape for a small design, where a macro's outline and channels cost more core than the array saves. A name no spec builds stops the build. Requires AUTO_MEMORIES=1.| | -| AUTO_MEMORIES_REGFILES| Experimental. Space-separated list of register-file spec files, one per RTL module to build as a register file of placed standard cells rather than synthesise to flops. Each spec names its module, words, bits, read and write ports by the RTL's own port names, and the cells. memories/regfile_ram.py checks the spec against the module's ports and has OpenROAD's generate_ram build it as `_ram`, under `$(RESULTS_DIR)/memories/`, with a wrapper in the module's place. A module named in AUTO_MEMORIES_MACRO_PLACE is blackboxed like an AUTO_MEMORIES macro and placed as one; any other is inlined as its generated netlist. A placed spec in `mode netlist` then dissolves into its cells after macro placement: its core FIRM where the macro was placed, in the macro's orientation, its periphery left to placement. Every register file appears in memories.json with kind `regfile`. Requires AUTO_MEMORIES=1.| | +| AUTO_MEMORIES_REGFILES| Experimental. Space-separated list of register-file spec files, one per RTL module to build as a register file of placed standard cells rather than synthesise to flops. Each spec names its module, words, bits, read and write ports by the RTL's own port names, and the cells. memories/regfile_ram.py checks the spec against the module's ports and has OpenROAD's generate_ram build it as `_ram`, under `$(AUTO_MEMORIES_DIR)`, with a wrapper in the module's place. A module named in AUTO_MEMORIES_MACRO_PLACE is blackboxed like an AUTO_MEMORIES macro and placed as one; any other is inlined as its generated netlist. A placed spec in `mode netlist` then dissolves into its cells after macro placement: its core FIRM where the macro was placed, in the macro's orientation, its periphery left to placement. Every register file appears in memories.json with kind `regfile`. Requires AUTO_MEMORIES=1.| | | BALANCE_ROWS| Balance rows during placement.| 0| | BLOCKS| Blocks used as hard macros in a hierarchical flow. Do note that you have to specify block-specific inputs file in the directory mentioned by Makefile.| | | BUFFER_PORTS_ARGS| Specify arguments to the buffer_ports call during placement. Only used if DONT_BUFFER_PORTS=0.| | @@ -151,7 +152,7 @@ configuration file. | FILL_CELLS| Fill cells are used to fill empty sites. If not set or empty, fill cell insertion is skipped.| | | FILL_CONFIG| JSON rule file for metal fill during chip finishing.| | | FLOORPLAN_DEF| Use the DEF file to initialize floorplan. Mutually exclusive with FOOTPRINT or DIE_AREA/CORE_AREA or CORE_UTILIZATION.| | -| FLOW_INPUT_VARIANT| Flow variant a stage reads the previous stage's result from, the .odb and the .sdc beside it. Defaults to FLOW_VARIANT. A variant forked off another sets it to that variant for the first stage it runs, then leaves it at the default: the shared stages run once, and the fork writes only its own results. A stage's later steps read the stage's own results. A stage stops when its input is in both variants. Not with AUTO_MEMORIES=1, whose memories are read from the variant that synthesised them.| | +| FLOW_INPUT_VARIANT| Flow variant a stage reads the previous stage's result from, the .odb and the .sdc beside it. Defaults to FLOW_VARIANT. A variant forked off another sets it to that variant for the first stage it runs, then leaves it at the default: the shared stages run once, and the fork writes only its own results. A stage's later steps read the stage's own results. A stage stops when its input is in both variants. With AUTO_MEMORIES=1, AUTO_MEMORIES_DIR names the memories of the variant that synthesised them, for every stage the fork runs.| | | FLOW_VARIANT| Flow variant to use, used in the flow variant directory name.| base| | FOOTPRINT| Custom footprint definition file for ICeWall-based floorplan initialization. Mutually exclusive with FLOORPLAN_DEF or DIE_AREA/CORE_AREA or CORE_UTILIZATION.| | | FOOTPRINT_TCL| Specifies a Tcl script with custom footprint-related commands for floorplan setup.| | @@ -675,6 +676,7 @@ configuration file. - [ADDITIONAL_LEFS](#ADDITIONAL_LEFS) - [ADDITIONAL_LIBS](#ADDITIONAL_LIBS) - [AUTO_MEMORIES](#AUTO_MEMORIES) +- [AUTO_MEMORIES_DIR](#AUTO_MEMORIES_DIR) - [CAP_MARGIN](#CAP_MARGIN) - [CDL_FILES](#CDL_FILES) - [CORNER](#CORNER) diff --git a/flow/Makefile b/flow/Makefile index 8ac020b6c5..9c0c0084f6 100644 --- a/flow/Makefile +++ b/flow/Makefile @@ -205,7 +205,7 @@ do-klayout: --output $(OBJECTS_DIR)/klayout.lyt \ --lef-files $(OBJECTS_DIR)/klayout_tech.lef $(SC_LEF) $(ADDITIONAL_LEFS) \ --map-files $(wildcard $(FLOW_HOME)/platforms/$(PLATFORM)/*map) \ - $(if $(filter 1,$(AUTO_MEMORIES)),--blackboxes $(RESULTS_DIR)/memories/blackboxes.txt) + $(if $(filter 1,$(AUTO_MEMORIES)),--blackboxes $(AUTO_MEMORIES_DIR)/blackboxes.txt) $(OBJECTS_DIR)/klayout_wrap.lyt: $(KLAYOUT_TECH_FILE) $(OBJECTS_DIR)/klayout_tech.lef $(UNSET_AND_MAKE) do-klayout_wrap @@ -258,6 +258,11 @@ yosys-dependencies: $(YOSYS_DEPENDENCIES) # AUTO_MEMORIES: detect memories in the RTL pre-synthesis and generate # .lib/.lef macro views for them. Experimental; see # docs/user/AutoMemories.md. +# +# Non-empty when AUTO_MEMORIES_DIR is this variant's own directory, the +# default, however it is spelled; empty when it names another variant's. +AUTO_MEMORIES_DIR_IS_OWN = $(filter $(abspath $(RESULTS_DIR)/memories),$(abspath $(AUTO_MEMORIES_DIR))) + ifeq ($(AUTO_MEMORIES),1) $(RESULTS_DIR)/memories_inferred.json: $(VERILOG_FILES) $(SCRIPTS_DIR)/memories/extract_memories.tcl mkdir -p $(RESULTS_DIR) $(LOG_DIR) @@ -270,7 +275,7 @@ do-auto-memories: $(RESULTS_DIR)/memories_inferred.json --platform $(PLATFORM) \ --top $(DESIGN_NAME) \ --yosys-json $(RESULTS_DIR)/memories_inferred.json \ - --out-dir $(RESULTS_DIR)/memories \ + --out-dir $(AUTO_MEMORIES_DIR) \ --json $(RESULTS_DIR)/memories.json \ $(foreach file,$(ADDITIONAL_MEMORIES),--memories $(file)) \ $(foreach file,$(AUTO_MEMORIES_REGFILES),--regfile-spec $(file)) \ @@ -285,8 +290,13 @@ $(RESULTS_DIR)/memories.json: $(RESULTS_DIR)/memories_inferred.json $(ADDITIONAL yosys-dependencies: $(RESULTS_DIR)/memories.json $(RESULTS_DIR)/1_1_yosys_canonicalize.rtlil: $(RESULTS_DIR)/memories.json # The generated LEFs are part of the KLayout technology the GDS merge -# reads the final DEF with. +# reads the final DEF with. Memories another variant generated +# (AUTO_MEMORIES_DIR set) are only read here, never regenerated. +ifneq ($(AUTO_MEMORIES_DIR_IS_OWN),) $(OBJECTS_DIR)/klayout.lyt: $(RESULTS_DIR)/memories.json +else +$(OBJECTS_DIR)/klayout.lyt: $(AUTO_MEMORIES_DIR)/blackboxes.txt +endif endif # OpenROAD stages read binary liberty (.blib) files from a cache shared by @@ -337,7 +347,10 @@ $(RESULTS_DIR)/1_2_yosys.v: $(RESULTS_DIR)/1_1_yosys_canonicalize.rtlil .PHONY: clean_synth clean_synth: rm -f $(RESULTS_DIR)/1_* $(RESULTS_DIR)/mem*.json - rm -rf $(RESULTS_DIR)/memories + # Another variant's memories, read in place, are not this variant's to remove. +ifneq ($(AUTO_MEMORIES_DIR_IS_OWN),) + rm -rf $(AUTO_MEMORIES_DIR) +endif rm -f $(REPORTS_DIR)/synth_* rm -f $(LOG_DIR)/1_* rm -f $(SYNTH_STATS) diff --git a/flow/scripts/load.tcl b/flow/scripts/load.tcl index 5e01c3ead3..f5210fc4e2 100644 --- a/flow/scripts/load.tcl +++ b/flow/scripts/load.tcl @@ -11,10 +11,15 @@ proc load_design { design_file } { # variant FLOW_INPUT_VARIANT names. proc load_stage_input { design_file } { if { $::env(INPUT_RESULTS_DIR) ne $::env(RESULTS_DIR) } { - if { $::env(AUTO_MEMORIES) } { - error "AUTO_MEMORIES=1 reads the memories synthesised in this variant,\ - $::env(FLOW_VARIANT), and FLOW_INPUT_VARIANT=$::env(FLOW_INPUT_VARIANT)\ - reads the design from another" + if { + $::env(AUTO_MEMORIES) + && [file normalize $::env(AUTO_MEMORIES_DIR)] + eq [file normalize $::env(RESULTS_DIR)/memories] + } { + error "AUTO_MEMORIES=1 reads the memories from AUTO_MEMORIES_DIR, this\ + variant's, $::env(FLOW_VARIANT), and FLOW_INPUT_VARIANT=$::env(FLOW_INPUT_VARIANT)\ + reads the design from another. Set AUTO_MEMORIES_DIR to the memories of\ + the variant that synthesised them, for every stage the variant runs." } if { [file exists $::env(RESULTS_DIR)/$design_file] } { error "$design_file is in both FLOW_VARIANT=$::env(FLOW_VARIANT) and\ diff --git a/flow/scripts/regfile_dissolve.tcl b/flow/scripts/regfile_dissolve.tcl index ab0898debc..23a942a48c 100644 --- a/flow/scripts/regfile_dissolve.tcl +++ b/flow/scripts/regfile_dissolve.tcl @@ -99,8 +99,8 @@ if { [llength $regfile_modules] > 0 } { utl::info FLW 9 "register file $module: no instance in the design (removed as dead logic)" continue } - set cells [regfile_netlist "$::env(RESULTS_DIR)/memories/$module.v"] - set place [regfile_place_file "$::env(RESULTS_DIR)/memories/$module.place"] + set cells [regfile_netlist "$::env(AUTO_MEMORIES_DIR)/$module.v"] + set place [regfile_place_file "$::env(AUTO_MEMORIES_DIR)/$module.place"] foreach macro $macros { set path [$macro getName] set parent [$macro getModule] diff --git a/flow/scripts/synth_preamble.tcl b/flow/scripts/synth_preamble.tcl index 1439b46571..d32e9238a7 100644 --- a/flow/scripts/synth_preamble.tcl +++ b/flow/scripts/synth_preamble.tcl @@ -67,7 +67,7 @@ proc read_auto_memories_inline { } { foreach {- name} [regexp -all -inline -- {parameter \\(\S+)} $dump] { setparam -unset $name t:$m } - read_verilog -overwrite "$::env(RESULTS_DIR)/memories/$m.v" + read_verilog -overwrite "$::env(AUTO_MEMORIES_DIR)/$m.v" } } diff --git a/flow/scripts/util.tcl b/flow/scripts/util.tcl index 372bb32fec..75ac048c39 100644 --- a/flow/scripts/util.tcl +++ b/flow/scripts/util.tcl @@ -112,7 +112,7 @@ proc env_var_exists_and_non_empty { env_var } { return [expr { [info exists ::env($env_var)] && ![string equal $::env($env_var) ""] }] } -# AUTO_MEMORIES: do-auto-memories writes into $RESULTS_DIR/memories the +# AUTO_MEMORIES: do-auto-memories writes into $AUTO_MEMORIES_DIR the # lists below, and every later step reads the files they name, never # what a directory happens to hold. # @@ -122,7 +122,7 @@ proc auto_memories_areas { } { if { ![env_var_equals AUTO_MEMORIES 1] } { return {} } - set f "$::env(RESULTS_DIR)/memories/blackboxes.txt" + set f "$::env(AUTO_MEMORIES_DIR)/blackboxes.txt" set fh [open $f r] set content [string map {\r ""} [read $fh]] close $fh @@ -154,7 +154,7 @@ proc auto_memories_names { list } { if { ![env_var_equals AUTO_MEMORIES 1] } { return {} } - set f "$::env(RESULTS_DIR)/memories/$list" + set f "$::env(AUTO_MEMORIES_DIR)/$list" set fh [open $f r] set content [read $fh] close $fh @@ -164,7 +164,7 @@ proc auto_memories_names { list } { # The view of every macro in blackboxes.txt, by extension (.lib, .lef). proc auto_memories_views { ext } { return [lmap m [dict keys [auto_memories_areas]] { - file join $::env(RESULTS_DIR) memories $m$ext + file join $::env(AUTO_MEMORIES_DIR) $m$ext }] } diff --git a/flow/scripts/variables.mk b/flow/scripts/variables.mk index 053937010e..950a93d4f4 100644 --- a/flow/scripts/variables.mk +++ b/flow/scripts/variables.mk @@ -57,6 +57,8 @@ export RESULTS_DIR = $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_ # Where a stage reads the previous stage's result. export FLOW_INPUT_VARIANT ?= $(FLOW_VARIANT) export INPUT_RESULTS_DIR = $(WORK_HOME)/results/$(PLATFORM)/$(DESIGN_NICKNAME)/$(FLOW_INPUT_VARIANT) +# Where AUTO_MEMORIES' generated views are written and read. +export AUTO_MEMORIES_DIR ?= $(RESULTS_DIR)/memories #------------------------------------------------------------------------------- ifeq (,$(strip $(NUM_CORES))) diff --git a/flow/scripts/variables.yaml b/flow/scripts/variables.yaml index d8711fe1ab..6ca1ec3030 100644 --- a/flow/scripts/variables.yaml +++ b/flow/scripts/variables.yaml @@ -183,6 +183,15 @@ SYNTH_USE_SYN: stages: - synth default: 0 +AUTO_MEMORIES_DIR: + description: > + Directory AUTO_MEMORIES writes its generated views and lists to in + synthesis, and every later stage reads them from. Defaults to + $(RESULTS_DIR)/memories. Set it to another variant's directory to run + stages on that variant's synthesis without copying its memories, with + FLOW_INPUT_VARIANT naming the variant the stage input is read from. + Like AUTO_MEMORIES, not tied to stages: every step that reads the + views needs it, the abstract among them. AUTO_MEMORIES: description: > Experimental. When set to 1, memories that yosys infers in the RTL @@ -190,7 +199,7 @@ AUTO_MEMORIES: pre-synthesis, inventoried in `$(RESULTS_DIR)/memories.json`, and — when idiomatic as an SRAM macro — given generated .lib/.lef views under - `$(RESULTS_DIR)/memories/`. Synthesis blackboxes those modules and + `$(AUTO_MEMORIES_DIR)`. Synthesis blackboxes those modules and all later stages read the generated views, so an existing design gets macro-based results without a memory compiler. Supported for the asap7 platform only. See docs/user/AutoMemories.md. @@ -241,7 +250,7 @@ AUTO_MEMORIES_REGFILES: bits, read and write ports by the RTL's own port names, and the cells. memories/regfile_ram.py checks the spec against the module's ports and has OpenROAD's generate_ram build it as `_ram`, under - `$(RESULTS_DIR)/memories/`, with a wrapper in the module's place. A + `$(AUTO_MEMORIES_DIR)`, with a wrapper in the module's place. A module named in AUTO_MEMORIES_MACRO_PLACE is blackboxed like an AUTO_MEMORIES macro and placed as one; any other is inlined as its generated netlist. A placed spec in `mode netlist` then dissolves into @@ -1643,8 +1652,8 @@ FLOW_INPUT_VARIANT: runs, then leaves it at the default: the shared stages run once, and the fork writes only its own results. A stage's later steps read the stage's own results. A stage stops when its input is in both - variants. Not with AUTO_MEMORIES=1, whose memories are read from the - variant that synthesised them. + variants. With AUTO_MEMORIES=1, AUTO_MEMORIES_DIR names the memories + of the variant that synthesised them, for every stage the fork runs. stages: - floorplan - place diff --git a/flow/test/test_def2stream.py b/flow/test/test_def2stream.py index cddfc7951d..9a2815182a 100644 --- a/flow/test/test_def2stream.py +++ b/flow/test/test_def2stream.py @@ -355,19 +355,18 @@ def test_auto_memories_cell_may_be_empty(self): class TestAutoMemoriesCells(unittest.TestCase): def test_off_reads_nothing(self): self.assertEqual( - def2stream.auto_memories_cells({"RESULTS_DIR": "/nonexistent"}), + def2stream.auto_memories_cells({"AUTO_MEMORIES_DIR": "/nonexistent"}), frozenset(), ) def test_names_from_blackboxes_txt(self): - with tempfile.TemporaryDirectory() as results: - os.mkdir(os.path.join(results, "memories")) - with open(os.path.join(results, "memories", "blackboxes.txt"), "w") as f: + with tempfile.TemporaryDirectory() as memories: + with open(os.path.join(memories, "blackboxes.txt"), "w") as f: # a name per line, optionally followed by more columns f.write("tage_entry_sram\nmbtb_entry_sram 491.400000\n\n") self.assertEqual( def2stream.auto_memories_cells( - {"AUTO_MEMORIES": "1", "RESULTS_DIR": results} + {"AUTO_MEMORIES": "1", "AUTO_MEMORIES_DIR": memories} ), frozenset(["tage_entry_sram", "mbtb_entry_sram"]), ) @@ -375,23 +374,25 @@ def test_names_from_blackboxes_txt(self): def test_missing_list_is_an_error(self): # the flow always writes it; a missing list is a broken flow, not # a design without generated macros - with tempfile.TemporaryDirectory() as results: + with tempfile.TemporaryDirectory() as memories: with self.assertRaisesRegex(RuntimeError, "blackboxes.txt is missing"): def2stream.auto_memories_cells( - {"AUTO_MEMORIES": "1", "RESULTS_DIR": results} + {"AUTO_MEMORIES": "1", "AUTO_MEMORIES_DIR": memories} ) - def test_missing_results_dir_is_an_error(self): - with self.assertRaisesRegex(RuntimeError, "RESULTS_DIR is not set"): - def2stream.auto_memories_cells({"AUTO_MEMORIES": "1"}) + def test_missing_auto_memories_dir_is_an_error(self): + # RESULTS_DIR is no stand-in: the memories may be another variant's + with self.assertRaisesRegex(RuntimeError, "AUTO_MEMORIES_DIR is not set"): + def2stream.auto_memories_cells( + {"AUTO_MEMORIES": "1", "RESULTS_DIR": "/nonexistent"} + ) def test_empty_list_allows_nothing(self): - with tempfile.TemporaryDirectory() as results: - os.mkdir(os.path.join(results, "memories")) - open(os.path.join(results, "memories", "blackboxes.txt"), "w").close() + with tempfile.TemporaryDirectory() as memories: + open(os.path.join(memories, "blackboxes.txt"), "w").close() self.assertEqual( def2stream.auto_memories_cells( - {"AUTO_MEMORIES": "1", "RESULTS_DIR": results} + {"AUTO_MEMORIES": "1", "AUTO_MEMORIES_DIR": memories} ), frozenset(), ) diff --git a/flow/util/def2stream.py b/flow/util/def2stream.py index 41f55800d3..ea4afe1362 100644 --- a/flow/util/def2stream.py +++ b/flow/util/def2stream.py @@ -146,10 +146,10 @@ def auto_memories_cells(environ): # do-auto-memories always writes the list, empty when nothing was # converted; without it the merge cannot tell a generated macro from # a cell whose GDS is missing. - results_dir = environ.get("RESULTS_DIR") - if not results_dir: - raise RuntimeError("AUTO_MEMORIES=1 but RESULTS_DIR is not set") - path = os.path.join(results_dir, "memories", "blackboxes.txt") + memories_dir = environ.get("AUTO_MEMORIES_DIR") + if not memories_dir: + raise RuntimeError("AUTO_MEMORIES=1 but AUTO_MEMORIES_DIR is not set") + path = os.path.join(memories_dir, "blackboxes.txt") if not os.path.isfile(path): raise RuntimeError( f"AUTO_MEMORIES=1 but {path} is missing; do-auto-memories writes it"