-
Notifications
You must be signed in to change notification settings - Fork 0
/
identify.py
134 lines (99 loc) · 3.64 KB
/
identify.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
from pyparsing import *
import re
class MOSFET:
def __init__(self, name, nd, ng, ns, nb, model_name, params={}):
self.name = name
self.nd = nd
self.ng = ng
self.ns = ns
self.nb = nb
self.model_name = model_name
self.params = params
def __repr__(self):
return "MOSFET(%s, %s, %s, %s, %s, %s, params=%s)" % (
self.name, self.nd, self.ng, self.ns, self.nb, self.model_name, self.params)
class Subckt:
def __init__(self, name, ports=[], content=[]):
self.name = name
self.ports = ports
self.content = content
def __repr__(self):
return "Subckt(%s, %s, %s)" % (self.name, self.ports, self.content)
class Include:
def __init__(self, path):
self.path = path
def __repr__(self):
return ".include '%s'" % self.path
def parse_spice(inp):
# Strip away comments but don't change number of lines.
inp = re.sub(r"^\*.*$", "", inp, flags=re.MULTILINE)
# Concatenate lines
inp = re.sub("\n\+", " ", inp, flags=re.MULTILINE)
# Don't ignore newline.
ParserElement.setDefaultWhitespaceChars(' \t')
# Elementary tokens
beginl = (Word('\n') * (0, None)).suppress()
endl = (LineEnd() * (1, None)).suppress()
def parse_float(t):
scale = 1
if len(t) > 1:
suffix = t[1]
units = {
'a': 1e-18,
'f': 1e-15,
'p': 1e-12,
'n': 1e-9,
'u': 1e-6,
'U': 1e-6,
'm': 1e-3,
'k': 1e3,
'M': 1e6,
'G': 1e9,
'T': 1e12
}
scale = units.get(suffix, 1)
return float(t[0]) * scale
# number = -123.123e-123
number = (Combine(
Optional('-') + Word(nums) + Optional('.' + Word(nums)) + Optional(Word('eE') + Optional('-') + Word(nums)))
+ Optional(Word(alphas)).leaveWhitespace()
).setParseAction(lambda t: parse_float(t)).setName('float')
name = Word(alphanums + '_' + '#')
net = name.setName('net')
path = CharsNotIn('\n')
# .end
end = (beginl + '.end' + Optional('s') + Optional(name)).suppress()
# Parameter list
param = (name + Suppress('=') + number).setParseAction(lambda t: (t[0].upper(), t[1]))
parameter_list = (param * (1, None)).setParseAction(lambda t: dict(list(t)))
# Components
mosfet = (
Combine(Word('mM') + name) + net + net + net + net + Optional(name) + Optional(parameter_list)
).setParseAction(lambda t: MOSFET(*t))
# Component
component = mosfet + endl
# Include
include = (Suppress('.include') + path + endl).setParseAction(lambda t: Include(*t))
# subckt start
subcircuit_def = (
beginl +
Suppress('.subckt') +
name +
(net * (0, None)).setParseAction(lambda t: [t]) +
endl
)
# subckt body
subcircuit = Forward()
subcircuit << subcircuit_def + ((component | subcircuit | include) * (0, None)).setParseAction(
lambda t: [t]) + end + endl
subcircuit.setParseAction(lambda t: Subckt(*t))
netlist = ((subcircuit | include) * (0, None))
parsed = netlist.parseString(inp, parseAll=True)
return parsed
def test_spice_parser():
with open('cells.txt', 'r') as file:
spice_content = file.read()
parsed_data = parse_spice(spice_content)
print(parsed_data)
#if __name__ == "__main__":
# test_spice_parser()