Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable cell-level multiprocessing #19

Merged
merged 10 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
339 changes: 17 additions & 322 deletions CharLib.py

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ all: osu350 gf180

osu350: CharLib.py test/osu350/osu350.yml
$(shell test/osu350/fetch_spice.sh)
python3 CharLib.py -l test/osu350
python3 CharLib.py test/osu350

gf180: CharLib.py test/gf180/gf180.yml
$(shell test/gf180/fetch_spice.sh)
python3 CharLib.py -l test/gf180
python3 CharLib.py test/gf180

clean:
rm -rf __pycache__
Expand Down
64 changes: 29 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,44 @@
# CharLib
# CharLib: An open-source standard cell library characterizer

## Introduction
CharLib is an open cell library characterizer originally based on [3]. The current version supports timing and power characterization of combinational and sequential cells. We are currently working on expanding the characterization profile as well as scope of parameters.

CharLib uses the OSU 0.35um SCMOS library for testing. This will be expanded to SKY130 and GF180 at a later date.

## Dependencies
CharLib uses a lightly customized version of PySpice. PySpice is compatible with ngspice and Xyce simulators; you should make sure you have one of those installed to use CharLib. CharLib defaults to the ngspice simulator, but this can be changed using the `simulator` YAML key or the `set_simulator` command.

Install information can be found at the links below:
* [ngspice](https://ngspice.sourceforge.io/download.html)
* [Xyce](https://xyce.sandia.gov/)

CharLib supports all PySpice simulator options. Available options can be found [here on the PySpice FAQ](https://pyspice.fabrice-salvaire.fr/releases/latest/faq.html#how-to-set-the-simulator).

## Usage
CharLib has three operating modes:

| Mode | Description |
| ---------------------------- | ----------- |
| Automatic mode (recommended) | Reads a YAML configuration file from the specified directory, then automatically characterizes cells using the provided settings. |
| Batchfile mode | Reads and executes CharLib commands from the specified batch file. |
| Shell mode (default) | Provides a command-line interface to execute CharLib commands one at a time. |

Using CharLib in shell or batchfile mode is a very manual process: you enter commands to configure the characterizer and add your standard cells, then execute characterization and export the results.
- 🔩 Supports combinational and sequential cells
- 📈 Plots timing and I/O voltages
- 🧑‍💻 Easy-to-use, with YAML-based configuration
- 🐍 Implemented in Python 3 with a modified PySpice backend
- 🌶️ Compatible with ngspice and Xyce

## Introduction
CharLib is an open cell library characterizer originally based on [libretto](https://github.com/shiniziwa/libretto). The current version supports timing and power characterization of combinational and sequential cells.

### Automatic Mode
Syntax: `python3 CharLib.py -l LIBRARY_PATH`
## Installation
CharLib requires the following dependencies:

Automatic mode scans the specified directory for YAML files with CharLib configuration settings, then characterizes cells based on those settings. Expected key-value pairs and file format are described in [yaml.md](https://github.com/stineje/CharLib/blob/main/docs/yaml.md).
- [Python version 3.9 or newer](https://www.python.org)
- [Our modified version of PySpice](https://github.com/infinitymdm/PySpice)
- A compatible circuit simulator ([ngspice](https://ngspice.sourceforge.io/) or [xyce](https://xyce.sandia.gov/)).

Once the software listed above are installed, clone CharLib and try to run one of our test configurations:

### Batchfile Mode
Syntax: `python3 CharLib.py -b BATCHFILE`
```
$ git clone https://github.com/stineje/CharLib
$ cd CharLib
$ make gf180
```

Batchfile executes a sequence of CharLib commands read in from a text file with one command on each line. Typically these files use the file extension ".cmd". You can include comments by starting a line with "#". See [commands.md](https://github.com/stineje/CharLib/blob/main/docs/commands.md) for detailed information on available CharLib commands and syntax.
A brief script will run to fetch the cell spice files, then you should see the software run characterization for several cells. If everything works as expected, CharLib will produce a liberty file called GF180.lib in the current directory.

## Usage
`./CharLib path/to/library/config/`

### Shell Mode
Syntax: `python3 CharLib.py`
CharLib searches the specified directory for a YAML file containing a valid cell library configuration, then characterizes the specified cells. See [yaml.md](https://github.com/stineje/CharLib/blob/main/docs/yaml.md) for information on constructing a config file.

Shell mode is identical to batchfile mode, but provides a command-line interface for users to enter one command at a time instead of reading a batchfile. See [commands.md](https://github.com/stineje/CharLib/blob/main/docs/commands.md) for detailed information on available CharLib commands and syntax.
The general process for using CharLib is as follows:
1. Acquire SPICE files and transistor models for the cells you want to characterize
2. Write a configuration YAML file for the library
3. Run CharLib

## References
[1] M. Mellor and J. E. Stine, "CharLib: an open-source characterization tool written in Python", 2023. <br>
[2] Synopsys, "What is Library Characterization?", https://www.synopsys.com/glossary/what-is-library-characterization.html, 2023 <br>
[3] S. Nishizawa and T. Nakura, libretto: An Open Cell Timing Characterizer for Open Source VLSI Design, IEICE Transactions on Fundamentals of Electronics, Communications and Computer Sciences, 論文ID 2022VLP0007, [早期公開] 公開日 2022/09/13, Online ISSN 1745-1337, Print ISSN 0916-8508, https://doi.org/10.1587/transfun.2022VLP0007, https://www.jstage.jst.go.jp/article/transfun/advpub/0/advpub_2022VLP0007/_article/-char/ja, <br>
[3] S. Nishizawa and T. Nakura, "libretto: An Open Cell Timing Characterizer for Open Source VLSI Design," IEICE Transactions on Fundamentals of Electronics, Communications and Computer Sciences, 論文ID 2022VLP0007, [早期公開] 公開日 2022/09/13, Online ISSN 1745-1337, Print ISSN 0916-8508, https://doi.org/10.1587/transfun.2022VLP0007, https://www.jstage.jst.go.jp/article/transfun/advpub/0/advpub_2022VLP0007/_article/-char/ja, <br>
[4] I. K. Rachit and M. S. Bhat, "AutoLibGen: An open source tool for standard cell library characterization at 65nm technology," 2008 International Conference on Electronic Design, Penang, Malaysia, 2008, pp. 1-6, doi: 10.1109/ICED.2008.4786726. <br>
[5] E. Salman, A. Dasdan, F. Taraporevala, K. Kucukcakar and E. G. Friedman, "Exploiting Setup-Holt-Time Interdependence in Static Timing Analysis," IEEE Transactions on Computer-Aided Design of Integrated Circuits and Systems, vol. 26, no. 6, pp. 1114-1125, June 2007, doi: 10.1109/TCAD.2006.885834.
115 changes: 77 additions & 38 deletions characterizer/Characterizer.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,90 @@
import shutil
"""Dispatches characterization jobs and manages cell data"""

from liberty.LibrarySettings import LibrarySettings
from multiprocessing import Pool, cpu_count
from pathlib import Path

from liberty.UnitsSettings import UnitsSettings
from liberty.library import Library
from characterizer.TestManager import TestManager, CombinationalTestManager, SequentialTestManager

class Characterizer:
"""Main object of Charlib. Keeps track of settings and cells."""

def __init__(self) -> None:
self.settings = LibrarySettings()
self.cells = []
self.num_files_generated = 0

def __str__(self) -> str:
lines = []
lines.append('Library settings:')
for line in str(self.settings).split('\n'):
lines.append(f' {line}')
lines.append('Cells:')
for cell in self.cells:
for line in str(cell).split('\n'):
lines.append(f' {line}')
return '\n'.join(lines)

def last_cell(self):
"""Get last cell"""
return self.cells[-1]
def __init__(self, **kwargs) -> None:
self.settings = CharacterizationSettings(**kwargs)
self.library = Library(kwargs.get('lib_name'), **kwargs)
self.tests = []

def add_cell(self, name, in_ports, out_ports, functions, **kwargs):
# Create a new logic cell
self.cells.append(CombinationalTestManager(name, in_ports, out_ports, functions, **kwargs))
"""Create a new logic cell test"""
self.tests.append(
CombinationalTestManager(name, in_ports, out_ports, functions, **kwargs)
)

def add_flop(self, name, in_ports, out_ports, clock, flops, functions, **kwargs):
# Create a new sequential cell
self.cells.append(SequentialTestManager(name, in_ports, out_ports, clock, flops, functions, **kwargs))

def initialize_work_dir(self):
if self.settings.run_sim:
# Clear out the old work_dir if it exists
if self.settings.work_dir.exists() and self.settings.work_dir.is_dir():
shutil.rmtree(self.settings.work_dir)
self.settings.work_dir.mkdir()
else:
print("Reusing previous working directory and files")
"""Create a new sequential cell test"""
self.tests.append(
SequentialTestManager(name, in_ports, out_ports, clock, flops, functions, **kwargs)
)

def characterize(self, *cells):
"""Characterize the passed cells, or all cells if none are passed"""
def characterize(self):
"""Characterize all cells"""

# If no target cells were given, characterize all cells
for cell in cells if cells else self.cells:
cell.characterize(self.settings)
if self.settings.use_multithreaded:
num_workers = max(len(self.tests), cpu_count())
with Pool(num_workers) as pool:
cells = pool.map(self.characterize_cell, [*self.tests])
else:
cells = [self.characterize_cell(cell) for cell in self.tests]

# Add cells to the library
[self.library.add_cell(cell) for cell in cells]

return self.library

def characterize_cell(self, cell):
"""Characterize a single cell. Helper for multiprocessing"""
return cell.characterize(self.settings)


class CharacterizationSettings:
"""Container for characterization settings"""
def __init__(self, **kwargs):
"""Create a new CharacterizationSettings instance"""
# Behavioral settings
self.simulator = kwargs.pop('simulator', 'ngspice-shared')
self.use_multithreaded = kwargs.pop('multithreaded', True)
self.results_dir = Path(kwargs.pop('results_dir', 'results'))
self.cell_defaults = kwargs.get('cell_defaults', {})

# Units and important voltages
self.units = UnitsSettings(**kwargs.get('units', {}))
nodes = kwargs.pop('named_nodes', {})
self.vdd = NamedNode(**nodes.get('vdd', {'name':'VDD'}))
self.vss = NamedNode(**nodes.get('vss', {'name':'VSS'}))
self.pwell = NamedNode(**nodes.get('pwell', {'name':'VPW'}))
self.nwell = NamedNode(**nodes.get('nwell', {'name':'VNW'}))

# Logic thresholds
logic_thresholds = kwargs.get('logic_thresholds', {})
self.logic_threshold_low = logic_thresholds.get('low', 0.2)
self.logic_threshold_high = logic_thresholds.get('high', 0.8)
self.logic_threshold_high_to_low = logic_thresholds.get('high_to_low', 0.5)
self.logic_threshold_low_to_high = logic_thresholds.get('low_to_high', 0.5)

# Operating conditions
self.temperature = kwargs.get('temperature', 25)


class NamedNode:
"""Binds supply node names to voltages"""
def __init__(self, name, voltage = 0):
self.name = name
self.voltage = voltage

def __str__(self) -> str:
return f'Name: {self.name}\nVoltage: {self.voltage}'

def __repr__(self) -> str:
return f'NamedNode({self.name}, {self.voltage})'
2 changes: 1 addition & 1 deletion characterizer/Harness.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import numpy as np
from PySpice.Unit import *

from liberty.export import Pin
from liberty.cell import Pin

@dataclass
class PinTestBinding:
Expand Down
Loading