[otbn,doc] Re-organise ISA rendering

Add some headings and generally re-order things a bit to make the
rendered documentation a bit more readable.

Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/ip/otbn/util/yaml_to_doc.py b/hw/ip/otbn/util/yaml_to_doc.py
index e7ffa9a..7630dd1 100755
--- a/hw/ip/otbn/util/yaml_to_doc.py
+++ b/hw/ip/otbn/util/yaml_to_doc.py
@@ -243,10 +243,11 @@
     assert heading_level > 0
 
     parts = []
+    mnem = insn.mnemonic.upper()
+    subhead = '#' * (heading_level + 1) + ' '
 
     # Heading, based on mnemonic (upper-cased)
-    parts.append('{} {}\n'.format('#' * heading_level,
-                                  insn.mnemonic.upper()))
+    parts.append('{} {}\n'.format('#' * heading_level, mnem))
 
     # If there's a note, render it as a callout
     if insn.note is not None:
@@ -263,18 +264,20 @@
     # Optional documentation (using existing markdown formatting). Add a blank
     # line afterwards to separate from the syntax and operand table.
     if insn.doc is not None:
-        parts.append(insn.doc + '\n\n')
-
-    # Syntax example: either given explicitly or figured out from operands
-    parts.append("```\n")
-    parts.append(insn.mnemonic.upper() + ('' if insn.glued_ops else ' '))
-    parts.append(insn.syntax.render_doc())
-    parts.append("\n```\n\n")
+        parts.append(insn.doc + '\n')
+    parts.append('\n')
 
     # If this came from the RV32I instruction set, say so.
     if insn.rv32i:
         parts.append('This instruction is defined in the RV32I instruction set.\n\n')
 
+    # Syntax example: either given explicitly or figured out from operands
+    parts.append(subhead + 'Syntax\n')
+    parts.append("```\n")
+    parts.append(insn.mnemonic.upper() + ('' if insn.glued_ops else ' '))
+    parts.append(insn.syntax.render_doc())
+    parts.append("\n```\n\n")
+
     is_pseudo = insn.literal_pseudo_op or insn.python_pseudo_op
 
     # If we have an encoding, match up encoding fields with operands
@@ -287,10 +290,12 @@
     # Show the operand table if there is at least one operand and this isn't a
     # pseudo-op.
     if insn.operands and not is_pseudo:
+        parts.append(subhead + 'Operands\n')
         parts.append(render_operand_table(insn.operands, o2e))
 
     # Show encoding if we have one
     if e2o is not None:
+        parts.append(subhead + 'Encoding\n')
         assert insn.encoding is not None
         parts.append(render_encoding(insn.mnemonic, insn.encoding, e2o))
 
@@ -299,8 +304,7 @@
         parts.append(render_literal_pseudo_op(insn.literal_pseudo_op))
 
     if impl is not None:
-        parts.append('{} Operation\n\n'
-                     .format('#' * (heading_level + 1)))
+        parts.append(subhead + 'Operation\n')
 
         # Add a handy header to remind readers that enum operands and option
         # operands are referred to by their integer values.