Output Formats¶
Basic HTML Output¶
HTML is used to generate documentation which can be opened in any browser.
In the selected output directory, the following files will be created:
- An HTML file for each Component, represent the unbound Component with a base address of 0.
- An HTML file for each MemoryMap, with a table of Instances, their offsets and sizes.
- A subdirectory for each MemoryMap, with a Component style HTML file for each Instance representing the bound Component with a start address determined by the MemoryMap.
- CSS styles for all of the HTML
In this way, the directory serves as a package of documentation for the register map source. It can be moved as one big atomic thing.
All HTML files have table of contents sidebars to help navigation.
Basic VHDL Output¶
This output makes no assumptions about what the bus type is, and expects
no support packages to be available. Words below encased in <angle brackets>
are meant to represent a fill-in-the-blank of the name of that thing, so a
tb_<REGISTERARRAY> would be tb_BUFFER for a RegisterArray named BUFFER.
Depending on the choice of names of things in the XML, it may be necessary to change the names of things to avoid either illegal characters or VHDL reserved words. Check the header comments of the generated VHDL files for information about changed elements.
Changed names indicate characters that were not legal VHDL, and will be different in all contexts, illegal characters will be replaced with _ characters.
Changed identifiers mean only that they cannot be bare words, which means they are only different in the context of something.identifier, such as registers in components or fields in registers. Changed identifiers will get an “_0” extension.
Types¶
- subtype
t_addrof integer - subtype
t_busdataof std_logic_vector, component width wide t_<REGISTER>- subtype of std_logic_vector, unsigned, or signed OR
- record if the register has fields
- record
tb_<REGISTERARRAY>if the registerarray has multiple registers - array
ta_<REGISTERARRAY>oftb_<REGISTERARRAY>ort_<REGISTER> - record
t_<COMPONENT>_regfileto hold the entire register file
Constants¶
<REGISTER>_ADDRword offsets from 0 for freestanding registers<REGISTER>_ADDRword offsets from array start in a registerarray<REGISTERARRAY>_BASEADDRoffsets the same way REGISTER_ADDR does<REGISTERARRAY>_FRAMESIZEis the number of words in each array element<REGISTERARRAY>_FRAMECOUNTis the number of FRAMESIZE element in the array<REGISTERARRAY>_LASTADDRis the offset for the last word in the array<REGISTER>_<FIELD>_<ENUM>is a value for field <REGISTER>.<FIELD>RESET_t_<REGISTER>is the reset value constant for at_<REGISTER>RESET_ta_<REGISTERARRAY>is the reset value constant for at_<REGISTERARRAY>RESET_t_<COMPONENT>_REGFILEis the reset value for at_<COMPONENT>_regfile
Subprograms¶
Addresses¶
GET_ADDR rips the appropriate number of LSBs to make a word address from the word address on the bus:
function GET_ADDR(address: std_logic_vector) return t_addr;
function GET_ADDR(address: unsigned) return t_addr;
Component¶
Component level subprograms manipulate the entire t_<COMPONENT>_regfile. For
register files that will be implemented entirely on flip-flops this is probably
viable; to use block RAM as part or all of the storage will require
some special casing around these functions. Note that these functions are
unconditional; read-enable and write-enable functions should be implemented
by selectively calling or not calling them:
procedure UPDATE_REGFILE(
dat: in t_busdata; byteen : in std_logic_vector;
offset: in t_addr;
variable reg: inout t_<COMPONENT>_regfile;
success: out boolean);
procedure UPDATESIG_REGFILE(
dat: in t_busdata; byteen : in std_logic_vector;
offset: in t_addr;
signal reg: inout t_<COMPONENT>_regfile;
success: out boolean);
procedure READ_REGFILE(
offset: in t_addr;
reg: in t_<COMPONENT>_regfile;
dat: out t_busdata;
success: out boolean);
UPDATE_REGFILE and UPDATESIG_REGFILE will update a single register based on the address in offset. The new data will be taken from dat on the byte lanes selected by byteen, which should be 1/8 as long as dat. Use UPDATE_REGFILE if the register are stored in a variable, or UPDATESIG_REGFILE if they are stored in a variable. There probably aren’t circumstances that warrant the use of both in the same design. In either case, success is set true if the write targeted a writeable register or false if not.
READ_REG gets the data from a single register based on the address in offset and returns it in a proper format for the data bus. dat is set with the data that has been read and success is set true if the read targeted a readable register or false if not.
RegisterArray¶
RegisterArray programs manipulate registers inside of a RegisterArray similarly to those in a Component. They’re a bit of an odd duck in terms of high-level vs. low-level accesses. Primarily they exist to be called by the _REGFILE routines; user use of them is mostly limited to knocking out a section of the register map to be implemented separately on BRAMs.
For each registerarray in the design there are procedures:
procedure UPDATE_<registerarray>(
dat: in t_busdata; byteen : in std_logic_vector;
offset: in t_addr;
variable ra: inout ta_<registerarray>;
success: out boolean);
procedure UPDATESIG_<registerarray>(
dat: in t_busdata; byteen : in std_logic_vector;
offset: in t_addr;
signal ra: inout ta_<registerarray>;
success: out boolean);
procedure READ_registerarray(
offset: in t_addr;
ra: in ta_<registerarray>;
dat: out t_busdata;
success: out boolean);
For all these procedures the offset parameter is relative to the baseaddress of that registerarray, available as <REGISTERARRAY>_BASEADDR, not to the start of the component.
Register¶
The functions available for Registers are low-level access functions. These are usable directly by users either to supplement or entirely circumvent the generated register decoding functions. For each register there are subprograms:
function DAT_TO_<register>(dat: t_busdata) return t_<register>;
function <register>_TO_DAT(reg: t_<register>) return t_busdata;
procedure UPDATE_<register>(
dat: in t_busdata; byteen: in std_logic_vector;
variable reg: inout t_<register>);
procedure UPDATESIG_<register>(
dat: in t_busdata; byteen: in std_logic_vector;
signal reg: inout t_<register>);
DAT_TO_<REGISTER> turns the abstract data on the bus into the register data type, which may be a simple type like a signed, unsigned, or std_logic_vector, or may be a record of such types, in which case the bits will be translated to the appropriate fields. <REGISTER>_TO_DAT reverses this operation, filling unused bits with ‘0’. All fields are operated on, regardless of readOnly and writeOnly settings.
UPDATE_<REGISTER> and UPDATESIG_<REGISTER> update those bits of the register data specified by the byte enable mask. Bits where byteen=‘0’ are unaltered. Again, UPDATE_<REGISTER> is used if the register storage is a VHDL variable, and UPDATESIG_<REGISTER> if it is a signal. As these functions are made to be executed in response to bus writes, readOnly fields are ignored.
AXI4-Lite VHDL¶
The AXI4-Lite VHDL format generates component VHDL template files. These templates rely on the packages generated by the basic VHDL output, which must be generated separately.
The template includes boilerplate bus read and write procedures, along with reset logic, but obviously no logic for the actual implementation of functionality which must be added separately.
Warning
Files from this output are made to be modified. Do not do so in the creation directory where they can be accidentally overwritten by regenerating this output. Move them manually to a working directory so that they can be safely edited.
WISHBONE (Registered Termination)¶
The WISHBONE Registered Termination VHDL format generates component VHDL template files for a WISHBONE B4 bus. This takes advantage of the new, simpler registered feedback mechanism in the B4 specification to provide fast pipelined transactions with minimal logic. Only the immediate address is used, the CTI_I and BTI_I are not necessary. STALL_O is provided to demonstrate that it the mechanism is used, but is always deasserted.
Only data granularity of 8 bits is supported and undefined tagged data signals TGD_I, TGD_O, TDA_I, and TGC_I need to be explicitly added by the user.
Slaves repond with ACK_O for accesses to valid register locations and ERR_O for invalid locations.
The templates rely on the packages generated by the basic VHDL output, which must be generated separately.
The template includes boilerplate bus read and write procedures, along with reset logic, but obviously no logic for the actual implementation of functionality which must be added separately.
Warning
Files from this output are made to be modified. Do not do so in the creation directory where they can be accidentally overwritten by regenerating this output. Move them manually to a working directory so that they can be safely edited.
WISHBONE (Asynchronous Termination)¶
The WISHBONE Asynchronous Termination VHDL format generates component VHDL template files for a WISHBONE B4 bus. This is a simpler mechanism than the registered feedback termination, but will ultimately present maximum clock frequency limitations on the bus. As such, this implementation supports only classic cycles, it does not provide the LOCK_I or STALL_O signals. Additionally, only data granularity of 8 bits is supported and undefined tagged data signals TGD_I, TGD_O, TDA_I, and TGC_I need to be explicitly added by the user.
Slaves repond with ACK_O for accesses to valid register locations and ERR_O for invalid locations.
The templates rely on the packages generated by the basic VHDL output, which must be generated separately.
The template includes boilerplate bus read and write procedures, along with reset logic, but obviously no logic for the actual implementation of functionality which must be added separately.
Warning
Files from this output are made to be modified. Do not do so in the creation directory where they can be accidentally overwritten by regenerating this output. Move them manually to a working directory so that they can be safely edited.
Basic Python Output¶
This output makes a directory full of Python files that use the
ctypes and bitfield libraries in order to create a
memory-mapped structure equivalent to the register map.
This is directly useful with a register map that is
connected directly into PC memory space, such as a PCI or VME card, but can
also serve as a base template for the remotestruct library to work
via an arbitrary transport layer.
Types¶
The Python outputs use the basic ctypes types of c_uint8,
c_int32, and so forth to represent entire registers.
In order to create structured bitfields in registers, additional types are
created with the naming convention _t_<REGISTER> using the
bitfield.make_bf() function. These Bitfield objects allow attribute
access to all of the fields as well, as well as dict-like methods like keys()
and items(). There is also a base attribute which represents the
entire register as its underlying unsigned integer. So if the component that
the register is in has a data width of 32 bits, the bitfield base will be a
c_uint32.
Enumeration Constants¶
Classes¶
For each component, a Python file is written defining the component as a subclass
of ctypes.Structure. Fields representing gaps in the contiguous
region will be named _dummy followed by a positional number.
RegisterArrays in Components are treated as arrays in standard ctypes fashion.
For each memorymap, a Python file is written defining the memorymap as a subclass
of ctypes.Structure. Fields representing gaps in the contiguous
region will be named _dummy followed by a positional number.
Instances in the memorymap will be the classes created by the component-level Python files, which are imported at the top of the memory map file.
Highland XML¶
The Highland XML output format is the same as the Highland XML input format. This means that the directory generated from the htixml format is usable as input for subsequent program invocations.
Because the placement algorithms are stable, there is no need to do this just to keep working with the same input files. However, sometimes you need to lock down register placements, particularly if they’ve already been released as a public API. You don’t want to go moving things around between revisions once the public has started writing code against them.
The regenerated XML has explicit values for all parameters including placement and sizing. This means that API compatibility is guaranteed if you use them as starting points to add additional functionality.
Text Tree Output¶
An extremely basic text output, primarily useful for debugging. Example output is:
component VMESPACE (size=256)
The VMESPACE peripheral holds registers to the VMEbus. An array of 256 16bit VME registers will
be implemented per described in the V280 manual.
This is visible only to the internal bus.
(0) MFR
Highland ID
(1) MODEL
V280 Model ID
(2) MODREV
Hardware Revision
(3) SERIAL
Unit serial number
(4) FIRWARE
Programmed firmware
(5) FREV
Firmware revision
(6) MCOUNT
1KHz real-time counter
(7) DASH
Unit dash number
(8) CALID
Calibration table status
(9) YCAL
Calibration date: year
(10) DCAL
Calibration date: month/day
Field DAY (writeOnly=None,format=bits,size=8,offset=0,readOnly=None)
Day (1-31)
Field MONTH (writeOnly=None,format=bits,size=8,offset=8,readOnly=None)
Month (1-12)
(12) ULED
User LED control
(16) MACRO
Macro register
RegisterArray MPARAM (writeOnly=False,count=4,offset=17,readOnly=False,size=4,framesize=1)
Macro parameter registers
(0) PARAMn
RegisterArray STATUS (writeOnly=False,count=3,offset=24,readOnly=False,size=3,framesize=1)
Current status of inputs
(0) STATUSn
RegisterArray RISE (writeOnly=False,count=3,offset=28,readOnly=False,size=3,framesize=1)
Rise debounce time
(0) RISEn
RegisterArray FALL (writeOnly=False,count=3,offset=32,readOnly=False,size=3,framesize=1)
Fall debouce time
(0) FALLn
RegisterArray BISTERROR (writeOnly=False,count=3,offset=36,readOnly=False,size=3,framesize=1)
Error registers for BIST
(0) BISTERRn
RegisterArray BUFFER (writeOnly=False,count=128,offset=128,readOnly=False,size=128,framesize=1)
Buffer registers
(0) BUFFn