Corsair manual

Introduction

Corsair is a tool that makes it easy to create and maintain control and status register (CSR) map for any HDL project. It allows you to describe your register map in a single file and then generate HDL code, headers, documentation and other things. This effectively eliminates any mismatches between hardware, software and documentation of your IP-core.

Corsair flow

Features

  • Various human-readable input formats: JSON, YAML or plain text table

  • HDL code generation: Verilog or VHDL module with register map, Verilog header or SystemVerilog package with parameters and definitions

  • Multi-protocol support: APB, AXI-Lite, Avalon-MM

  • Documentation generation: Markdown, AsciiDoc

  • Generation of software-related files: C header, Python module

  • Extensibility: support of external file generators

  • API: creation of custom workflow with corsair API

Installing

Install the latest stable version from pypi:

python3 -m pip install -U corsair

Using the CLI

Corsair workflow is clean and straight-forward:

  • describe your register map in one of the supported formats (check this page to get more details)

  • create configuration file csrconfig (configuration file is explained here)

  • run corsair to generate all needed artifacts

Good point for start is to generate templates. For example, to generate YAML register map template just run:

corsair -t yaml

You will have the following catalog structure:

./csrconfig
./regs.yaml

To get all the generation artifacts simply run corsair:

corsair

You can run corsair from other directory. For example, if your configuration file is under project/ip-core/csrconfig:

corsair project/ip-core

If your csrconfig has other name you can try this:

corsair -c my.csrconfig

If your csrconfig has no definition for the register map path you can specify it explicitly:

corsair -r uart.txt

Using the API

You can use corsair classes to build your own workflow inside a Python script. Demonstration of this can be found here.

More information about internal classes can be found in the API section:

Examples

Check the examples directory to see how corsair works.

Register map

Register map is a special memory area that consists of named addresses called registers aka Control and Status Registers (CSR). These registers, in turn, are made up of bit fields - group of bits with special properties. When any register is accessed, collection of bit fields is read or written.

Register map usually is a part of an IP-core like timer, UART, SPI, USB, Ethernet and plenty of others. It is used by software to rule the core.

From the hardware perspective, typical register map has bus interface (APB, AXI-Lite, Avalon-MM or other) on the one end, and group of signals that integrates the map to HDL logic on the other end.

Register map

Register

As it said before, register map is nothing but collection of registers. Register have 4 main attributes:

Parameter

Description

name

Register name

description

Register description

address

Register address (offset from register map base address)

bitfields

List of register bit fields

Bit field

Bit field

One level down register consists of one or more bitfields. Attributes of a bitfield:

Parameter

Description

name

Field name

description

Field description

reset

Reset value of the field

width

Field width (bits)

lsb

Field least significant bit (LSB) position

access

Access mode. One of the options below.

hardware

Hardware options. Options are below.

enums

Enumerated values for the field

Access mode for the field is related to the bus accesses from software (or from one who drives the bus interface). Use one of:

Access modes

Description

rw

Read and Write. The field can be read or written.

rw1c

Read and Write 1 to Clear. The field can be read, and when 1 is written field is cleared.

rw1s

Read and Write 1 to Set The field can be read, and when 1 is written field is set.

ro

Read Only. Write has no effect.

roc

Read Only to Clear. The field is cleared after every read.

roll

Read Only / Latch Low. The field capture hardware active low pulse signal and stuck in 0. The field is set after every read.

rolh

Read Only / Latch High. The field capture hardware active high pulse signal and stuck in 1. Read the field to clear it.

wo

Write only. Zeros are always read.

wosc

Write Only / Self Clear. The field is cleared on the next clock tick after write.

Hardware options is used to define how bit field will interact with HDL logic. All the options are below.

Hardware options

Description

i

Input. Use input value from hardware to update the field.

o

Output. Enable output value from the field to be accessed by hardware.

c

Clear. Add signal to clear the field (fill with all zeros).

s

Set. Add signal to set the field (fill with all ones).

e

Enable. Add signal to enable the field to capture input value (must be used with i).

l

Lock. Add signal to lock the field (to prevent any changes).

a

Access. Add signals to notify when bus access to the field is performed

q

Queue. Enable queue (LIFO, FIFO) access

f

Fixed. Enable fixed mode (field is a constant)

n

None. No hardware access to the field.

Set of hardware options is just a string like q, ioel. There are few rules:

  • Options n, f, q can be used only alone

  • Any combination of i, o, u, c, s, l, a is allowed

These are just some ideas of how bit field access mode and hardware options can be combined with each other. Of course, full list of possible combinations is quite bigger, but these ones cover most of the cases.

Access

Hardware

Description

rw

o

Values can be read and written from software. Hardware can only access the current value.

rw

ol

Value that can be always read, but writing is done only when lock signal is inactive. Hardware can only access the current value.

rw

ioe

Values that can be read and written from software. Hardware either can access the current value or update it.

rw

ioea

Same as above, but hardware can also track when value was read or written by software.

rw

oc

Values that can be read and written from software. Hardware can clean the value.

rw

os

Values that can be read and written from software. Hardware can set the value.

rw

q

Software can read and write data. Hardware transforms these accesses to the queue read/write operations.

rw

n

Software can read and write data. But hardware has no access to the field.

rw1c

s

Software can read current state and write 1 to clear the field. Hardware can set the value.

rw1s

c

Software can read current state and write 1 to set the field. Hardware can clear the value.

ro

i

Software can only read the field. Hardware assign current state to some internal variable.

ro

f

Software can only read the constatnt value from the field. Hardware has no access to the field.

ro

ie

Software can only read the field. Hardware can update the value when enable signal is active.

ro

q

Software can only read data from the field. Hardware transform this to the queue read operation.

roc

ie

Software can only read data from the field, field is cleared after read. Hardware can update the value when enable signal is active.

roll

i

Value of the field will stuck at 0 when assigned hardware variable becomes 0. Software can only read data from the field, field is set after read.

rolh

i

Value of the field will stuck at 1 when assigned hardware variable becomes 1. Software can only read data from the field, field is cleared after read.

wo

o

Software can only write the field. Hardware can access the current value.

wo

q

Software can only write data to the field. Hardware transform this to the queue write operation.

wosc

o

Software can only write the field, the value will be cleared on the next tick. Hardware can access the field.

Enumerated value

A bit field may have one or more special named values aka enumerated values aka enums. In fact, they are just mnemonics assigned to specific values being read or written to the field. Every enumerated value has 3 properties:

Parameter

Description

name

Enum name

description

Enum description

value

Enum value

Input formats

YAML

YAML example:

regmap:
-   name: CTRL
    description: Control register
    address: 8
    bitfields:
    -   name: BAUD
        description: Baudrate value
        reset: 0
        width: 2
        lsb: 0
        access: rw
        hardware: o
        enums:
        -   name: B9600
            description: 9600 baud
            value: 0
        -   name: B38400
            description: 38400 baud
            value: 1
        -   name: B115200
            description: 115200 baud
            value: 2
-   name: ID
    description: IP-core ID register
    address: 4092
    bitfields:
    -   name: UID
        description: Unique ID
        reset: 3405645414
        width: 32
        lsb: 0
        access: ro
        hardware: f
        enums: []

More detailed example can be found in the repository.

JSON

JSON example is bit more verbose than YAML, but it is still the same register map:

{
    "regmap":[
        {
            "name": "CTRL",
            "description": "Control register",
            "address": 8,
            "bitfields": [
                {
                    "name": "BAUD",
                    "description": "Baudrate value",
                    "reset": 0,
                    "width": 2,
                    "lsb": 0,
                    "access": "rw",
                    "hardware": "o",
                    "enums": [
                        {
                            "name": "B9600",
                            "description": "9600 baud",
                            "value": 0
                        },
                        {
                            "name": "B38400",
                            "description": "38400 baud",
                            "value": 1
                        },
                        {
                            "name": "B115200",
                            "description": "115200 baud",
                            "value": 2
                        }
                    ]
                }
                                            ]
                },
                            {
            "name": "ID",
            "description": "IP-core ID register",
            "address": 4092,
            "bitfields": [
                {
                    "name": "UID",
                    "description": "Unique ID",
                    "reset": 3405645414,
                    "width": 32,
                    "lsb": 0,
                    "access": "ro",
                    "hardware": "f",
                    "enums": []
                }
            ]
        }
    ]
}

More detailed example can be found in the repository.

TXT

Simple plain text format. Looks like Markdown table. The example below

| Address | Name   | Width | Access | Hardware | Reset      | Description      |
| ------- | ------ | ----- | ------ | -------- | ---------- | ---------------- |
| 0x0000  | DATA   | 32    | rw     | ioe      | 0x00000000 | Data register    |
| 0x0004  | CTRL   | 16    | rw     | o        | 0x00000100 | Control register |
| 0x0008  | STATUS | 8     | ro     | i        | 0x00000000 | Status register  |
| 0x0100  | START  | 1     | wosc   | o        | 0x00000000 | Start register   |

It is much simpler than JSON/YAML formats, but it is just enough for many applications. However, you have to pay for this simplicity:

  • Only one bit field per register is allowed. Columns Address, Name, Description store CSR attributes. Columns Width, Access, Hardware, Reset - bit field ones. LSB for this single bit field is always 0.

  • No enums

More detailed example can be found in the repository.

Configuration file

Corsair uses simple flat INI configuration file called csrconfig. It is used for the two things:

  • to pass global parameters to corsair

  • to specify all generation targets with their attributes

Example of csrconfig is below:

[globcfg]
data_width = 32
address_width = 16
register_reset = sync_pos

[v_module]
path = regs.v
interface = axil
generator = Verilog

[c_header]
path = regs.h
generator = CHeader

It has one special section globcfg for global parameters, and one or many sections for generation targets.

globcfg section

Global parameters available:

Parameter

Default value

Description

base_address

0

Register map base address in global address map

data_width

32

Width of all data buses and registers

address_width

16

Address bus width (capacity of the register map)

register_reset

sync_pos

Flip-flop reset style

sync_pos

Synchronous active high reset

sync_neg

Synchronous active low reset

async_pos

Asynchronous active high reset

async_neg

Asynchronous active low reset

address_increment

none

Address auto increment mode, if no address is provided for a register

none

Address auto increment mode is disabled

data_width

Enable address auto increment with value based on globcfg.data_width

<positive-integer>

Enable address auto increment with provided number of bytes, e.g 4

address_alignment

data_width

Check for address alignment of registers.

none

No check of address alignment

data_width

Enable check of address alignment based on globcfg.data_width

<positive-integer>

Enable check of address alignment based on provided number of bytes, e.g 4

force_name_case

none

Force case for all the names (regsiters, bit fields, enums)

none

Names used as they are

lower

Force names to have lowercase

upper

Force names to have uppercase

You can omit any of this in your csrconfig file - default value will be used.

You also can add your own parameters and access them inside your custom flow the same way as standart ones. This is valid config:

[globcfg]
data_width = 32
address_width = 16
register_reset = sync_pos
foo = bar

Target sections

Target section defines file generator and specify its parameters. Generator is a Python class that produces some output based on input arguments. Usually, one target section - one output file.

Few simple rules to remember:

  • target name should be unique

  • targets without generator parameter is ignored

Parameter generator can be defined in the two ways. To use built-in generator:

[target]
generator = Verilog

Or to use custom created one:

[target]
generator = custom_generator.py::MyCustomGenerator

If you are interesting in expanding corsair functionality, there is the example of how to build your own generator and use it with corsair CLI.

Generators

Corsair provides many built-in generators:

Generator

Description

Json

Dump register map to a JSON file

Yaml

Dump register map to a YAML file

Txt

Dump register map to a text file

Verilog

Create Verilog file with register map

Vhdl

Create VHDL file with register map

VerilogHeader

Create Verilog header file with register map defines

CHeader

Create C header file with register map define

SystemVerilogPackage

Create SystemVerilog package with register map parameters

Markdown

Create documentation for a register map in Markdown

Asciidoc

Create documentation for a register map in AsciiDoc

Python

Create Python file with register map

There are even more generators but these ones are normally don’t used in csrconfig file - they are helpfull for creating custom generators or other development tasks:

Generator

Description

Generator

Base generator class

Jinja2

Basic class for rendering Jinja2 templates

Wavedrom

Basic class for rendering register images with wavedrom

LbBridgeVerilog

Create Verilog file with bridge to Local Bus

LbBridgeVhdl

Create Vhdl file with bridge to Local Bus

Note

These parameters in csrconfig file are nothing but arguments for the class constructor. If parameter is not provided - default value will be used. Please note that the tables below were created mannualy, while data in Generators API page was collected automaticaly. As these things are exactrly the same information just in different forms, please refer to API if you have any doubts.

Json

Parameter

Default

Description

path

regs.json

Path to the output file

Yaml

Parameter

Default

Description

path

regs.yaml

Path to the output file

Txt

Parameter

Default

Description

path

regs.txt

Path to the output file

Verilog

Parameter

Default

Description

path

regs.v

Path to the output file

read_filler

0

Numeric value to return if wrong address was read

interface

axil

Register map bus protocol

axil

AXI4-Lite

amm

Avalon-MM

apb

APB4

lb

Custom LocalBus interface

Vhdl

Parameter

Default

Description

path

regs.vhd

Path to the output file

read_filler

0

Numeric value to return if wrong address was read

interface

axil

Register map bus protocol

axil

AXI4-Lite

amm

Avalon-MM

apb

APB4

lb

Custom LocalBus interface

VerilogHeader

Parameter

Default

Description

path

regs.vh

Path to the output file

preifx

CSR

Prefix for all defines. If empty, output file name will be used.

CHeader

Parameter

Default

Description

path

regs.h

Path to the output file

preifx

CSR

Prefix for all defines. If empty, output file name will be used.

SystemVerilogPackage

Parameter

Default

Description

path

regs_pkg.sv

Path to the output file

preifx

CSR

Prefix for the all parameters. If empty, output file name will be used.

Markdown

Parameter

Default

Description

path

regs.md

Path to the output file

title

Register map

Document title

print_images

True

Enable generating images for bit fields of a register

image_dir

regs_img

Path to directory where all images will be saved

print_conventions

True

Enable generating table with register access modes explained

Asciidoc

Parameter

Default

Description

path

regs.md

Path to the output file

title

Register map

Document title

print_images

True

Enable generating images for bit fields of a register

image_dir

regs_img

Path to directory where all images will be saved

print_conventions

True

Enable generating table with register access modes explained

Python

Parameter

Default

Description

path

regs.py

Path to the output file

APB

Signals

These signals will be used in the interface of the register map.

Signal

Width

Direction

Description

psel

1

input

APB select

paddr

>1

input

APB address

penable

1

input

APB enable

pwrite

1

input

APB write

pwdata

>1

input

APB write data

pstrb

>1

input

APB write strobe

prdata

>1

output

APB read data

pready

1

output

APB ready

pslverr

1

output

APB slave error

Note

Specific bit widths for buses are defined in globcfg section of a csrconfig file.

Implementation details:

  • APB4 slave

  • pprot signal is not implemented

  • pslverr tied to 0 - slave is always OKAY

Protocol

Refer to official ARM documentation: IHI0024C AMBA® APB Protocol Version: 2.0.

AXI-Lite

Signals

These signals will be used in the interface of the register map.

Signal

Width

Direction

Description

axil_awaddr

>1

input

Write address channel: write address

axil_awprot

3

input

Write address channel: protection type

axil_awvalid

1

input

Write address channel: write address valid

axil_awready

1

output

Write address channel: write address ready

axil_wdata

>1

input

Write data channel: write data

axil_wstrb

>1

input

Write data channel: write strobes

axil_wvalid

1

input

Write data channel: write valid

axil_wready

1

output

Write data channel: write ready

axil_bresp

2

output

Write response channel: write response

axil_bvalid

1

output

Write response channel: write valid

axil_bready

1

input

Write response channel: write ready

axil_araddr

>1

input

Read address channel: read address

axil_arprot

3

input

Read address channel: protection type

axil_arvalid

1

input

Read address channel: read address valid

axil_arready

1

output

Read address channel: read address ready

axil_rdata

>1

output

Read data channel: read data

axil_rresp

2

output

Read data channel: read response

axil_rvalid

1

output

Read data channel: read valid

axil_rready

1

input

Read data channel: read ready

Note

Specific bit widths for buses are defined in globcfg section of a csrconfig file.

Implementation details:

  • AXI4-Lite slave

  • *resp signals are tied to 0 - always OKAY

  • *prot signals are not handled

Protocol

Refer to official ARM documentation: IHI0022G AMBA AXI and ACE Protocol Specification AXI3, AXI4, and AXI4-Lite ACE and ACE-Lite.

Avalon-MM

Signals

These signals will be used in the interface of the register map.

Signal

Width

Direction

Description

address

>1

input

Avalon-MM address

read

1

input

Avalon-MM read

readdata

>1

output

Avalon-MM read data

readdatavalid

1

output

Avalon-MM read data valid

byteenable

>1

input

Avalon-MM byte enable

write

1

input

Avalon-MM write

writedata

>1

input

Avalon-MM write data

waitrequest

1

output

Avalon-MM wait request

Note

Specific bit widths for buses are defined in globcfg section of a csrconfig file.

Protocol

Refer to official Intel documentation: Avalon® Interface Specifications.

LocalBus

LocalBus is a custom bus interface. You can use it for your register map, hovewer, it was designed specially to simplify integrating more common bus interfaces to register map. It acts as internal “virtual” interface.

In fact, all other supported buses (APB, AXI-Lite and etc.) in corsair are nothing more than just bridges to LocalBus interface under the hood.

Signals

Signal

Width

Direction

Description

waddr

>1

input

Write address bus

wdata

>1

input

Write data bus

wen

1

input

Write request enable signal

wstrb

>1

input

Write byte strobe bus (one bit for every write data byte)

wready

1

output

Write request ready signal

raddr

>1

input

Read address bus

ren

1

input

Read request enable signal

rdata

>1

output

Read data bus

rvalid

1

output

Read data valid signal

Note

Specific bit widths for buses are defined in globcfg section of a csrconfig file.

Transfers

Only simple single transfers are supported. No bursts or stream accesses. Every transfer can be extended with special signals.

Just for example, data bus is 32 bits wide for all the waveforms below.

Simple write

Write data D0 to address A0.

_images/wavedrom-05876a99-4cb5-4647-aaaf-202625975c68.svg

Write with bytes strobes

Byte strobe signalling to write only bytes 1 and 2 (wstrb = 0x6 = 0b0110) of D0 word.

_images/wavedrom-9ccf94ad-6d1a-4153-b636-52d6aeada787.svg

Write with wait states

Write data D0 to address A0, then write D1 to A1 ends (wen goes low) as soon as wready become high.

_images/wavedrom-0af8aff7-20df-4198-8f0d-7b4d2b07849a.svg

Simple read

Read data D0 from address A0. Minimum response time - 1 tick. “Combinatoral” (in the same tick) read is not supported. Read ends (ren goes low) after rvalid is asserted.

_images/wavedrom-aecca48b-af43-4980-84a6-38f80930841e.svg

Read with wait states

Read data D0 from address A0 with 2 wait states.

_images/wavedrom-448a950d-577a-479c-8684-bf633d4e44f4.svg

Register map

EnumValue

class corsair.EnumValue(name='enum', value=0, description='Enumerated value', **args)[source]

Enumerated value.

Parameters:
  • name (str) – Enum name

  • value (int) – Enum value

  • description (str) – Enum description

as_dict()[source]

Create a dictionary with the key attributes of the bit field.

as_str(indent='')[source]

Create an indented string with the enum information.

property description

Description of the enum.

property name

Name of the enum.

validate()[source]

Validate parameters of the enum.

property value

Value of the enum.

BitField

class corsair.BitField(name='val', description='Value of the register', reset=0, width=1, lsb=0, access='rw', hardware='n', **args)[source]

Bit field.

Parameters:
  • name (str) – Bit field name

  • description (str) – Bit field description

  • reset (int) – Bit field reset vaue

  • width (int) – Bit field width vaue

  • lsb (int) – Bit field LSB vaue

  • access (str) – Bit field access mode

  • hardware (str) – Bit field hardware options

property access

Access mode for the bitfield.

add_enums(new_enums)[source]

Add enum or list of enums.

Enums are automatically sorted and stored in the ascending order of value attributes.

as_dict()[source]

Create a dictionary with the key attributes of the bit field.

as_str(indent='')[source]

Create an indented string with the bit field information.

property bits

Create list with all positions of the bits represented by the bit field.

property byte_strobes

Dictionary with LSB and MSB values for the every byte in the write data bus.

property description

Description of the bitfield.

property enum_names

List with all enum names.

property enums

List with enum objects.

property hardware

Hardware mode for the bitfield.

is_vector()[source]

Check if the width of the bit field > 1.

property lsb

LSB value of the bitfield.

property mask

Bit mask for the field.

property msb

Position of most significant bit (MSB) of the field.

property name

Name of the bit field.

property reset

Inital value of the bitfield.

validate()[source]

Validate parameters of the bit field.

property width

Width value of the bitfield.

Register

class corsair.Register(name='csr0', description='Control and status register 0', address=None, **args)[source]

Control and status register.

Parameters:
  • name (str) – Bit field name

  • description (str) – Bit field description

  • address (int, None) – Register address

property access

Register access mode, based on bitfields.

add_bitfields(new_bitfields)[source]

Add bit field or list of bit feilds.

Bit fields are automatically sorted and stored in the ascending order of msb attributes.

property address

Address of the register.

as_dict()[source]

Create a dictionary with the key attributes of the register.

as_str(indent='')[source]

Create an indented string with the information about the register.

property bitfield_names

List with all bit field names.

property bitfields

List with bit field objects.

property description

Description of the register.

property name

Name of the register.

property reset

Reset value of the refister after reset.

validate()[source]

Validate parameters of the register.

RegisterMap

class corsair.RegisterMap[source]

CSR map

add_registers(new_regs)[source]

Add list of registers.

Register are automatically sorted and stored in the ascending order of addresses.

as_dict()[source]

Return register map as a dictionary.

as_str(indent='')[source]

Create indented string with the information about register map.

read_file(path)[source]

Read register map from file (based on extension).

read_json(path)[source]

Read register map from JSON file.

read_txt(path)[source]

Read register map from text file.

read_yaml(path)[source]

Read register map from YAML file.

property reg_names

List with all register names.

property regs

List with register objects.

validate()[source]

Validate the register map.

Generators

Generator

class corsair.generators.Generator(rmap, **args)[source]

Bases: object

Base generator class.

Parameters:

rmap (corsair.RegisterMap) – Register map object

generate()[source]

Do file generation.

make_target(name)[source]

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

validate()[source]

Validate generator parameters.

Jinja2

class corsair.generators.Jinja2[source]

Bases: object

Basic class for rendering Jinja2 templates

render(template, vars, templates_path=None)[source]

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)[source]

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Wavedrom

class corsair.generators.Wavedrom[source]

Bases: object

Basic class for rendering register images with wavedrom

draw_regs(imgdir, rmap)[source]

Json

class corsair.generators.Json(rmap=None, path='regs.json', **args)[source]

Bases: Generator

Dump register map to a JSON file.

Parameters:
generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

validate()

Validate generator parameters.

Yaml

class corsair.generators.Yaml(rmap=None, path='regs.yaml', **args)[source]

Bases: Generator

Dump register map to a YAML file.

Parameters:
generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

validate()

Validate generator parameters.

Txt

class corsair.generators.Txt(rmap=None, path='regs.txt', **args)[source]

Bases: Generator

Dump register map to a text table.

Note: only registers with single bitfield are allowed.

Parameters:
generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

validate()

Validate generator parameters.

Verilog

class corsair.generators.Verilog(rmap=None, path='regs.v', read_filler=0, interface='axil', **args)[source]

Bases: Generator, Jinja2

Create Verilog file with register map.

Parameters:
  • rmap (corsair.RegisterMap) – Register map object

  • path (str) – Path to the output file

  • read_filler (int) – Numeric value to return if wrong address was read

  • interface (str) – Register map bus protocol. Use one of: axil, apb, amm, lb

generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

render(template, vars, templates_path=None)

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

validate()[source]

Validate generator parameters.

Vhdl

class corsair.generators.Vhdl(rmap=None, path='regs.vhd', read_filler=0, interface='axil', **args)[source]

Bases: Generator, Jinja2

Create VHDL file with register map.

Parameters:
  • rmap (corsair.RegisterMap) – Register map object

  • path (str) – Path to the output file

  • read_filler (int) – Numeric value to return if wrong address was read

  • interface (str) – Register map bus protocol. Use one of: axil, apb, amm, lb

generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

render(template, vars, templates_path=None)

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

validate()[source]

Validate generator parameters.

VerilogHeader

class corsair.generators.VerilogHeader(rmap=None, path='regs.vh', prefix='CSR', **args)[source]

Bases: Generator, Jinja2

Create Verilog header file with register map defines.

Parameters:
  • rmap (corsair.RegisterMap) – Register map object

  • path (str) – Path to the output file

  • prefix (str) – Prefix for the all defines. If empty output file name will be used.

generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

render(template, vars, templates_path=None)

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

validate()

Validate generator parameters.

CHeader

class corsair.generators.CHeader(rmap=None, path='regs.h', prefix='CSR', **args)[source]

Bases: Generator, Jinja2

Create C header file with register map defines.

Parameters:
  • rmap (corsair.RegisterMap) – Register map object

  • path (str) – Path to the output file

  • prefix (str) – Prefix for the all defines and types. If empty output file name will be used.

generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

render(template, vars, templates_path=None)

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

validate()[source]

Validate generator parameters.

SystemVerilogPackage

class corsair.generators.SystemVerilogPackage(rmap=None, path='regs_pkg.sv', prefix='CSR', **args)[source]

Bases: Generator, Jinja2

Create SystemVerilog package with register map parameters.

Parameters:
  • rmap (corsair.RegisterMap) – Register map object

  • path (str) – Path to the output file

  • prefix (str) – Prefix for the all parameters and types. If empty output file name will be used.

generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

render(template, vars, templates_path=None)

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

validate()

Validate generator parameters.

Markdown

class corsair.generators.Markdown(rmap=None, path='regs.md', title='Register map', print_images=True, image_dir='regs_img', print_conventions=True, **args)[source]

Bases: Generator, Jinja2, Wavedrom

Create documentation for a register map in Markdown.

Parameters:
  • rmap (corsair.RegisterMap) – Register map object

  • path (str) – Path to the output file

  • title (str) – Document title

  • print_images (bool) – Enable generating images for bit fields of a register

  • image_dir (str) – Path to directory where all images will be saved

  • print_conventions (bool) – Enable generating table with register access modes explained

draw_regs(imgdir, rmap)
generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

render(template, vars, templates_path=None)

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

validate()

Validate generator parameters.

Asciidoc

class corsair.generators.Asciidoc(rmap=None, path='regs.adoc', title='Register map', print_images=True, image_dir='regs_img', print_conventions=True, **args)[source]

Bases: Generator, Jinja2, Wavedrom

Create documentation for a register map in AsciiDoc.

Parameters:
  • rmap (corsair.RegisterMap) – Register map object

  • path (str) – Path to the output file

  • title (str) – Document title

  • print_images (bool) – Enable generating images for bit fields of a register

  • image_dir (str) – Path to directory where all images will be saved

  • print_conventions (bool) – Enable generating table with register access modes explained

draw_regs(imgdir, rmap)
generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

render(template, vars, templates_path=None)

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

validate()

Validate generator parameters.

Python

class corsair.generators.Python(rmap=None, path='regs.py', **args)[source]

Bases: Generator, Jinja2

Create Python file to access register map via some interface.

Parameters:
generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

render(template, vars, templates_path=None)

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

validate()

Validate generator parameters.

LbBridgeVerilog

class corsair.generators.LbBridgeVerilog(rmap=None, path='axil2lb.v', bridge_type='axil', **args)[source]

Bases: Generator, Jinja2

Create Verilog file with bridge to Local Bus.

Parameters:
  • rmap (corsair.RegisterMap) – Register map object

  • path (str) – Path to the output file

  • bridge_type (str) – Bridge protocol. Use one of axil, apb, amm.

generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

render(template, vars, templates_path=None)

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

validate()[source]

Validate generator parameters.

LbBridgeVhdl

class corsair.generators.LbBridgeVhdl(rmap=None, path='axil2lb.v', bridge_type='axil', **args)[source]

Bases: Generator, Jinja2

Create VHDL file with bridge to Local Bus.

Parameters:
  • rmap (corsair.RegisterMap) – Register map object

  • path (str) – Path to the output file

  • bridge_type (str) – Bridge protocol. Use one of axil, apb, amm.

generate()[source]

Do file generation.

make_target(name)

Dump class attributes to dictionary that can be used as target for csrconfig generation.

Parameters:

name – Name of the target

Returns:

Target dictionary

render(template, vars, templates_path=None)

Render text with Jinja2.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

Returns:

String with rendered text

render_to_file(template, vars, path, templates_path=None)

Render text with Jinja2 and save it to the file.

Parameters:
  • template – Jinja2 template filename

  • vars – Dictionary with variables for Jinja2 rendering

  • path – Path to the output file

  • templates_path – Path to search templates. If no path provided, then internal templates will be used

validate()[source]

Validate generator parameters.

Configuration

Module to operate with Corsair configuration files

corsair.config.default_globcfg()[source]

Create a global configuration with parameters by default.

corsair.config.read_csrconfig(cfgpath)[source]

Parse Corsair configuration file. Return two dictionaries: global configuration and targets.

corsair.config.set_globcfg(globcfg_)[source]

Use specified global configuration for all operations

corsair.config.validate_globcfg(globcfg)[source]

Validate a dictionary with global configuration.

corsair.config.write_csrconfig(cfgpath, globcfg, targets)[source]

Save Corsair configuration file.

Developer’s guide

Installation

Note

Depending on your system, Python executable might be python or python3. If there any permissions issues, add --user key to the installation scripts.

Install dependencies first:

python3 -m pip install gitpython pyyaml jinja2 wavedrom

Then clone GitHub repository and you’ll be able to run application from the project root:

git clone https://github.com/esynr3z/corsair.git
cd corsair
python3 -m corsair --help

Or install it:

python3 setup.py install

Code style

PEP 8 Speaks is added to automatically review Python code style over Pull Requests.

Linter settings:

  • Linter: pycodestyle

  • Max line length: 120

  • Errors and warnings to ignore: W504, E402, E731, C406, E741

You can also install PEP8 Git Commit Hook and code style will be checked before any commit.

Testing

Install PyTest:

python3 -m pip install -U pytest pytest-xdist

HDL tests use Modelsim, so make sure that Modelsim is installed and visible in PATH.

Run tests from the root folder on all available cores:

pytest -v -n auto

Run tests for docstrings:

pytest --doctest-modules corsair

Documentation

Install Sphinx and extensions:

python3 -m pip install -r docs/requirements.txt

Run from docs folder to build the documentation:

make clean html

Changelog

1.0.4 (2023-03-17)

  • Fix rolh/roll missing latch bug

  • Fix constants comparison on address in vhdl

  • Fix C/C++ header generation

1.0.3 (2023-03-06)

  • Various bug fixes

1.0.2 (2021-09-26)

  • Fix overlapping of bitfiled names in rendered images for registers

1.0.1 (2021-09-08)

  • Fix an issue where the input globconfig file was not being applied to generators

1.0.0 (2021-09-03)

Reworking the entire project almost from scratch. Lots of breaking changes.

  • New configuration file format (INI)

  • New file generation flow (more clear)

  • Do refactoring of all core modules

  • Add enums

  • Add C header generator

  • Add Verilog header generator

  • Add SystemVerilog package generator

  • Embed bus interface (AXI-Lite, APB, Avalon-MM) into a register map

  • Add VHDL register map generator

  • Add plenty of examples

  • Rework of documentation

  • Update the tests

  • Many minor tweaks and fixes

0.3.0 (2021-02-21)

  • Fix Markdown table row endings.

  • Add ‘Reserved’ bitfields to Markdown.

  • Fix installation guides.

  • Implement access_strobes attribute for register.

  • Implement complementary registers.

  • Implement write_lock attribute for register.

  • Implement FIFO bitfield modifier.

  • Implement AXI-Lite to Local Bus bridge on Verilog.

  • Implement Avalon-MM to Local Bus bridge on Verilog.

0.2.0 (2021-01-08)

  • Rework CLI keys

  • Fix entry point for CLI

  • Add Verilog and Markdown writers for a register map

  • Add Local Bus bridge writer

  • Implement APB to Local Bus bridge on Verilog

  • Setup HDL testing environment

  • Setup CI/CD via Github Actions

  • Documentation fixes, code prettifying and etc.

0.1.0 (2020-12-16)

  • Setup repository

  • Setup documentation

  • Setup testing

  • Implementation of core classes

  • Add support of running from a command line

  • Add JSON and YAML readers

  • Add JSON and YAML writers

Keyword Index