blob: 46f27e8e68764ad2127d1aab417789f0e75ae2b5 [file] [log] [blame]
Tim Edwardsdae621a2021-09-08 09:28:02 -04001#!/usr/bin/env python3
emayecs5966a532021-07-29 10:07:02 -04002#--------------------------------------------------------
3# make_icon_from_soft.py --
4#
5# Create an electric icon (manually) from information taken from
6# a verilog module.
7#-----------------------------------------------------------------
8
9import os
10import re
11import sys
12import json
13import datetime
14import subprocess
15
16def create_symbol(projectpath, verilogfile, project, destfile=None, debug=False, dolist=False):
17 if not os.path.exists(projectpath):
18 print('No path to project ' + projectpath)
19 return 1
20
21 if not os.path.isfile(verilogfile):
22 print('No path to verilog file ' + verilogfile)
23 return 1
24
25 if not os.path.exists(projectpath + '/elec'):
26 print('No electric subdirectory /elec/ in project.')
27 return 1
28
29 if not destfile:
30
31 delibdir = projectpath + '/elec/' + project + '.delib'
32 if not os.path.isdir(delibdir):
33 print('No electric library ' + project + '.delib in project.')
34 return 1
35
36 if os.path.isfile(delibdir + '/' + project + '.ic'):
37 print('Symbol file ' + project + '.ic exists already.')
38 print('Please remove it if you want to overwrite it.')
39 return 1
40
41 # By default, put the icon file in the project's electric library
42 destfile = projectpath + '/elec/' + project + '.delib/' + project + '.ic'
43 desthdr = projectpath + '/elec/' + project + '.delib/header'
44
45 else:
46 if os.path.isfile(destfile):
47 print('Symbol file ' + project + '.ic exists already.')
48 print('Please remove it if you want to overwrite it.')
49 return 1
50
51 destdir = os.path.split(destfile)[0]
52 desthdr = destdir + '/header'
53 if not os.path.isdir(destdir):
54 os.makedirs(destdir)
55
56 # Original verilog source can be very complicated to parse. Run through
57 # qflow's vlog2Verilog tool to get a much simplified header, which also
58 # preprocesses the verilog, handles parameters, etc.
59
60 vdir = os.path.split(verilogfile)[0]
61 vtempfile = vdir + '/vtemp.out'
62 p = subprocess.run(['/ef/apps/ocd/qflow/current/share/qflow/bin/vlog2Verilog',
63 '-p', '-o', vtempfile, verilogfile], stdout = subprocess.PIPE)
64
65 if not os.path.exists(vtempfile):
66 print('Error: Failed to create preprocessed verilog from ' + verilogfile)
67 return 1
68
69 # Okay, ready to go. Now read the verilog source file and get the list
70 # of pins.
71
72 commstr1 = '/\*.*\*/'
73 commstr2 = '//[^\n]*\n'
74 c1rex = re.compile(commstr1)
75 c2rex = re.compile(commstr2)
76
77 # Find and isolate the module and its pin list.
78 modstr = 'module[ \t]+' + project + '[ \t]*\(([^\)]+)\)[ \t\n]*;'
79 modrex = re.compile(modstr)
80
81 # End parsing on any of these tokens
82 endrex = re.compile('[ \t]*(initial|function|task|always)')
83
84 inpins = []
85 outpins = []
86 iopins = []
87 invecs = []
88 outvecs = []
89 iovecs = []
90
91 with open(vtempfile, 'r') as ifile:
92 vlines = ifile.read()
93
94 # Remove comments
95 vlines2 = c2rex.sub('\n', c1rex.sub('', vlines))
96
97 # Find and isolate the module pin list
98 modpinslines = modrex.findall(vlines2)
99
100 modpinsstart = modrex.search(vlines2)
101 if modpinsstart:
102 startc = modpinsstart.span()[0]
103 else:
104 startc = 0
105 modpinsend = endrex.search(vlines2[startc:])
106 if modpinsend:
107 endc = modpinsend.span()[0]
108 else:
109 endc = len(vlines2)
110
111 vlines2 = vlines2[startc:endc]
112
113 # Find the module (there should be only one) and get pins if in the
114 # format with input / output declarations in the module heading.
115
116 pinlist = []
117 if len(modpinslines) > 0:
118 modpins = modpinslines[0]
119 pinlist = re.sub('[\t\n]', '', modpins).split(',')
120
121 # If each pinlist entry is only one word, then look for following
122 # lines "input", "output", etc., and compile them into a similar
123 # list. Then parse each list entry.
124
125 knownreal = {}
126 knownpower = {}
127 knownground = {}
128
129 if len(pinlist) > 0 and len(pinlist[0].split()) == 1:
130
131 invecrex = re.compile('\n[ \t]*input[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*([^;]+);')
132 insigrex = re.compile('\n[ \t]*input[ \t]+([^\[;]+);')
133 outvecrex = re.compile('\n[ \t]*output[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*([^;]+);')
134 outsigrex = re.compile('\n[ \t]*output[ \t]+([^;\[]+);')
135 iovecrex = re.compile('\n[ \t]*inout[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*([^;]+);')
136 iosigrex = re.compile('\n[ \t]*inout [ \t]+([^;\[]+);')
137
138 # Find input, output, and inout lines
139 for test in insigrex.findall(vlines2):
140 pinname = list(item.strip() for item in test.split(','))
141 inpins.extend(pinname)
142 for test in outsigrex.findall(vlines2):
143 pinname = list(item.strip() for item in test.split(','))
144 outpins.extend(pinname)
145 for test in iosigrex.findall(vlines2):
146 pinname = list(item.strip() for item in test.split(','))
147 iopins.extend(pinname)
148 for test in invecrex.finditer(vlines2):
149 tpin = test.group(3).split(',')
150 for pin in tpin:
151 pinname = pin.strip() + '[' + test.group(1) + ':' + test.group(2) + ']'
152 invecs.append(pinname)
153 for test in outvecrex.finditer(vlines2):
154 tpin = test.group(3).split(',')
155 for pin in tpin:
156 pinname = pin.strip() + '[' + test.group(1) + ':' + test.group(2) + ']'
157 outvecs.append(pinname)
158 for test in iovecrex.finditer(vlines2):
159 tpin = test.group(3).split(',')
160 for pin in tpin:
161 pinname = pin.strip() + '[' + test.group(1) + ':' + test.group(2) + ']'
162 iovecs.append(pinname)
163
164 # Apply syntax checks (to do: check for "real" above)
165 powerrec = re.compile('VDD|VCC', re.IGNORECASE)
166 groundrec = re.compile('VSS|GND|GROUND', re.IGNORECASE)
167 for pinname in inpins + outpins + iopins + invecs + outvecs + iovecs:
168 pmatch = powerrec.match(pinname)
169 gmatch = groundrec.match(pinname)
170 if pmatch:
171 knownpower[pinname] = True
172 if gmatch:
173 knownground[pinname] = True
174 else:
175
176 # Get pin lists from module pin list. These are simpler to
177 # parse, since they have to be enumerated one by one.
178
179 invecrex = re.compile('[ \t]*input[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*(.+)')
180 insigrex = re.compile('[ \t]*input[ \t]+([a-zA-Z_][^ \t]+)')
181 outvecrex = re.compile('[ \t]*output[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*(.+)')
182 outsigrex = re.compile('[ \t]*output[ \t]+([a-zA-Z_][^ \t]+)')
183 iovecrex = re.compile('[ \t]*inout[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*(.+)')
184 iosigrex = re.compile('[ \t]*inout[ \t]+([a-zA-Z_][^ \t]+)')
185 realrec = re.compile('[ \t]+real[ \t]+')
186 logicrec = re.compile('[ \t]+logic[ \t]+')
187 wirerec = re.compile('[ \t]+wire[ \t]+')
188 powerrec = re.compile('VDD|VCC', re.IGNORECASE)
189 groundrec = re.compile('VSS|GND|GROUND', re.IGNORECASE)
190
191 for pin in pinlist:
192 # Pull out any reference to "real", "logic", or "wire" to get pin name
193 ppin = realrec.sub(' ', logicrec.sub(' ', wirerec.sub(' ', pin.strip())))
194 pinname = None
195
196 # Make syntax checks
197 rmatch = realrec.match(pin)
198 pmatch = powerrec.match(pin)
199 gmatch = groundrec.match(pin)
200
201 imatch = insigrex.match(ppin)
202 if imatch:
203 pinname = imatch.group(1)
204 inpins.append(pinname)
205 omatch = outsigrex.match(ppin)
206 if omatch:
207 pinname = omatch.group(1)
208 outpins.append(pinname)
209 bmatch = iosigrex.match(ppin)
210 if bmatch:
211 pinname = bmatch.group(1)
212 iopins.append(pinname)
213 ivmatch = invecrex.match(ppin)
214 if ivmatch:
215 pinname = ivmatch.group(3) + '[' + ivmatch.group(1) + ':' + ivmatch.group(2) + ']'
216 invecs.append(pinname)
217 ovmatch = outvecrex.match(ppin)
218 if ovmatch:
219 pinname = ovmatch.group(3) + '[' + ovmatch.group(1) + ':' + ovmatch.group(2) + ']'
220 outvecs.append(pinname)
221 bvmatch = iovecrex.match(ppin)
222 if bvmatch:
223 pinname = bvmatch.group(3) + '[' + bvmatch.group(1) + ':' + bvmatch.group(2) + ']'
224 iovecs.append(pinname)
225
226 # Apply syntax checks
227 if pinname:
228 if rmatch:
229 knownreal[pinname] = True
230 if pmatch and rmatch:
231 knownpower[pinname] = True
232 if gmatch and rmatch:
233 knownground[pinname] = True
234
235 if (os.path.exists(vtempfile)):
236 os.remove(vtempfile)
237
238 if len(inpins) + len(outpins) + len(iopins) + len(invecs) + len(outvecs) + len(iovecs) == 0:
239 print('Failure to parse pin list for module ' + project + ' out of verilog source.')
240 return 1
241
242 if debug:
243 print("Input pins of module " + project + ":")
244 for pin in inpins:
245 print(pin)
246 print("Output pins of module " + project + ":")
247 for pin in outpins:
248 print(pin)
249 print("Bidirectional pins of module " + project + ":")
250 for pin in iopins:
251 print(pin)
252
253 # If "dolist" is True, then create a list of pin records in the style used by
254 # project.json, and return the list.
255
256 if dolist == True:
257 pinlist = []
258 for pin in inpins:
259 pinrec = {}
260 pinrec["name"] = pin
261 pinrec["description"] = "(add description here)"
262 if pin in knownreal:
263 pinrec["type"] = 'signal'
264 else:
265 pinrec["type"] = 'digital'
266 pinrec["Vmin"] = "-0.5"
267 pinrec["Vmax"] = "VDD + 0.3"
268 pinrec["dir"] = "input"
269 pinlist.append(pinrec)
270 for pin in outpins:
271 pinrec = {}
272 pinrec["name"] = pin
273 pinrec["description"] = "(add description here)"
274 if pin in knownreal:
275 pinrec["type"] = 'signal'
276 else:
277 pinrec["type"] = 'digital'
278 pinrec["Vmin"] = "-0.5"
279 pinrec["Vmax"] = "VDD + 0.3"
280 pinrec["dir"] = "output"
281 pinlist.append(pinrec)
282 for pin in iopins:
283 pinrec = {}
284 pinrec["name"] = pin
285 pinrec["description"] = "(add description here)"
286 if pin in knownpower:
287 pinrec["type"] = 'power'
288 pinrec["Vmin"] = "3.6"
289 pinrec["Vmax"] = "3.0"
290 elif pin in knownground:
291 pinrec["type"] = 'ground'
292 pinrec["Vmin"] = "0"
293 pinrec["Vmax"] = "0"
294 elif pin in knownreal:
295 pinrec["type"] = 'signal'
296 pinrec["Vmin"] = "-0.5"
297 pinrec["Vmax"] = "VDD + 0.3"
298 else:
299 pinrec["type"] = 'digital'
300 pinrec["Vmin"] = "-0.5"
301 pinrec["Vmax"] = "VDD + 0.3"
302 pinrec["dir"] = "inout"
303 pinlist.append(pinrec)
304 for pin in invecs:
305 pinrec = {}
306 pinrec["name"] = pin
307 pinrec["description"] = "(add description here)"
308 if pin in knownreal:
309 pinrec["type"] = 'signal'
310 else:
311 pinrec["type"] = 'digital'
312 pinrec["dir"] = "input"
313 pinrec["Vmin"] = "-0.5"
314 pinrec["Vmax"] = "VDD + 0.3"
315 pinlist.append(pinrec)
316 for pin in outvecs:
317 pinrec = {}
318 pinrec["name"] = pin
319 pinrec["description"] = "(add description here)"
320 if pin in knownreal:
321 pinrec["type"] = 'signal'
322 else:
323 pinrec["type"] = 'digital'
324 pinrec["dir"] = "output"
325 pinrec["Vmin"] = "-0.5"
326 pinrec["Vmax"] = "VDD + 0.3"
327 pinlist.append(pinrec)
328 for pin in iovecs:
329 pinrec = {}
330 pinrec["name"] = pin
331 pinrec["description"] = "(add description here)"
332 if pin in knownpower:
333 pinrec["type"] = 'power'
334 pinrec["Vmin"] = "3.6"
335 pinrec["Vmax"] = "3.0"
336 elif pin in knownground:
337 pinrec["type"] = 'ground'
338 pinrec["Vmin"] = "0"
339 pinrec["Vmax"] = "0"
340 elif pin in knownreal:
341 pinrec["type"] = 'signal'
342 pinrec["Vmin"] = "-0.5"
343 pinrec["Vmax"] = "VDD + 0.3"
344 else:
345 pinrec["type"] = 'digital'
346 pinrec["Vmin"] = "-0.5"
347 pinrec["Vmax"] = "VDD + 0.3"
348 pinrec["dir"] = "inout"
349 pinlist.append(pinrec)
350
351 return pinlist
352
353 # Okay, we've got all the pins, now build the symbol.
354
355 leftpins = len(inpins) + len(invecs)
356 rightpins = len(outpins) + len(outvecs)
357 # Arbitrarily, bidirectional pins are put on bottom and vectors on top.
358 toppins = len(iovecs)
359 botpins = len(iopins)
360
361 height = 2 + max(leftpins, rightpins) * 10
362 width = 82 + max(toppins, botpins) * 10
363
364 # Enforce minimum height (minimum width enforced above)
365 if height < 40:
366 height = 40
367
368 # Run electric -v to get version string
369 p = subprocess.run(['/ef/apps/bin/electric', '-v'], stdout = subprocess.PIPE)
370 vstring = p.stdout.decode('utf-8').rstrip()
371
372 # Get timestamp
373 timestamp = str(int(datetime.datetime.now().strftime("%s")) * 1000)
374
375 with open(destfile, 'w') as ofile:
376 print('H' + project + '|' + vstring, file=ofile)
377 print('', file=ofile)
378 print('# Cell ' + project + ';1{ic}', file=ofile)
379 print('C' + project + ';1{ic}||artwork|' + timestamp + '|' + timestamp + '|E', file=ofile)
380 print('Ngeneric:Facet-Center|art@0||0|0||||AV', file=ofile)
381 print('NBox|art@1||0|0|' + str(width) + '|' + str(height) + '||', file=ofile)
382 pnum = 0
383
384 # Title
385 print('Ngeneric:Invisible-Pin|pin@' + str(pnum) + '||0|5|||||ART_message(BD5G5;)S' + project, file=ofile)
386
387 pnum += 1
388 # Fill in left side pins
389 px = -(width / 2)
390 py = -(height / 2) + 5
391 for pin in inpins:
392 print('Nschematic:Wire_Pin|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|1|1||', file=ofile)
393 pnum += 1
394 print('NPin|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|1|1||', file=ofile)
395 pnum += 1
396 print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile)
397 pnum += 1
398 py += 10
399 for pin in invecs:
400 print('Nschematic:Bus_Pin|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|1|1||', file=ofile)
401 pnum += 1
402 print('NPin|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|1|1||', file=ofile)
403 pnum += 1
404 print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile)
405 pnum += 1
406 py += 10
407
408 # Fill in right side pins
409 px = (width / 2)
410 py = -(height / 2) + 5
411 for pin in outpins:
412 print('Nschematic:Wire_Pin|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|1|1||', file=ofile)
413 pnum += 1
414 print('NPin|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|1|1||', file=ofile)
415 pnum += 1
416 print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile)
417 pnum += 1
418 py += 10
419 for pin in outvecs:
420 print('Nschematic:Bus_Pin|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|1|1||', file=ofile)
421 pnum += 1
422 print('NPin|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|1|1||', file=ofile)
423 pnum += 1
424 print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile)
425 pnum += 1
426 py += 10
427
428 # Fill in bottom side pins
429 py = -(height / 2)
430 px = -(width / 2) + 45
431 for pin in iopins:
432 print('Nschematic:Wire_Pin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py - 10) + '|1|1||', file=ofile)
433 pnum += 1
434 print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile)
435 pnum += 1
436 print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py - 10) + '|1|1||', file=ofile)
437 pnum += 1
438 px += 10
439
440 # Fill in top side pins
441 py = (height / 2)
442 px = -(width / 2) + 45
443 for pin in iovecs:
444 print('Nschematic:Bus_Pin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py + 10) + '|1|1||', file=ofile)
445 pnum += 1
446 print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile)
447 pnum += 1
448 print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py + 10) + '|1|1||', file=ofile)
449 pnum += 1
450 px += 10
451
452 # Start back at pin 1 and retain the same order when drawing wires
453 pnum = 1
454 nnum = 0
455
456 px = -(width / 2)
457 py = -(height / 2) + 5
458 for pin in inpins:
459 pnum += 1
460 print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py), file=ofile)
461 pnum += 2
462 nnum += 1
463 py += 10
464
465 for pin in invecs:
466 pnum += 1
467 print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py), file=ofile)
468 pnum += 2
469 nnum += 1
470 py += 10
471
472 px = (width / 2)
473 py = -(height / 2) + 5
474 for pin in outpins:
475 pnum += 1
476 print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py), file=ofile)
477 pnum += 2
478 nnum += 1
479 py += 10
480
481 for pin in outvecs:
482 pnum += 1
483 print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py), file=ofile)
484 pnum += 2
485 nnum += 1
486 py += 10
487
488 py = -(height / 2)
489 px = -(width / 2) + 45
490 for pin in iopins:
491 pnum += 1
492 print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py - 10), file=ofile)
493 pnum += 2
494 nnum += 1
495 px += 10
496
497 py = (height / 2)
498 px = -(width / 2) + 45
499 for pin in iovecs:
500 pnum += 1
501 print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py + 10), file=ofile)
502 pnum += 2
503 nnum += 1
504 px += 10
505
506 # Add the exports (which are the only nontrivial elements)
507 pnum = 1
508 for pin in inpins:
509 print('E' + pin + '||D6G4;X12.0;Y0.0;|pin@' + str(pnum) + '||I', file=ofile)
510 pnum += 3
511 for pin in invecs:
512 print('E' + pin + '||D6G4;X12.0;Y0.0;|pin@' + str(pnum) + '||I', file=ofile)
513 pnum += 3
514 for pin in outpins:
515 print('E' + pin + '||D4G4;X-12.0;Y0.0;|pin@' + str(pnum) + '||O', file=ofile)
516 pnum += 3
517 for pin in outvecs:
518 print('E' + pin + '||D4G4;X-12.0;Y0.0;|pin@' + str(pnum) + '||O', file=ofile)
519 pnum += 3
520 for pin in iopins:
521 print('E' + pin + '||D6G4;RX0.0;Y12.0;|pin@' + str(pnum) + '||B', file=ofile)
522 pnum += 3
523 for pin in iovecs:
524 print('E' + pin + '||D6G4;RRRX0.0;Y-12.0;|pin@' + str(pnum) + '||B', file=ofile)
525 pnum += 3
526
527 # X marks the spot, or at least the end.
528 print('X', file=ofile)
529
530 if not os.path.isfile(desthdr):
531 with open(desthdr, 'w') as ofile:
532 print('# header information:', file=ofile)
533 print('H' + project + '|' + vstring, file=ofile)
534 print('', file=ofile)
535 print('# Views:', file=ofile)
536 print('Vicon|ic', file=ofile)
537 print('', file=ofile)
538 print('# Tools:', file=ofile)
539 print('Ouser|DefaultTechnology()Sschematic', file=ofile)
540 print('Osimulation|VerilogUseAssign()BT', file=ofile)
541 print('C____SEARCH_FOR_CELL_FILES____', file=ofile)
542
543 return 0
544
545def usage():
546 print("make_icon_from_soft.py <project_path> [<verilog_source>] [<output_file>]")
547 print("")
548 print(" where <project_path> is the path to a standard efabless project, and")
549 print(" <verilog_source> is the path to a verilog source file.")
550 print("")
551 print(" The module name must be the same as the project's ip-name.")
552 print("")
553 print(" <verilog_source> is assumed to be in verilog/source/<ip-name>.v by")
554 print(" default if not otherwise specified.")
555 print("")
556 print(" If <output_file> is not specified, output goes in the project's")
557 print(" electric library.")
558 print("")
559
560if __name__ == '__main__':
561 arguments = []
562 options = []
563
564 for item in sys.argv[1:]:
565 if item[0] == '-':
566 options.append(item.strip('-'))
567 else:
568 arguments.append(item)
569
570 debug = True if 'debug' in options else False
571
572 numarg = len(arguments)
573 if numarg > 3 or numarg == 0:
574 usage()
575 sys.exit(0)
576
577 projectpath = arguments[0]
578
579 projdirname = os.path.split(projectpath)[1]
580 jsonfile = projectpath + '/project.json'
581 if not os.path.isfile(jsonfile):
582 # Legacy behavior is to have the JSON file name the same as the directory name.
583 jsonfile = projectpath + '/' + projdirname + '.json'
584 if not os.path.isfile(jsonfile):
585 print('Error: No project JSON file found for project ' + projdirname)
586 sys.exit(1)
587
588 project = None
589 with open(jsonfile, 'r') as ifile:
590 datatop = json.load(ifile)
591 dsheet = datatop['data-sheet']
592 project = dsheet['ip-name']
593
594 if not project:
595 print('Error: No project IP name in project JSON file.')
596 sys.exit(1)
597
598 if numarg > 1:
599 verilogfile = arguments[1]
600 else:
601 verilogfile = projectpath + '/verilog/source/' + project + '.v'
602 if not os.path.exists(verilogfile):
603 print('Error: No verilog file ' + verilogfile + ' found.')
604 print('Please specify full path as 2nd argument.')
605 sys.exit(1)
606
607 if numarg > 2:
608 destfile = arguments[2]
609 else:
610 destfile = projectpath + '/elec/' + project + '.delib/' + project + '.ic'
611 if os.path.exists(destfile):
612 print('Error: Icon file ' + destfile + ' already exists.')
613 print('Please delete any unwanted original before running this script.')
614 sys.exit(1)
615
616 result = create_symbol(projectpath, verilogfile, project, destfile, debug)
617 sys.exit(result)