Skip to content

Commit

Permalink
Misc small fixes: Joules, Sky130 srams, A-machines setup (#821)
Browse files Browse the repository at this point in the history
* fixing paths on A machines

* adding more reporting options and documentation

* Create README.md

* Update README.md

* small fix

* all report power commands work

* changed joules tcl name

* different simv names

* small fixes

* adding wmask to all Sram22 SRAMs to match behavioral verilog and pass sim

* time-based analysis turned off when not required to save time

* small e2e tweaks

* fixing paths on A machines

* joules docs update

* reverting vcs file

* reverting vcs file

* added link to joules readme, removed old comment
  • Loading branch information
nayiri-k authored Nov 13, 2023
1 parent 81a1731 commit 7dfbb0b
Show file tree
Hide file tree
Showing 11 changed files with 279 additions and 111 deletions.
1 change: 1 addition & 0 deletions doc/CAD-Tools/Joules.md
1 change: 1 addition & 0 deletions doc/CAD-Tools/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ The package should contain an class object named 'tool' to create an instance of
Hammer-CAD-Tools
Tool-Plugin-Setup
OpenROAD
Joules
ICV
Pegasus
6 changes: 3 additions & 3 deletions e2e/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ TOOLS_CONF ?= configs-tool/$(tools).yml
# design-specific overrides of default configs
DESIGN_CONF ?= configs-design/$(design)/common.yml
DESIGN_PDK_CONF ?= configs-design/$(design)/$(pdk).yml
SIM_CONF ?= $(if $(findstring rtl,$(MAKECMDGOALS)), configs-design/$(design)/sim-rtl.yml, \
$(if $(findstring syn,$(MAKECMDGOALS)), configs-design/$(design)/sim-syn.yml, \
$(if $(findstring par,$(MAKECMDGOALS)), configs-design/$(design)/sim-par.yml, )))
SIM_CONF ?= $(if $(findstring -rtl,$(MAKECMDGOALS)), configs-design/$(design)/sim-rtl.yml, \
$(if $(findstring -syn,$(MAKECMDGOALS)), configs-design/$(design)/sim-syn.yml, \
$(if $(findstring -par,$(MAKECMDGOALS)), configs-design/$(design)/sim-par.yml, )))
POWER_CONF ?= $(if $(findstring power-rtl,$(MAKECMDGOALS)), configs-design/$(design)/power-rtl-$(pdk).yml, \
$(if $(findstring power-syn,$(MAKECMDGOALS)), configs-design/$(design)/power-syn-$(pdk).yml, \
$(if $(findstring power-par,$(MAKECMDGOALS)), configs-design/$(design)/power-par-$(pdk).yml, )))
Expand Down
20 changes: 12 additions & 8 deletions e2e/configs-env/a-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,33 @@ cadence.CDS_LIC_FILE: "[email protected]:[email protected]
cadence.extra_env_vars: [{"LM_PROJECT": "bwrc_users"}]

synopsys.synopsys_home: "/ecad/tools/synopsys"
synopsys.SNPSLMD_LICENSE_FILE: "[email protected]:[email protected]"
synopsys.SNPSLMD_LICENSE_FILE: "[email protected]:[email protected]:[email protected]"
synopsys.MGLS_LICENSE_FILE: "[email protected]:[email protected]"

# Commercial tool versions
synthesis.genus.version: "211"
par.innovus.version: "211"
power.joules.version: "201"
synthesis.genus.genus_bin: "/ecad/tools/cadence/GENUS/GENUS211/bin/genus" # must point to binaries bc Hammer assumes DDI path now
par.innovus.innovus_bin: "/ecad/tools/cadence/INNOVUS/INNOVUS211/bin/innovus"
sim.vcs.version: "P-2019.06-SP1"
sim.vcs.verdi_home: "/ecad/tools/synopsys/verdi/P-2019.06-SP2-2"
power.joules.joules_bin: "/ecad/tools/cadence/JLS/JLS201/bin/joules"
sim.vcs.version: "S-2021.09-SP1-1"
sim.vcs.verdi_home: "/ecad/tools/synopsys/verdi/S-2021.09-SP1-1"
sim.vcs.verdi_home_meta: lazysubst
lvs.calibre.version: "2022.2_24.16"
drc.calibre.version: "2022.2_24.16"

# Open-source tool paths
synthesis.yosys.yosys_bin: "/nscratch/vighneshiyer/miniconda3/envs/sky130/bin/yosys"
par.openroad.openroad_bin: "/nscratch/vighneshiyer/miniconda3/envs/sky130/bin/openroad"
drc.magic.magic_bin: "/nscratch/vighneshiyer/miniconda3/envs/sky130/bin/magic"
lvs.netgen.netgen_bin: "/nscratch/vighneshiyer/miniconda3/envs/sky130/bin/netgen"
synthesis.yosys.yosys_bin: "/nscratch/sky130/conda-yosys/bin/yosys"
par.openroad.openroad_bin: "/nscratch/sky130/conda-openroad/bin/openroad"
par.openroad.klayout_bin: "/nscratch/sky130/conda-klayout/bin/klayout"
drc.klayout.klayout_bin: "/nscratch/sky130/conda-klayout/bin/klayout"
drc.magic.magic_bin: "/nscratch/sky130/conda-signoff/bin/magic"
lvs.netgen.netgen_bin: "/nscratch/sky130/conda-signoff/bin/netgen"

# Sky130 paths
technology.sky130:
sky130A: "/nscratch/vighneshiyer/miniconda3/envs/sky130/share/pdk/sky130A"
sky130A: "/nscratch/sky130/conda-sky130/share/pdk/sky130A"
sram22_sky130_macros: "/nscratch/sky130/sram22_sky130_macros"
# sky130_nda:

Expand Down
5 changes: 3 additions & 2 deletions e2e/configs-env/bwrc-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ drc.klayout.klayout_bin: "/tools/commercial/skywater/local/chipyard-tutorial/.co
drc.magic.magic_bin: "/tools/commercial/skywater/local/chipyard-tutorial/.conda-signoff/bin/magic"
lvs.netgen.netgen_bin: "/tools/commercial/skywater/local/chipyard-tutorial/.conda-signoff/bin/netgen"


# Sky130 paths
technology.sky130:
sky130A: "/tools/scratch/nayiri/sky130/open_pdks/sky130/sky130A"
sram22_sky130_macros: "/tools/commercial/skywater/local/chipyard-tutorial/sram22_sky130_macros"
sky130A: "/tools/commercial/skywater/local/sky130A"
sram22_sky130_macros: "/tools/commercial/skywater/local/sram22_sky130_macros"
openram_lib: "/tools/commercial/skywater/local/sky130_sram_macros"
sky130_nda: "/tools/commercial/skywater/swtech130/skywater-src-nda-20221031"
sky130_cds: "/tools/commercial/skywater/sky130_cds/sky130_prelim_release_091123"
Expand Down
5 changes: 4 additions & 1 deletion hammer/config/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,10 @@ power.inputs:
# Default: waveform file name
# output_formats (List[str]) - Optional. Report types to generate. Default: ["report"]
# Valid options are:
# "report" - average power report (*.rpt), default
# "report" - average power report (*.power.rpt, *.hier.power.rpt), default
# "activity" - design activity during stimulus (*.activity.rpt, *.hier.activity.rpt)
# "ppa" - power, performance, area characteristics of the design (*.ppa.rpt)
# "area" - area report (*.area.rpt)
# "plot_profile" - power profile over time, requires frame-based analysis (*.png, *.png.data)
# "write_profile" - profiles all power types on all categories for all the sub-hierarchies for a given design instance (*.fsdb)
# "profile" - run plot_profile + dump_profile
Expand Down
25 changes: 25 additions & 0 deletions hammer/power/joules/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Cadence Joules RTL Power Tool Plugin
====================================

Tool Steps
----------

See ``__init__.py`` for the implementation of these steps.

init_design
synthesize_design
report_power


A variety of different output reports may be generated with this tool.
Within the [Hammer default configs file](https://github.com/ucb-bar/hammer/blob/joules-fixes/hammer/config/defaults.yml),
the `power.inputs.report_configs` struct description
contains a summary of the different reporting options, specified via the `output_formats` struct field.

Known Issues
------------

* Joules supports saving the read stimulus file to the SDB (stimulus database) format via the `write_sdb` command. However, subsequent reads of this SDB file via the `read_sdb` command fail for no apparent reason
* As a result, `read_stimulus`/`compute_power` cannot be a separate step in the plugin, because there is no way to save the results of these commands before running the various power reporting commands.
Thus these two commands are run as part of the `report_power` step.
* NOTE: this might not be a problem anymore with the new Joules version, so we should re-try this!!
45 changes: 21 additions & 24 deletions hammer/power/joules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import os
import errno
from textwrap import dedent
from datetime import datetime

from hammer.vlsi import HammerPowerTool, HammerToolStep, HammerToolHookAction, HammerTool, \
MMMCCornerType, FlowLevel, PowerReport
Expand Down Expand Up @@ -240,6 +241,9 @@ def report_power(self) -> bool:
# Replace . to / formatting in case argument passed from sim tool
tb_dut = self.tb_dut.replace(".", "/")

# Fixes issues seen with several different reporting commands
self.block_append("read_db pre_report_power")

power_report_configs = []
# create power report config for each waveform
for waveform in self.waveforms:
Expand All @@ -263,7 +267,7 @@ def report_power(self) -> bool:
if report.end_time:
read_stim_cmd += " -end {ETIME}ns".format(ETIME=report.end_time.value_in_units("ns"))

frame_based_analysis = (report.interval_size or (report.toggle_signal and report.num_toggles))
time_based_analysis = (report.interval_size or (report.toggle_signal and report.num_toggles))
if report.interval_size:
read_stim_cmd += " -interval_size {INTERVAL}ns".format(INTERVAL=report.interval_size.value_in_units("ns"))
if report.toggle_signal:
Expand All @@ -280,24 +284,19 @@ def report_power(self) -> bool:

stim_alias, new_stim = self.get_alias_name(read_stim_cmd)

# if new_stim:
# NOTE: only reading new stimuli with -append mode breaks frame-based power analysis
# with error message: "Invalid frame name /stim#2/frame#3. No stimulus read. Using vectorless power computation"
# Interestingly, this does not happen when starting from a database checkpoint (i.e. after read_db pre_report_power)
# For now, re-run read_stimulus for each power report config, even if it's an identical stimulus
block_append(f"{read_stim_cmd} -alias {stim_alias}")
# block_append(f"write_sdb -out {alias}.sdb") # NOTE: subsequent read_sdb command errors when reading this file back in, so don't cache for now
# TODO: avg mode saves time, run this based on output_formats mode?
# block_append(f"compute_power -mode average -stim {stim_alias} -append")
block_append(f"compute_power -mode time_based -stim {stim_alias} -append")
if new_stim:
block_append(f"{read_stim_cmd} -alias {stim_alias} -append")
# block_append(f"write_sdb -out {alias}.sdb") # NOTE: subsequent read_sdb command errors when reading this file back in, so don't cache for now
mode = "time_based" if time_based_analysis else "average"
block_append(f"compute_power -mode {mode} -stim {stim_alias} -append")

# remove only file extension (last .*) in filename
waveform_name = '.'.join(os.path.basename(report.waveform_path).split('.')[0:-1])

inst_str = f"-inst {report.inst}" if report.inst else ""
module_str = f"-module {report.module}" if report.module else ""
levels_str = f"-levels {report.levels}" if report.levels else ""
m_levels_str = levels_str if report.module else ""
m_levels_str = levels_str if (report.module or report.inst) else ""
output_formats = set(report.output_formats) if report.output_formats else {'report'}

report_path = report.report_name if report.report_name else waveform_name
Expand All @@ -313,22 +312,25 @@ def report_power(self) -> bool:
# use set intersection to determine whether two lists have at least one element in common
if {'report','all'} & output_formats:
# -frames $frames explodes the runtime & doesn't seem to change result
self.block_append(f"report_power -stims {stim_alias} {inst_str} {module_str} {levels_str} -unit mW -out {report_path}.power.rpt")
self.block_append(f"report_power -stims {stim_alias} -by_hierarchy {levels_str} -unit mW -out {report_path}.hier.power.rpt")
h_levels_str = "-levels all" if levels_str == "" else levels_str
self.block_append(f"report_power -stims {stim_alias} {inst_str} {module_str} {m_levels_str} -unit mW -out {report_path}.power.rpt")
self.block_append(f"report_power -stims {stim_alias} {inst_str} {module_str} {m_levels_str} -by_hierarchy {h_levels_str} -unit mW -out {report_path}.hier.power.rpt")
if {'activity','all'} & output_formats:
self.block_append(f"report_activity -stims {stim_alias} {inst_str} {module_str} {levels_str} -out {report_path}.activity.rpt")
self.block_append(f"report_activity -stims {stim_alias} -by_hierarchy {levels_str} -out {report_path}.hier.activity.rpt")
if {'ppa','all'} & output_formats:
root_str = inst_str.replace('-inst','-root')
self.block_append(f"report_ppa {root_str} {module_str} -out {report_path}.ppa.rpt")
self.block_append(f"report_ppa {root_str} {module_str} > {report_path}.ppa.rpt")
if {'area','all'} & output_formats:
self.block_append(f"report_area > {report_path}.area.rpt")
if {'plot_profile','profile','all'} & output_formats:
if not frame_based_analysis:
if not time_based_analysis:
self.logger.error("Must specify either interval_size or toggle_signal+num_toggles in power.inputs.report_configs to generate plot_profile report (frame-based analysis).")
return False
# NOTE: we don't include levels_str here bc category is total power anyways
self.block_append(f"plot_power_profile -stims {stim_alias} {inst_str} {module_str} {m_levels_str} -by_category {{total}} -types {{total}} -unit mW -format png -out {report_path}.profile.png")
if {'write_profile','profile','all'} & output_formats:
if not frame_based_analysis:
if not time_based_analysis:
self.logger.error("Must specify either interval_size or toggle_signal+num_toggles in power.inputs.report_configs to generate write_profile report (frame-based analysis).")
return False
block_append(f"write_power_profile -stims {stim_alias} -root [get_insts -rtl_type hier] {levels_str} -unit mW -format fsdb -out {report_path}.profile.fsdb")
Expand All @@ -350,11 +352,8 @@ def run_joules(self) -> bool:

# Create power analysis script
# with unique filename so that multiple runs don't overwrite each others' TCL scripts
i = 0
joules_tcl_filename = os.path.join(self.run_dir, f"joules.{i}.tcl")
while os.path.exists(joules_tcl_filename):
i += 1
joules_tcl_filename = os.path.join(self.run_dir, f"joules.{i}.tcl")
now = datetime.now().strftime("%Y%m%d-%H%M%S")
joules_tcl_filename = os.path.join(self.run_dir, f"joules-{now}.tcl")
self.write_contents_to_path("\n".join(self.output), joules_tcl_filename)

# Make sure that generated-scripts exists.
Expand Down Expand Up @@ -390,8 +389,6 @@ def run_joules(self) -> bool:

self.run_executable(args, cwd=self.run_dir)

shutil.copy2(joules_tcl_filename, os.path.join(self.run_dir, f"joules.tcl"))

HammerVLSILogging.enable_colour = True
HammerVLSILogging.enable_tag = True

Expand Down
8 changes: 4 additions & 4 deletions hammer/technology/sky130/extra/sram22/sram-cache-gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ def main(args: List[str]) -> int:
port_dict['input port name'] = "din"
port_dict['input port polarity'] = "active high"

if mask_gran != width:
port_dict['mask port name'] = "wmask"
port_dict['mask granularity'] = mask_gran
port_dict['mask port polarity'] = "active high" # ???
# if mask_gran != width:
port_dict['mask port name'] = "wmask"
port_dict['mask granularity'] = mask_gran
port_dict['mask port polarity'] = "active high" # ???

sram_dict['ports'].append(port_dict.copy())

Expand Down
Loading

0 comments on commit 7dfbb0b

Please sign in to comment.