Skip to content

Commit 6dcf971

Browse files
Add VHDL support via GHDL
Signed-off-by: Michael Riegert <michael@eowyn.net>
1 parent cb701d3 commit 6dcf971

File tree

1 file changed

+38
-5
lines changed

1 file changed

+38
-5
lines changed

sphinxcontrib_hdl_diagrams/__init__.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ class HDLDiagram(Directive):
165165
"hdl_diagram_output_format": ["svg", "png"],
166166
"hdl_diagram_skin": ["default"], # or path
167167
"hdl_diagram_yosys_script": ["default"], # or path
168-
"hdl_diagram_yosys": ["yowasp", "system"] # or path
168+
"hdl_diagram_yosys": ["yowasp", "system"], # or path
169+
"hdl_diagram_ghdl": ["module", "system"] # or path
169170
}
170171

171172
def run(self):
@@ -237,18 +238,20 @@ def run(self):
237238
return [node]
238239

239240

240-
def run_yosys(src, cmd, yosys='yowasp'):
241+
def run_yosys(src, cmd, yosys='yowasp', opt=''):
241242
if yosys == 'yowasp':
242243
import yowasp_yosys
243244
ycmd = ["-q", "-p", "{}".format(cmd), src]
245+
if opt != '':
246+
ycmd.insert(0, opt)
244247
print("Running YoWASP yosys: {}".format(ycmd))
245248
yowasp_yosys.run_yosys(ycmd)
246249
elif yosys == 'system':
247-
ycmd = "yosys -p '{cmd}' {src}".format(src=src, cmd=cmd)
250+
ycmd = "yosys {opt} -p '{cmd}' {src}".format(opt=opt, src=src, cmd=cmd)
248251
print("Running yosys: {}".format(ycmd))
249252
subprocess.check_output(ycmd, shell=True)
250253
else:
251-
ycmd = "{yosys} -p '{cmd}' {src}".format(yosys=yosys, src=src, cmd=cmd)
254+
ycmd = "{yosys} {opt} -p '{cmd}' {src}".format(opt=opt, yosys=yosys, src=src, cmd=cmd)
252255
print("Running yosys: {}".format(ycmd))
253256
subprocess.check_output(ycmd, shell=True)
254257

@@ -372,6 +375,29 @@ def nmigen_to_rtlil(fname, oname):
372375
cmd = "{python} {script} > {output}".format(python=sys.executable, script=fname, output=oname)
373376
subprocess.run(cmd, shell=True, check=True)
374377

378+
def vhdl_to_verilog(fname, oname, module, ghdl, yosys):
379+
assert os.path.exists(fname)
380+
381+
if ghdl == "module":
382+
yosys_opt = "-m ghdl "
383+
elif ghdl == "prebuilt":
384+
yosys_opt = ""
385+
elif os.path.exists(ghdl):
386+
yosys_opt = "-m '{}'".format(ghdl)
387+
else:
388+
raise HDLDiagramError("hdl_diagram_ghdl can only be \"module\", \"prebuilt\", or "
389+
"a path to a ghdl-yosys-plugin shared library, not '{}'".format(ghdl))
390+
391+
assert yosys != "yowasp", HDLDiagramError('Cannot use YoWASP for VHDL - GHDL is not compatible with YoWASP')
392+
393+
output_dir = os.path.dirname(oname)
394+
os.makedirs(output_dir, exist_ok=True)
395+
cmd = "ghdl {input} -e {module}; write_verilog {output}".format(
396+
module=module,
397+
input=fname,
398+
output=oname
399+
)
400+
run_yosys('', cmd, yosys, opt=yosys_opt)
375401

376402
def render_diagram(self, code, options, format, skin, yosys_script):
377403
# type: (nodes.NodeVisitor, unicode, Dict, unicode, unicode) -> Tuple[unicode, unicode]
@@ -384,13 +410,20 @@ def render_diagram(self, code, options, format, skin, yosys_script):
384410
relfn = posixpath.join(self.builder.imgpath, fname)
385411
outfn = path.join(self.builder.outdir, self.builder.imagedir, fname)
386412

413+
yosys = self.builder.config.hdl_diagram_yosys
414+
387415
if source_ext == '.py':
388416
module = 'top'
389417
ilfn = path.join(self.builder.outdir, self.builder.imagedir, options['outname'] + '.il')
390418
nmigen_to_rtlil(source_path, ilfn)
391419
source_path = ilfn
392420
elif source_ext == '.il' or source_ext == '.v':
393421
module = options['module']
422+
elif source_ext == '.vhd' or source_ext == '.vhdl':
423+
module = options['module']
424+
ilfn = path.join(self.builder.outdir, self.builder.imagedir, options['outname'] + '.v')
425+
vhdl_to_verilog(source_path, ilfn, module, self.builder.config.hdl_diagram_ghdl, yosys)
426+
source_path = ilfn
394427
else:
395428
raise HDLDiagramError("hdl_diagram_code file extension must be one of '.v', "
396429
"'.il', or '.py', but is %r" % source_ext)
@@ -404,7 +437,6 @@ def render_diagram(self, code, options, format, skin, yosys_script):
404437
yosys_script = options['yosys_script'] if options['yosys_script'] is not None else yosys_script
405438
skin = options['skin'] if options['skin'] is not None else skin
406439

407-
yosys = self.builder.config.hdl_diagram_yosys
408440
yosys_options = HDLDiagram.global_variable_options["hdl_diagram_yosys"]
409441
if yosys not in yosys_options and not os.path.exists(yosys):
410442
raise HDLDiagramError("Yosys not found!")
@@ -568,4 +600,5 @@ def setup(app):
568600
app.add_config_value('hdl_diagram_skin', 'default', 'html')
569601
app.add_config_value('hdl_diagram_yosys_script', 'default', 'html')
570602
app.add_config_value('hdl_diagram_yosys', 'yowasp', 'html')
603+
app.add_config_value('hdl_diagram_ghdl', 'module', 'html')
571604
return {'version': '1.0', 'parallel_read_safe': True}

0 commit comments

Comments
 (0)