Graphics
Graphics help people learn, break up text, and can overall improve your document content.
While AsciiDoc can render graphics in all popular formats, by far the highest quality graphics rendering is from .svg format. This format is the preferred graphic type to use in RISC-V documents.
The asciidoctor-diagram extension supports numerous diagram types. Some types that are common are:
You can certainly use one of the other supported types, but know that they might cause issues with the build. Please contact the RISC-V docs team before using them.
Graphics best practices
Follow these guidelines for graphics.
-
Store your graphics in a subfolder. For the RISC-V main ISA doc, this folder is the
imagesfolder. Place your graphic in the subfolder that correspondes to its type. -
The build process creates the final image object. Do not create any generated image files into GitHub.
-
Introduce your graphic with a lead-in sentence. "The following image shows …"
-
Use "following" and "preceding" to locate your image. Avoid using "above" or "below" (Doesn’t make sense for people that use screen readers.)
-
Avoid using text in your image. If it can be included as regular text, then don’t include it as part of the image. (screen readers again).
-
Images should support your text. Do not put important information in only an image.
Wavedrom diagrams in specifications
Wavedrom diagrams are used mainly for registers. To specify a wavedrom file, create a json file and then call it from your text. For more information, see WaveDrom sequence diagrams.
The following json-formatted script, when added within an AsciiDoc block with the macro indicators [wavedrom, ,svg], embeds the diagram output into the PDF:
{reg:[
{ bits: 7, name: 0x3b, attr: ['OP-32'] },
{ bits: 5, name: 'rd' },
{ bits: 3, name: 0x0, attr: ['ADD.UW'] },
{ bits: 5, name: 'rs1' },
{ bits: 5, name: 'rs2' },
{ bits: 7, name: 0x04, attr: ['ADD.UW'] },
]}
|
The macro DO NOT make the mistake of simply using |
In the specifications, there are numerous instances in which several Wavedrom diagrams are grouped and presented as a single figure. To handle these cases while preserving consistency in how the build renders figure titles, we use a minimalistic, white graphic with the filename image_placeholder.png that blends in with the page background. The following example shows the pattern of its use (minus the macro indicator [] in the first line:
include::../partials/wavedrom/instruction_formats.adoc
[[instruction_formats]]
.Test for wavedrom
image::image_placeholder.png[]
With the following result:
-
Wavedrom code for all diagrams in this illustration are stored in
../partials/wavedromsubdirectory within the partials directory. -
Link target that, along with settings in the
book_headerfile, automates the inclusion, in the text, of the figure number and caption. -
Figure caption.
-
"Invisible" placeholder needed for figure caption to display consistently and correctly.
Explanation
For the previous example to build into a diagram that includes a figure title, and a figure title and a macro the specifies the diagram type before the code block. You can add a target filename and, in addition, specify the image output format to be svg.
When prepended to the javascript for a Wavedrom diagram, the following creates file-name.svg with the legend Figure title:
.Figure title
[wavedrom,target="file-name",svg]
Following are some examples of Wavedrom diagrams:
.Figure title
[wavedrom,target="op-32-add-uw",]
....
{reg:[
{ bits: 7, name: 0x3b, attr: ['OP-32'] },
{ bits: 5, name: 'rd' },
{ bits: 3, name: 0x0, attr: ['ADD.UW'] },
{ bits: 5, name: 'rs1' },
{ bits: 5, name: 'rs2' },
{ bits: 7, name: 0x04, attr: ['ADD.UW'] },
]}
....
Wavedrom Conversion
|
The following string is lacking macro brackets (
|
Graphviz
The Unpriv appendices contain Graphviz diagrams with associated keys that are arranged in tables. While in the LaTeX version, the diagrams and tables are arranged side-by-side, for the AsciiDoc version;
-
each Graphviz diagram should be directly above the key table.
-
store scripts for Graphviz diagrams in the
graphvizsubdirectory within the images directory (modules/ROOT/images/graphviz/), as <filename>.txt -
import the Graphviz by reference using the pattern in the following example.
.Sample litmus test
graphviz::images/graphviz/litmus_sample.txt[align="center"]
[cols="2,1"]
_Key for sample litmus test_
[width="60%",cols="^,<,^,<",options="header",align="center"]
|===
|Hart 0 | |Hart 1 |
| |latexmath:[$\vdots$] | |latexmath:[$\vdots$]
| |li t1,1 | |li t4,4
|(a) |sw t1,0(s0) |(e) |sw t4,0(s0)
| |latexmath:[$\vdots$] | |latexmath:[$\vdots$]
| |li t2,2 | |
|(b) |sw t2,0(s0) | |
| |latexmath:[$\vdots$] | |latexmath:[$\vdots$]
|(c) |lw a0,0(s0) | |
| |latexmath:[$\vdots$] | |latexmath:[$\vdots$]
| |li t3,3 | |li t5,5
|(d) |sw t3,0(s0) |(f) |sw t5,0(s0)
| |latexmath:[$\vdots$] | |latexmath:[$\vdots$]
|===
ENOENT: no such file or directory, open 'images/graphviz/litmus_sample.txt' - graphviz::images/graphviz/litmus_sample.txt[]
Key for sample litmus test
| Hart 0 | Hart 1 | ||
|---|---|---|---|
|
|
||
li t1,1 |
li t4,4 |
||
(a) |
sw t1,0(s0) |
(e) |
sw t4,0(s0) |
|
|
||
li t2,2 |
|||
(b) |
sw t2,0(s0) |
||
|
|
||
(c) |
lw a0,0(s0) |
||
|
|
||
li t3,3 |
li t5,5 |
||
(d) |
sw t3,0(s0) |
(f) |
sw t5,0(s0) |
|
|
| The procedures for Graphviz diagrams are similar but not identical to procedures for Wavedrom diagrams in specifications. |
Following is an example of Graphviz diagram source:
.Graphviz s
[graphviz, target="ethane",svg]
....
graph ethane {
C_0 -- H_0 [type=s];
C_0 -- H_1 [type=s];
C_0 -- H_2 [type=s];
C_0 -- C_1 [type=s];
C_1 -- H_3 [type=s];
C_1 -- H_4 [type=s];
C_1 -- H_5 [type=s];
}
....
This renders as:
Ditaa diagrams
Following is source for simple ditaa diagram:
[ditaa,target="image-example",svg]
....
+-------------+
| Asciidoctor |-------+
| diagram | |
+-------------+ | SVG out
^ |
| ditaa in |
| v
+--------+ +--------+----+ /---------------\
| | --+ Asciidoctor +--> | |
| Text | +-------------+ | Beautiful |
|Document| | !magic! | | Output |
| {d}| | | | |
+---+----+ +-------------+ \---------------/
: ^
| Lots of work |
+-----------------------------------+
....
Which renders to:
Following is source for a simple plantuml diagram:
[plantuml, diagram-classes, svg]
....
class BlockProcessor
class DiagramBlock
class DitaaBlock
class PlantUmlBlock
BlockProcessor <|-- DiagramBlock
DiagramBlock <|-- DitaaBlock
DiagramBlock <|-- PlantUmlBlock
....
Which renders to:
| Asciidoctor supports additional diagram types. For information on additional diagram types, see the Asciidoctor-diagram documentation. |
Bytefield diagrams
Bytefield diagrams are used for register graphics that cannot be rendered in wavedrom. For more information, see Bytefield diagrams.
Bytefield diagrams look similar to the following example.
(defattrs :plain [:plain {:font-family "M+ 1p Fallback" :font-size 24}])
(def row-height 40 )
(def row-header-fn nil)
(def left-margin 30)
(def right-margin 30)
(def boxes-per-row 32)
(draw-column-headers {:height 24 :font-size 24 :labels (reverse ["0" "1" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "HSXLEN-1" ""])})
(draw-box "Guest External Interrupts" {:span 18 :text-anchor "end" :borders {:left :border-unrelated :top :border-unrelated :bottom :border-unrelated}})
(draw-box (text "(WARL)" {:font-weight "bold" :font-size 24}) {:span 13 :text-anchor "start" :borders {:top :border-unrelated :bottom :border-unrelated}})
(draw-box "0" )
(draw-box "HSXLEN" {:font-size 24 :span 31 :borders {}})
(draw-box "1" {:borders {}})
Then you can include it with the following statement (the {} are to keep it from rendering):
{.Counter-enable (`mcounteren`) register.
include::../partials/bytefield/examplebyte.adoc[]}
After the build, it looks like this example:
mcounteren) register.Editing Wavedrom diagrams for Unpriv
Relevant contextual information
Wavedrom is a utility that is available at https://wavedrom.com/.
Example Wavedrom code, before and after
Following is an example Wavedrom file that is typical of one the needs just a few edits, minus the [] brackets that indicate a macro (because using the macro even within a code block activates a process in the Asciidoctor build):
{reg: [
{bits: 7, name: 'opcode', attr: ['FMADD', 'FNMADD', 'FMSUB', 'FNMSUB'], type: 8},
{bits: 5, name: 'rd', attr: 'dest', type: 2},
{bits: 3, name: 'func3', attr: 'RM', type: 8},
{bits: 5, name: 'rs1', attr: 'src1', type: 4},
{bits: 5, name: 'rs2', attr: 'src2', type: 4},
{bits: 2, name: 'fmt', attr: 'Q', type: 8},
{bits: 5, name: 'rs3', attr: 'src3', type: 4},
]}
This renders as follows:
type: attribute so that it remains easy to see:{reg: [
{bits: 7, name: 'opcode', type: 8, attr: ['FMADD', 'FNMADD', 'FMSUB', 'FNMSUB'], },
{bits: 5, name: 'rd', type: 2, attr: 'dest', },
{bits: 3, name: 'func3', type: 8, attr: 'RM', },
{bits: 5, name: 'rs1', type: 4, attr: 'src1', },
{bits: 5, name: 'rs2', type: 4, attr: 'src2', },
{bits: 2, name: 'fmt', type: 8, attr: 'Q', },
{bits: 5, name: 'rs3', type: 8, attr: 'src3', },
]}
The output remains the same:
-
For each line that contain a single value for the
attrattribute:-
add
[]to contain additional values—and-- -
follow the convention for commas to contain and separate additional values until all the lines contain the same number of values for
attrthat are in the 'opcodes' row:
-
{reg: [
{bits: 7, name: 'opcode', type: 8, attr: ['FMADD', 'FNMADD', 'FMSUB', 'FNMSUB'], },
{bits: 5, name: 'rd', type: 2, attr: ['dest','dest','dest','dest',],},
{bits: 3, name: 'func3', type: 8, attr: ['RM','RM','RM','RM',], },
{bits: 5, name: 'rs1', type: 4, attr: ['src1','src1','src1','src1',], },
{bits: 5, name: 'rs2', type: 4, attr: ['src2','src2', 'src2', 'src2', ], },
{bits: 2, name: 'fmt', type: 8, attr: ['Q','Q','Q','Q',], },
{bits: 5, name: 'rs3', type: 8, attr: ['src3','src3','src3','src3',], },
]}
|
Wavedrom makes use of straight single quotes like |
Here’s the result:
-
Check the LaTeX version of the diagram to check for the numerical values that are needed within the missing row:
{reg: [
{bits: 7, name: 'opcode', type: 8, attr: ['8', 'FMADD', 'FNMADD', 'FMSUB', 'FNMSUB'], },
{bits: 5, name: 'rd', type: 2, attr: ['6', 'dest','dest','dest','dest',], },
{bits: 3, name: 'func3', type: 8, attr: ['4', 'RM','RM','RM','RM',], },
{bits: 5, name: 'rs1', type: 4, attr: ['6', 'src1','src1','src1','src1',], },
{bits: 5, name: 'rs2', type: 4, attr: ['6', 'src2','src2', 'src2', 'src2', ], },
{bits: 2, name: 'fmt', type: 8, attr: ['4', 'Q','Q','Q','Q',], },
{bits: 5, name: 'rs3', type: 8, attr: ['6', 'src3','src3','src3','src3',], },
]}
Now the diagram should contain all of the content that exists within the LaTeX version:
-
If you or a member of your team can build locally, please ensure that someone checks that the diagrams build without errors.
-
Generate a PR to the convert2adoc branch and indicate whether you or a member of the team has tested your changes in a local build.
-
As always, thanks for your participation in the success of RISC-V.
Caveats for editing wavedrom diagrams
At the time of this writing, we have noticed the following unexpected results during diagram builds using the asciidoctor-pdf toolchain, as follows:
-
Some, but not all, unicode that works in AsciiDoc (see [useful-unicode] ) actually breaks the Wavedrom diagram build, and other unicode does not break the Wavedrom diagram build but still doesn’t render properly.
-
Latexmath appears to not work at all in Wavedrom diagrams.
-
After struggling to understand why various options that we explored for an acceptable ≠ in Wavedrom diagrams and discovering the above rather confusing results, we decided to use
!=as a workaround. With the fact that both Asciidoctor and Wavedrom are evolving, and also the fact that bytefield is being considered as an alternative diagrams rendering solution, it seems possible that this workaround will be temporary.