Skip to main content

Crate yarig

Crate yarig 

Source
Expand description

§YARIG: Yet Another Register Interface Generator

YARIG is a code generation tool to describe register interface of an IP or ASIC/FPGA design.

This allows to have one common source to describes registers for all the different views:

  • Hardware: for the actual hardware implementation (SystemVerilog and VHDL)
  • Software: for interacting with the register such a C header, UVM RAL, python classes, …
  • Documentation: for readable description (HTML/Latex/…)

§Quick Start

YARIG uses its own file format named .rif to describe registers. The objectives when designing the language were to make it easy to read and write, keep simple registers on a single line, offer fine control on the generated hardware, and allow re-use and hierarchical description.

§Example

rif: test_rif
  addrWidth: 8
  dataWidth: 16
  - Main:
    registers:
      - ctrl: "Basic control register"
        - en      = 0    0:0        "Block enable"
        - start   = 0    0:0  pulse "Start block"
        - version = 0x12 15:8 ro    "Block version"
          hw na
    instances: auto

§Usage as a Library

While YARIG is primarily used as a command-line tool, you can also use it as a library in your Rust projects. The main modules are:

  • cfg: Configuration management and generation orchestration
  • parser: RIF file parsing
  • rifgen: Parsed RIF data structures
  • comp: Compiled component instances with hardware abstractions
  • generator: Code generation for various output targets

The typical flow is: parsecompilegenerate

See the cfg::YarigCfg documentation for examples of programmatic usage.

§Detailed Documentation

§RIF syntax

The syntax for the RIF is loosely inspired by YAML: a human readable text file with structure based on indentation. It supports comments starting with // or #.

It is composed of different levels:

  • Top : Top level structure, only one per file, contains settings, parameters and pages
  • Page: group of register and register instance, with a base address
  • Registers: Register declaration, regrouping field
  • Field : N bits inside a register
  • RegisterInstance: Instance name of a register with a given address

The convention notation when describing syntax is the following:

  • name inside angle bracket (e.g. <value>) represents a mandatory value (integer/string/expression depending on the context)
  • name inside straight bracket represents optional values or keyword (e.g. [<value>] or [kw])
  • List of label separated by pipe (e.g. ro|rw|rclr) represents a list of valid keywords expected. This can be combined with straight bracket for list of optional keywords.

The casing convention is snake_case in the RIF definition: generators have option to individually change the casing of the generated files.

§Example

Here is a simple RIF definition:

rif: test_rif
  addrWidth: 8
  dataWidth: 16
  - Main:
    registers:
      - ctrl: "Basic control register"
        - en      = 0    0:0        "Block enable"
        - start   = 0    0:0  pulse "Start block"
        - version = 0x12 15:8 ro    "Block version"
          hw na
      - interrupt: "Interrupt register"
        interrupt rising en=0x13 mask=0x37 pending w1clr
        enable.description "Enable interrupt"
        mask.description "Mask interrupt"
        pending.description "Pending interrupt"
        - gen   = 0 7:0 rw "Generic Events"
        - busy  = 0 8:8 "Busy"
        - ready = 0 9:9 "Ready"
      - status: "Status register"
        - state  3:0 "Current state"
        - success 4:4 "Last operation succeed"
        - failed  5:5 "Last operation failed"
    instances: auto

§Top

The component regroups some top level information about the RIF, definition of signals and parameters. Syntax is rif: <rifName> where rifName is the name which be used for the RTL module name as well as the base filename of all outputs.

The possible properties, indented by one level compare to the RIF declaration, are:

  • addrWidth : <addrWidth> : Number of bits of the address bus (byte aligned)
  • dataWidth : <dataWidth> : Number of bits of the data bus
  • interface : <ifname> : Define the type of interface used for the RIF. Possible value are default, apb, uaux. By default uses a memory like interface (with a done signal asserted when access is complete).
  • description : <blabla> : Provides some high level information. Mainly for documentation (e.g. HTML output). Quotation mark are optional and removed for the first line. Description can be on multiple lines as long as it is indented by at least one level compare to the keyword description. For example:
  description:
    First line of description
    Second line of description
  • swClock : <clock_name> : Name the software clock signal clock_name (clk by default)
  • hwClock : <clock_name0> <clock_name1> ... : Declare hardware clocks. The first one will be the default one.
  • swReset|hwReset : <rst_name> [activeLow|activeHigh] [async|sync]: Specify reset signal for software/hardware.
  • swClkEn|hwClkEn : <clk_en_name> : Specify default clock enable signal for software/hardware clocks. This can be overriden on a register basis
  • swClear : <clear_name> : Declare a global clear clear_name active high to clear all software register (no clear by default)
  • hwClear : <clear_name0> <clear_name1> ... : Declare global hardware clears clear_name active high to clear all hardware register (no clear by default). There should be as many signal declared as there are hwClock: same name can be repeated and the minus character - can be used indicate that there is no clear for the corresponding hwClock.
  • suffixPkg : <boolean> : Apply suffix to the generated package file as well (default: false)
  • parameters : : Start a parameter list. See paragraph Parameters.
  • generics : : Start a generic list. See paragraph Generics.
  • - pageName : [description] : Start a page named pageName. See below. The name is used only inside the documentation.

The only mandatory property is at least one page. By default the address is on 16b, the data on 32, the clock is named clk, the reset is rst_n (asynchronous, active low) and used for both hardware and software logic.

§Parameters

A parameter is pair name/value declared with - <NAME> = <value_or_expr>.

Parameters can be used as reset value, field width, array size (both register and field): simply prefix the name of the parameter by $

Declaration of parameter can use arithmetic operation and reference other parameters: - PARAM1 = 2*$PARAM2-1 + ceil(log2($WIDTH)). It supports all basic arithmetic operation and a few functions like pow, log2, log10, ceil and floor. Note that pow, log2 and log10 output is a floating point number and should typically be associated with ceil/floor operation when the parameter value is used for field width or array size.

Parameters value can be overridden by a command-line argument --parameters <name>=<value>

§Generics

A generic is defined as - <name> = [<min>:]<default>:<max> "description".

This generate an RTL with input parameter. The generic value can be used for register instances array size, control of optional register or optional component in a RifMux. If no minimum value is provided, it is set to 1.

§Page

The page contains the definition of n registers , their register instances and a few page properties.

The available options, indented by one level compare to the page, are:

  • baseAddress <offset> : Address offset of all register inside the page. Format can be decimal (64) or hexadecimal (0x20)
  • addrWidth <nb_bit> : Define the page range in Number of bits. Format can be decimal (64) or hexadecimal (0x20). This is only required for external pages
  • description : Page description. Mainly for documentation (e.g. HTML output).
  • clkEn : <clock_enable_name> : Define a clock enable signal for all register in the page
  • external : Indicates that the page logic is external. The only logic provided will be the address decoding.
  • optional : <condition> : Indicate that the register of a page are instantiated only if the condition is true. The condition should be a valid arithemtic expression where parameters can be used: this supports standard math operation (+,-,*,%,<<,>>) or comparison operator (==,!=,>,<,…).
  • registers: : Start the register declaration entry. See below for detail.
  • instances: : Start the register instances entry. See below for detail.
  • include <rifName>.<pageName> : Include a page from another RIF, both register definition and instance. This cannot be mixed with manual registers/instances entry !

§Register

The register is a group of fields with some basic properties.

Its declaration is indented by one level compare to the registers keyword and follow the syntax: - <reg_name>: [(<regGroup>)] ["Register short description"]

The optional register group is specific to the RTL view and allows to regroup multiple registers under the same structure. regGroup can be in the form of rifname::groupname to reference a structure from another RIF.

The register properties, indented by one level compare to the register declaration, are:

  • clock <clock_name> : Indicate which clock (amongst the software and all hardware clocks) should be used for this register. By default the first hardware clock is used for all register with write access from hardware, and the software clock used for all others.
  • hwReset <reset_name> : Indicate which reset (amongst all hardware reset) should be used for this register. By default the swReset is used for every register controled by software and the hwReset for every register controlled by hardware. If the clock is changed manually the reset should also be set manually
  • clkEn <clock_enable_name> : Define a clock enable signal for all fields in the register. If a global clock enable was defined, the value False can be used to have a register with no clock enable.
  • description: <long description> : More detailled register description. Mainly for documentation (e.g. HTML output). Description can be on multiple lines as long as it is indented by at least one level compare to the keyword description Description can contains latex equation enclosed between backtick: e.g. eq=`\\frac{e^3}{c_1 + c_2}`
  • description.hidden: <extra description : Extra description displayed only when documentation is generated without the –doc_hide flag
  • mask|enable.description <long description> : For interrupt register, set the description of the associated mask and enable register.
  • external : The register logic is handled outside of the RIF which provides additional signal related to address decoding.
  • externalDone : The register logic for the done access is handled outside of the RIF, allowing to add wait state.
  • wrPulse|rdPulse|accPulse [comb|reg] [<clock_name>] : A pulse is generated when the register is, respectively written, read or both. The pulse can be combinatorial (i.e. the pulse happens at the same time as the register access) or registered (i.e. one clock latency). By default, the read pulse is combinatorial while the write/access are registered. When registered, a clock can be provided to indicate a different clock than the register one to generate the pulse.
  • interrupt high|low|rising|falling|edge [en[=<val_enable>]] [mask[=<val_mask>]] [pending] [rclr|wclr|w0clr|w1clr|hwclr] : Indicates that all fields in the register are interrupts, active either on a level (high or low) or an edge (rising, falling or both). The optional enable property will auto declare a register to enable the interrupt with same name as the interrupt register plus _en with a reset value valEnable (for the whole register). Every hardware interrupt goes through an and of the enable register before updating the status register. The optional mask property will auto declare a register to mask the interrupt with same name as the interrupt register plus _mask with a reset value valMask (for the whole register). The interrupt request signal is the OR of an AND between the status register and the mask register. So, when the value for a field is 0, the corresponding interrupt status is asserted but this does not trigger the interrupt request. The optional pending property (only allowed if a mask is used) will auto declare a read-only register containing the AND of the status and the mask (which was used to generate the external interrupt request signal). Default to level high, with clear on read with no mask, enable or pending if no information is provided.
  • alt <name> [en[=<val_enable>]] [mask[=<val_mask>]] [pending] ["<description>"]: only valid for interrupt register. Allows to define an alternative interrupt register with a different enable/mask/pending settings and a secondary interrupt request output. This is useful when needing two configurable interrupt lines with different priority using the same set of interrupt event
  • clear : Synchronous clear signal for the register, setting all fields to their reset values
  • hidden : Hide the register in any documentation (HTML, MIF, C Header) when the visibility is set to public (generator setting)
  • disabled : Force the register to its reset value. Used typically when overloading included register.
  • reserved : Rename register in any documentation to rsvd when the visibility is set to public (generator setting). Also remove description.
  • optional : <condition> : Indicate that the register is defined only if the condition is true or different from 0. The condition should be a valid arithmetic expression where parameters can be used (e.g. $REG1_EN==1): this supports standard math operation (+,-,*,%,<<,>>) or comparison operator (==,!=,>,<,…).
  • optional_acc: [na|ro|rw]: Control the software access (ro) of register which are due to parameters value. Default is na (any access will generate a bus access error).
  • - <fieldName> ... : Define a fields named fieldName inside the register. See below for detail.

It is also possible to include the definition from another rif file using the following syntax:

  • - include <rifName>.* : Include all register definition
  • - include <rifName>.<pageName>.* : Include all register defined in a page
  • - include <rifName>.<regName> : Include only one register

§Field

The field is group of bits inside a registers.

Its declaration is indented by one level compare to the register declaration and follow the syntax: - <field_name> [= <reset_value>] <msb>:<lsb> [ro|rw|rclr|w1clr|w0clr|w1set|pulse|pulsecomb] ["Field short description"]

The reset_value supports multiple format:

  • decimal value: if it starts by + or -, the field will be automatically flagged as signed
  • hexadecimal value using C or SystemVerilog notation (0xABCD or 11'h4CD)
  • parameter value using $<PARAM_NAME>
  • enum value if the field has an enum property defined
  • floating value if the field has a number of fractional bit defined (e.g. for a field with 3 fractional bit a reset value of 4.125 will be translated as a reset value of 33).

The field position can also use the systemVerilog range syntax <lsb>+:<width> instead of <msb>:<lsb> or even just <width> in which case the field is position on the next available bit (starting from 0). The lsb, msb and width must be integer or a parameter (but not an arithmetic expression). The alternative syntax is particularly useful when the width is a parameter.

Following the field position is the field software access kind: it is optional and its default value is ro if no reset value is provided and rw if a reset value is provided.

The default hardware access kind depends on the software access:

  • If a register can be read/write by the software then the hardware access is in read-only
  • If the register is in read-only for the software then the hardware access is write-only

If both software and hardware can modify a register value, then the hardware access needs some mechanism to indicate when its value should be used to modify the register value (via we|wel|hwset|hwclr|hwtgl)

The optional properties of a field, indented by one level compare to the field declaration, are:

  • description: <long description> : More detailed register description. Mainly for documentation (e.g. HTML output). Quotation mark are removed on the first line. Description can be on multiple lines as long as it is indented by at least one level compare to the keyword description
  • description.hidden: <extra description : Extra description displayed only when documentation is generated without the –doc_hide flag
  • mask|enable|pending.description <long description> : For interrupt register, set the description of the associated mask/enable/pending register field. Again, description can be done on multiple lines.
  • hw [r|w|rw|na] : Specify a type of access from the hardware
  • r : read-only (Default)
  • w : write-only
  • rw : read/write
  • na : Not accessible from HW
  • clkEn <clock_enable_name> : Define a clock enable signal for this field
  • hwset [<set_signal>] [<data_signal>] : Hardware high set the field to 1. The set_signal can be in the form self.field_name in which case a field is added to the hardware structure of the register (if it does not exists). If set_signal is in the form reg_name.signal_name, then it references a field in another register structure. If set_signal is simply of the form signal_name, then a port with this name is added. If set_signal starts with a dot like .signal_name, then it reference an internal signal of the module (for example the address decode signals). If no set_signal is provided, a field with the name reg_name_hwset is automatically added. When used on multi-bit field a data_signal must be provided: each bit high will set the corresponding bit high in the field when the set_signal goes high.
  • hwclr [<clr_signal>] [<data_signal>] : Hardware high set the field to 0. If no clr_signal is provided, a field with the name reg_name_hwclr is automatically added. When used on multi-bit field if no data_signal is provided the whole field is set to 0. Otherwise only bits high in data_signal are reset to 0 when set_signal goes high.
  • hwtgl [<tglSignal>] [<data_signal>] : Hardware high toggle the field value. If no tglSignal is provided, a field with the name reg_name_hwtgl is automatically added. When used on multi-bit field if no data_signal is provided the whole field is inverted. Otherwise only bits high in data_signal are toggled set_signal goes high.
  • lock [<lock_signal>] : Signal to prevent a register to be written. lock_signal follow the same rule as set_signal just above.
  • pulse [comb] : The field stays high only one cycle after being set. If pulse is followed by comb, then the pulse is generated on the write signal without extra flop in the block.
  • toggle : When a 1 is written by software on this field, the field inverts its value.
  • signed : Indicates that the value stored is a signed value.
  • we [<weSignal>] : The copy from hardware to the RIF field value is done only when a write enable signal is high. Valid only for field with write access from hardware.
  • wel [<welSignal>] : Same as ‘we’ but write enable signal is active low.
  • clear [<clearSignal>] : Synchronous clear, setting the field to its reset value. clr_signal follow the same rule as the hwset/hwclr/hwtgl. This property is slightly different from the hwclr: first the field is set to its default reset value instead of just 0 and second the clear signal bypass the clock enable
  • counter up|down|updown [incrVal[=<width>]] [decrVal[=<width>]] [clr] [sat]: The field is a counter up and/or down, with optional input signal for the increment/decrement value and the clear. By default the increment/decrement value signals have the same width as the counter but this can be changed by specifying a number after the incr/decrVal keyword. Note: the counter value is not accessible by default from hardware, but this this can be changed with hw rw property which must be placed after the counter declaration.
  • partial <lsb_pos> : Indicates that this field is larger than the register and that the LSB correspond to the bit lsb_pos of a larger field. The field name must be identical in each register definition.
  • interrupt high|low|rising|falling|edge [en=<val_enable>] [mask=<val_mask>] [rclr|wclr|w0clr|w1clr|hwclr] : override default interrupt settings.
  • limit ([<min>:<max>]|{<v0>,<v1>,<...>}|enum) [<bypass_signal>] : Limit valid write value for a field. The limit can be a range in the form of [min:max] (min & max included, one can be omitted), a set of value with {v0,v1,v2} or, when the field is an enum using the keyword enum will automatically limit the value to the enumerated values. When writing an invalid value, the register will not be updated and an access error will be raised on the control bus. If a bypass signal is provided, when the signal is high the limit is ignored.
  • nb_frac [value] : Number of fractional bits for fixed-point representation. This can be used in description with $f to display the format of the field: for example s7.4 or u8.10 for respectively a signed 7 bits wide field with 4 fractional bits (range [-4:3.9375] with a precision of 1/16) or an unsigned 8 bits wide field with 12 fractional bits (range [0:0.249] with a precision of 1/1024).
  • password [once=<val>] [hold=<val>] [protect] : The field is used to generate an internal signal named <regname>_<fieldname>_locked which is initialized to 1 and reset to 0 if the written value match one of the password value. If the password corresponds to the once value the field will stay low until the next write. If it corresponds to the hold value, it stays low until a value different from the a valid password is written. The optional protect will lock the password until the next reset if a wrong value (except 0) is written. This field has automatically the property hidden (i.e. won’t appear in public documentation). The read value correspond to the state of the password: 1 for locked, 0 for unlocked once, 2 for unlocked hold and 3 for stuck (i.e. need reset).
  • hidden : allows to hide the field in any documentation (HTML, MIF, C Header) when the visibility is set to public (generator setting)
  • disable : force the field to the reset value. Used typically when overloading included register.
  • reserved : Renamed field in any documentation to rsvdxx (where xx is the LSB) when the visibility is set to public (generator setting). Also remove description.
  • optional : <condition> : Indicate that the field is defined only if the condition is true. The condition should be a valid arithmetic expression where parameters can be used. For example: $WIDTH<16 * $FIELD_EN

The value described as signals (set_signal, clr_signal, tglSignal) can not only be signal name but also simple logical expression, using systemVerilog syntax. For example hwset (self.field_en && !reg1.freeze).

Some fields can be declared as enum, with description of each possible value. This starts by adding the property enum with enum : [type|<type_name>|<pkg::name>]:

  • If no type is provided the enum values are only part of the documentation.
  • If the keyword type is provided a typedef enum will be declared with the type name e_regname_fieldname.
  • If a simple type name is used, this override the default value of type.
  • If the type name is preceded by a scope package (my_pkg::my_type), then the type is assumed to be defined in another package. The enum property must then be followed by a list of all possible value, indented one level compare to the enum property, following the syntax - <name> = <value> [(<reprValue>)] "description". The optional reprValue can be an integer or a float: it allows to provide the real value behind an enum for example when the enum is a list of data-rate For example:
  - decoder: "Viterbi decoder control register"
    - coding_rate = 0    4:2   rw "Coding rate selection"
      enum: e_cr
        - CR_1_2    = 0 "Code rate 1/2"
        - CR_2_3    = 1 "Code rate 2/3"
        - CR_3_4    = 2 "Code rate 3/4"

A field can also be declared as array by simply giving the array size with the fieldname: - <fieldName>[<arraySize>] ...:

  • The reset value can be given either as a single value when all element have the same value or as an array of value enclosed in curly bracket (e.g. - arr[5] = {1,2,3,4,5}).
  • The position of the field corresponds to the position of the field at index 0.
  • The others are auto-instantiated, with a position that increment by the size of the fields by default. To change the increment, add the property arrayPosIncr <value>.
  • It is also possible to have an array that extends on more than one register: this works like the partial field, with the property arrayPartial <offset>. The registers must belong to the same register group. Another possibility is to declared the register itself as an array: the total field array size will be given by the register array size multiply by the field array size or the length of the reset value array if it is bigger than the field array itself. In this case all fields of the register must be arrays.
  • In the description, the field index can be referenced by $i or even in a formula such as ${2*i+1}.

First example of field array split on two distinct register. This create a field array coeff with a total size of 5 elements of 7 bits. The first three elements are inside reg1 starting at bits 8, 16 and 24 due to the use arrayPosIncr while the last two element are inside reg2 at position 0 and 8. The description of each coeff register will be “Coefficient value 0”, “Coefficient value 1”, …

  - reg1 : (ctrl) "Control register 1"
    - enable = 0 0:0 "Enable block"
    - status   0 7:4 ro "Block status"
    - coeff[3] = {0x01,0x12,0x23} 14:8 "Coefficient value $i"
      arrayPosIncr 8
  - reg2 : (ctrl) "Control register 2"
    - coeff[2] = {0x34,0x45} 6:0  "Coefficient value $i"
      arrayPosIncr 8
      arrayPartial 3

This second example shows the use of a register array definition. The total size of fields key and val is 5.

  - reg_kv[5] : (ctrl) "Key value pairs $i"
    - key[1] = {0,1,2,3,4} 7:0 "Key $i"
    - val[1] = {0x101,0x202,0x303,0x404,0x505} 27:8 "Value $i"

§RegisterInstance

If all the register declared have to be instantiated just once, in order, the simplest way is to simply use instances: auto or instances: auto-legacy.

The auto-legacy mode uses legacy order for interrupts (mask before enable), while auto uses the standard order (enable before mask).

If the auto keyword is not used, then all instance of register are added with the following syntax, indented by one level compare to the instances keyword: - <reg_name> [= <regType>] [(<groupName>)] [@ <regAddr>]

By default the register type is the same as the register name, and the address is auto incremented compare to the previous register.

The address is always aligned on byte, no matter what the address width.

The groupName is only necessary when there is multiple instances of register belonging to a register group.

It is possible to override some properties at the instance level. Here the syntax to use, indented by one level

  • description : <bla bla> : register description, can be multi-line as long as it is indented by another level. Quotation mark on first line are removed.
  • hw r|w|rw|na : change the hardware access of a register
  • <field_name>.description <bla bla> : change a field description
  • <field_name>.reset = <rst_val> : change a field reset value
  • <field_name>.disable [= <disable_val>] : disable a field (i.e. value is fixed). If no value is provided, it default to the reset value.
  • optional : <condition> : Indicate that the register is created only if the condition is true or different from 0.
  • optional_acc: [na|ro|rw]: Control the software access (ro) of register which are due to parameters value. Default is na (any access will generate a bus access error).

It is also possible to create an array of register by specifying - <regname>[<arraysize>]. The address is auto-incremented for each register instance. Note that if the register is part of a group, all the register must be instantiated with the same array size.

It is possible to override properties of array element (register or fields). The array index can be a single value ([0]), a comma separated list ([1,5]) and/or a range ([0:3]).

Here is an example with a register array and various override:

    instances:
      - version   @ 0x00
      - cfg[$NUM_PINS] = cfg
        description:  GPIO[$i]  configuration register
        [0,5,6].pull_mode.reset = 2
        [0:6,12:14].clk_en.disable = 0

§Extra information

In almost every context (rif, rifmux, register/field definition and instance) it is possible to attach some extra information stored in a dictionary to be used by a custom generator. This starts with info: and then each line indented by one level below this should have the format - <key> : <value> where key is a single word and value is a quoted or unquoted string. Value can be omitted, in which case it is set to True

§RIF Mux syntax

The RIF Mux allows to instantiate multiple RIF with a given address offset for each.

It always starts with rifmux: <name>

The possible properties, indented by one level compare to the rifmux declaration, are:

  • dataWidth <data_width> : Number of bits of the data bus
  • addrWidth <addr_width> : Number of bits of the address bus (byte aligned). Should be large enough to address all instantiated register (i.e. ceil(log2(nb_reg * data_width/4)))
  • interface : <ifname> : Define the type of interface used to control the RIF Mux. Possible value are default, apb, uaux. By default uses a memory like interface (with a done signal asserted when access is complete).
  • parameters : : Start a parameter list. See paragraph Parameters.
  • generics : : Start a generic list. See paragraph Generics.
  • top : Specify the top-level RIF component name
  • map: : start the mapping of RIFs in the memory space

Each entry of the map is indented by one level compare to the map keyword and follow the syntax: - <rif_name> = <rif_type> @ <rifAddr> ["short description"]

Every RIF definition should be either in the same directory as the rifmux or in the include path list define on the command line.

For each RIF instance it is possible to override :

  • the description using description : ....
  • parameters value with a parameters: section using the same syntax as the RIF (cf. Parameters).
  • suffix name using suffix : <suffix_info> to add a suffix to the file generated (useful when using parameters different from default)
  • optional : <condition> : Indicate that the component is instantiated only if the condition is true. The condition should be a valid arithemtic expression where parameters can be used: this supports standard math operation (+,-,*,%,<<,>>) or comparison operator (==,!=,>,<,…). The condition can also simply the name of a generic.

You can also use external RIF (to access memory-like block) with the syntax: - <rif_name> external <addr_width> @ <rifAddr> where addr_width is the range of address that can be addressed in number of bits.

The address can be made relative:

  • Using @+ instead of @ uses the rifAddr as an offset to the previous absolute address
  • Using @+= is the same, except it also update the previous absolute address

§Example

rifmux: soc_rifmux
  addrWidth:  20
  dataWidth:  32
  parameters :
    - AON_ADDR_BASE = 0xC0000
    - MDM_ADDR_BASE = 0xD0000
  interface : default
  map:
    group: AON @ $AON_ADDR_BASE  "Always-On Power domain"
      - pmu_aon    = pmu_aon      @ 0x0000
      - ccu_aon    = ccu_aon      @ 0x1000
        parameters:
          - HAS_LF_XOSC = True
    group: MDM @ $MDM_ADDR_BASE  "Modem Power domain"
      - mdm0          = modem       @ 0x0000
        description : Modem 0 with high speed support
        parameters:
          - tx.HIGH_SPEED = True
          - rx.HIGH_SPEED = True
      - mdm1          = modem       @+= 0x200
        description : Modem 1
        suffix: ctrl=dmi(alt)
      - mdm2          = modem       @+= 0x200
        description : Modem 2 (low power)
        parameters:
          - rx.LOW_POWER = True
    // Analog control, not part of any group
    - ana_fe = ana_fe @ 0xF0000

§Configuration File Documentation

The RIF generator uses a TOML configuration file to control various aspects of documentation/code generation.

§Basic Configuration

§Top-Level Options

# Required: Path to the RIF file to compile
filename = "my_chip.rif"

# Optional: Reference path for relative paths (auto-detected from config file location)
path = "/path/to/project"

# Optional: List of include paths for referenced RIF files
include = ["./include", "../common"]

# Optional: List of included references to generate (use ["*"] for all)
gen_inc = ["*"]

# Optional: List of included references to generate locally,
# i.e. using the RIF file location as the reference for relative path
# (use ["*"] to match all components in gen_inc)
local = ["module1", "module2"]

# Required: List of target formats to generate
targets = ["sv", "c", "html", "py", "ral"]

# Optional: Generate only public registers/fields (hide private ones)
public = false

# Optional: Override the HDL interface type
# Valid values: "default", "apb", "uaux"
interface = "apb"

# Optional: Use suffixes only for RTL generation targets
suffix_rtl_only = false

§Parameters

Override parameter value defined in RIF files:

[parameters]
DATA_WIDTH = 32
ADDR_WIDTH = 16
NUM_CHANNELS = 4

§Output Paths

Specify where generated files should be placed.

There are a few fallback target:

  • doc correspond to any document generator (htnl, latex, adoc, mif, json)
  • sw correspond to any software generator (c, python, svd, ipxact)
  • rtl correspond to any hardware generator (sv, vhdl)
  • sim correspond to any simulation generator (ral)
[outputs]
# Documentation outputs
doc = "./doc"
html = "./doc/html"
latex = "./doc/latex"
adoc = "./doc/adoc"
mif = "./doc/mif"
json = "./doc/json"

# Software outputs
c = "./sw/include"
sw = "./sw"
py = "./python"
svd = "./sw/svd"
ipxact = "./sw/ipxact"

# Hardware outputs
rtl = "./rtl"
sv = "./rtl/sv"
vhdl = "./rtl/vhdl"

# Simulation outputs
sim = "./sim"
ral = "./sim/ral"

# Custom target outputs
custom_target = "./custom"

§Suffixes

When generating RIF using parameters, it is sometimes useful to add suffix to the generated file.

The syntax to set the suffix of a rif is to defined a new table named [suffixes.<rif_name>] and provides at least a name. There are two optional key/value boolean pairs, default to false:

  • pkg : Suffix apply to the generate package file as well
  • alt_pos : Place suffix after the _pkg instead of before when generating package
[suffixes.spi]
name = "full"
pkg = true
alt_pos = true

[suffixes.uart]
name = "lite"
pkg = false

§Casing

It is possible to specify the casing use in regiater/field name either globaly or for each generator (if supported by the generator).

The casing options supported are :

  • Raw: as-is, casing is not modified
  • Snake : snake_case
  • Pascal: PascalCase
  • Camel: camelCase
  • Kebab: kebab-case
  • Title: Title Case

§Optional: Specify casing convention for generated code

§Valid values depend on target language

casing = “Snake”

§Reserved keywords handling

The parser can check that field name are not using keyword of certain language. For the moment it support only a check on common keyword from SystemVerilog and VHDL which could be used as field name.

If a field has the same name as a keyword, the parser will generate an error if the setting error is true (default) of a warning and will prefix the name with an underscore to avoid a syntax error in the generated file.

# Optional: Specify reserved keyword handling
# This example correspond to the default value
[keywords]
sv = true
vhdl = false
error = true

§Target-Specific Configuration

Each generator can have its own options, and can override also default setting such as gen_inc or local.

§HTML Generation

[html]
# Optional: Path to custom CSS file
css = "./custom.css"

# Optional: Split output into multiple files (one file per RIF)
split = true

# Optional: casing of register/field
casing = "Snake"

# Optional: Sub-directory name for generated file which are not the top level
subdir = "subdir_name"

§AsciiDoctor Generation

[adoc]
# Optional: Split output into multiple files (one file per RIF)
split = true

# Optional: Override global gen_inc for this target
gen_inc = ["module1", "module2"]

# Optional: Override global local for this target
local = ["*"]

# Optional: Sub-directory name for generated file which are not the top level
subdir = "subdir_name"

# Optional: casing of register/field
casing = "Snake"

§C Header Generation

[c]
# Optional: Name of base address offset constant (default: PERIPH_BASE_ADDR)
base_offset = "CUSTOM_BASE_ADDR"

# Optional: Override global gen_inc for this target
gen_inc = ["*"]

# Optional: Override global local for this target
local = ["module1"]

# Optional: Sub-directory name for generated file which are not the top level
subdir = "subdir_name"

§RTL Generation (SystemVerilog/VHDL)

[rtl]
# Optional: Number of pipeline levels for register access (default: 1)
# Currently ignored
nb_pipe = 2

# Optional: Override global gen_inc for this target
gen_inc = ["*"]

# Optional: Override global local for this target
local = ["module1", "module2"]

# Optional: Sub-directory name for generated file which are not the top level
subdir = "subdir_name"

# Generate constant for register address in the package
const_reg = true

# Generate constant for field reset/position/width
const_field = true

§Register Abstraction Layer (RAL)

[ral]
# Optional: Name of register block class (default: uvm_reg_block)
class = "my_reg_block"

# Optional: Macro name for RAL instantiation (default: ral_create_reg_block)
macro_name = "MY_RAL_MACRO"

# Optional: Override global gen_inc for this target
gen_inc = ["*"]

# Optional: Override global local for this target
local = ["module1=sim", "module2=../sim"]

# Optional: Sub-directory name for generated file which are not the top level
subdir = "subdir_name"

# Optional: List of package import per register block
imports.blk0 = "blk0_sim_pkg"
imports.blk1 = "blk1_sim_pkg"

§Python Generation

[py]
# Optional: Target Python version
# Valid values: "3.8", "3.9", "3.10", "3.11", "3.12"
version = "3.10"

# Optional: Python class naming convention
class = "MyPeripheral"

# Optional: path where regmap.py should be created
# If a class is define, the class name is used as filename
regmap_dir = ../my_lib

# Optional: Create an __init__.py file in the output path
init_file = false

# Optional: Override global gen_inc for this target
gen_inc = ["*"]

# Optional: Override global local for this target
local = ["module1"]

# Optional: Sub-directory name for generated file which are not the top level
subdir = "subdir_name"

§JSON Generation

[json]
# Optional: Override global gen_inc for this target
gen_inc = ["*"]

# Optional: Override global local for this target
local = ["module1"]

# Optional: Sub-directory name for generated file which are not the top level
subdir = "subdir_name"

§SVD (System View Description)

[svd]
# Optional: Vendor name for SVD file
vendor = "MyCompany"

# Optional: Version string for SVD file
version = "1.0.0"

§IP-XACT Generation

[ipxact]
# Optional: Vendor identifier
vendor = "mycompany.com"

# Optional: Library name
library = "peripherals"

# Optional: Version string
version = "2.1.0"

# Optional: Sub-directory name for generated file which are not the top level
subdir = "subdir_name"

§LaTeX Generation

[latex]
# Optional: Split output into multiple files (one file per RIF)
split = true

# Optional: Sub-directory name for generated file which are not the top level
subdir = "subdir_name"

# Optional: casing of register/field
casing = "Snake"

§MIF (Framemaker) Generation

[mif]
# Optional: Split output into multiple files (one file per RIF)
split = true

# Style definitions for different elements
anchor = "Anchor"
h2 = "Heading2"
h3 = "Heading3"
table_title = "TableTitle"
table_heading = "TableHeading"
table_cell = "TableCell"

# Table styles by type
table_kind_rifmux = "RifMuxTable"
table_kind_mapping = "MappingTable"
table_kind_reg = "RegisterTable"

# Column width specifications
width_3col = [2.0, 3.0, 4.0]    # For 3-column tables (RifMux, Pages)
width_4col = [1.5, 2.0, 1.0, 3.0]  # For 4-column tables (registers)
width_5col = [1.0, 1.5, 1.0, 1.0, 3.0]  # For 5-column tables (fields)

# Optional: Override global gen_inc for this target
gen_inc = ["*"]

# Optional: Override global local for this target
local = ["module1"]

# Optional: Sub-directory name for generated file which are not the top level
subdir = "subdir_name"

# Optional: casing of register/field
casing = "Snake"

§Complete Example

# Basic configuration
filename = "my_soc.rif"
include = ["./common", "../ip_library"]
gen_inc = ["*"]
local = ["spi", "uart"]
targets = ["sv", "c", "html", "py", "ral", "svd"]
public = false
suffix_rtl_only = true

# Parameters
[parameters]
DATA_WIDTH = 32
NUM_INTERRUPTS = 16
BASE_ADDR = 0x40000000

# Output paths
[outputs]
rtl = "./generated/rtl"
c = "./generated/sw/include"
html = "./docs/html"
py = "./python/drivers"
sim = "./verification/ral"
svd = "./sw/svd"

# Suffixes
[suffixes.spi]
name = "full"
pkg = true
alt_pos = true

# Target-specific settings
[html]
css = "./docs/custom.css"
split = true

[c]
base_offset = "SOC_BASE_ADDR"

[py]
version = "3.10"
class = "SocPeripheral"

[ral]
class = "soc_reg_block"
macro_name = "SOC_RAL_CREATE"

[svd]
vendor = "MyCompany"
version = "1.2.0"

[rtl]
nb_pipe = 1

§RTL Package & Module

When generating the RTL (SystemVerilog & VHDL) for a RIF, two files are created:

  • a module/entity containing all the logic for address decoding and the registers storage.
  • a package with structures/record for all the register type described in the RIF file.

§Package

Each register is split in two structures / record:

  • the software one (suffixed by _sw_t) driven by the RIF,
  • the hardware one (suffixed by _hw_t) driven by the rest of the design.

The name of the structure is based on the register name: register REGNAME gives two structure regname_sw_t and regname_hw_t.

The description property of each field is used as a comment near each field.

§Register group

Multiple register can be grouped to be create only one pair of structure sw/hw. This is done at the register declaration, by adding (reg_group_name) just before the shorst description to group all registers under the same name reg_group_name.

§Field Type

By default all field have the type logic / std_logic with the width defined in the RIF. Adding the property signed inside a field allows to change the type to logic signed.

§Special fields

Some structure field are automatically added based on properties defined in the RIF. Here is the convention used.

Property external in a register:

  • ext_read (sw): High during a read access on this register
  • ext_write (sw): High during a read access on this register
  • ext_done (hw): high when access (read or write) is done

If a register group is used there will be one ext_regName_* signal per register of the group

Register properties wrPulse, rdPulse, accPulse creates a signal named respectively p_read, p_write or p_access in the software structure: this signal is asserted for one cycle when the register is accessed for, respectively, read, write or both. If a register belong to a register group and those properties are used more than one in the group, the register nam is appended to the signal name.

Field properties hwclr and hwset simply add a suffix to the fieldname in the hardware structure.

Field Properties we and wel add a field in the hardware structure with the name fieldname_we or fieldname_wel.

A name can be specified directly after the property:

  • this can be a signal name, declared in the signal, which will be added to the top interface
  • an existing field in the register
  • an undeclared field in the register (using the syntax regName.mywe) and in this case the field will be added to the hardware structure.

§Module I/O

§Clock

By default there is only one clock name is clk. There is two kind of clock internally: software (only one possible) and hardware (multiple are allowed for different hardware driven register), but both should synchronous even if frequency/gating is different. Any clock domain crossing should be handled outside of the RIF.

The software clock name can be changed via swClock : <sw_clock_name> in the rif properties (alongside addrWidth, …). The hardware clocks are declared via hwClock : <hw_clk0> <hw_clk1> ... : by default the first clock will be used for all hardware driven register, but any clock declared (hardware and software) can be used by a register using clock <clock_name> in the register property.

§Reset

There is two kind of reset:

  • “Software Reset” which control all register that can be written by software. By default it is named rst_n and can be changed with the syntax swReset <sw_rst_name>
  • “Hardware Reset” which control all register written exclusively by hardware. By default it is also named rst_n. It can be changed with the syntax hwReset <hw_rst_name> either at the page level, affecting all registers or at the field level to override the default register.

By default the reset signal is asynchronous and active low but this can be changed with the following syntax when declaring the signal: swReset|hwReset : <rst_name> activeLow|activeHigh async|sync

§Register

All registers (or group of registers) with field driven by the RIF generate an output named rif_reg_instance_name and the type regType_sw_t. All registers (or group of registers) with field driven by the hardware generate an input named reg_instance_name and the type regType_hw_t.

By default the reg_instance_name of a group of register is the group_name of the register type. This can be changed by adding (instance_group_name) just before the address information (if any). If there are multiple instances of group of registers it is mandatory to provide a group_name for each of the register instance

§RIF interface

The default interface to access the register is using a simple interface similar to the one used by memories.

The interface, named rif_if, has two parameters automatically set by the RIF property:

  • W_ADDR: Number of bits of the address bus, set by the property addrWidth in the RIF.
  • W_DATA: Number of bits of the data bus, set by the property dataWidth in the RIF.

The following fields are driven by the CPU:

  • en : High for register access. Last one clock cycle per access even if done takes more than one clock cycle to be asserted
  • rd_wrn : High for read, low for write (valid when en is high)
  • addr : Address on W_ADDR bits
  • wr_data : Write data on W_DATA bits

The following fields are driven by the RIF:

  • done : Pulse high when access is complete
  • rd_data : Read data on W_DATA bits, only valid when done is high
  • err_addr : Qualifier of done signal, high if access failed due to invalid address
  • err_access : Qualifier of done signal, high if access failed due to rd/wr access status

There is two cases to consider:

  • Fixed latency: access can be piped meaning that it is possible to do back-to-back access to different address without waiting for the done to be asserted. This is the case for all internal register generated by RifGen.
  • Mixed latency: it is possible to mix register access that have different latencies (typically when some register are defined as external and they cross domain crossing or access shared ressources with random latency) but in this case enable can be asserted only after the done signal is asserted to preserve access order.

Here are a few waveform example:

{head:{text:'Access with no latency',tick:0,},
signal: [
  {name: 'clk',          wave: 'p........'},
  {name: 'en',           wave: '01010.1.0'},
  {name: 'rd_wrn',       wave: '010....10'},
  {name: 'addr',         wave: 'x2x3x.45x', data: ['A0', 'A1', 'A2', 'A3']},
  {name: 'wr_data',      wave: 'x..3x.4x.', data: [ 'D1', 'D2']},
  {} ,
  {name: 'done',         wave: '01010.1.0'},
  {name: 'rd_data',      wave: 'x2x...x5x', data: ['D0', 'D3']},
  {name: 'error_access', wave: '02030.450'},
  {name: 'error_addr'  , wave: '02030.450'},
]}
{head:{text:'Access with fixed latency (e.g. 1 clock)',tick:0,},
signal: [
  {name: 'clk',          wave: 'p.........'},
  {name: 'en',           wave: '01010.1.0.'},
  {name: 'rd_wrn',       wave: '010....10.'},
  {name: 'addr',         wave: 'x2x3x.45x.', data: ['A0', 'A1', 'A2', 'A3']},
  {name: 'wr_data',      wave: 'x..3x.4x..', data: [ 'D1', 'D2']},
  {} ,
  {name: 'done',         wave: '0.1010.1.0'},
  {name: 'rd_data',      wave: 'x.2x...x5x', data: ['D0', 'D3']},
  {name: 'error_access', wave: '0.2030.450'},
  {name: 'error_addr'  , wave: '0.2030.450'},
]}
{head:{text:'Access with mixed latency',tick:0,},
signal: [
  {name: 'clk',          wave: 'p...........'},
  {name: 'en',           wave: '01010.10.1.0'},
  {name: 'rd_wrn',       wave: '010......10.'},
  {name: 'addr',         wave: 'x2x3x.4x.52x', data: ['A0', 'A1', 'A2', 'A3','A4']},
  {name: 'wr_data',      wave: 'x..3x.4x..2x', data: [ 'D1', 'D2','D4']},
  {} ,
  {name: 'done',         wave: '0.1.0...1..0'},
  {name: 'rd_data',      wave: 'x.2x...x.5x.', data: ['D0', 'D3']},
  {name: 'error_access', wave: '0.230...4520'},
  {name: 'error_addr'  , wave: '0.230...4520'},
]}

The APB interface is also supported, just use interface : apb in the RIF properties (same place as the address width and register width).

§Targets

This page provides information about the different generator outputs (except hardware which has its own dedicated page).


§UVM RAL

This target generate one file per peripheral defining register blocks based on the uvm class uvm_reg_block, but it is possible to use a proprietary class as-long as it is derived from uvm_reg_block.

For the rifmux it creates a reg_block instantiating each peripheral at the proper address. It defines a macro ral_create_reg_block to call the configure/build/add_submap functions, but again it is possible to provide a user-defined macro which has the same kind of parameters: block_name, block_type, address.


§C

For each register file definition the generator outputs a header file containing:

  • One structure per register (union between “uint32 reg32” and a struct of bitfields called fields)
  • Macro definition for each field giving their position and mask
  • One structure per page grouping all register together, and inserting reserved register when needed

The naming convention is:

  • Register struct: RifName + RegisterName + “Reg_u” (using PascalCase)
  • Field name inside register struct uses camelCase
  • Macro: RIFNAME_REGNAME_FIELDNAME + “_POS”|“_MASK”|“_SMASK”
  • RIF struct: RifName + “Regs” (using PascalCase).
  • Register name inside RIF struct uses camelCase

If a rifmux is provided, an additional file is generated including all others header files and defining macro for base address and pointer to those addresses.

The naming convention is:

  • Base address : RIFINSTNAME_BASE_ADDR
  • Pointer : P_RIFINSTNAME

When there is more than one page in a RIF, the page name is appended to the RIF name.


§Python

The generator create one file per peripheral. A base python class provides common API for all peripheral, register and fields.

There are classes defined for each registers and fields, which are then instantiated when an object is created. So to use the resulting python class simply create an instance of the rifmux regmap = MyRifmux().

The python output has proper typing to provide good auto-complete and documentation through LSP (tested with pyright).


§JSON

The JSON output is one file per peripheral with basic information.

Each registers has the following entries:

  • addr: address (integer)
  • desc: Register description (string)
  • readOnly: false/true
  • flags: array of special properties such as “interrupt” and “external”
  • fields: dictionnary of all fields available in the register

Each fields has the following entries:

  • pos : Field position in the register (i.e. lsb)
  • width : Number of bits of the fields
  • value : reset value
  • signed: true/false
  • kind : String representing the software access kind (ro, rw, wo, rclr, w1clr, w1set, w1tgl, pulse, password)
  • desc : Field description

§HTML

The HTML output for a rifmux provides a summary table of all peripheral (name & address) with link to paragraph providing a list of the registers in the peripheral which itself links to detailled register description in sub-paragraph.

The split option allows to generate one file per peripheral instead of a grouping all peripherals.

§CSS Styling

To customize the appearance of the generated HTML documentation, you can provide your own CSS file using the css option. The default CSS file is located at src/generator/resources/style.css and can be used as a reference or starting point for your custom stylesheet.

The HTML generator uses the following CSS classes and selectors:

§Document Structure
  • div.fulldoc - Main document container that wraps all content
  • h2 - Section headings (peripheral pages)
  • h3 - Subsection headings (register descriptions)
§Tables
  • table - Base styling for all tables (register tables, summaries)
  • th - Table header cells with gray background (#CCCCCC)
  • td - Table data cells with gray borders
  • caption - Table captions (appears above tables)
§Register Layout Tables
  • table.map - Register bit layout tables with full borders
  • td.map - Standard cells in layout tables (8pt font, centered)
  • td.mapv - Vertical text cells for long field names (rotated 90 degrees)
  • td.rsvd - Reserved/unused bit fields (light gray background #EEEEEE)
§Register Instance Tables
  • table.noborders - Tables without borders (used for register instance listings)
  • td.noborders - Cells without borders
§Enumeration Descriptions
  • td.enum-name - Enumeration value and name (5% width, no wrap)
  • td.enum-desc - Enumeration description (95% width)
§Notes and Information
  • table.note - Note/information tables
  • td.noteHeader - Note header cell (bold, red text #990000, right border)
  • td.noteContent - Note content cell
§Conditional Fields
  • tr.cond - Conditional register rows (yellow background #F0F0C0)
  • #cond - Conditional elements (nested conditionals use different shades: #FBDFC7, #ABCBCB)
§Popups
  • div.popup - Popup container (hidden by default, positioned absolutely)
  • table.popup - Popup table styling (brown borders #76461f)
  • th.popup - Popup header (brown background #B6865E)
  • td.popup - Popup content cell (tan background #DBAF8B)
  • a - All links (pointer cursor)

When creating a custom CSS file, you can override any of these selectors to match your preferred styling. The default CSS uses Arial/Verdana fonts at 10pt for main content and 8pt for layout tables, with gray color scheme (#CCCCCC, gray borders). You can modify colors, fonts, spacing, borders, and any other visual properties to suit your documentation standards.


§AsciiDoc

The AsciiDoc format is similar to HTML.

The split option allows to generate one file per peripheral instead of a grouping all peripherals.

The AsciiDoc generator creates anchors and links that can be referenced from other AsciiDoc documents. The following link formats are used:

§Anchors

Anchors are created using the [[id]] format:

  • [[top]] - Anchor at the top of the document
  • [[rifname]] - Anchor for a RIF/peripheral (where rifname is the RIF instance name)
  • [[rifname.pagename]] - Anchor for a page within a peripheral
  • [[rifname.regname]] - Anchor for a register (where regname is the register name)
  • Table anchors use the ID passed to the table generation function

Within the same document, links use the <<id,text>> format:

  • <<top,Back to Top>> - Link to the top of the document
  • <<rifname,Peripheral Name>> - Link to a peripheral section
  • <<rifname.pagename,Page Name>> - Link to a page section
  • <<rifname.regname,Register Name>> - Link to a register section

When the split option is enabled, cross-document references use the xref: format:

  • xref:component_name.adoc#rifname[Peripheral Name] - Link to a peripheral in another document
  • xref:component_name.adoc#rifname.pagename[Page Name] - Link to a page in another document
  • xref:component_name.adoc#rifname.regname[Register Name] - Link to a register in another document

Where component_name is the RIF component name (without the .rif extension).

§Example Usage

To reference a register from another AsciiDoc document:

See the xref:spi.adoc#spi.ctrl[SPI Control Register] for details.

To reference a register within the same document:

See the <<spi.ctrl,SPI Control Register>> for details.

§Framemaker (MIF)

The MIF format is similar to HTML.

The split option allows to generate one file per peripheral instead of grouping all peripherals.

§Style Definitions

FrameMaker style definitions can be customized through the configuration file to match your document template. The following style options are available:

§Paragraph Styles
  • anchor (default: "Body") - Paragraph style for anchor paragraphs and general information text
  • h2 (default: "2heading") - Paragraph style for level 2 headings, used for peripheral titles, page titles, and “Address Mapping” section headings
  • h3 (default: "3headingReg") - Paragraph style for level 3 headings, used for register titles (includes register name, description, and address)
§Table Format Paragraph Tags

These define the table format/style applied to entire tables:

  • table_title (default: "Mapping Table") - Table format paragraph tag for RifMux tables (peripheral summary) and mapping tables (page address mapping)
  • table_heading (default: "Mapping Table") - Table format paragraph tag for register instance tables
  • table_cell (default: "Register") - Table format paragraph tag for field definition tables
§Table Cell Paragraph Tags

These define the paragraph style applied to cells within tables:

  • table_kind_rifmux (default: "TableTitle") - Paragraph style for table title/caption text (e.g., “Table 1. Registers address mapping”)
  • table_kind_mapping (default: "CellHeading") - Paragraph style for table header cells (column headers)
  • table_kind_reg (default: "CellBodyLeft") - Paragraph style for table body cells (data cells in register and field tables)
§Column Width Specifications

These arrays define the column widths in centimeters for different table types:

  • width_3col (default: [2.5, 3.4, 11.1]) - Column widths for 3-column tables: RifMux tables (Offset, Name, Description) and Page mapping tables
  • width_4col (default: [2.5, 3.4, 2.1, 9.4]) - Column widths for 4-column register instance tables (Offset, Name, Reset, Description)
  • width_5col (default: [1.4, 3.4, 2.0, 2.1, 8.5]) - Column widths for 5-column field definition tables (Width, Name, Access, Reset, Description)

All style names must correspond to paragraph formats or table formats defined in your FrameMaker document template. See doc/config.md for the complete configuration reference.


§LaTeX

The LaTeX output is similar to HTML.

The split option allows to generate one file per peripheral instead of grouping all peripherals.

The casing option allows to specify the casing convention for register and field names.

It has labels for each register and field register. To easily reference them, here is an example of command that add hyperlink and proper formatting.

\makeatletter
\DeclareRobustCommand*{\escapeus}[1]{%
  \begingroup\@activeus\scantokens{#1\endinput}\endgroup}
\begingroup\lccode`\~=`\_\relax
   \lowercase{\endgroup\def\@activeus{\catcode`\_=\active \let~\_}}
\makeatother

% Define command to display registers properly and with a link to the RIF table
\newcounter{rif}
\newcommand{\reg}[1]{\hyperref[rif:rifname.#1]{\texttt{\escapeus{#1}}}}

§CMSIS-SVD (System View Description)

Standard CMSIS-SVD output file.

The vendor and version properties can be set via the configutation file.


§IP-XACT

Standard IP-XACT with one file per peripheral.

The vendor, library and version properties can be set via the configutation file.

Modules§

cfg
Configuration management for YARIG code generation.
cli
comp
Compiled component instances and hardware abstractions.
error
generator
Code generation for various output targets.
parser
Parser logic using the Winnow crate
rifgen