@@ -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' , options = '' ):
241242 if yosys == 'yowasp' :
242243 import yowasp_yosys
243244 ycmd = ["-q" , "-p" , "{}" .format (cmd ), src ]
245+ if options != '' :
246+ ycmd .insert (0 , options )
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 {options} -p '{cmd}' {src}" .format (options = options , 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} {options} -p '{cmd}' {src}" .format (options = options , 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 , options = 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,16 +410,25 @@ 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+ if yosys == "yowasp" :
424+ raise HDLDiagramError ("Cannot use YoWASP for VHDL" )
425+ module = options ['module' ]
426+ ilfn = path .join (self .builder .outdir , self .builder .imagedir , options ['outname' ] + '.v' )
427+ vhdl_to_verilog (source_path , ilfn , module , self .builder .config .hdl_diagram_ghdl , yosys )
428+ source_path = ilfn
394429 else :
395430 raise HDLDiagramError ("hdl_diagram_code file extension must be one of '.v', "
396- "'.il', or '.py ', but is %r" % source_ext )
431+ "'.il', '.py', '.vhd', or '.vhdl ', but is %r" % source_ext )
397432
398433 if path .isfile (outfn ):
399434 print ('Exiting file:' , outfn )
@@ -404,7 +439,6 @@ def render_diagram(self, code, options, format, skin, yosys_script):
404439 yosys_script = options ['yosys_script' ] if options ['yosys_script' ] is not None else yosys_script
405440 skin = options ['skin' ] if options ['skin' ] is not None else skin
406441
407- yosys = self .builder .config .hdl_diagram_yosys
408442 yosys_options = HDLDiagram .global_variable_options ["hdl_diagram_yosys" ]
409443 if yosys not in yosys_options and not os .path .exists (yosys ):
410444 raise HDLDiagramError ("Yosys not found!" )
@@ -441,6 +475,9 @@ def render_diagram_html(
441475 self , node , code , options , imgcls = None , alt = None ):
442476 # type: (nodes.NodeVisitor, hdl_diagram, unicode, Dict, unicode, unicode, unicode) -> Tuple[unicode, unicode] # NOQA
443477
478+ diagram_error = False
479+ diagram_error_message = ""
480+
444481 yosys_script = self .builder .config .hdl_diagram_yosys_script
445482 if yosys_script != 'default' and not path .exists (yosys_script ):
446483 raise HDLDiagramError ("Yosys script file {} does not exist! Change hdl_diagram_yosys_script variable" .format (yosys_script ))
@@ -457,9 +494,14 @@ def render_diagram_html(
457494 fname , outfn = render_diagram (self , code , options , format , skin , yosys_script )
458495 except HDLDiagramError as exc :
459496 logger .warning ('hdl_diagram code %r: ' % code + str (exc ))
460- raise nodes .SkipNode
461-
462- if fname is None :
497+ diagram_error = True
498+ diagram_error_message = str (exc )
499+ # raise nodes.SkipNode
500+
501+ if diagram_error :
502+ self .body .append ("WARNING: hdl_diagram code '{file}': {err}" .format (
503+ file = self .encode (code ).strip (), err = diagram_error_message ))
504+ elif fname is None :
463505 self .body .append (self .encode (code ))
464506 else :
465507 if alt is None :
@@ -568,4 +610,5 @@ def setup(app):
568610 app .add_config_value ('hdl_diagram_skin' , 'default' , 'html' )
569611 app .add_config_value ('hdl_diagram_yosys_script' , 'default' , 'html' )
570612 app .add_config_value ('hdl_diagram_yosys' , 'yowasp' , 'html' )
613+ app .add_config_value ('hdl_diagram_ghdl' , 'module' , 'html' )
571614 return {'version' : '1.0' , 'parallel_read_safe' : True }
0 commit comments