Examples

Working examples are available in the examples directory. This section provides complete examples with input files, commands, and generated outputs for each format.


SystemVerilog Example: Audio Processor

Input File (audio_proc.sv):

// -----------------------------------------------------------------------------
// Audio Processor Example - SystemVerilog Annotations
// -----------------------------------------------------------------------------

// @axion_def BASE_ADDR=0x2000 CDC_EN CDC_STAGE=3

module audio_proc (
    input  logic        clk,
    input  logic        rst_n,
    input  logic [31:0] audio_in,
    output logic [31:0] audio_out
);

    // Volume control register
    logic [31:0] volume; // @axion RW DEFAULT=100 DESC="Volume level (0-100)"

    // Status register: bit0=active, bit1=muted, bit2=clipped
    logic [2:0]  status; // @axion RO R_STROBE DESC="Audio status flags"

    // Filter coefficients (wide register spanning 2 addresses)
    logic [63:0] coeffs; // @axion RW DESC="64-bit filter coefficients"

    // Command register (trigger actions)
    logic [31:0] cmd;    // @axion WO W_STROBE DESC="Command register"

endmodule

Command:

axion-hdl -s audio_proc.sv -o output --all

Terminal Output:

SystemVerilog source file added: audio_proc.sv

============================================================
Starting analysis of SystemVerilog files...
============================================================
  Parsing: audio_proc.sv
Found 1 modules from SystemVerilog files.

Analysis complete. Found 1 total modules.

==============================================================================================================
Module: audio_proc
File: audio_proc.sv
CDC: Enabled (Stages: 3)
Base Address: 0x2000
==============================================================================================================

Signal Name               Type     Abs.Addr   Offset     Access   Strobes         Ports Generated
------------------------- -------- ---------- ---------- -------- --------------- ----------------------------------------
volume                    [31:0]   0x2000     0x00       RW       None            volume
status                    [2:0]    0x2004     0x04       RO       RD              status, status_rd_strobe
coeffs                    [63:0]   0x2008     0x08       RW       None            coeffs
cmd                       [31:0]   0x2010     0x10       WO       WR              cmd, cmd_wr_strobe

Total Registers: 4

============================================================
Generating SystemVerilog register modules...
============================================================
  Generated: audio_proc_axion_reg.sv

============================================================
All files generated successfully!
Output directory: output
============================================================

Generated SystemVerilog Module (audio_proc_axion_reg.sv):

// -----------------------------------------------------------------------------
// File: audio_proc_axion_reg.sv
// Module: audio_proc_axion_reg
// Description: AXI4-Lite Register Interface for audio_proc
// Generated by: Axion-HDL
// -----------------------------------------------------------------------------

module audio_proc_axion_reg #(
    parameter int ADDR_WIDTH = 32,
    parameter int DATA_WIDTH = 32
) (
    // AXI4-Lite Interface
    input  logic                      axi_aclk,
    input  logic                      axi_aresetn,
    input  logic [ADDR_WIDTH-1:0]     axi_awaddr,
    input  logic [2:0]                axi_awprot,
    input  logic                      axi_awvalid,
    output logic                      axi_awready,
    input  logic [DATA_WIDTH-1:0]     axi_wdata,
    input  logic [(DATA_WIDTH/8)-1:0] axi_wstrb,
    input  logic                      axi_wvalid,
    output logic                      axi_wready,
    output logic [1:0]                axi_bresp,
    output logic                      axi_bvalid,
    input  logic                      axi_bready,
    input  logic [ADDR_WIDTH-1:0]     axi_araddr,
    input  logic [2:0]                axi_arprot,
    input  logic                      axi_arvalid,
    output logic                      axi_arready,
    output logic [DATA_WIDTH-1:0]     axi_rdata,
    output logic [1:0]                axi_rresp,
    output logic                      axi_rvalid,
    input  logic                      axi_rready,

    // Module Clock (CDC enabled)
    input  logic                      module_clk,

    // Register Interface
    output logic [31:0]                   volume,
    input  logic [2:0]                    status,
    output logic                      status_rd_strobe,
    output logic [63:0]                   coeffs,
    output logic [31:0]                   cmd,
    output logic                      cmd_wr_strobe
);

    // AXI4-Lite response codes
    localparam [1:0] OKAY   = 2'b00;
    localparam [1:0] SLVERR = 2'b10;

    // Register addresses
    localparam [ADDR_WIDTH-1:0] ADDR_VOLUME = 32'h00002000;
    localparam [ADDR_WIDTH-1:0] ADDR_STATUS = 32'h00002004;
    localparam [ADDR_WIDTH-1:0] ADDR_COEFFS = 32'h00002008;
    localparam [ADDR_WIDTH-1:0] ADDR_CMD = 32'h00002010;

    // AXI4-Lite state machine
    typedef enum logic [2:0] {
        IDLE,
        WRITE_ADDR,
        WRITE_DATA,
        WRITE_RESP,
        READ_ADDR,
        READ_DATA
    } axi_state_t;

    axi_state_t state, next_state;

    // Internal registers
    logic [31:0]                   volume_reg;
    logic [63:0]                   coeffs_reg;
    logic [31:0]                   cmd_reg;

    // Internal signals
    logic [DATA_WIDTH-1:0] rdata_reg;
    logic [1:0]            rresp_reg;
    logic [1:0]            bresp_reg;
    logic [ADDR_WIDTH-1:0] write_addr;
    logic [ADDR_WIDTH-1:0] read_addr;

    // Sink for unused signals to silence lint warnings
    logic _unused_ok;
    assign _unused_ok = &{1'b0, axi_awprot, axi_arprot, axi_wstrb, axi_wdata, 1'b0};

    // Strobe signals
    logic cmd_wr_strobe_int;


    //-------------------------------------------------------------------------
    // Clock Domain Crossing (CDC) Synchronizers
    //-------------------------------------------------------------------------

    // Input Synchronizers (Module -> AXI)
    // -----------------------------------
    // CDC for status (RO)
    logic [2:0]                    status_sync [3];

    always_ff @(posedge axi_aclk or negedge axi_aresetn) begin
        if (!axi_aresetn) begin
            status_sync <= '{default: '0};
        end else begin
            status_sync[0] <= status;
            status_sync[1] <= status_sync[0];
            status_sync[2] <= status_sync[1];
        end
    end

    // Output Synchronizers (AXI -> Module)
    // ------------------------------------
    // CDC for volume (RW)
    logic [31:0]                   volume_sync [3];
    // CDC for coeffs (RW)
    logic [63:0]                   coeffs_sync [3];
    // CDC for cmd (WO)
    logic [31:0]                   cmd_sync [3];

    always_ff @(posedge module_clk or negedge axi_aresetn) begin
        if (!axi_aresetn) begin
            volume_sync <= '{default: '0};
            coeffs_sync <= '{default: '0};
            cmd_sync <= '{default: '0};
        end else begin
            volume_sync[0] <= volume_reg;
            volume_sync[1] <= volume_sync[0];
            volume_sync[2] <= volume_sync[1];
            coeffs_sync[0] <= coeffs_reg;
            coeffs_sync[1] <= coeffs_sync[0];
            coeffs_sync[2] <= coeffs_sync[1];
            cmd_sync[0] <= cmd_reg;
            cmd_sync[1] <= cmd_sync[0];
            cmd_sync[2] <= cmd_sync[1];
        end
    end

    // ... (State machine and I/O logic omitted for brevity) ...

endmodule

VHDL Example: SPI Master

Input File (spi_master.vhd):

--------------------------------------------------------------------------------
-- SPI Master Example - VHDL Annotations
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-- Enable CDC with 2 synchronization stages (default)
-- @axion_def BASE_ADDR=0x0000 CDC_EN

entity spi_master is
    port (
        clk       : in  std_logic;
        rst_n     : in  std_logic;
        spi_clk   : out std_logic;
        spi_mosi  : out std_logic;
        spi_miso  : in  std_logic;
        spi_cs_n  : out std_logic
    );
end entity spi_master;

architecture rtl of spi_master is
    -- Control register: start transfer, clock divider, etc.
    signal control_reg : std_logic_vector(31 downto 0); -- @axion RW W_STROBE DESC="SPI control: bit0=start, bits[15:8]=clk_div"
    
    -- Status register: busy flag, transfer complete, errors
    signal status_reg : std_logic_vector(31 downto 0); -- @axion RO R_STROBE DESC="SPI status: bit0=busy, bit1=done, bit2=error"
    
    -- TX data register (write-only from software perspective)
    signal tx_data_reg : std_logic_vector(31 downto 0); -- @axion WO DESC="Transmit data buffer"
    
    -- RX data register (read-only from software perspective)
    signal rx_data_reg : std_logic_vector(31 downto 0); -- @axion RO DESC="Receive data buffer"
    
    -- Configuration register at specific address
    signal config_reg : std_logic_vector(31 downto 0); -- @axion RW ADDR=0x20 DESC="SPI configuration"
    
    -- Interrupt control
    signal irq_enable_reg : std_logic_vector(31 downto 0); -- @axion RW ADDR=0x30 DESC="Interrupt enable mask"
    signal irq_status_reg : std_logic_vector(31 downto 0); -- @axion RW ADDR=0x34 R_STROBE W_STROBE DESC="Interrupt status"
begin
    spi_clk  <= '0';
    spi_mosi <= '0';
    spi_cs_n <= '1';
end architecture rtl;

Command:

axion-hdl -s spi_master.vhd -o output --all

Terminal Output:

VHDL source file added: spi_master.vhd

============================================================
Starting analysis of VHDL files...
============================================================
Parsing VHDL file: spi_master.vhd
Found 1 modules from VHDL files.

Analysis complete. Found 1 total modules.

================================================================================
Module: spi_master
File: spi_master.vhd
CDC: Enabled (Stages: 2)
Base Address: 0x0000
================================================================================

Signal Name               Type     Abs.Addr   Offset     Access   Strobes
------------------------- -------- ---------- ---------- -------- ---------------
control_reg               [31:0]   0x00       0x00       RW       WR
status_reg                [31:0]   0x04       0x04       RO       RD
tx_data_reg               [31:0]   0x08       0x08       WO       None
rx_data_reg               [31:0]   0x0C       0x0C       RO       None
config_reg                [31:0]   0x20       0x20       RW       None
irq_enable_reg            [31:0]   0x30       0x30       RW       None
irq_status_reg            [31:0]   0x34       0x34       RW       RD, WR

Total Registers: 7

================================================================================

============================================================
Generating VHDL register modules...
============================================================
  Generated: spi_master_axion_reg.vhd

============================================================
Generating documentation (MD)...
============================================================
  Generated: register_map.md

============================================================
Generating XML register map...
============================================================
  Generated: spi_master_regs.xml

============================================================
Generating YAML register map...
============================================================
  Generated: spi_master_regs.yaml

============================================================
Generating JSON register map...
============================================================
  Generated: spi_master_regs.json

============================================================
Generating C header files...
============================================================
  Generated: spi_master_regs.h

============================================================
All files generated successfully!
Output directory: output
============================================================

Generated VHDL Module (spi_master_axion_reg.vhd):

--------------------------------------------------------------------------------
-- File: spi_master_axion_reg.vhd
-- Description: AXI Register Interface Module
-- Generated by Axion HDL
--
-- Module: spi_master
-- Source: spi_master.vhd
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity spi_master_axion_reg is
    generic (
        BASE_ADDR : std_logic_vector(31 downto 0) := x"00000000"
    );
    port (
        -- AXI4-Lite Interface
        axi_aclk    : in  std_logic;
        axi_aresetn : in  std_logic;
        
        -- AXI Write Address Channel
        axi_awaddr  : in  std_logic_vector(31 downto 0);
        axi_awvalid : in  std_logic;
        axi_awready : out std_logic;
        
        -- AXI Write Data Channel
        axi_wdata   : in  std_logic_vector(31 downto 0);
        axi_wstrb   : in  std_logic_vector(3 downto 0);
        axi_wvalid  : in  std_logic;
        axi_wready  : out std_logic;
        
        -- AXI Write Response Channel
        axi_bresp   : out std_logic_vector(1 downto 0);
        axi_bvalid  : out std_logic;
        axi_bready  : in  std_logic;
        
        -- AXI Read Address Channel
        axi_araddr  : in  std_logic_vector(31 downto 0);
        axi_arvalid : in  std_logic;
        axi_arready : out std_logic;
        
        -- AXI Read Data Channel
        axi_rdata   : out std_logic_vector(31 downto 0);
        axi_rresp   : out std_logic_vector(1 downto 0);
        axi_rvalid  : out std_logic;
        axi_rready  : in  std_logic;
        
        -- Module Clock (for CDC)
        module_clk  : in  std_logic;
        
        -- Register Signals
        control_reg : out std_logic_vector(31 downto 0);  -- SPI control: bit0=start, bits[15:8]=clk_div
        control_reg_wr_strobe : out std_logic;
        status_reg : in  std_logic_vector(31 downto 0);  -- SPI status: bit0=busy, bit1=done, bit2=error
        status_reg_rd_strobe : out std_logic;
        tx_data_reg : out std_logic_vector(31 downto 0);  -- Transmit data buffer
        rx_data_reg : in  std_logic_vector(31 downto 0);  -- Receive data buffer
        config_reg : out std_logic_vector(31 downto 0);  -- SPI configuration
        irq_enable_reg : out std_logic_vector(31 downto 0);  -- Interrupt enable mask
        irq_status_reg : out std_logic_vector(31 downto 0);  -- Interrupt status
        irq_status_reg_rd_strobe : out std_logic;
        irq_status_reg_wr_strobe : out std_logic
    );
end entity spi_master_axion_reg;

-- Full architecture includes:
-- - AXI4-Lite state machine (IDLE, WR_WAIT_ADDR, WR_WAIT_DATA, WR_DO_WRITE, WR_RESP, RD_ADDR, RD_DATA)
-- - 2-stage CDC synchronizers for all registers
-- - Byte-level write strobe support (WSTRB)
-- - Address decoding and access control
-- - Read/write strobe generation

YAML Example: LED Blinker

Input File (led_blinker.yaml):

# LED Blinker Example - Beginner Level

module: led_blinker
base_addr: "0x0000"

registers:
  # Enable/disable LED blinking and set speed
  - name: control
    addr: "0x00"
    access: RW
    width: 32
    default: 0
    description: "LED control register"

  # Current LED state (read-only from software)
  - name: led_state
    addr: "0x04"
    access: RO
    width: 32
    description: "Current LED output state"

  # Blink period in milliseconds
  - name: period_ms
    addr: "0x08"
    access: RW
    width: 32
    default: 500
    description: "Blink period in milliseconds"

  # LED pattern for multi-LED designs
  - name: pattern
    addr: "0x0C"
    access: RW
    width: 32
    default: "0x55"
    description: "LED pattern (8-bit pattern for 8 LEDs)"

Command:

axion-hdl -s led_blinker.yaml -o output --all

Terminal Output:

YAML source file added: led_blinker.yaml

============================================================
Starting analysis of YAML files...
============================================================
Parsing YAML file: led_blinker.yaml
Found 1 modules from YAML files.

Analysis complete. Found 1 total modules.

================================================================================
Module: led_blinker
File: led_blinker.yaml
CDC: Disabled
Base Address: 0x0000
================================================================================

Signal Name               Type       Abs.Addr   Offset     Access   Strobes
------------------------- ---------- ---------- ---------- -------- ---------------
control                   [31:0]     0x00       0x00       RW       None
led_state                 [31:0]     0x04       0x04       RO       None
period_ms                 [31:0]     0x08       0x08       RW       None
pattern                   [31:0]     0x0C       0x0C       RW       None

Total Registers: 4

================================================================================

============================================================
Generating VHDL register modules...
============================================================
  Generated: led_blinker_axion_reg.vhd

============================================================
All files generated successfully!
Output directory: output
============================================================

Generated VHDL Module (led_blinker_axion_reg.vhd):

--------------------------------------------------------------------------------
-- File: led_blinker_axion_reg.vhd
-- Description: AXI Register Interface Module
-- Generated by Axion HDL
--
-- Module: led_blinker
-- Source: led_blinker.yaml
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity led_blinker_axion_reg is
    generic (
        BASE_ADDR : std_logic_vector(31 downto 0) := x"00000000"
    );
    port (
        -- AXI4-Lite Interface
        axi_aclk    : in  std_logic;
        axi_aresetn : in  std_logic;
        
        -- AXI Write Address Channel
        axi_awaddr  : in  std_logic_vector(31 downto 0);
        axi_awvalid : in  std_logic;
        axi_awready : out std_logic;
        
        -- AXI Write Data Channel
        axi_wdata   : in  std_logic_vector(31 downto 0);
        axi_wstrb   : in  std_logic_vector(3 downto 0);
        axi_wvalid  : in  std_logic;
        axi_wready  : out std_logic;
        
        -- AXI Write Response Channel
        axi_bresp   : out std_logic_vector(1 downto 0);
        axi_bvalid  : out std_logic;
        axi_bready  : in  std_logic;
        
        -- AXI Read Address Channel
        axi_araddr  : in  std_logic_vector(31 downto 0);
        axi_arvalid : in  std_logic;
        axi_arready : out std_logic;
        
        -- AXI Read Data Channel
        axi_rdata   : out std_logic_vector(31 downto 0);
        axi_rresp   : out std_logic_vector(1 downto 0);
        axi_rvalid  : out std_logic;
        axi_rready  : in  std_logic;
        
        -- Register Signals
        control : out std_logic_vector(31 downto 0);  -- LED control register
        led_state : in  std_logic_vector(31 downto 0);  -- Current LED output state
        period_ms : out std_logic_vector(31 downto 0);  -- Blink period in milliseconds
        pattern : out std_logic_vector(31 downto 0)  -- LED pattern (8-bit pattern for 8 LEDs)
    );
end entity led_blinker_axion_reg;

-- Features:
-- - Default values: period_ms = 0x000001F4 (500), pattern = 0x00000055 (0x55)
-- - No CDC (single clock domain)
-- - Full AXI4-Lite compliance

XML Example: PWM Controller

Input File (pwm_controller.xml):

<?xml version="1.0" encoding="UTF-8"?>
<!--
  PWM Controller Example - Intermediate Level
  Demonstrates CDC with 3 stages, read/write strobes
-->
<register_map module="pwm_controller" base_addr="0x0000">
    <!-- Enable CDC for safe cross-clock-domain access -->
    <config cdc_en="true" cdc_stage="3"/>
    
    <!-- Global control register -->
    <register name="global_enable" addr="0x00" access="RW" width="32" 
              w_strobe="true" description="Global PWM enable"/>
    
    <!-- Channel 0 -->
    <register name="ch0_duty" addr="0x04" access="RW" width="32" 
              default="128" description="Channel 0 duty cycle (0-255)"/>
    <register name="ch0_period" addr="0x08" access="RW" width="32" 
              default="255" description="Channel 0 period"/>
    
    <!-- Channel 1 -->
    <register name="ch1_duty" addr="0x0C" access="RW" width="32" 
              default="128" description="Channel 1 duty cycle"/>
    <register name="ch1_period" addr="0x10" access="RW" width="32" 
              default="255" description="Channel 1 period"/>
    
    <!-- Status register with read strobe -->
    <register name="status" addr="0x20" access="RO" width="32" 
              r_strobe="true" description="PWM status (clears on read)"/>
    
    <!-- Interrupt control -->
    <register name="irq_enable" addr="0x24" access="RW" width="32" 
              description="Interrupt enable mask"/>
    <register name="irq_status" addr="0x28" access="RW" width="32" 
              r_strobe="true" w_strobe="true" 
              description="Interrupt status (write 1 to clear)"/>
</register_map>

Command:

axion-hdl -s pwm_controller.xml -o output --all

Terminal Output:

XML source file added: pwm_controller.xml

============================================================
Starting analysis of XML files...
============================================================
Parsing XML file: pwm_controller.xml
Found 1 modules from XML files.

Analysis complete. Found 1 total modules.

================================================================================
Module: pwm_controller
File: pwm_controller.xml
CDC: Enabled (Stages: 3)
Base Address: 0x0000
================================================================================

Signal Name               Type       Abs.Addr   Offset     Access   Strobes
------------------------- ---------- ---------- ---------- -------- ---------------
global_enable             [31:0]     0x00       0x00       RW       WR
ch0_duty                  [31:0]     0x04       0x04       RW       None
ch0_period                [31:0]     0x08       0x08       RW       None
ch1_duty                  [31:0]     0x0C       0x0C       RW       None
ch1_period                [31:0]     0x10       0x10       RW       None
status                    [31:0]     0x20       0x20       RO       RD
irq_enable                [31:0]     0x24       0x24       RW       None
irq_status                [31:0]     0x28       0x28       RW       RD, WR

Total Registers: 8

================================================================================

============================================================
All files generated successfully!
Output directory: output
============================================================

Generated VHDL Module (pwm_controller_axion_reg.vhd):

--------------------------------------------------------------------------------
-- File: pwm_controller_axion_reg.vhd
-- Description: AXI Register Interface Module
-- Generated by Axion HDL
--
-- Module: pwm_controller
-- Source: pwm_controller.xml
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity pwm_controller_axion_reg is
    generic (
        BASE_ADDR : std_logic_vector(31 downto 0) := x"00000000"
    );
    port (
        -- AXI4-Lite Interface
        axi_aclk    : in  std_logic;
        axi_aresetn : in  std_logic;
        
        -- AXI Write Address Channel
        axi_awaddr  : in  std_logic_vector(31 downto 0);
        axi_awvalid : in  std_logic;
        axi_awready : out std_logic;
        
        -- AXI Write Data Channel
        axi_wdata   : in  std_logic_vector(31 downto 0);
        axi_wstrb   : in  std_logic_vector(3 downto 0);
        axi_wvalid  : in  std_logic;
        axi_wready  : out std_logic;
        
        -- AXI Write Response Channel
        axi_bresp   : out std_logic_vector(1 downto 0);
        axi_bvalid  : out std_logic;
        axi_bready  : in  std_logic;
        
        -- AXI Read Address Channel
        axi_araddr  : in  std_logic_vector(31 downto 0);
        axi_arvalid : in  std_logic;
        axi_arready : out std_logic;
        
        -- AXI Read Data Channel
        axi_rdata   : out std_logic_vector(31 downto 0);
        axi_rresp   : out std_logic_vector(1 downto 0);
        axi_rvalid  : out std_logic;
        axi_rready  : in  std_logic;
        
        -- Module Clock (for CDC)
        module_clk  : in  std_logic;
        
        -- Register Signals
        global_enable : out std_logic_vector(31 downto 0);  -- Global PWM enable
        global_enable_wr_strobe : out std_logic;
        ch0_duty : out std_logic_vector(31 downto 0);  -- Channel 0 duty cycle (0-255)
        ch0_period : out std_logic_vector(31 downto 0);  -- Channel 0 period
        ch1_duty : out std_logic_vector(31 downto 0);  -- Channel 1 duty cycle
        ch1_period : out std_logic_vector(31 downto 0);  -- Channel 1 period
        status : in  std_logic_vector(31 downto 0);  -- PWM status (clears on read)
        status_rd_strobe : out std_logic;
        irq_enable : out std_logic_vector(31 downto 0);  -- Interrupt enable mask
        irq_status : out std_logic_vector(31 downto 0);  -- Interrupt status (write 1 to clear)
        irq_status_rd_strobe : out std_logic;
        irq_status_wr_strobe : out std_logic
    );
end entity pwm_controller_axion_reg;

-- Features:
-- - 3-stage CDC synchronizers (module_clk <-> axi_aclk)
-- - Default values: ch0_duty = 128, ch0_period = 255, ch1_duty = 128, ch1_period = 255
-- - Read/write strobes for status and irq_status

JSON Example: GPIO Controller

Input File (gpio_controller.json):

{
    "module": "gpio_controller",
    "base_addr": "0x1000",
    "registers": [
        {
            "name": "direction",
            "addr": "0x00",
            "access": "RW",
            "width": 32,
            "default": 0,
            "description": "GPIO direction (0=input, 1=output)"
        },
        {
            "name": "output_data",
            "addr": "0x04",
            "access": "RW",
            "width": 32,
            "default": 0,
            "description": "GPIO output values"
        },
        {
            "name": "input_data",
            "addr": "0x08",
            "access": "RO",
            "width": 32,
            "description": "GPIO input values (directly from pins)"
        },
        {
            "name": "irq_enable",
            "addr": "0x0C",
            "access": "RW",
            "width": 32,
            "default": 0,
            "description": "Interrupt enable per pin"
        },
        {
            "name": "irq_status",
            "addr": "0x10",
            "access": "RW",
            "width": 32,
            "w_strobe": true,
            "description": "Interrupt status (write 1 to clear)"
        }
    ]
}

Command:

axion-hdl -s gpio_controller.json -o output --all

Terminal Output:

JSON source file added: gpio_controller.json

============================================================
Starting analysis of JSON files...
============================================================
Parsing JSON file: gpio_controller.json
Found 1 modules from JSON files.

Analysis complete. Found 1 total modules.

================================================================================
Module: gpio_controller
File: gpio_controller.json
CDC: Disabled
Base Address: 0x1000
================================================================================

Signal Name               Type       Abs.Addr   Offset     Access   Strobes
------------------------- ---------- ---------- ---------- -------- ---------------
direction                 [31:0]     0x1000     0x00       RW       None
output_data               [31:0]     0x1004     0x04       RW       None
input_data                [31:0]     0x1008     0x08       RO       None
irq_enable                [31:0]     0x100C     0x0C       RW       None
irq_status                [31:0]     0x1010     0x10       RW       WR

Total Registers: 5

================================================================================

============================================================
All files generated successfully!
Output directory: output
============================================================

Generated VHDL Module (gpio_controller_axion_reg.vhd):

--------------------------------------------------------------------------------
-- File: gpio_controller_axion_reg.vhd
-- Description: AXI Register Interface Module
-- Generated by Axion HDL
--
-- Module: gpio_controller
-- Source: gpio_controller.json
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity gpio_controller_axion_reg is
    generic (
        BASE_ADDR : std_logic_vector(31 downto 0) := x"00001000"
    );
    port (
        -- AXI4-Lite Interface
        axi_aclk    : in  std_logic;
        axi_aresetn : in  std_logic;
        
        -- AXI Write Address Channel
        axi_awaddr  : in  std_logic_vector(31 downto 0);
        axi_awvalid : in  std_logic;
        axi_awready : out std_logic;
        
        -- AXI Write Data Channel
        axi_wdata   : in  std_logic_vector(31 downto 0);
        axi_wstrb   : in  std_logic_vector(3 downto 0);
        axi_wvalid  : in  std_logic;
        axi_wready  : out std_logic;
        
        -- AXI Write Response Channel
        axi_bresp   : out std_logic_vector(1 downto 0);
        axi_bvalid  : out std_logic;
        axi_bready  : in  std_logic;
        
        -- AXI Read Address Channel
        axi_araddr  : in  std_logic_vector(31 downto 0);
        axi_arvalid : in  std_logic;
        axi_arready : out std_logic;
        
        -- AXI Read Data Channel
        axi_rdata   : out std_logic_vector(31 downto 0);
        axi_rresp   : out std_logic_vector(1 downto 0);
        axi_rvalid  : out std_logic;
        axi_rready  : in  std_logic;
        
        -- Register Signals
        direction : out std_logic_vector(31 downto 0);  -- GPIO direction (0=input, 1=output)
        output_data : out std_logic_vector(31 downto 0);  -- GPIO output values
        input_data : in  std_logic_vector(31 downto 0);  -- GPIO input values (directly from pins)
        irq_enable : out std_logic_vector(31 downto 0);  -- Interrupt enable per pin
        irq_status : out std_logic_vector(31 downto 0);  -- Interrupt status (write 1 to clear)
        irq_status_wr_strobe : out std_logic
    );
end entity gpio_controller_axion_reg;

-- Features:
-- - Base address set to 0x1000 (absolute addresses: 0x1000-0x1010)
-- - No CDC (single clock domain)
-- - Write strobe for irq_status (write-1-to-clear pattern)

TOML Example: SPI Master

Input File (spi_master.toml):

# SPI Master Controller Register Definitions
# TOML format example for Axion HDL

module = "spi_master"
base_addr = "0x0000"

[config]
cdc_en = true
cdc_stage = 2

[[registers]]
name = "control"
addr = "0x00"
access = "RW"
width = 32
w_strobe = true
description = "SPI control register"

[[registers]]
name = "status"
addr = "0x04"
access = "RO"
width = 32
r_strobe = true
description = "SPI status register"

[[registers]]
name = "tx_data"
addr = "0x08"
access = "WO"
width = 32
description = "Transmit data register"

[[registers]]
name = "rx_data"
addr = "0x0C"
access = "RO"
width = 32
description = "Receive data register"

[[registers]]
name = "clock_div"
addr = "0x10"
access = "RW"
width = 32
default = "0x00000008"
description = "Clock divider (SPI clock = system clock / (2 * clock_div))"

[[registers]]
name = "chip_select"
addr = "0x14"
access = "RW"
width = 32
description = "Chip select control (one-hot encoding)"

Command:

axion-hdl -s spi_master.toml -o output --all

Terminal Output:

Axion-HDL v1.0.1
Automated AXI4-Lite Register Interface Generator
Developed by bugratufan
--------------------------------------------------
TOML source file added: spi_master.toml

============================================================
Starting analysis of TOML files...
============================================================
Found 1 modules from TOML files.

Analysis complete. Found 1 total modules.

==============================================================================================================
Module: spi_master
File: spi_master.toml
CDC: Enabled (Stages: 2)
Base Address: 0x0000
==============================================================================================================

Signal Name               Type     Abs.Addr   Offset     Access   Strobes         Ports Generated
------------------------- -------- ---------- ---------- -------- --------------- ----------------------------------------
control                   std_logic_vector(31 downto 0) 0x00       0x00       RW       WR              control, control_wr_strobe
status                    std_logic_vector(31 downto 0) 0x04       0x04       RO       RD              status, status_rd_strobe
tx_data                   std_logic_vector(31 downto 0) 0x08       0x08       WO       None            tx_data
rx_data                   std_logic_vector(31 downto 0) 0x0C       0x0C       RO       None            rx_data
clock_div                 std_logic_vector(31 downto 0) 0x10       0x10       RW       None            clock_div
chip_select               std_logic_vector(31 downto 0) 0x14       0x14       RW       None            chip_select

Total Registers: 6

==============================================================================================================
Summary: 1 module(s) analyzed
Total Registers: 6
==============================================================================================================


============================================================
Generating VHDL register modules...
============================================================
  Generated: spi_master_axion_reg.vhd

VHDL files generated in: output

============================================================
Generating documentation (HTML)...
============================================================
  Generated: index.html

Documentation generated in: output

============================================================
Generating XML register map...
============================================================
  Generated: spi_master_regs.xml

XML files generated in: output

============================================================
Generating YAML register map...
============================================================
  Generated: spi_master_regs.yaml

YAML files generated in: output

============================================================
Generating JSON register map...
============================================================
  Generated: spi_master_regs.json

JSON files generated in: output

============================================================
Generating C header files...
============================================================
  Generated: spi_master_regs.h

C header files generated in: output

============================================================
All files generated successfully!
Output directory: output
============================================================

Generated Files:

$ ls -lh output/
total 88K
drwxrwxr-x 2 bugra bugra   80 Jan 31 20:57 html
-rw-rw-r-- 1 bugra bugra  19K Jan 31 20:57 index.html
-rw-rw-r-- 1 bugra bugra  24K Jan 31 20:57 register_map.html
-rw-rw-r-- 1 bugra bugra  21K Jan 31 20:57 spi_master_axion_reg.vhd
-rw-rw-r-- 1 bugra bugra 3.8K Jan 31 20:57 spi_master_regs.h
-rw-rw-r-- 1 bugra bugra 1.2K Jan 31 20:57 spi_master_regs.json
-rw-rw-r-- 1 bugra bugra 4.8K Jan 31 20:57 spi_master_regs.xml
-rw-rw-r-- 1 bugra bugra  754 Jan 31 20:57 spi_master_regs.yaml

Generated C Header Excerpt (spi_master_regs.h):

#ifndef SPI_MASTER_REGS_H
#define SPI_MASTER_REGS_H

#include <stdint.h>

/* Module Base Address */
#define SPI_MASTER_BASE_ADDR    0x00000000

/* Register Address Offsets (relative to base) */
#define SPI_MASTER_CONTROL_OFFSET    0x00  /* SPI control register */
#define SPI_MASTER_STATUS_OFFSET     0x04  /* SPI status register */
#define SPI_MASTER_TX_DATA_OFFSET    0x08  /* Transmit data register */
#define SPI_MASTER_RX_DATA_OFFSET    0x0C  /* Receive data register */
#define SPI_MASTER_CLOCK_DIV_OFFSET  0x10  /* Clock divider */
#define SPI_MASTER_CHIP_SELECT_OFFSET 0x14  /* Chip select control */

/* Register Structure */
typedef struct {
    volatile uint32_t control;      /* 0x00 - RW - SPI control register */
    volatile uint32_t status;       /* 0x04 - RO - SPI status register */
    volatile uint32_t tx_data;      /* 0x08 - WO - Transmit data register */
    volatile uint32_t rx_data;      /* 0x0C - RO - Receive data register */
    volatile uint32_t clock_div;    /* 0x10 - RW - Clock divider */
    volatile uint32_t chip_select;  /* 0x14 - RW - Chip select control */
} spi_master_regs_t;

/* Access register block as structure */
#define SPI_MASTER_REGS    ((volatile spi_master_regs_t*)(SPI_MASTER_BASE_ADDR))

#endif /* SPI_MASTER_REGS_H */

Generated VHDL Entity:

entity spi_master_axion_reg is
    generic (
        BASE_ADDR : std_logic_vector(31 downto 0) := x"00000000"
    );
    port (
        -- AXI4-Lite Interface
        axi_aclk    : in  std_logic;
        axi_aresetn : in  std_logic;

        -- AXI Write/Read Channels...

        -- Module Clock (for CDC)
        module_clk  : in  std_logic;

        -- Register Signals
        control : out std_logic_vector(31 downto 0);
        control_wr_strobe : out std_logic;
        status : in  std_logic_vector(31 downto 0);
        status_rd_strobe : out std_logic;
        tx_data : out std_logic_vector(31 downto 0);
        rx_data : in  std_logic_vector(31 downto 0);
        clock_div : out std_logic_vector(31 downto 0);
        chip_select : out std_logic_vector(31 downto 0)
    );
end entity spi_master_axion_reg;

Key Features Demonstrated:

  • TOML’s clean syntax - No braces, minimal punctuation

  • CDC synchronizers with 2 stages for clock domain crossing

  • Register strobes for control/status (control_wr_strobe, status_rd_strobe)

  • Default values (clock_div = 0x00000008)

  • Mixed access modes (RO, WO, RW)

  • Comprehensive output - VHDL (21KB), C header (3.8KB), docs, XML/YAML/JSON

  • Production-ready code with full AXI4-Lite compliance


Generated Output Files Summary

Each example generates the following files:

File

Description

*_axion_reg.vhd

AXI4-Lite slave VHDL module

*_regs.h

C header with register macros

*_regs.xml

IP-XACT style XML register map

*_regs.yaml

YAML register map (re-importable)

*_regs.json

JSON register map (re-importable)

register_map.md

Markdown documentation

*_regs.py

Python register model (golden model use, --python)


Golden Model Example

Use the Python register model to simulate register space behavior in software (e.g. verification, golden models, unit tests for firmware drivers).

Step 1 — Generate the Python model:

axion-hdl -s my_module.yaml -o ./output --python
# Produces: ./output/my_module_regs.py

Step 2 — Import and use in your golden model:

from my_module_regs import MY_MODULE

# AXI4-Lite bus simulation — access by absolute address (base + offset)
base = MY_MODULE.base_address
MY_MODULE.write(base + 0x0000, 0x1)   # Write to control register (offset 0x0000)
val = MY_MODULE.read(base + 0x0000)   # Read it back

# Named register access
MY_MODULE.control.value = 0x42

# Bit-field access (packed registers)
print(MY_MODULE.status.ready.value)      # 0 or 1
print(MY_MODULE.status.ready.enum_name)  # 'NOT_READY' or 'READY'

# Write-strobe callback — simulate hardware side effects
def handle_control_write(reg_name, value):
    print(f"[HW] {reg_name} written → 0x{value:08X}")
    # Trigger DUT stimulus, update scoreboard, etc.

MY_MODULE.on_write("control", handle_control_write)
MY_MODULE.write(base + 0x0000, 0xDEAD)  # → prints "[HW] control written → 0x0000DEAD"

# Reset all registers to power-on defaults
MY_MODULE.reset()

# Dump full state (useful for debugging golden model vs DUT)
print(MY_MODULE.dump())

Access mode semantics (matching hardware):

Mode

read()

write()

RW

Returns current value

Updates value

RO

Returns current value

Raises ReadOnlyError

WO

Returns 0 (bus behavior)

Updates value

Use .raw_value to inspect a WO register’s internal state regardless of bus semantics — useful for scoreboard comparisons.

Alternative: use the Python API directly (without generating a file):

from axion_hdl import AxionHDL

axion = AxionHDL(output_dir="./output")
axion.add_source("my_module.yaml")
axion.analyze()

space = axion.get_model("my_module")
space.write(space.base_address + 0x0000, 0x1)
print(space.dump())