Skip to content

Commit 7ad987c

Browse files
author
jonathan.hess
committed
Start of restructure, still mostly stable.
1 parent cec2557 commit 7ad987c

13 files changed

+288
-86
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#Work related code
2+
work_related/
3+
14
# SKILL
25
**/.skillide.*
36
*.ils~

.vscode/launch.json

+24
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@
44
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
55
"version": "0.2.0",
66
"configurations": [
7+
78

9+
{
10+
"name": "Python: Current File",
11+
"type": "python",
12+
"request": "launch",
13+
"program": "${file}",
14+
"console": "integratedTerminal"
15+
},
816

917
{
1018
"name": "Python: Schematic Test",
@@ -14,6 +22,22 @@
1422
"console": "integratedTerminal",
1523
"justMyCode": true
1624
},
25+
{
26+
"name": "Python: Schematic getDUT Test",
27+
"type": "python",
28+
"request": "launch",
29+
"program": "tests/addWirestoSchematic.py",
30+
"console": "integratedTerminal",
31+
"justMyCode": true
32+
},
33+
{
34+
"name": "Python: Maestro get Schematic and add equations Test",
35+
"type": "python",
36+
"request": "launch",
37+
"program": "tests/schematicimporttest.py",
38+
"console": "integratedTerminal",
39+
"justMyCode": true
40+
},
1741
{
1842
"name": "Python: Manager Test",
1943
"type": "python",

environment.yml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dependencies:
1313
- skillbridge=1.5.0 #python-skill communication
1414
- beautifulsoup4 #XML
1515
- lxml
16+
- ruamel.yaml
1617
# Development and Testing
1718
- PyInstaller=5.13.0 #build
1819
- conda=23.5.2 #ENV

morpheus/CadenceManager.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,17 @@ def log_stdout():
6565

6666
attempts = 0
6767

68-
while attempts < 10:
68+
while attempts <= 10:
6969
try:
7070
self.ws = Workspace.open(id)
7171
self.ws['load'](command)
7272
break;
7373
except:
74+
print("failed to start ws server. Attempting again.")
7475
sleep(5)
7576
attempts += 1
7677

77-
if(attempts>=10):
78+
if(attempts>10):
7879
print("failed to start ws server.")
7980
return
8081

morpheus/Config.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class config_types(Enum):
4141
}
4242

4343

44-
class config:
44+
class config: #yaml_tag = u"!Nokia" https://stackoverflow.com/questions/64587958/yaml-constructor-constructorerror-while-constructing-a-python-object-cannot-fin
4545
path_locations = list()
4646
userConfig = None
4747
types = dict()
@@ -122,9 +122,10 @@ def saveUserConfig():
122122
morpheus_home = os.path.join(user_home,".morpheus")
123123

124124
filename = os.path.join(morpheus_home,"user.sysm.yml");
125-
125+
os.makedirs(os.path.dirname(filename), exist_ok=True) #create morpheus directory if not already
126126
with open(filename, 'w') as outfile:
127-
yaml.dump(config.userConfig, outfile, default_flow_style=False)
127+
yaml.dump(config.userConfig, outfile, default_flow_style=False)#,transform=strip_python_tags)
128+
128129

129130
def addDir(dir):
130131
config.loadUserConfig();
@@ -153,8 +154,9 @@ def getConfigs(file_type): #TODO test as MIGHT BE BROKEN
153154
if( file_type_part == "." + config_dict_types[file_type]):
154155
with open(filepath, 'r') as file:
155156
config_temp = config()
157+
config_temp = yaml.load(file)
156158
#data = yaml.safe_load(file) #cleaner solution?
157-
config_temp.__dict__.update(json.loads(json.dumps(yaml.load(file,Loader=SafeLoaderIgnoreUnknown)), object_hook=load_object).__dict__)
159+
#config_temp.__dict__.update(json.loads(json.dumps(yaml.load(file,Loader=SafeLoaderIgnoreUnknown)), object_hook=load_object).__dict__)
158160
config_temp.filename = file_name_part
159161
configs.append(config_temp);
160162
except Exception as e:
@@ -168,3 +170,11 @@ def ignore_unknown(self, node):
168170
SafeLoaderIgnoreUnknown.add_constructor(None, SafeLoaderIgnoreUnknown.ignore_unknown)
169171

170172
#path_locations = list(os.path.join(script_dir, "Test_bench_definitions"), os.path.join(morpheus_home,"testbenches"))
173+
def strip_python_tags(s):
174+
result = []
175+
for line in s.splitlines():
176+
idx = line.find("!!python/")
177+
if idx > -1:
178+
line = line[:idx]
179+
result.append(line)
180+
return '\n'.join(result)

morpheus/Maestro.py

+97-49
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,28 @@
22
from morpheus.Schematic import *
33

44
class maestro:
5-
def __init__(self,ws,lib,DUT,test = None) -> None:
5+
def __init__(self,ws,lib,cell,view,DUT,config, build = False) -> None:
6+
self.build = build #temp
67
self.DUT = DUT
78
self.ws = ws
89
self.lib = lib
9-
self.cell = DUT.cell_name + "_AUTO_TB"
10-
10+
self.cell =cell
11+
self.view =view
1112
self.equationDict = {
1213
"DUT" : "DUT" #test.schem.DUT.name
1314
}
1415

15-
self.open() #TODO delete? become part of GUI Handler
16+
17+
#TODO MAKE SURE TO CLOSE ON ANY ERROR. Otherwise data is lost.
1618
self.schematics = dict()
17-
if(test):
18-
schem = self.getSchematic(test) #TODO should run in create test not before
19-
self.createTest(test,schem)
20-
19+
self.config = config
20+
#if(self.config):
21+
# schem = self.getSchematic(self.config) #TODO should run in create test not before
22+
#self.createTest(config,schem)
23+
if(self.build):
24+
self.open() #TODO delete? become part of GUI Handler
25+
self.createTests() #build everything
26+
self.close() #TODO SAVE STATE OF OPEN/CLOSE FOR INDIVIDUAL FUNCTIONS
2127

2228
@staticmethod
2329
def createMaestroView(ws,dut_lib,dut_cell,tb_lib):
@@ -28,18 +34,26 @@ def createMaestroView(ws,dut_lib,dut_cell,tb_lib):
2834

2935
return maestro(ws,tb_lib,DUT)
3036

31-
def getSchematic(self,test):
32-
schem = self.schematics.get(test.schematic)
33-
if(schem is None): #doesnt exist
34-
sconfig = config("{filename}".format(filename = test.schematic),config_types.SCHEMATIC)
35-
schem = schematic(self.ws,self.lib,self.DUT,sconfig,test)
36-
schem.evaluate()
37-
#
38-
schem.plan()
39-
schem.build()
40-
self.schematics.update({test.schematic:schem})
37+
def getSchematic(self,testConfig):
38+
schem = self.schematics.get(testConfig.schematic)
39+
if(schem is None): #schematic doesnt already exist in dictionary
40+
#sconfig = config("{filename}".format(filename = test.schematic),config_types.SCHEMATIC)
41+
sconfig = config(testConfig.schematic,config_types.SCHEMATIC)#find the config file for the schematic
42+
43+
#FIX!!!!!!!!!
44+
sconfig.cell = self.cell#TODO
45+
sconfig.name = "schematic" #MUST FIX!
46+
47+
schem = schematic(self.ws,self.lib,self.DUT,sconfig,testConfig)#check if exists as well
48+
if(self.build): #build (even if overwriting) in build mode
49+
schem.plan()
50+
schem.build()
51+
self.schematics.update({testConfig.schematic:schem})
4152
return schem
4253

54+
#def getConfig(self,testConfig):
55+
56+
4357
def createConfig(self,Config):
4458
config_view = self.ws.hdb.Open(self.lib, self.cell, "config_" + Config.name, "a", "CDBA")
4559
self.ws.hdb.SetTopCellViewName(config_view, self.lib, self.cell, Config.schematic)
@@ -49,20 +63,37 @@ def createConfig(self,Config):
4963
self.ws.hdb.Save(config_view)
5064
self.ws.hdb.Close(config_view)
5165

52-
def createTest(self,Config,schem):
53-
54-
for test in Config.tests: #create all tests in maestro view
66+
def createTests(self):
67+
#SINGLE TEST
68+
if not hasattr(self.config, "tests"): #TODO not this. I don't like this.
69+
self.createDictFromSchem(self.config)
70+
self.createTest(self.config)
71+
else: #MULTITEST
72+
for test in self.config.tests: #create all tests in the test config
73+
self.createDictFromSchem(test)
74+
createTest(test)
75+
#add variables (TODO break into new function)
76+
for var in self.config.variables:
77+
self.ws.mae.SetVar(var.name.format(**self.equationDict),var.value,typeValue=var.test, #Attach varaibles to Maestro view
78+
session=self.session)
79+
#add corners
80+
#self.createCorners()
81+
def createTest(self,test):
82+
schem = self.getSchematic(test)
5583
setattr(test,"schem",schem)
5684
print("create test {test}\n".format( test= test.name))
5785
self.ws.mae.CreateTest(test.name, session = self.session, # Create Test within Maestro
5886
lib = self.lib, cell = self.cell, view = test.schem.view)
59-
60-
self.ws.mae.SetAnalysis(test.name, test.analysis.type , #Add Test Analysis within Maestro
61-
session = self.session, options = test.analysis.options)
87+
88+
if not isinstance(test.analysis, list):
89+
test.analysis = [test.analysis]
90+
for analysis in test.analysis:
91+
self.ws.mae.SetAnalysis(test.name, analysis.type , #Add Test Analysis within Maestro
92+
session = self.session, options = analysis.options)
6293

6394
self.x_mainSDB = self.ws.axl.GetMainSetupDB( self.session )
6495

65-
self.ws.sev.AddExpression(self.session,"ocean","") #ocean scripts broken
96+
#self.ws.sev.AddExpression(self.session,"ocean","") #ocean scripts broken
6697

6798
if(hasattr(test,"corners")): #add corners if present
6899
self.createCorners(test)
@@ -73,15 +104,6 @@ def createTest(self,Config,schem):
73104
if(hasattr(test,"equations")):
74105
self.createEquations(test)
75106
#self.addOceanScripts(test)
76-
77-
for var in Config.variables:
78-
79-
self.ws.mae.SetVar(var.name.format(**self.equationDict),var.value,typeValue=var.test, #Attach varaibles to Maestro view
80-
session=self.session)
81-
82-
83-
84-
self.close()
85107

86108

87109
def createCorners(self, test):
@@ -97,32 +119,58 @@ def createCorner(self,corner):
97119
self.ws.axl.PutVar(newCorner, var.name, var.value)
98120

99121
def createEquations(self, test):
122+
100123
for equation in test.equations:
101124
self.createEquation(test, equation)
102125
def createEquation(self, test, equation):
103-
104-
self.createEquDict(test,equation)
105-
try:
106-
name = equation.name.format(**self.equationDict)
107-
expression = equation.equation.format(**self.equationDict)
108-
self.ws.mae.AddOutput(name,test.name, session = self.session,expr = expression)
109-
except:
110-
print("no pins of type", equation.type)
111-
126+
#creates equation for all of same type
127+
#if hasattr(equation,"type"):
128+
# self.createEquDict(test,equation)
129+
#if type is an array then sweep those values but for now assume 1 sweeping pin type.
130+
if(self.equationDict.get(equation.type) is not None):
131+
for pin in self.equationDict.get(equation.type):#TODO MOVE FOR LOOP TO CREATE EQUATIONS?!?!
132+
tempDict = self.equationDict
133+
tempDict.update({equation.type:pin}) #TODO add linked varriables
134+
expression = equation.equation.format(**tempDict)
135+
name = equation.name.format(**tempDict)
136+
self.ws.mae.AddOutput(name,test.name, session = self.session,expr = expression)#TODO CHECK IF EXISTS AND UPDATE
137+
138+
#def recursiveFormat():
139+
112140

113141
def createSignals(self,test):
114142
for signal in test.signals: #create all requred signals
115143
self.createSignal(test, signal)
116144

117145
def createSignal(self, test, signal):
146+
if(self.equationDict.get(signal.type) is not None):
147+
for pin in self.equationDict.get(signal.type):#TODO MOVE FOR LOOP TO CREATE SIGNALS?!?!
148+
tempDict = self.equationDict.copy() #MAKE COPY
149+
tempDict.update({signal.type:pin}) #TODO add linked varriables
150+
expression = signal.signal.format(**tempDict)
151+
name = signal.name.format(**tempDict)
152+
signal_type = "net"
153+
if(hasattr(signal, "signal_type")):
154+
signal_type = signal.signal_type
155+
#self.ws.mae.AddOutput(name,test.name, session = self.session,expr = expression)#TODO CHECK IF EXISTS AND UPDATE
156+
self.ws.mae.AddOutput(name,test.name, session = self.session,outputType = signal_type,signalName = expression)
157+
158+
def createDictFromSchem(self,test): #auto run after loading schem
159+
schematic = self.getSchematic(test)
160+
#add pintypes
118161

119-
if hasattr(signal,"type"):
120-
self.createEquDict(test,signal)
121-
122-
self.ws.mae.AddOutput(signal.name,test.name, session = self.session,outputType ="net",signalName = signal.signal.format(**self.equationDict))
162+
self.equationDict.update({"DUT":schematic.DUTinst.name}) #add linked varriables
163+
164+
for pin in schematic.evaluatedPins:
165+
if pin.type is not None:
166+
if pin.type not in self.equationDict:
167+
self.equationDict.setdefault(pin.type, []) #initialize array
168+
self.equationDict[pin.type].append(pin.label) #TODO Independent per test!
169+
123170

124171
def createEquDict(self,test, data):#TODO add pins despite if none
125-
pins_of_type = [pin for pin in test.schem.evaluatedPins if pin.type == data.type]
172+
schematic = self.getSchematic(test)
173+
pins_of_type = [pin for pin in schematic.evaluatedPins if pin.type == data.type]
126174
for pin in pins_of_type:
127175
self.equationDict.update({data.type: pin.label})
128176
#format equation string with dict
@@ -136,7 +184,7 @@ def simulate(self):
136184
pass
137185

138186
def open(self):
139-
self.session = self.ws.mae.OpenSetup(self.lib, self.cell,"maestro") #create new maestro view
187+
self.session = self.ws.mae.OpenSetup(self.lib, self.cell,self.view) #create new maestro view
140188
def close(self):
141189
self.ws.mae.SaveSetup(session = self.session)
142190
self.ws.mae.CloseSession(session = self.session)

morpheus/PlottingTemplate.py morpheus/PlottingTemplateManager.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from xml.dom import minidom
66
import os
77

8-
class PlottingTemplate:
8+
class plottingTemplateManager:
99
def __init__(self,ws,lib,cell,view) -> None: #for pin terminals
1010
self.ws = ws
1111
self.lib = lib

0 commit comments

Comments
 (0)