This commit is contained in:
David Harris 2022-07-10 03:18:30 +00:00
commit ad92d0876e
10 changed files with 224 additions and 222 deletions

View File

@ -1,14 +1,15 @@
# #
# Makefile for synthesis # Makefile for synthesis
# Shreya Sanghai (ssanghai@hmc.edu) 2/28/2022 # Shreya Sanghai (ssanghai@hmc.edu) 2/28/2022
# Madeleine Masser-Frye (mmasserfrye@hmc.edu) 7/8/2022
NAME := synth NAME := synth
# defaults # defaults
export DESIGN ?= wallypipelinedcore export DESIGN ?= wallypipelinedcore
export FREQ ?= 3000 export FREQ ?= 3000
export CONFIG ?= rv32e export CONFIG ?= rv32e
# title to add a note in the synth's directory name
TITLE = TITLE =
# tsmc28, sky130, and sky90 presently supported # tsmc28, sky130, and sky90 presently supported
export TECH ?= sky90 export TECH ?= sky90
# MAXCORES allows parallel compilation, which is faster but less CPU-efficient # MAXCORES allows parallel compilation, which is faster but less CPU-efficient
@ -21,20 +22,14 @@ export DRIVE ?= FLOP
time := $(shell date +%F-%H-%M) time := $(shell date +%F-%H-%M)
hash := $(shell git rev-parse --short HEAD) hash := $(shell git rev-parse --short HEAD)
export OUTPUTDIR := newRuns/$(DESIGN)_$(CONFIG)_$(TECH)nm_$(FREQ)_MHz_$(time)_$(TITLE)_$(hash) export OUTPUTDIR := runs/$(DESIGN)_$(CONFIG)_$(TECH)nm_$(FREQ)_MHz_$(time)_$(TITLE)_$(hash)
export SAIFPOWER ?= 0 export SAIFPOWER ?= 0
CONFIGDIR ?= ${WALLY}/pipelined/config CONFIGDIR ?= ${WALLY}/pipelined/config
CONFIGFILES ?= $(shell find $(CONFIGDIR) -name rv*_*) CONFIGFILES ?= $(shell find $(CONFIGDIR) -name rv*_*)
CONFIGFILESTRIM = $(notdir $(CONFIGFILES)) CONFIGFILESTRIM = $(notdir $(CONFIGFILES))
# FREQS = 25 50 100 150 200 250 300 350 400 # FREQS = 25 50 100 150 200 250 300 350 400
k = 3 6 # k = 3 6
ifeq ($(TECH), sky130)
FREQS = 25 50 100 150 200 250 300 350 400
else ifeq ($(TECH), sky90)
FREQS = 500 550 600 650 700 750 800 850 900 950 1000
endif
print: print:
@echo $(FREQS) @echo $(FREQS)
@ -44,12 +39,7 @@ print:
default: default:
@echo " Basic synthesis procedure for Wally:" @echo " Basic synthesis procedure for Wally:"
@echo " Invoke with make synth" @echo " Invoke with make synth"
@echo "Use wallySynth.py to run a concurrent sweep "
test: rv%
echo "Running test on $<"
rv%.log: rv%
echo $<
DIRS32 = rv32e rv32gc rv32ic DIRS32 = rv32e rv32gc rv32ic
@ -62,21 +52,21 @@ DIRS = $(DIRS32) $(DIRS64)
# @$(foreach kval, $(k), sed -i 's/BPRED_SIZE.*/BPRED_SIZE $(kval)/g' $(CONFIGDIR)/rv64gc_bpred_$(kval)/wally-config.vh;) # @$(foreach kval, $(k), sed -i 's/BPRED_SIZE.*/BPRED_SIZE $(kval)/g' $(CONFIGDIR)/rv64gc_bpred_$(kval)/wally-config.vh;)
# @$(foreach kval, $(k), make synth DESIGN=wallypipelinedcore CONFIG=rv64gc_bpred_$(kval) TECH=sky90 FREQ=500 MAXCORES=4 --jobs;) # @$(foreach kval, $(k), make synth DESIGN=wallypipelinedcore CONFIG=rv64gc_bpred_$(kval) TECH=sky90 FREQ=500 MAXCORES=4 --jobs;)
copy: copy:
# remove old config files
rm -rf $(CONFIGDIR)/*_*
@$(foreach dir, $(DIRS), rm -rf $(CONFIGDIR)/$(dir)_orig;) @$(foreach dir, $(DIRS), rm -rf $(CONFIGDIR)/$(dir)_orig;)
@$(foreach dir, $(DIRS), cp -r $(CONFIGDIR)/$(dir) $(CONFIGDIR)/$(dir)_orig;) @$(foreach dir, $(DIRS), cp -r $(CONFIGDIR)/$(dir) $(CONFIGDIR)/$(dir)_orig;)
@$(foreach dir, $(DIRS), sed -i 's/WAYSIZEINBYTES.*/WAYSIZEINBYTES 512/g' $(CONFIGDIR)/$(dir)_orig/wally-config.vh;) @$(foreach dir, $(DIRS), sed -i 's/WAYSIZEINBYTES.*/WAYSIZEINBYTES 512/g' $(CONFIGDIR)/$(dir)_orig/wally-config.vh;)
@$(foreach dir, $(DIRS), sed -i 's/NUMWAYS.*/NUMWAYS 1/g' $(CONFIGDIR)/$(dir)_orig/wally-config.vh;) @$(foreach dir, $(DIRS), sed -i 's/NUMWAYS.*/NUMWAYS 1/g' $(CONFIGDIR)/$(dir)_orig/wally-config.vh;)
@$(foreach dir, $(DIRS), sed -i 's/BPRED_SIZE.*/BPRED_SIZE 5/g' $(CONFIGDIR)/$(dir)_orig/wally-config.vh;) @$(foreach dir, $(DIRS), sed -i 's/BPRED_SIZE.*/BPRED_SIZE 4/g' $(CONFIGDIR)/$(dir)_orig/wally-config.vh;)
@$(foreach dir, $(DIRS32), sed -i "s/RAM_RANGE.*/RAM_RANGE 34\'h01FF/g" $(CONFIGDIR)/$(dir)_orig/wally-config.vh ;) @$(foreach dir, $(DIRS32), sed -i "s/RAM_RANGE.*/RAM_RANGE 34\'h01FF/g" $(CONFIGDIR)/$(dir)_orig/wally-config.vh ;)
@$(foreach dir, $(DIRS64), sed -i "s/RAM_RANGE.*/RAM_RANGE 56\'h01FF/g" $(CONFIGDIR)/$(dir)_orig/wally-config.vh ;) @$(foreach dir, $(DIRS64), sed -i "s/RAM_RANGE.*/RAM_RANGE 56\'h01FF/g" $(CONFIGDIR)/$(dir)_orig/wally-config.vh ;)
del:
rm -rf $(CONFIGDIR)/*_*
configs: $(DIRS) configs: $(DIRS)
$(DIRS): $(DIRS):
# turn off FPU # turn off FPU
rm -rf $(CONFIGDIR)/$@_FPUoff rm -rf $(CONFIGDIR)/$@_FPUoff
cp -r $(CONFIGDIR)/$@_orig $(CONFIGDIR)/$@_FPUoff cp -r $(CONFIGDIR)/$@_orig $(CONFIGDIR)/$@_FPUoff
@ -106,18 +96,10 @@ $(DIRS):
freqs: freqs:
@$(foreach freq, $(FREQS), make synth DESIGN=wallypipelinedcore CONFIG=rv32e FREQ=$(freq) MAXCORES=1;) @$(foreach freq, $(FREQS), make synth DESIGN=wallypipelinedcore CONFIG=rv32e FREQ=$(freq) MAXCORES=1;)
allsynth: $(CONFIGFILESTRIM)
$(CONFIGFILESTRIM):
make synth DESIGN=wallypipelinedcore CONFIG=$@ TECH=sky90 FREQ=3000 MAXCORES=1
synth: synth:
rm -f hdl/*
rm -rf WORK
@echo "DC Synthesis" @echo "DC Synthesis"
@mkdir -p hdl/
@mkdir -p $(OUTPUTDIR) @mkdir -p $(OUTPUTDIR)
@mkdir -p $(OUTPUTDIR)/hdl
@mkdir -p $(OUTPUTDIR)/reports @mkdir -p $(OUTPUTDIR)/reports
@mkdir -p $(OUTPUTDIR)/mapped @mkdir -p $(OUTPUTDIR)/mapped
@mkdir -p $(OUTPUTDIR)/unmapped @mkdir -p $(OUTPUTDIR)/unmapped
@ -125,11 +107,11 @@ ifeq ($(SAIFPOWER), 1)
cp -f ../pipelined/regression/power.saif . cp -f ../pipelined/regression/power.saif .
endif endif
dc_shell-xg-t -64bit -f scripts/$(NAME).tcl | tee $(OUTPUTDIR)/$(NAME).out dc_shell-xg-t -64bit -f scripts/$(NAME).tcl | tee $(OUTPUTDIR)/$(NAME).out
rm -rf $(OUTPUTDIR)/hdl
rm -rf $(OUTPUTDIR)/WORK
rm -rf $(OUTPUTDIR)/alib-52
clean: clean:
# fix should make del be here
rm -rf alib-52 WORK analyzed $(NAME).out
rm -f hdl/*
rm -f default.svf rm -f default.svf
rm -f command.log rm -f command.log
rm -f filenames*.log rm -f filenames*.log
@ -137,6 +119,5 @@ clean:
rm -f Synopsys_stack_trace_*.txt rm -f Synopsys_stack_trace_*.txt
rm -f crte_*.txt rm -f crte_*.txt
fresh: clean copy configs
@echo "synth directory cleaned and fresh config files written"

View File

@ -7,10 +7,10 @@ import subprocess
from matplotlib.cbook import flatten from matplotlib.cbook import flatten
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib.lines as lines import matplotlib.lines as lines
from wallySynth import testFreq
import numpy as np import numpy as np
from ppa.ppaAnalyze import noOutliers from ppa.ppaAnalyze import noOutliers
from matplotlib import ticker from matplotlib import ticker
import argparse
def synthsintocsv(): def synthsintocsv():
@ -74,14 +74,13 @@ def synthsfromcsv(filename):
allSynths[i] = Synth(*allSynths[i]) allSynths[i] = Synth(*allSynths[i])
return allSynths return allSynths
def freqPlot(tech, width, config): def freqPlot(tech, width, config):
''' plots delay, area for syntheses with specified tech, module, width ''' plots delay, area for syntheses with specified tech, module, width
''' '''
freqsL, delaysL, areasL = ([[], []] for i in range(3)) freqsL, delaysL, areasL = ([[], []] for i in range(3))
for oneSynth in allSynths: for oneSynth in allSynths:
if (width == oneSynth.width) & (config == oneSynth.config) & (tech == oneSynth.tech) & (oneSynth.special == ''): if (width == oneSynth.width) & (config == oneSynth.config) & (tech == oneSynth.tech) & ('' == oneSynth.special):
ind = (1000/oneSynth.delay < oneSynth.freq) # when delay is within target clock period ind = (1000/oneSynth.delay < oneSynth.freq) # when delay is within target clock period
freqsL[ind] += [oneSynth.freq] freqsL[ind] += [oneSynth.freq]
delaysL[ind] += [oneSynth.delay] delaysL[ind] += [oneSynth.delay]
@ -124,74 +123,93 @@ def freqPlot(tech, width, config):
addFO4axis(fig, ax1, tech) addFO4axis(fig, ax1, tech)
plt.savefig('./plots/wally/freqSweep_' + tech + '_' + width + config + '.png') plt.savefig('./plots/wally/freqSweep_' + tech + '_' + width + config + '.png')
# plt.show()
def areaDelay(tech, delays, areas, labels, fig, ax, norm=False):
def areaDelay(tech, fig=None, ax=None, freq=None, width=None, config=None, norm=False):
delays, areas, labels = ([] for i in range(3))
for oneSynth in allSynths:
if (width==None) or (width == oneSynth.width):
if (tech == oneSynth.tech) & (freq == oneSynth.freq):
if (config == None) & (oneSynth.special == 'FPUoff'): #fix
delays += [oneSynth.delay]
areas += [oneSynth.area]
labels += [oneSynth.width + oneSynth.config]
elif (config != None) & (oneSynth.config == config):
delays += [oneSynth.delay]
areas += [oneSynth.area]
labels += [oneSynth.special]
if width == None:
width = ''
if (fig == None) or (ax == None):
fig, (ax) = plt.subplots(1, 1)
ax.ticklabel_format(useOffset=False, style='plain')
plt.subplots_adjust(left=0.18) plt.subplots_adjust(left=0.18)
if norm: fo4 = techdict[tech].fo4
delays = [d/techdict[tech][0] for d in delays] add32area = techdict[tech].add32area
areas = [a/techdict[tech][1] for a in areas] marker = techdict[tech].shape
color = techdict[tech].color
plt.scatter(delays, areas) if norm:
delays = [d/fo4 for d in delays]
areas = [a/add32area for a in areas]
plt.scatter(delays, areas, marker=marker, color=color)
plt.xlabel('Cycle time (ns)') plt.xlabel('Cycle time (ns)')
plt.ylabel('Area (sq microns)') plt.ylabel('Area (sq microns)')
ytop = ax.get_ylim()[1] ytop = ax.get_ylim()[1]
plt.ylim(ymin=0, ymax=1.1*ytop) plt.ylim(ymin=0, ymax=1.1*ytop)
titleStr = tech + ' ' + width
saveStr = tech + '_' + width
if config:
titleStr += config
saveStr = saveStr + config + '_versions_'
if (config == None):
saveStr = saveStr + '_origConfigs_'
saveStr += str(freq)
titleStr = titleStr
plt.title(titleStr)
ax.yaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}')) ax.yaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}'))
for i in range(len(labels)): for i in range(len(labels)):
plt.annotate(labels[i], (delays[i], areas[i]), textcoords="offset points", xytext=(0,10), ha='center') plt.annotate(labels[i], (delays[i], areas[i]), textcoords="offset points", xytext=(0,10), ha='center')
# addFO4axis(fig, ax1, tech) return fig
plt.savefig('./plots/wally/areaDelay_' + saveStr + '.png') def plotFeatures(tech, width, config):
delays, areas, labels = ([] for i in range(3))
freq = techdict[tech].targfreq
for oneSynth in allSynths:
if (tech == oneSynth.tech) & (freq == oneSynth.freq):
if (oneSynth.config == config) & (width == oneSynth.width):
delays += [oneSynth.delay]
areas += [oneSynth.area]
labels += [oneSynth.special]
fig, (ax) = plt.subplots(1, 1)
fig = areaDelay(tech, delays, areas, labels, fig, ax)
titlestr = tech+'_'+width+config
plt.title(titlestr)
plt.savefig('./plots/wally/features_'+titlestr+'.png')
def plotConfigs(tech, special=''):
delays, areas, labels = ([] for i in range(3))
freq = techdict[tech].targfreq
for oneSynth in allSynths:
if (tech == oneSynth.tech) & (freq == oneSynth.freq) & (oneSynth.special == special):
delays += [oneSynth.delay]
areas += [oneSynth.area]
labels += [oneSynth.width + oneSynth.config]
fig, (ax) = plt.subplots(1, 1)
fig = areaDelay(tech, delays, areas, labels, fig, ax)
titleStr = tech+'_'+special
plt.title(titleStr)
plt.savefig('./plots/wally/configs_' + titleStr + '.png')
def normAreaDelay(special=''):
fig, (ax) = plt.subplots(1, 1)
fullLeg = []
for tech in list(techdict.keys()):
delays, areas, labels = ([] for i in range(3))
spec = techdict[tech]
freq = spec.targfreq
for oneSynth in allSynths:
if (tech == oneSynth.tech) & (freq == oneSynth.freq) & (oneSynth.special == special):
delays += [oneSynth.delay]
areas += [oneSynth.area]
labels += [oneSynth.width + oneSynth.config]
areaDelay(tech, delays, areas, labels, fig, ax, norm=True)
fullLeg += [lines.Line2D([0], [0], markerfacecolor=spec.color, label=tech, marker=spec.shape, markersize=10, color='w')]
def normAreaDelay():
fig2, (ax) = plt.subplots(1, 1)
areaDelay('sky90', fig=fig2, ax=ax, freq=testFreq[0], norm=True)
areaDelay('tsmc28', fig=fig2, ax=ax, freq=testFreq[1], norm=True)
ax.set_title('Normalized Area & Cycle Time by Configuration') ax.set_title('Normalized Area & Cycle Time by Configuration')
ax.set_xlabel('Cycle Time (FO4)') ax.set_xlabel('Cycle Time (FO4)')
ax.set_ylabel('Area (add32)') ax.set_ylabel('Area (add32)')
fullLeg = [lines.Line2D([0], [0], color='royalblue', label='tsmc28')]
fullLeg += [lines.Line2D([0], [0], color='orange', label='sky90')]
ax.legend(handles = fullLeg, loc='upper left') ax.legend(handles = fullLeg, loc='upper left')
plt.savefig('./plots/wally/normAreaDelay.png') plt.savefig('./plots/wally/normAreaDelay.png')
def addFO4axis(fig, ax, tech): def addFO4axis(fig, ax, tech):
fo4 = techdict[tech][0] fo4 = techdict[tech].fo4
ax3 = fig.add_axes((0.125,0.14,0.775,0.0)) ax3 = fig.add_axes((0.125,0.14,0.775,0.0))
ax3.yaxis.set_visible(False) # hide the yaxis ax3.yaxis.set_visible(False) # hide the yaxis
@ -215,15 +233,22 @@ def addFO4axis(fig, ax, tech):
if __name__ == '__main__': if __name__ == '__main__':
techdict = {'sky90': [43.2e-3, 1440.600027], 'tsmc28': [12.2e-3, 209.286002]} parser = argparse.ArgumentParser()
parser.add_argument("-s", "--skyfreq", type=int, default=3000, help = "Target frequency used for sky90 syntheses")
parser.add_argument("-t", "--tsmcfreq", type=int, default=10000, help = "Target frequency used for tsmc28 syntheses")
args = parser.parse_args()
# synthsintocsv() TechSpec = namedtuple("TechSpec", "color shape targfreq fo4 add32area add32lpower add32denergy")
techdict = {}
techdict['sky90'] = TechSpec('green', 'o', args.skyfreq, 43.2e-3, 1440.600027, 714.057, 0.658023)
techdict['tsmc28'] = TechSpec('blue', 's', args.tsmcfreq, 12.2e-3, 209.286002, 1060.0, .081533)
synthsintocsv()
synthsfromcsv('Summary.csv') synthsfromcsv('Summary.csv')
freqPlot('tsmc28', 'rv32', 'e') freqPlot('tsmc28', 'rv32', 'e')
freqPlot('sky90', 'rv32', 'e') freqPlot('sky90', 'rv32', 'e')
areaDelay('tsmc28', freq=testFreq[1], width= 'rv64', config='gc') plotFeatures('sky90', 'rv64', 'gc')
areaDelay('sky90', freq=testFreq[0], width='rv64', config='gc') plotFeatures('tsmc28', 'rv64', 'gc')
areaDelay('tsmc28', freq=testFreq[1]) plotConfigs('sky90', special='orig')
areaDelay('sky90', freq=testFreq[0]) plotConfigs('tsmc28', special='orig')
normAreaDelay(special='orig')
# normAreaDelay()

32
synthDC/ppa/README Normal file
View File

@ -0,0 +1,32 @@
Wally PPA Study
July 8, 2022
Madeleine Masser-Frye
mmasserfrye@hmc.edu
___________________
Apologies for issues in this folder, code was written originally for individual use and documentation was compiled in haste. Please feel free to contact the author with questions.
-------------------
ppaSynth.py
Run to synthesize datapath modules from src/ppa.
To run a specific combination of widths, modules, techs, and freqs,
modify those lists and use allCombos() to generate synthsToRun (comment out freqSweep).
To run a sweep of frequencies around the best delay found in existing syntheses (according to bestSynths.csv), modify the parameters and use freqSweep to generate synthsToRun.
To remove synths to be run that already exist in /runs from synthsToRun, use filterRedundant().
Syntheses run in parallel but you may encounter issues doing more than a dozen or so at once.
-------------------
ppaAnalyze.py
Run to plot results of PPA syntheses. See docstrings for individual function info.
-------------------
bestSynths.csv
Results of the synthesis for each combination of module, width, and tech with the best achievable delay. Generated by csvOfBest() in ppaAnalyze.py
-------------------
ppaFitting.csv & ppaEquations.csv
Representations of the regression fit for each module and metric. Generated in ppaAnalyze.py by makeCoefTable() and makeEqTable().
-------------------
ppaData.csv
Results from all synthesis runs. Generated by synthsintocsv() and used by synthsfromcsv in ppaAnalyze.py.

View File

@ -8,9 +8,11 @@ import re
from matplotlib.cbook import flatten from matplotlib.cbook import flatten
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib.lines as lines import matplotlib.lines as lines
import matplotlib as mpl
import numpy as np import numpy as np
from collections import namedtuple from collections import namedtuple
import sklearn.metrics as skm import sklearn.metrics as skm
import os
def synthsfromcsv(filename): def synthsfromcsv(filename):
Synth = namedtuple("Synth", "module tech width freq delay area lpower denergy") Synth = namedtuple("Synth", "module tech width freq delay area lpower denergy")
@ -518,7 +520,7 @@ def plotPPA(mod, freq=None, norm=True, aleOpt=False):
if no freq specified, uses the synthesis with best achievable delay for each width if no freq specified, uses the synthesis with best achievable delay for each width
overlays data from both techs overlays data from both techs
''' '''
plt.rcParams["figure.figsize"] = (7,3.46) with mpl.rc_context({"figure.figsize": (7,3.46)}):
fig, axs = plt.subplots(2, 2) fig, axs = plt.subplots(2, 2)
arr = [['delay', 'area'], ['lpower', 'denergy']] arr = [['delay', 'area'], ['lpower', 'denergy']]
@ -555,6 +557,8 @@ def plotPPA(mod, freq=None, norm=True, aleOpt=False):
# plt.show() # plt.show()
def makeLineLegend(): def makeLineLegend():
''' generates legend to accompany normalized plots
'''
plt.rcParams["figure.figsize"] = (5.5,0.3) plt.rcParams["figure.figsize"] = (5.5,0.3)
fig = plt.figure() fig = plt.figure()
fullLeg = [lines.Line2D([0], [0], color='black', label='fastest', linestyle='-')] fullLeg = [lines.Line2D([0], [0], color='black', label='fastest', linestyle='-')]
@ -619,6 +623,8 @@ def muxPlot(fits='clsgn', norm=True):
plt.savefig('./plots/mux.png') plt.savefig('./plots/mux.png')
def stdDevError(): def stdDevError():
''' calculates std deviation and error for paper-writing purposes
'''
for var in ['delay', 'area', 'lpower', 'denergy']: for var in ['delay', 'area', 'lpower', 'denergy']:
errlist = [] errlist = []
for module in modules: for module in modules:
@ -668,6 +674,30 @@ def stdDevError():
print(var, ' ', avgErr, ' ', stdv) print(var, ' ', avgErr, ' ', stdv)
def makePlotDirectory():
''' creates plots directory in same level as this script to store plots in
'''
current_directory = os.getcwd()
final_directory = os.path.join(current_directory, 'plots')
if not os.path.exists(final_directory):
os.makedirs(final_directory)
os.chdir(final_directory)
for folder in ['freqBuckshot', 'normalized', 'unnormalized']:
new_directory = os.path.join(final_directory, folder)
if not os.path.exists(new_directory):
os.makedirs(new_directory)
os.chdir(new_directory)
if 'freq' in folder:
for tech in ['sky90', 'tsmc28']:
for mod in modules:
tech_directory = os.path.join(new_directory, tech)
mod_directory = os.path.join(tech_directory, mod)
if not os.path.exists(mod_directory):
os.makedirs(mod_directory)
os.chdir('..')
os.chdir(current_directory)
if __name__ == '__main__': if __name__ == '__main__':
############################## ##############################
@ -686,26 +716,22 @@ if __name__ == '__main__':
############################## ##############################
# cleanup() # run to remove garbage synth runs # cleanup() # run to remove garbage synth runs
# synthsintocsv() # slow, run only when new synth runs to add to csv synthsintocsv() # slow, run only when new synth runs to add to csv
allSynths = synthsfromcsv('ppaData.csv') # your csv here! allSynths = synthsfromcsv('ppaData.csv') # your csv here!
bestSynths = csvOfBest('bestSynths.csv') bestSynths = csvOfBest('bestSynths.csv')
makePlotDirectory()
# ### function examples # ### other functions
# squareAreaDelay('sky90', 'add', 32)
# oneMetricPlot('mult', 'lpower')
# freqPlot('sky90', 'mux4', 16)
# plotBestAreas('add')
# makeCoefTable() # makeCoefTable()
# makeEqTable() # makeEqTable()
# makeLineLegend()
# muxPlot() # muxPlot()
# stdDevError() # stdDevError()
for mod in modules: for mod in modules:
plotPPA(mod, norm=False)
plotPPA(mod, aleOpt=True)
for w in widths: for w in widths:
freqPlot('sky90', mod, w) freqPlot('sky90', mod, w)
freqPlot('tsmc28', mod, w) freqPlot('tsmc28', mod, w)
plotPPA(mod, norm=False)
plotPPA(mod, aleOpt=True)
plt.close('all') plt.close('all')

View File

@ -10,47 +10,64 @@ def runCommand(module, width, tech, freq):
command = "make synth DESIGN=ppa_{}_{} TECH={} DRIVE=INV FREQ={} MAXOPT=1 MAXCORES=1".format(module, width, tech, freq) command = "make synth DESIGN=ppa_{}_{} TECH={} DRIVE=INV FREQ={} MAXOPT=1 MAXCORES=1".format(module, width, tech, freq)
subprocess.Popen(command, shell=True) subprocess.Popen(command, shell=True)
def deleteRedundant(LoT): def deleteRedundant(synthsToRun):
'''removes any previous runs for the current synthesis specifications''' '''removes any previous runs for the current synthesis specifications'''
synthStr = "rm -rf runs/ppa_{}_{}_rv32e_{}nm_{}_*" synthStr = "rm -rf runs/ppa_{}_{}_rv32e_{}nm_{}_*"
for synth in LoT: for synth in synthsToRun:
bashCommand = synthStr.format(*synth) bashCommand = synthStr.format(*synth)
outputCPL = subprocess.check_output(['bash','-c', bashCommand]) outputCPL = subprocess.check_output(['bash','-c', bashCommand])
if __name__ == '__main__': def freqSweep(module, width, tech):
LoT = []
synthsToRun = [] synthsToRun = []
##### Run specific syntheses
# widths = [8]
# modules = ['mult', 'add', 'shiftleft', 'flop', 'comparator', 'priorityencoder', 'add', 'csa', 'mux2', 'mux4', 'mux8']
# techs = ['sky90']
# freqs = [5000]
# for w in widths:
# for module in modules:
# for tech in techs:
# for freq in freqs:
# LoT += [[module, str(w), tech, str(freq)]]
##### Run a sweep based on best delay found in existing syntheses
arr = [-8, -6, -4, -2, 0, 2, 4, 6, 8] arr = [-8, -6, -4, -2, 0, 2, 4, 6, 8]
allSynths = synthsfromcsv('bestSynths.csv') allSynths = synthsfromcsv('bestSynths.csv')
for synth in allSynths: for synth in allSynths:
if (synth.module == module) & (synth.tech == tech) & (synth.width == width):
f = 1000/synth.delay f = 1000/synth.delay
for freq in [round(f+f*x/100) for x in arr]: for freq in [round(f+f*x/100) for x in arr]:
LoT += [[synth.module, str(synth.width), synth.tech, str(freq)]] synthsToRun += [[synth.module, str(synth.width), synth.tech, str(freq)]]
return synthsToRun
##### Only do syntheses for which a run doesn't already exist def filterRedundant(synthsToRun):
bashCommand = "find . -path '*runs/ppa*rv32e*' -prune" bashCommand = "find . -path '*runs/ppa*rv32e*' -prune"
output = subprocess.check_output(['bash','-c', bashCommand]) output = subprocess.check_output(['bash','-c', bashCommand])
specReg = re.compile('[a-zA-Z0-9]+') specReg = re.compile('[a-zA-Z0-9]+')
allSynths = output.decode("utf-8").split('\n')[:-1] allSynths = output.decode("utf-8").split('\n')[:-1]
allSynths = [specReg.findall(oneSynth)[2:7] for oneSynth in allSynths] allSynths = [specReg.findall(oneSynth)[2:7] for oneSynth in allSynths]
allSynths = [oneSynth[0:2] + [oneSynth[3][:-2]] + [oneSynth[4]] for oneSynth in allSynths] allSynths = [oneSynth[0:2] + [oneSynth[3][:-2]] + [oneSynth[4]] for oneSynth in allSynths]
for synth in LoT: output = []
for synth in synthsToRun:
if (synth not in allSynths): if (synth not in allSynths):
synthsToRun += [synth] output += [synth]
return output
def allCombos(widths, modules, techs, freqs):
synthsToRun = []
for w in widths:
for module in modules:
for tech in techs:
for freq in freqs:
synthsToRun += [[module, str(w), tech, str(freq)]]
return synthsToRun
if __name__ == '__main__':
##### Run specific syntheses
widths = [8, 16, 32, 64, 128]
modules = ['mult', 'add', 'shiftleft', 'flop', 'comparator', 'priorityencoder', 'add', 'csa', 'mux2', 'mux4', 'mux8']
techs = ['sky90', 'tsmc28']
freqs = [5000]
synthsToRun = allCombos(widths, modules, techs, freqs)
##### Run a sweep based on best delay found in existing syntheses
module = 'add'
width = 32
tech = 'sky90'
synthsToRun = freqSweep(module, width, tech)
##### Only do syntheses for which a run doesn't already exist
synthsToRun = filterRedundant(synthsToRun)
pool = Pool(processes=25) pool = Pool(processes=25)
pool.starmap(runCommand, synthsToRun) pool.starmap(print, synthsToRun)

View File

@ -1,64 +0,0 @@
#!/usr/bin/python3
# Shreya Sanghai (ssanghai@hmc.edu) 2/28/2022
import glob
import re
import csv
import linecache
import os
# field_names = [ 'Name', 'Critical Path Length', 'Cell Area', 'Synth Time']
# data = []
# for name in glob.glob("/home/ssanghai/riscv-wally/synthDC/runs/*/reports/wallypipelinedcore_qor.rep"):
# f = open(name, 'r')
# # trimName = re.search("runs\/(.*?)\/reports", name).group(1)
# trimName = re.search("wallypipelinedcore_(.*?)_sky9",name).group(1)
# for line in f:
# if "Critical Path Length" in line:
# pathLen = re.search("Length: *(.*?)\\n", line).group(1)
# if "Cell Area" in line:
# area = re.search("Area: *(.*?)\\n", line).group(1)
# if "Overall Compile Time" in line:
# time = re.search("Time: *(.*?)\\n", line).group(1)
# data += [{'Name' : trimName, 'Critical Path Length': pathLen, 'Cell Area' : area, 'Synth Time' :time}]
def main():
data = []
curr_dir = os.path.dirname(os.path.abspath(__file__))
output_file = os.path.join(curr_dir,"..","Summary.csv")
runs_dir = os.path.join(curr_dir,"..","runs/*/reports/wallypipelinedcore_qor.rep")
# cruns_dir = "/home/ssanghai/Desktop/cleanRun/*/reports/wallypipelinedcore_qor.rep"
search_strings = [
"Critical Path Length:", "Cell Area:", "Overall Compile Time:",
"Critical Path Clk Period:", "Critical Path Slack:"
]
for name in glob.glob(runs_dir):
f = open(name, 'r')
trimName = re.search("wallypipelinedcore_(.*?)_sky",name).group(1)
output = {'Name':trimName}
num_lines = len(f.readlines())
curr_line_index = 0
while curr_line_index < num_lines:
line = linecache.getline(name, curr_line_index)
for search_string in search_strings:
if search_string in line:
val = getVal(name,search_string,line,curr_line_index)
output[search_string] = val
curr_line_index +=1
data += [output]
with open(output_file, 'w') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=['Name'] + search_strings)
writer.writeheader()
writer.writerows(data)
def getVal(filename, search_string, line, line_index):
data = re.search(f"{search_string} *(.*?)\\n", line).group(1)
if data == '': #sometimes data is stored in two line
data = linecache.getline(filename, line_index+1).strip()
return data
if __name__=="__main__":
main()

View File

@ -1,9 +0,0 @@
#!/usr/bin/bash
# rm -r runs/*
make clean
make del
make copy
make configs
make allsynth
scripts/extractSummary.py
make del

View File

@ -1,7 +0,0 @@
#!/usr/bin/bash
# rm -r runs/*
make clean
make del
make freqs TECH=$1
scripts/extractSummary.py
make del

View File

@ -26,11 +26,11 @@ set saifpower $::env(SAIFPOWER)
set maxopt $::env(MAXOPT) set maxopt $::env(MAXOPT)
set drive $::env(DRIVE) set drive $::env(DRIVE)
eval file copy -force ${cfg} {hdl/} eval file copy -force ${cfg} {$outputDir/hdl/}
eval file copy -force ${cfg} $outputDir eval file copy -force ${cfg} $outputDir
eval file copy -force [glob ${hdl_src}/../config/shared/*.vh] {hdl/} eval file copy -force [glob ${hdl_src}/../config/shared/*.vh] {$outputDir/hdl/}
eval file copy -force [glob ${hdl_src}/*/*.sv] {hdl/} eval file copy -force [glob ${hdl_src}/*/*.sv] {$outputDir/hdl/}
eval file copy -force [glob ${hdl_src}/*/flop/*.sv] {hdl/} eval file copy -force [glob ${hdl_src}/*/flop/*.sv] {$outputDir/hdl/}
# Only for FMA class project; comment out when done # Only for FMA class project; comment out when done
# eval file copy -force [glob ${hdl_src}/fma/fma16.v] {hdl/} # eval file copy -force [glob ${hdl_src}/fma/fma16.v] {hdl/}
@ -41,7 +41,7 @@ if { $saifpower == 1 } {
} }
# Verilog files # Verilog files
set my_verilog_files [glob hdl/*] set my_verilog_files [glob $outputDir/hdl/*]
# Set toplevel # Set toplevel
set my_toplevel $::env(DESIGN) set my_toplevel $::env(DESIGN)
@ -56,7 +56,8 @@ set vhdlout_show_unconnected_pins "true"
# Due to parameterized Verilog must use analyze/elaborate and not # Due to parameterized Verilog must use analyze/elaborate and not
# read_verilog/vhdl (change to pull in Verilog and/or VHDL) # read_verilog/vhdl (change to pull in Verilog and/or VHDL)
# #
define_design_lib WORK -path ./WORK set alib_library_analysis_path ./$outputDir
define_design_lib WORK -path ./$outputDir/WORK
analyze -f sverilog -lib WORK $my_verilog_files analyze -f sverilog -lib WORK $my_verilog_files
elaborate $my_toplevel -lib WORK elaborate $my_toplevel -lib WORK

View File

@ -14,7 +14,7 @@ def mask(command):
subprocess.Popen(command, shell=True) subprocess.Popen(command, shell=True)
def freshStart(): def freshStart():
out = subprocess.check_output(['bash','-c', 'make clean']) out = subprocess.check_output(['bash','-c', 'make fresh'])
for x in out.decode("utf-8").split('\n')[:-1]: for x in out.decode("utf-8").split('\n')[:-1]:
print(x) print(x)
return return