# Outputs Axion-HDL generates multiple output formats from a single input definition. This section describes each output type in detail. ## Output Summary | Output | File Pattern | Description | |--------|--------------|-------------| | **VHDL Module** | `_axion_reg.vhd` | AXI4-Lite slave entity | | **SystemVerilog** | `_axion_reg.sv` | AXI4-Lite slave module with structs | | **C Header** | `_regs.h` | Register macros and addresses | | **Markdown** | `register_map.md` | Human-readable documentation | | **HTML** | `.html`, `index.html` | Styled web documentation | | **XML** | `_regs.xml` | IP-XACT compatible register map | | **YAML** | `_regs.yaml` | Re-importable YAML definition | | **JSON** | `_regs.json` | Machine-readable JSON format | | **Address Map** | `address_map.html` | Instance address space overview (requires `--hier`) | --- ## VHDL Register Module **File:** `_axion_reg.vhd` A fully compliant AXI4-Lite slave module with the following features: ### Entity Structure ```vhdl 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, when enabled) module_clk : in std_logic; -- Register Signals control_reg : out std_logic_vector(31 downto 0); control_reg_wr_strobe : out std_logic; status_reg : in std_logic_vector(31 downto 0); status_reg_rd_strobe : out std_logic; -- ... additional signals ... ); end entity; ``` ### Features | Feature | Description | |---------|-------------| | **Full AXI4-Lite Compliance** | Proper handshaking, response codes (OKAY, SLVERR) | | **State Machine** | Handles independent address/data phases per AXI-LITE-005 | | **Byte-Level Writes** | `wstrb` support for partial register updates | | **Clock Domain Crossing** | Optional multi-stage synchronizers | | **Access Control** | Proper RO/WO/RW behavior with error responses | | **Strobe Generation** | Single-cycle read/write strobe outputs | | **Default Values** | Register initialization on reset | | **Address Decoding** | Automatic offset-based routing | ### Port Directions by Access Mode | Access | Register Port | Direction | Strobe Ports | |--------|---------------|-----------|--------------| | `RO` | `signal_name` | `in` | `_rd_strobe : out` | | `WO` | `signal_name` | `out` | `_wr_strobe : out` | | `RW` | `signal_name` | `out` | `_rd_strobe`, `_wr_strobe : out` | ### Typed AXI Ports (axion_common_pkg) By default, AXI4-Lite signals are exposed as individual flat ports. When the `use_axion_types` option is enabled, the 19 flat AXI signals are replaced by two typed record ports from [axion-common](https://github.com/bugratufan/axion-common): ```vhdl use work.axion_common_pkg.all; entity spi_master_axion_reg is generic ( BASE_ADDR : std_logic_vector(31 downto 0) := x"00000000" ); port ( axi_aclk : in std_logic; axi_aresetn : in std_logic; -- AXI4-Lite typed record ports (axion_common_pkg) axi_m2s : in t_axi_lite_m2s; -- master-to-slave signals axi_s2m : out t_axi_lite_s2m; -- slave-to-master signals -- Register Signals control_reg : out std_logic_vector(31 downto 0); -- ... ); end entity; ``` The architecture body uses intermediate signals for every AXI channel signal. The record ports are automatically unpacked/packed via concurrent signal assignments — the internal state machine is unchanged. **Enable per module (YAML):** ```yaml module: spi_master base_addr: "0x00000000" config: use_axion_types: true registers: - name: control access: RW ``` **Enable globally (CLI):** ```bash axion-hdl -s regs.yaml -o output/ --vhdl --use-axion-types ``` > **Note:** `axion_common_pkg` must be compiled into the `work` library before this module can be elaborated. See [axion-common](https://github.com/bugratufan/axion-common) for the package source. --- ## SystemVerilog Register Module **File:** `_axion_reg.sv` A modern SystemVerilog AXI4-Lite slave module optimized for verification and integration. ### Module Structure ```systemverilog module sensor_controller_axion_reg #( parameter int ADDR_WIDTH = 32, parameter int DATA_WIDTH = 32 ) ( // AXI4-Lite Interface input logic axi_aclk, input logic axi_aresetn, // ... AXI channels ... // Module Clock (CDC enabled) input logic module_clk, // Register Interface using Packed Structs output ctrl_reg_t control_reg, input logic [31:0] status_reg ); ``` ### Key Features | Feature | Description | |---------|-------------| | **Packed Structs** | Generates `typedef struct packed` for registers with subfields, enabling clean access (e.g., `ctrl.enable`). | | **Wide Registers** | Automatically maps registers >32 bits to multiple address offsets. | | **Reset Values** | Initializes registers to defined defaults (hex/dec) upon reset. | | **Lint Clean** | Passes `verilator --lint-only -Wall` validation. | | **CDC Support** | Built-in synchronization for both Read-Only and Read-Write registers across clock domains. | ### Typed AXI Ports (axion_common_pkg) When `use_axion_types` is enabled, the 19 flat AXI signals are replaced by two typed struct ports from `axion_common_pkg`: ```systemverilog import axion_common_pkg::*; module spi_master_axion_reg #( parameter int ADDR_WIDTH = 32, parameter int DATA_WIDTH = 32 ) ( // AXI4-Lite Interface (typed record ports from axion_common_pkg) input logic axi_aclk, input logic axi_aresetn, input t_axi_lite_m2s axi_m2s, output t_axi_lite_s2m axi_s2m, // Register Interface output logic [31:0] control_reg ); ``` Intermediate `logic` signals bridge the record ports to the existing state machine logic. The state machine itself is unchanged. **Enable per module (YAML):** ```yaml config: use_axion_types: true ``` **Enable globally (CLI):** ```bash axion-hdl -s regs.yaml -o output/ --sv --use-axion-types ``` --- ## C Header File **File:** `_regs.h` A C header providing register definitions for embedded software development. ### Contents ```c /** * @file spi_master_regs.h * @brief Register definitions for spi_master module * @note Generated by Axion HDL - Do not edit manually */ #ifndef SPI_MASTER_REGS_H #define SPI_MASTER_REGS_H #include /* Module Base Address */ #define SPI_MASTER_BASE_ADDR 0x00000000 /* Register Address Offsets (relative to base) */ #define SPI_MASTER_CONTROL_REG_OFFSET 0x00 /* SPI control */ #define SPI_MASTER_STATUS_REG_OFFSET 0x04 /* SPI status */ #define SPI_MASTER_TX_DATA_REG_OFFSET 0x08 /* Transmit data buffer */ #define SPI_MASTER_RX_DATA_REG_OFFSET 0x0C /* Receive data buffer */ /* Absolute Register Addresses */ #define SPI_MASTER_CONTROL_REG_ADDR 0x00 #define SPI_MASTER_STATUS_REG_ADDR 0x04 #define SPI_MASTER_TX_DATA_REG_ADDR 0x08 #define SPI_MASTER_RX_DATA_REG_ADDR 0x0C /* Bit Field Helper Macros */ #define GET_FIELD(val, mask, shift) (((val) & (mask)) >> (shift)) #define SET_FIELD(val, mask, shift, new_val) (((val) & ~(mask)) | (((new_val) << (shift)) & (mask))) /* Read Macros */ #define SPI_MASTER_READ_CONTROL_REG() \ (*((volatile uint32_t*)(SPI_MASTER_BASE_ADDR + SPI_MASTER_CONTROL_REG_OFFSET))) #define SPI_MASTER_READ_STATUS_REG() \ (*((volatile uint32_t*)(SPI_MASTER_BASE_ADDR + SPI_MASTER_STATUS_REG_OFFSET))) /* Write Macros */ #define SPI_MASTER_WRITE_CONTROL_REG(val) \ (*((volatile uint32_t*)(SPI_MASTER_BASE_ADDR + SPI_MASTER_CONTROL_REG_OFFSET)) = (val)) #define SPI_MASTER_WRITE_TX_DATA_REG(val) \ (*((volatile uint32_t*)(SPI_MASTER_BASE_ADDR + SPI_MASTER_TX_DATA_REG_OFFSET)) = (val)) #endif /* SPI_MASTER_REGS_H */ ``` ### Macro Naming Convention All macros use the pattern `__`: | Suffix | Description | Example | |--------|-------------|---------| | `_OFFSET` | Offset from base address | `SPI_MASTER_STATUS_REG_OFFSET` | | `_ADDR` | Absolute address | `SPI_MASTER_STATUS_REG_ADDR` | | `READ_()` | Read accessor macro | `SPI_MASTER_READ_STATUS_REG()` | | `WRITE_(val)` | Write accessor macro | `SPI_MASTER_WRITE_CONTROL_REG(val)` | --- ## Documentation Outputs ### Markdown (`register_map.md`) Human-readable documentation with: - Module overview (name, base address, CDC status) - Register table with all fields - Address mapping - Descriptions ### HTML (`.html`, `index.html`) Styled web documentation featuring: - Navigation index across all modules - Sortable register tables - Embedded CSS (no external dependencies) - Responsive design - Per-module detail pages --- ## Re-exportable Formats These outputs can be used as inputs to Axion-HDL, enabling round-trip workflows. ### YAML Output (`_regs.yaml`) ```yaml module: spi_master base_addr: '0x0000' config: cdc_en: true cdc_stage: 2 registers: - name: control_reg addr: '0x00' access: RW width: 32 w_strobe: true description: 'SPI control: bit0=start, bits[15:8]=clk_div' - name: status_reg addr: '0x04' access: RO width: 32 r_strobe: true description: 'SPI status: bit0=busy, bit1=done, bit2=error' ``` ### JSON Output (`_regs.json`) ```json { "module": "spi_master", "base_addr": "0x0000", "config": { "cdc_en": true, "cdc_stage": 2 }, "registers": [ { "name": "control_reg", "addr": "0x00", "access": "RW", "width": 32, "w_strobe": true, "description": "SPI control: bit0=start, bits[15:8]=clk_div" } ] } ``` ### XML Output (`_regs.xml`) IP-XACT compatible format for EDA tool integration: ```xml ``` ### Python Register Model (`_regs.py`) An importable Python file that contains the register space as a live, simulation-ready Python object. No re-parsing of YAML/VHDL sources is required — import the generated file directly in your golden model. ```python # my_module_regs.py — generated by axion-hdl --python # DO NOT EDIT — regenerate with: axion-hdl --python from axion_hdl.register_model import RegisterSpaceModel _MODULE_DICT = { ... } # register definitions frozen at generation time MY_MODULE = RegisterSpaceModel.from_module_dict(_MODULE_DICT) ``` **Usage in a golden model:** ```python from my_module_regs import MY_MODULE # AXI4-Lite bus simulation — use absolute addresses (base + offset) base = MY_MODULE.base_address MY_MODULE.write(base + 0x0000, 0x1) val = MY_MODULE.read(base + 0x0000) # Named register access MY_MODULE.control.value = 0x42 print(MY_MODULE.status.ready.enum_name) # 'READY' # Strobe callback def on_write(name, val): print(f"{name} written: 0x{val:08X}") MY_MODULE.on_write('control', on_write) # Full register dump print(MY_MODULE.dump()) ``` **Access mode semantics:** | Mode | `.read()` | `.write()` | |------|-----------|------------| | `RW` | Returns current value | Updates value | | `RO` | Returns current value | Raises `ReadOnlyError` | | `WO` | Returns `0` (bus semantics) | Updates value | Use `.raw_value` on any register to inspect the internal state regardless of access mode — useful for golden model verification. --- ## Generation Control ### CLI Flags | Flag | Output | Default | |------|--------|---------| | `--vhdl` | VHDL register module | Disabled | | `--c-header` | C header file | Disabled | | `--doc` | Documentation (default: Markdown) | Disabled | | `--doc-format FORMAT` | Documentation format: `md`, `html`, `pdf` | `md` | | `--xml` | XML register map | Disabled | | `--yaml` | YAML register map | Disabled | | `--json` | JSON register map | Disabled | | `--python`, `--py` | Python register model | Disabled | | `--all` | All output formats | Disabled | ### Example Commands ```bash # Generate only VHDL axion-hdl -s input.yaml -o output --vhdl # Generate VHDL and C headers axion-hdl -s input.yaml -o output --vhdl --c-header # Generate all formats axion-hdl -s input.yaml -o output --all # Generate documentation in HTML format axion-hdl -s input.yaml -o output --doc --doc-format html ``` --- ## Output Directory Structure After running `axion-hdl -s sources/ -o output/ --all`: ``` output/ ├── index.html # Navigation page ├── register_map.md # Combined Markdown docs ├── module1_axion_reg.vhd # VHDL module ├── module1_regs.h # C header ├── module1_regs.xml # XML export ├── module1_regs.yaml # YAML export ├── module1_regs.json # JSON export ├── module1.html # HTML detail page ├── module2_axion_reg.vhd ├── module2_regs.h ├── module2_regs.xml ├── module2_regs.yaml ├── module2_regs.json ├── module2.html └── ... ``` --- ## Integration Examples ### Vivado IP Integrator 1. Generate VHDL output 2. Add `_axion_reg.vhd` to your project 3. Instantiate in your top-level design 4. Connect AXI4-Lite interface to your bus ### Embedded C Development 1. Generate C header output 2. Include `_regs.h` in your firmware 3. Use provided read/write macros 4. Optionally redefine `BASE_ADDR` for your memory map ### Documentation Workflow 1. Generate HTML/Markdown outputs 2. Publish to documentation server or include in project wiki 3. Re-export YAML/JSON for version control tracking --- ## Enumerated Values in Outputs ### Docs (Markdown/HTML/PDF) When a packed register field has `enum_values`, the field table includes an "Enum Values" column: | Field | Bits | Type | Access | Default | Description | Enum Values | |-------|------|------|--------|---------|-------------|-------------| | `status` | [1:0] | [1:0] | RW | 0x0 | Status | 0:IDLE, 1:WAITING, 3:READY | ### C Header Enum macros are generated after the field mask/shift definitions: ```c /* status enumerated values */ #define MYMOD_STATUS_REG_STATUS_IDLE 0x0 #define MYMOD_STATUS_REG_STATUS_WAITING 0x1 #define MYMOD_STATUS_REG_STATUS_READY 0x3 ``` ### YAML / JSON Export `enum_values` is included in the field entry with string keys: ```yaml fields: - name: status bit_offset: 0 width: 2 enum_values: "0": IDLE "1": WAITING "3": READY ``` ### XML (SPIRIT) Export `` is emitted inside each field element with enum values. ### VHDL Package (`*_regs_pkg.vhd`) Generated when any field has `enum_values`: ```vhdl package mymod_regs_pkg is -- status_reg.status enumerated values constant C_STATUS_REG_STATUS_IDLE : std_logic_vector(1 downto 0) := "00"; constant C_STATUS_REG_STATUS_WAITING : std_logic_vector(1 downto 0) := "01"; constant C_STATUS_REG_STATUS_READY : std_logic_vector(1 downto 0) := "11"; end package mymod_regs_pkg; ``` ### SystemVerilog Package (`*_regs_pkg.sv`) Generated when any field has `enum_values`: ```systemverilog package mymod_regs_pkg; typedef enum logic [1:0] { IDLE = 2'b00, WAITING = 2'b01, READY = 2'b11 } t_status_reg_status_e; endpackage // mymod_regs_pkg ``` --- ## Address Map Report (Hierarchy Mode) **File:** `address_map.html` **Generated when:** `--hier ` is provided. A styled HTML report showing all module instances with their assigned address ranges. Useful for reviewing the full design address space at a glance. ### Table Columns | Column | Description | |--------|-------------| | **Instance Name** | The instance identifier from the hierarchy file (or module name for single-instance modules) | | **Module** | The source module name | | **Base Address** | The base address assigned in the hierarchy file | | **End Address** | Base address + register space size − 1 | | **Size** | Total register space size (bytes) | ### Example ``` Instance Name Module Base Address End Address Size spi_master_0 spi_master 0x00020000 0x0002000F 16 B spi_master_1 spi_master 0x00021000 0x0002100F 16 B uart_ctrl_0 uart_ctrl 0x00030000 0x0003001F 32 B ``` The rows are sorted by base address.