@@ -165,7 +165,9 @@ 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" : ["built-in" , "module" ], # or path
170+ "hdl_diagram_ghdl_std" : ["87" , "93" , "93c" , "00" , "02" , "08" ]
169171 }
170172
171173 def run (self ):
@@ -237,18 +239,20 @@ def run(self):
237239 return [node ]
238240
239241
240- def run_yosys (src , cmd , yosys = 'yowasp' ):
242+ def run_yosys (src , cmd , yosys = 'yowasp' , options = '' ):
241243 if yosys == 'yowasp' :
242244 import yowasp_yosys
243245 ycmd = ["-q" , "-p" , "{}" .format (cmd ), src ]
246+ if options != '' :
247+ ycmd .insert (0 , options )
244248 print ("Running YoWASP yosys: {}" .format (ycmd ))
245249 yowasp_yosys .run_yosys (ycmd )
246250 elif yosys == 'system' :
247- ycmd = "yosys -p '{cmd}' {src}" .format (src = src , cmd = cmd )
251+ ycmd = "yosys {options} -p '{cmd}' {src}" .format (options = options , src = src , cmd = cmd )
248252 print ("Running yosys: {}" .format (ycmd ))
249253 subprocess .check_output (ycmd , shell = True )
250254 else :
251- ycmd = "{yosys} -p '{cmd}' {src}" .format (yosys = yosys , src = src , cmd = cmd )
255+ ycmd = "{yosys} {options} -p '{cmd}' {src}" .format (options = options , yosys = yosys , src = src , cmd = cmd )
252256 print ("Running yosys: {}" .format (ycmd ))
253257 subprocess .check_output (ycmd , shell = True )
254258
@@ -372,6 +376,28 @@ def nmigen_to_rtlil(fname, oname):
372376 cmd = "{python} {script} > {output}" .format (python = sys .executable , script = fname , output = oname )
373377 subprocess .run (cmd , shell = True , check = True )
374378
379+ def vhdl_to_verilog (fname , oname , module , ghdl , ghdl_std , yosys ):
380+ assert os .path .exists (fname )
381+
382+ if ghdl == "module" :
383+ yosys_opt = "-m ghdl "
384+ elif ghdl == "built-in" :
385+ yosys_opt = ""
386+ elif os .path .exists (ghdl ):
387+ yosys_opt = "-m '{}'" .format (ghdl )
388+ else :
389+ raise HDLDiagramError ("hdl_diagram_ghdl can only be \" module\" , \" built-in\" , or "
390+ "a path to a ghdl-yosys-plugin shared library, not '{}'" .format (ghdl ))
391+
392+ output_dir = os .path .dirname (oname )
393+ os .makedirs (output_dir , exist_ok = True )
394+ cmd = "ghdl --std={std} {input} -e {module}; write_verilog {output}" .format (
395+ std = ghdl_std ,
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,26 @@ 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 (yet)" )
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 ,
428+ self .builder .config .hdl_diagram_ghdl , self .builder .config .hdl_diagram_ghdl_std , yosys )
429+ source_path = ilfn
394430 else :
395431 raise HDLDiagramError ("hdl_diagram_code file extension must be one of '.v', "
396- "'.il', or '.py ', but is %r" % source_ext )
432+ "'.il', '.py', '.vhd', or '.vhdl ', but is %r" % source_ext )
397433
398434 if path .isfile (outfn ):
399435 print ('Exiting file:' , outfn )
@@ -404,7 +440,6 @@ def render_diagram(self, code, options, format, skin, yosys_script):
404440 yosys_script = options ['yosys_script' ] if options ['yosys_script' ] is not None else yosys_script
405441 skin = options ['skin' ] if options ['skin' ] is not None else skin
406442
407- yosys = self .builder .config .hdl_diagram_yosys
408443 yosys_options = HDLDiagram .global_variable_options ["hdl_diagram_yosys" ]
409444 if yosys not in yosys_options and not os .path .exists (yosys ):
410445 raise HDLDiagramError ("Yosys not found!" )
@@ -441,6 +476,9 @@ def render_diagram_html(
441476 self , node , code , options , imgcls = None , alt = None ):
442477 # type: (nodes.NodeVisitor, hdl_diagram, unicode, Dict, unicode, unicode, unicode) -> Tuple[unicode, unicode] # NOQA
443478
479+ diagram_error = False
480+ diagram_error_message = ""
481+
444482 yosys_script = self .builder .config .hdl_diagram_yosys_script
445483 if yosys_script != 'default' and not path .exists (yosys_script ):
446484 raise HDLDiagramError ("Yosys script file {} does not exist! Change hdl_diagram_yosys_script variable" .format (yosys_script ))
@@ -457,9 +495,16 @@ def render_diagram_html(
457495 fname , outfn = render_diagram (self , code , options , format , skin , yosys_script )
458496 except HDLDiagramError as exc :
459497 logger .warning ('hdl_diagram code %r: ' % code + str (exc ))
460- raise nodes .SkipNode
461-
462- if fname is None :
498+ diagram_error = True
499+ diagram_error_message = str (exc )
500+ # raise nodes.SkipNode
501+
502+ if diagram_error :
503+ self .body .append ('<div class="admonition warning">'
504+ '<paragraph class="admonition-title">{title}: </paragraph>'
505+ '<paragraph>hdl_diagram code <code>{file}</code>: {message}</paragraph>'
506+ '</div>' .format (title = "Warning" , file = code , message = diagram_error_message ))
507+ elif fname is None :
463508 self .body .append (self .encode (code ))
464509 else :
465510 if alt is None :
@@ -568,4 +613,6 @@ def setup(app):
568613 app .add_config_value ('hdl_diagram_skin' , 'default' , 'html' )
569614 app .add_config_value ('hdl_diagram_yosys_script' , 'default' , 'html' )
570615 app .add_config_value ('hdl_diagram_yosys' , 'yowasp' , 'html' )
616+ app .add_config_value ('hdl_diagram_ghdl' , 'built-in' , 'html' )
617+ app .add_config_value ('hdl_diagram_ghdl_std' , '08' , 'html' )
571618 return {'version' : '1.0' , 'parallel_read_safe' : True }
0 commit comments