Skip to content

Commit

Permalink
Merge pull request #95 from efabless/new-substitution
Browse files Browse the repository at this point in the history
New substitution format and other improvements
  • Loading branch information
mole99 authored Aug 13, 2024
2 parents 051aeea + f8d9dee commit b5701e4
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 34 deletions.
10 changes: 10 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion cace/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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='')
23 changes: 19 additions & 4 deletions cace/common/cace_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down
10 changes: 7 additions & 3 deletions cace/common/cace_regenerate.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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?
Expand Down Expand Up @@ -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:
Expand All @@ -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',
Expand All @@ -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
Expand Down
36 changes: 26 additions & 10 deletions cace/parameter/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}

Expand Down Expand Up @@ -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}.')
Expand Down Expand Up @@ -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 = []
Expand Down
32 changes: 16 additions & 16 deletions docs/source/reference_manual/template_format.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit b5701e4

Please sign in to comment.