Sphinx HDL Diagrams¶
sphinx-hdl-diagrams is an extension to Sphinx to make it easier to write nice documentation from HDL source files, in the form of Verilog, nMigen, or RTLIL code.
You use the .. hdl-diagram RST directive to generate various styles of diagrams from HDL code.
Most of the time there will be a license header at the top of source code, which we might not want to show in the documentation. This extension also provides the .. no-license RST directive which works exactly like the .. literalinclude directive, but the lines option is overridden to only show the lines after the license header.
The project repository is hosted on GitHub.
Installation¶
Python 3.5+ is required.
pip install sphinxcontrib-hdl-diagrams
Or,
python3 -m pip install sphinxcontrib-hdl-diagrams
Sphinx integration¶
In your conf.py, add the following lines.
extensions = [
...,
'sphinxcontrib_hdl_diagrams',
]
Non-python dependencies¶
These dependencies can either be installed on your system or you can install them using the conda environment.yml file.
yosys (required)
netlistsvg (optional)
Usage¶
hdl-diagram¶
The hdl-diagram RST directive can be used to generate a diagram from HDL code and include it in your documentation.
.. hdl-diagram:: file.v
:type: XXXXX
:module: XXXX
:flatten:
Options¶
:type: - Verilog Diagram Types;
yosys-blackbox - Netlist rendered by Yosys.
yosys-aig - Verilog file run through aigmap before image is generated directly in Yosys.
netlistsvg - Render output with netlistsvg
:module: - Which module to diagram.
:flatten: - Use the Yosys flatten command before generating the image.
no-license¶
The no-license RST directive can be used to include code without license headers.
.. no-license:: file.v
:language: verilog
:linenos:
:caption: examples/verilog/dff.v
Options¶
This directive merely overrides the lines and lineno-start options of the literalinclude directive. So, refer to literalinclude for the available options.
Directives¶
hdl-diagram¶
The hdl-diagram RST directive can be used to generate a diagram from HDL code and include it in your documentation.
.. hdl-diagram:: file.v
:type: XXXXX
:module: XXXX
:flatten:
Note
The verilog-diagram directive is kept as an alias of this directive for compatibility purposes.
:type: - Verilog Diagram Types;
yosys-blackbox - Netlist rendered by Yosys.
yosys-aig - Verilog file run through aigmap before image is generated directly in Yosys.
netlistsvg - Render output with netlistsvg
:module: - Which module to diagram.
:flatten: - Use the Yosys flatten command before generating the image.
This directive supports 3 input formats: Verilog code, nMigen code, and RTLIL.
19 20 21 22 23 24 25 26 27 | module top (
input clk,
output o
);
reg [2:0] counter = 0;
always @(posedge clk)
counter <= counter + 1;
assign o = counter[2];
endmodule
|
1 2 | .. hdl-diagram:: ../code/verilog/counter.v
:type: netlistsvg
|
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | from nmigen import *
from nmigen.back import rtlil
class Counter(Elaboratable):
def __init__(self, width):
self.v = Signal(width, reset=2**width-1)
self.o = Signal()
def elaborate(self, platform):
m = Module()
m.d.sync += self.v.eq(self.v + 1)
m.d.comb += self.o.eq(self.v[-1])
return m
ctr = Counter(width=16)
print(rtlil.convert(ctr, ports=[ctr.o]))
|
1 2 | .. hdl-diagram:: ../code/nmigen/counter.py
:type: netlistsvg
|
Note
As hdl-diagram expects the nMigen script to write RTLIL code to stdout, make sure to include the following lines of code.
1 2 | from nmigen.back import rtlil
print(rtlil.convert(..., ports=[...]))
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | attribute \generator "nMigen"
attribute \top 1
attribute \nmigen.hierarchy "top"
module \top
attribute \src "counter.py:9"
wire width 1 output 0 \o
attribute \src "/usr/local/lib/python3.7/site-packages/nmigen/hdl/ir.py:526"
wire width 1 input 1 \clk
attribute \src "/usr/local/lib/python3.7/site-packages/nmigen/hdl/ir.py:526"
wire width 1 input 2 \rst
attribute \src "counter.py:8"
wire width 16 \v
attribute \src "counter.py:8"
wire width 16 \v$next
attribute \src "counter.py:13"
wire width 17 $1
attribute \src "counter.py:13"
wire width 17 $2
attribute \src "counter.py:13"
cell $add $3
parameter \A_SIGNED 1'0
parameter \A_WIDTH 5'10000
parameter \B_SIGNED 1'0
parameter \B_WIDTH 1'1
parameter \Y_WIDTH 5'10001
connect \A \v
connect \B 1'1
connect \Y $2
end
connect $1 $2
process $group_0
assign \v$next \v
assign \v$next $1 [15:0]
attribute \src "/usr/local/lib/python3.7/site-packages/nmigen/hdl/xfrm.py:530"
switch \rst
case 1'1
assign \v$next 16'1111111111111111
end
sync init
update \v 16'1111111111111111
sync posedge \clk
update \v \v$next
end
process $group_1
assign \o 1'0
assign \o \v [15]
sync init
end
end
|
1 2 | .. hdl-diagram:: ../code/rtlil/counter.il
:type: netlistsvg
|
no-license¶
The no-license RST directive can be used to include code without license headers.
.. no-license:: file.v
:language: verilog
:linenos:
:caption: examples/verilog/dff.v
This directive merely overrides the lines and lineno-start options of the literalinclude directive. So, refer to literalinclude for the available options.
1 2 3 | .. literalinclude:: ../code/verilog/dff.v
:language: verilog
:linenos:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /*
* Copyright (C) 2020 The SymbiFlow Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
// Single flip-flip test.
module top(input clk, input di, output do);
always @( posedge clk )
do <= di;
endmodule // top
|
Examples¶
Combinational Full Adder¶
1 2 3 | .. no-license:: ../code/verilog/adder.v
:language: verilog
:linenos:
|
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | module ADDER (
a, b, cin,
sum, cout
);
input wire a;
input wire b;
input wire cin;
output wire sum;
output wire cout;
// Full adder combinational logic
assign sum = a ^ b ^ cin;
assign cout = ((a ^ b) & cin) | (a & b);
endmodule
|
1 2 3 | .. hdl-diagram:: ../code/verilog/adder.v
:type: yosys-bb
:module: ADDER
|
CARRY4 example for Series 7 FPGA¶
19 20 21 22 23 24 25 | module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
assign O = S ^ {CO[2:0], CI | CYINIT};
assign CO[0] = S[0] ? CI | CYINIT : DI[0];
assign CO[1] = S[1] ? CO[0] : DI[1];
assign CO[2] = S[2] ? CO[1] : DI[2];
assign CO[3] = S[3] ? CO[2] : DI[3];
endmodule
|
1 2 3 | .. hdl-diagram:: ../code/verilog/carry4-whole.v
:type: netlistsvg
:module: CARRY4
|
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | `include "muxcy.v"
`include "xorcy.v"
module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
wire CIN = CI | CYINIT;
MUXCY muxcy0 (.O(CO[0]), .CI(CIN), .DI(DI[0]), .S(S[0]));
MUXCY muxcy1 (.O(CO[1]), .CI(CO[0]), .DI(DI[1]), .S(S[1]));
MUXCY muxcy2 (.O(CO[2]), .CI(CO[1]), .DI(DI[2]), .S(S[2]));
MUXCY muxcy3 (.O(CO[3]), .CI(CO[2]), .DI(DI[3]), .S(S[3]));
XORCY xorcy0 (.O(O[0]), .CI(CIN), .LI(S[0]));
XORCY xorcy1 (.O(O[1]), .CI(CO[0]), .LI(S[1]));
XORCY xorcy2 (.O(O[2]), .CI(CO[1]), .LI(S[2]));
XORCY xorcy3 (.O(O[3]), .CI(CO[2]), .LI(S[3]));
endmodule
|
19 20 21 | module MUXCY(output O, input CI, DI, S);
assign O = S ? CI : DI;
endmodule
|
19 20 21 | module XORCY(output O, input CI, LI);
assign O = CI ^ LI;
endmodule
|
1 2 3 4 | .. hdl-diagram:: ../code/verilog/muxcy.v
:type: netlistsvg
:caption: muxcy.v
:module: MUXCY
|
muxcy.v¶
1 2 3 4 | .. hdl-diagram:: ../code/verilog/xorcy.v
:type: netlistsvg
:caption: xorcy.v
:module: XORCY
|
xorcy.v¶