diff --git a/Changelog.md b/Changelog.md index 63d3937..a377b31 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,13 @@ +# 2.4.3 + +## Common + +- **New format for CACE substitutions** + - `CACE{condition}` and `CACE[expression]` + - Fallback for datasheet version <= 5.0 +- Export the schematic netlist with `top_is_subckt` enabled, which preserves certain spice parameters. This improves the simulation accuracy compared to layout extracted. +- Fix for layout extraction: Reload the top cell after `readspice` + # 2.4.2 ## Common diff --git a/cace/__version__.py b/cace/__version__.py index b2c2d09..be171fc 100644 --- a/cace/__version__.py +++ b/cace/__version__.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -__version__ = '2.4.2' +__version__ = '2.4.3' if __name__ == '__main__': print(__version__, end='') diff --git a/cace/common/cace_read.py b/cace/common/cace_read.py index f5bd239..485bb61 100755 --- a/cace/common/cace_read.py +++ b/cace/common/cace_read.py @@ -529,6 +529,9 @@ def cace_read_yaml(filename, debug=False): return valdiate_datasheet(datasheet) +CACE_DATASHEET_VERSION = 5.1 + + def valdiate_datasheet(datasheet): # Check for missing field @@ -547,11 +550,23 @@ def valdiate_datasheet(datasheet): # Check if 'cace_format' is a key of the datasheet if not 'cace_format' in datasheet: - warn('No cace_format given, trying to read as 5.0.') - datasheet['cace_format'] = 5.0 + warn( + f'No cace_format given, trying to read as {CACE_DATASHEET_VERSION}.' + ) + datasheet['cace_format'] = CACE_DATASHEET_VERSION else: - if datasheet['cace_format'] != 5.0: - warn('Unsupported format version. Please update to version 5.0.') + if datasheet['cace_format'] != CACE_DATASHEET_VERSION: + warn( + f'Unsupported format version. Please update to version {CACE_DATASHEET_VERSION}.' + ) + warn( + 'More information in the reference manual: [link=https://cace.readthedocs.io/en/latest/reference_manual/index.html]https://cace.readthedocs.io/en/latest/reference_manual/index.html[/link].' + ) + + if datasheet['cace_format'] <= 5.0: + warn( + 'Please convert CACE placeholders from `{condition}` and `\[expression]` to `CACE{condition}` and `CACE\[expression]`.' + ) # Check if 'authorship' is a key of the datasheet if not 'authorship' in datasheet: diff --git a/cace/common/cace_regenerate.py b/cace/common/cace_regenerate.py index 4c3cb15..e1610bf 100755 --- a/cace/common/cace_regenerate.py +++ b/cace/common/cace_regenerate.py @@ -384,6 +384,8 @@ def regenerate_rcx_netlist(datasheet, runtime_options): mproc.stdin.write('load ' + dname + '\n') # Use readspice to get the port order mproc.stdin.write('readspice ' + schem_netlist + '\n') + # necessary after readspice + mproc.stdin.write('load ' + dname + '\n') mproc.stdin.write('select top cell\n') mproc.stdin.write('expand\n') mproc.stdin.write('flatten ' + dname + '_flat\n') @@ -560,6 +562,8 @@ def regenerate_lvs_netlist(datasheet, runtime_options, pex=False): magic_input += f'load {dname}\n' # Use readspice to get the port order magic_input += f'readspice {schem_netlist}\n' + # necessary after readspice + magic_input += f'load {dname}\n' # magic_input += 'select top cell\n' magic_input += f'select {dname}\n' # TODO? @@ -796,7 +800,7 @@ def regenerate_schematic_netlist(datasheet, runtime_options): newenv['PDK'] = pdk """tclstr = set_xschem_paths( - datasheet, schem_netlist_path, 'set lvs_netlist 1' + datasheet, schem_netlist_path, 'set top_is_subckt 1' )""" # Xschem arguments: @@ -805,7 +809,7 @@ def regenerate_schematic_netlist(datasheet, runtime_options): # -r: Bypass readline (because stdin/stdout are piped) # -x: No X11 / No GUI window # -q: Quit after processing command line - # --tcl "set lvs_netlist 1": Require ".subckt ... .ends" wrapper + # --tcl "set top_is_subckt 1": Require ".subckt ... .ends" wrapper xschemargs = [ 'xschem', @@ -815,7 +819,7 @@ def regenerate_schematic_netlist(datasheet, runtime_options): '-x', '-q', '--tcl', - 'set lvs_netlist 1', + 'set top_is_subckt 1', ] # tclstr] # See if there is an xschemrc file in the project we can source diff --git a/cace/parameter/parameter.py b/cace/parameter/parameter.py index 9c41d8c..cdde690 100755 --- a/cace/parameter/parameter.py +++ b/cace/parameter/parameter.py @@ -586,9 +586,15 @@ def get_condition_names_used(self, template, escape=False): # Regular expressions # varex: variable name {name} if escape: - varex = re.compile(r'\\\{([^ \}\t]+)\\\}') + if self.datasheet['cace_format'] <= 5.0: + varex = re.compile(r'\\\{([^ \}\t]+)\\\}') + else: + varex = re.compile(r'CACE\\\{([^ \}\t]+)\\\}') else: - varex = re.compile(r'\{([^ \}\t]+)\}') + if self.datasheet['cace_format'] <= 5.0: + varex = re.compile(r'\{([^ \}\t]+)\}') + else: + varex = re.compile(r'CACE\{([^ \}\t]+)\}') conditions = {} @@ -634,13 +640,23 @@ def substitute( # brackrex: expressions in [expression] format if escape: - varex = re.compile(r'\\\{([^\\\}]+)\\\}') - sweepex = re.compile(r'\\\{([^\\\}]+)\|([^ \\\}]+)\\\}') - brackrex = re.compile(r'\[([^\]]+)\]') + if self.datasheet['cace_format'] <= 5.0: + varex = re.compile(r'\\\{([^\\\}]+)\\\}') + sweepex = re.compile(r'\\\{([^\\\}]+)\|([^ \\\}]+)\\\}') + brackrex = re.compile(r'\[([^\]]+)\]') + else: + varex = re.compile(r'CACE\\\{([^\\\}]+)\\\}') + sweepex = re.compile(r'CACE\\\{([^\\\}]+)\|([^ \\\}]+)\\\}') + brackrex = re.compile(r'CACE\[([^\]]+)\]') else: - varex = re.compile(r'\{([^\}]+)\}') - sweepex = re.compile(r'\{([^\}]+)\|([^ \}]+)\}') - brackrex = re.compile(r'\[([^\]]+)\]') + if self.datasheet['cace_format'] <= 5.0: + varex = re.compile(r'\{([^\}]+)\}') + sweepex = re.compile(r'\{([^\}]+)\|([^ \}]+)\}') + brackrex = re.compile(r'\[([^\]]+)\]') + else: + varex = re.compile(r'CACE\{([^\}]+)\}') + sweepex = re.compile(r'CACE\{([^\}]+)\|([^ \}]+)\}') + brackrex = re.compile(r'CACE\[([^\]]+)\]') if not os.path.isfile(template_path): err(f'Could not find template file {template_path}.') @@ -760,9 +776,9 @@ def brackrex_sub(matchobj): try: return str(safe_eval(expression)) - except (ValueError, SyntaxError): + except: err(f'Invalid expression: {expression}.') - return '' + return matchobj.group(0) # Substitute values substituted_lines = [] diff --git a/docs/source/reference_manual/template_format.md b/docs/source/reference_manual/template_format.md index 84e8faf..fce5c12 100644 --- a/docs/source/reference_manual/template_format.md +++ b/docs/source/reference_manual/template_format.md @@ -1,61 +1,61 @@ # Template Format Schematics are drawn normally but statements can have special syntax -that is substituted by CACE. The syntax follows three essential rules: +that is substituted by CACE. The syntax follows three essential rules: 1. Condition and variable names in the project specification file - are written in the schematic in braces, so "temperature" in the - project file is "{temperature}" in the schematic. + are written in the schematic in braces prefixed with "CACE", so "temperature" in the + project file is "CACE{temperature}" in the schematic. 2. Expressions involving equations using condition and variable - names are written in the schematic in brackets, so, for example, - half of condition vdd would be written "[{vdd} / 2]". These - expressions are evaluated in python, so any python expression + names are written in the schematic in brackets prefixed with "CACE", so, for example, + half of condition vdd would be written "CACE[CACE{vdd} / 2]". These + expressions are evaluated in python, so any arithmetic python expression that evaluates to a valid result may appear inside the brackets. 3. There are a handful of reserved variable names that are automatically substituted by CACE if they appear in the schematic: -- `{filename}` +- `CACE{filename}` > The root name of the schematic file. -- `{simpath}` +- `CACE{simpath}` > The name of the path to simulation files. -- `{random}` +- `CACE{random}` > A random integer number. -- `{DUT_path}` +- `CACE{DUT_path}` > The full path to the DUT subcircuit definition netlist. -- `{DUT_name}` +- `CACECACE{DUT_name}` > The name of the DUT subcircuit -- `{PDK_ROOT}` +- `CACE{PDK_ROOT}` > The path to the directory containing the PDK -- `{PDK}` +- `CACE{PDK}` > The name of the PDK -- `{N}` +- `CACE{N}` > This is substituted with the simulation index. Most often used as a filename suffix for the output data file. -- `{cond=value}` +- `CACE{cond=value}` For any condition cond, this form indicates that "value" is to be subsituted for the condition if the condition is not declared in the CACE project file. -- `{cond|minimum}` `{cond|maximum}` `{cond|stepsize}` `{cond|steps}` +- `CACE{cond|minimum}` `{cond|maximum}` `{cond|stepsize}` `{cond|steps}` > Instead of substituting one value for a condition, a value over all conditions is substituted, including the maximum