@@ -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
376402def 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