RegisterSystem
This page describes the register system that was introduced with the NetFPGA 2.0.0 package release.
The register system assigns addresses to all registers in a project.
Each project has a configuration file that specifies the modules that it uses, and each module has a configuration file that specifies the registers that it provides. The register system reads a project's configuration file to identify the modules (and number of instances of each module); reads the individual module configuration files; allocates memory in the register address space to each module instance and it's registers; and finally outputs Verilog, C, and Perl files with the register allocation.
Operation of the register system is summarized in the diagram below.
Steps in the allocation process are:
- Begin processing when the user invokes register generation via nf_register_gen.pl or when the user simulates or synthesizes a project.
- Read all global configuration files from lib/verilog/core/common/xml.
- Read the project's project.xml configuration file from projects/<project_dir>/include.
- Read the configuration files for all modules specified in the project's nf:use_modules section.
- Read the configuration files for any locally defined modules. (Configuration files for locally-defined modules are placed in the same directory as project.xml.)
- Identify the modules used by the project as specified in the project's nf:mem_alloc section.
- Identify and read any shared configuration files used by the modules. (Shared configuration files are used to share common constants and types.)
- Identify all constants defined in the project and the modules. (Precedence from highest to lowest is: project, shared, module, global.)
- Identify all types defined in the projects and modules. Types must be unique; it is an error for the same type to be defined in two different configuration files.
- Expand all constants.
- Verify that the specified module sizes are large enough to contain the specified number of registers.
- Allocate memory to each module, and to each register within each module.
- Output the Verilog, C, and Perl files.
Configuration files can be broadly classified as one of four types: project, module, global, and shared. Each of these files are explained below, with the elements listed in Configuration file elements.
The project configuration file describes the project, listing the library modules, and specifying the memory layout. The file is named project.xml and is located in the project's include directory.
An example project configuration file is listed below. This file defines a project named "Project example", version 1.0.2, with the unique device ID 100. It uses two library modules ( cpu_dma_queue and ethernet_mac), and it uses the reference memory layout. (For more information on memory layouts see FIXME.)
<nf:project ...> <nf:name>Project example</nf:name> <nf:description>Example of a project.xml file</nf:description> <nf:version_major>1</nf:version_major> <nf:version_minor>0</nf:version_minor> <nf:version_revision>2</nf:version_revision> <nf:dev_id>100</nf:dev_id> <nf:use_modules> core/io_queues/cpu_dma_queue core/io_queues/ethernet_mac </nf:use_modules> <nf:memalloc layout="reference"> <nf:group name="core1"> <nf:instance name="device_id" /> <nf:instance name="dma" base="0x0500000" /> <nf:instance name="nf2_mac_grp" count="4" /> </nf:group> <nf:group name="udp"> <nf:instance name="in_arb" /> <nf:instance name="router_op_lut" /> </nf:group> </nf:memalloc> </nf:project>
Valid elements that can be declared in a project configuration file are:
Element | Count | Comment |
nf:name | 1 | Short name of the project |
nf:description | 0/1 | Textual description of the project |
nf:version_major | 0/1 | Version number (major) |
nf:version_minor | 0/1 | Version number (minor) |
nf:version_revision | 0/1 | Version number (revision) |
nf:dev_id | 0/1 | Unique numeric identifier for the project (refer to the Device ID List) |
nf:constants | 0/1 | Constant definitions |
nf:types | 0/1 | Type definitions |
nf:use_modules | 0/1 | Library modules used by the project |
nf:memalloc | 1 | Memory layout/allocation |
Each module has a configuration file that specifies the list of registers that it provides. The configuration file may also specify constants and types, and may reference shared configuration files for additional constants and types. It also specifies the "location" (the region of the NetFPGA where the module should be used) and the size of the memory block that the module should be allocated.
Module configuration files should be located in the xml directory inside the module directory if the module is a library module, or within the project's include directory if the module is local to the project.
An example configuration file is provided below. This file declares a simple input arbiter. The module should be instantied within the user datapath (UDP), it should be allocated 256 bytes of memory, and it provides one register.
<nf:module ... > <nf:name>in_arb</nf:name> <nf:prefix>in_arb</nf:prefix> <nf:location>udp</nf:location> <nf:description>Simple round-robin input arbiter</nf:description> <nf:blocksize>256</nf:blocksize> <nf:registers> <nf:register> <nf:name>num_pkts_sent</nf:name> <nf:description>Number of packets sent</nf:description> <nf:type>counter32</nf:type> </nf:register> </nf:registers> </nf:module>
Valid elements that can be declared in a module configuration file are:
Element | Count | Comment |
nf:name | 1 | Short name of the module (used in the nf:memalloc section of the project configuration) |
nf:prefix | 1 | Prefix to prepend to all registers |
nf:location | 1 | Location within the NetFPGA where the module can be instantiated |
nf:description | 0/1 | Longer description of the module |
nf:blocksize | 1 | Memory to allocate to each instance (bytes) |
nf:preferred_base | 0/1 | Preferred base address. Do not use with nf:force_base. |
nf:force_base | 0/1 | Force this base address. Do not use with nf:preferred_base. |
nf:registers | 0/1 | Registers definitions |
nf:constants | 0/1 | Contstant defnitions |
nf:types | 0/1 | Type definitions |
nf:use_shared | 0/1 | Shared configuration files to include |
Global configuration files specify constants and types that should be used by all projects. Projects (and modules) can override global constants. Global configuration files are located in lib/verilog/core/common/xml.
An example global configuration file is provided below. The file defines one constant and one type.
<nf:global ... > <nf:constants> <nf:constant> <nf:name>MAX_PHY_PORTS</nf:name> <nf:description>Maximum number of phy ports</nf:description> <nf:value>4</nf:value> </nf:constant> </nf:constants> <nf:types> <nf:type xsi:type="nf:SimpleType"> <nf:name>ethernet_addr</nf:name> <nf:width>48</nf:width> </nf:type> </nf:types> </nf:global>
Valid elements that can be declared in a global configuration file are:
Element | Count | Comment |
nf:constants | 0/1 | Contstant defnitions |
nf:types | 0/1 | Type definitions |
Shared configuration files specify constants and types that are shared by some modules. Each module should reference the shared configuration file to include the constants and types.
Note: Shared configuration files and global configurations are almost identical in structure.
An example shared configuration file is provided below. The file defines one constant.
<nf:shared ... > <nf:description>Example shared constants</nf:description> <nf:constants> <nf:constant> <nf:name>ETHERTYPE</nf:name> <nf:description>Example ethertype</nf:description> <nf:value>0xffab</nf:value> <nf:width>16</nf:width> </nf:constant> </nf:constants> </nf:shared>
Valid elements that can be declared in a shared configuration file are:
Element | Count | Comment |
nf:description | 0/1 | Description of shared configuration |
nf:constants | 0/1 | Contstant defnitions |
nf:types | 0/1 | Type definitions |
Configuration file elements are listed in the Configuration file elements.
Types were introduced for two reasons: to aid the understanding of the "kind" of data that particular registers hold, and to generate code to simplify register processing in C and Perl. Strictly speaking types are not needed. All registers could be defined by specifying the width of the register.
There are three main categories of types: simple, compound, and table. (See nf:type)
Simple types represent a single "thing", such as a MAC or IP address, or a collection of "things" identified by their bit positions, such as an interrupt vector.
Compound types represent collections of things. A compound type is composed of fields, each field can be either another type or a width. Compound types and simple types with bitmasks are very similar, the main difference is that a compound type can be composed of other types. (A simple type with bitmasks could be equivalently expressed as a compound type with fields specified by widths.)
Table types represent table data structures. A table is an element composed of rows, with each row containing data of the same type. Tables have multiple rows, the number of which is defined by the table's depth.
Nine simple data types are predefined in the global configuration files. Those types are:
Type | Width (bits) | Description |
ethernet_addr | 48 | Ethernet MAC address |
ip_addr | 32 | IP address |
counter32 | 32 | 32-bit counter |
software32 | 32 | 32-bit register written to by software |
generic_counter32 | 32 | 32-bit counter%BR% Implemented as part of a generic registers instance |
generic_hardware32 | 32 | 32-bit register controlled by hardware (read-only by software) %BR% Implemented as part of a generic registers instance |
generic_software32 | 32 | 32-bit register controlled by software (written by software, read-only by hardware) %BR% Implemented as part of a generic registers instance |
dataword | 64 (DATA_WIDTH) | Data word in the data path |
ctrlword | 8 (CTRL_WIDTH) | Control word in the data path |