-
Notifications
You must be signed in to change notification settings - Fork 140
DevelopersGuide
Attention: This guide applies to the 3.0.0 and above releases. |
This guide explains the process of developing for the NetFPGA platform. The primary focus is on developing projects, although the lessons also apply to module development.
The NetFPGA platform consists of many elements including the physical hardware, hardware designs that are downloaded to the FPGA, software associated with a particular hardware design, general software tools for interacting with the hardware, and the simulation and synthesis environment for building new designs. Developers will most frequently develop new hardware designs to run on the FPGA and software for use with particular hardware projects.
Developers work with projects and modules. Projects are complete designs, consisting of a hardware component, tests (simulations and hardware regression tests), and associated software components. Modules are small reusable hardware units that are incorporated into projects.
The hardware component for a project is typically built by interconnecting a number of reusable modules and some project-specific HDL code. Some projects, notably some of the reference designs, are built entirely by assembling the reusable modules. The simulation and regression tests associated with a project are used to specify the features of the design and demonstrate the correctness of that design (as explained in Regression Tests). The software associated with a project allows the user to interact with the hardware in a meaningful way; for example in the Reference Router project, the software provides a command-line interface for manipulating the ARP and routing tables inside the hardware.
Modules consists of HDL code, specification of IP blocks built using the Xilinx Core Generator, and a specification of any registers that the module exposes. Registers and associated information are specified using an XML-based system; this system takes care of allocating memory for the registers within each module when the modules are integrated into projects.
The process below explains how to develop for NetFPGA platform using the new python based unified infrastructure for simulation and hardware testing. For information on using the previous Perl based testing infrastructure visit here.
The directory structure of the NetFPGA source tree is as follows:
netfpga {Base directory} bin {Scripts for simulation/synthesis/register gen} bitfiles {Compiled hardware bitfiles} lib {Libraries and software tools} C {C libraries/programs} java {Java libraries} Makefiles {Makefile templates used for sim/synth} Perl5 {Perl libraries} python {Python libraries} release {XML files for packaging} scripts {Utility scripts} verilog contributed {Contributed Verilog modules} core {Official Verilog modules} xml {XML schemas} projects {project directory} <project> {contributed project} doc {documentation} include {project.xml, project specific module XML} lib {Perl and C headers} src {non-library verilog} sw {Project-specific software} synth {Synthesis directory (contains all .xco files)} test {Unified (Hw/Sw) tests}
A new project is created by following these steps:
- Create a new project directory inside netfpga/projects
- Update the NF_DESIGN_DIR directory to point to the new project directory. Example (Bourne shell syntax): export NF_DESIGN_DIR=$(HOME)/netfpga/projects/my_first_project (See the guide for more information.)
- Create the following directories inside the project directory: include, src, synth, and test. Optionally create doc, lib, and sw. (Note: lib will be automatically created when the register generation tool is run.)
- Create a project.xml file inside the include directory. See the Register System section below for more information.
- Add any library modules to the project.xml file.
- Write any project-specific Verilog and place inside the src directory.
- Write module-specific XML files for any new modules you have written and place in the include directory.
- In the new python testing infrastructure, simulation and hardware (previously regression) tests have been unified, so a test can be written once and run as either a simulation or hardware test, unless hardware specific functions are needed. Tests should be placed in a project's test directory. Test directories should be named both_<major>_<minor> if they can be run in both simulation and hardware, hw_<major>_<minor> if the test can only be run as a hardware test, and sim_<major>_<minor>; if the test can only be run as a simulation test. Neither major or minor can have underscores in the name, nor can they be blank.
- Copy the Makefile from the reference router synth directory into your synth directory.
- Synthesize the design by running make inside the synth directory.
- Write hardware tests and place them in the test directory. Run with nf_test.py (See Verification for more information.)
- Write any software and place inside the sw directory.
- Add documentation to the doc directory.
- Contribute your project if you think your project may be useful to others. See the Develop page for more information.
The build system manages the process of compiling projects for simulation and synthesizing projects for download to the FPGA.
The following steps are undertaken during a build:
- Query the register system for a list of all modules used by the project.
- Instruct the register system to generate the registers. This involves reading the register descriptions for each module, allocating memory for all registers, and outputting that resultant allocation for use in Verilog, C, and Perl.
- Generate cores associated with each module and the project.
- Compile/synthesize the code associated with each module and the project.
As previously mentioned, the NetFPGA platform supports reusable hardware modules that can be incorporated into projects. The build system makes using modules extremely simple: a developer simply specifies which modules that they'd like included in their project and the build system allocates addresses for registers within each module, generates any necessary IP blocks, and includes the necessary source files during compilation.
Many new developers do not realize that modules are included as part of the compilation process; this causes confusion to many new developers when they look at the src directory of a project and see very few files, or even none at all. For example, reference router's src directory is completely empty; all of the functionality of the reference router is provided by the reusable modules.
The set of modules that a project uses is specified in the project's project.xml file (see Register System for more information). The nf:use_modules section of the XML files specifies which modules to include. Part of the use_modules section from the reference router is shown below:
<nf:use_modules> core/io_queues/cpu_dma_queue core/io_queues/ethernet_mac core/input_arbiter/rr_input_arbiter core/nf2/generic_top core/nf2/reference_core ... </nf:use_modules>
This section of code instructs the build system to use these modules: CPU DMA queues, Ethernet MAC, the generic top-level Verilog file ( generic_top), and the reference core. The reusable modules are located in the netfpga/lib/verilog directory. For example, the CPU DMA queues (specified as core/io_queues/cpu_dma_queue in the above code snippet), is located in netfpga/lib/verilog/core/io_queues/cpu_dma_queue.
TBD. This section should discuss the shared makefiles.
This section provides an overview of the register system. Detailed information about the register system can be found on the Register System page.
The register system provides a mechanism for:
- specifying the registers provided by each module
- specifying the modules used by each project
- generating a register map/memory allocation for each project
The project.xml file provides information about the project and specifies the list of shared modules used by the project. A sample XML file is shown below:
< ?xml version="1.0" encoding="UTF-8"? > <nf:project xmlns:nf="http://www.NetFPGA.org/NF2_register_system" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.NetFPGA.org/NF2_register_system NF2_register_system.xsd "> <nf:name>Reference router</nf:name> <nf:description>Reference IPv4 router</nf:description> <nf:version_major>1</nf:version_major> <nf:version_minor>0</nf:version_minor> <nf:version_revision>0</nf:version_revision> <nf:dev_id>0</nf:dev_id> <nf:use_modules> core/io_queues/cpu_dma_queue core/io_queues/ethernet_queue contrib/ucsd/gig_eth_mac core/input_arbiter/rr_input_arbiter ... </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="mdio" /> <nf:instance name="nf2_mac_grp" count="4" /> <nf:instance name="cpu_dma_queue" count="4" /> </nf:group> <nf:group name="udp"> <nf:instance name="in_arb" /> <nf:instance name="router_op_lut" /> <nf:instance name="strip_headers" /> <nf:instance name="output_queues" /> </nf:group> </nf:memalloc> </nf:project>
Line 1 specifies that this is an XML file.
Line 2 declares that we're working with a project and specifies the XML schema that this file is based on.
Lines 3 -- 8 provide information about the project. Name is a short textual description of the project. Description is a slightly longer description of what the project does. The version major, minor, and revision are used to tag the resultant bitfile; the information is placed in the Device ID module that is instantiated by default in each design. (This module can be queried to identify the currently active bitfile.) The device ID is also incorporated into the Device ID module; currently it serves no purpose other than acting as an opaque identifier.
Lines 9 -- 14 specify the shared modules to use. The modules are listed one per line between nf:use_module tags. Each module is located in the NF2/lib/verilog directory.
Lines 15 -- 29 specify the memory layout of the design, maps modules to particular regions of the address space, and specifies the number of instances for each module.
Lines 16 and 23 begin groups for memory regions (core1 and udp respectively). udp is the region allocated to the User Data Path; many of the modules written by developers would be instantiated inside the User Data Path. Core1 is a region located outside of the user data path. More information about memory regions can be found in the Register Layout section of the Register System guide.
Line 17 specifies that the device_id module should be instantiated inside the core1 region. The addresses allocated the module will be left entirely to the register system. Note: The name "=device_id=" is the name specified in the module's XML file.
Line 18 specifies that the dma module should be instantiated inside the core1 region. The base attribute specifies that the module should be allocated addresses starting at 0x0500000. Generally developers should leave the address allocation to the register system (it gives the register system more flexibility in it's allocation).
Line 20 specifies that the nf2_mac_grp module should be instantiated inside the core1 region. The count attribute specifies the number of instances of this module to allocate memory for; in this example there are four instances. Each instance requires it's own memory allocation so that the registers for one instance can be uniquely identified from the registers for another instance.
Not shown in the example above is the ability to specify types and constants within the project.xml. These features and more are documented in more detail on the Register System page.
An XML file is provided for each module and specifies the registers, constants, and types used by each module. The XML file should be located in the module's xml directory for shared modules, or the project's include directory for project-specific modules. A sample module XML file is shown below:
< ?xml version="1.0" encoding="UTF-8"? > <nf:module xmlns:nf="http://www.NetFPGA.org/NF2_register_system" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.NetFPGA.org/NF2_register_system NF2_register_system.xsd "> <nf:name>phy_test</nf:name> <nf:prefix>phy_test</nf:prefix> <nf:location>core</nf:location> <nf:description>Ethernet PHY test</nf:description> <nf:blocksize>256k</nf:blocksize> <nf:registers> <nf:register> <nf:name>status</nf:name> <nf:description>Status of the test</nf:description> <nf:type>phy_test_status</nf:type> </nf:register> <nf:register_group> <nf:name>phy</nf:name> <nf:description>Individual PHY registers</nf:description> <nf:instances>4</nf:instances> <nf:register> <nf:name>tx_status</nf:name> <nf:description>Transmit status</nf:description> <nf:type>phy_test_phy_tx_status</nf:type> </nf:register> </nf:register_group> </nf:registers> <nf:constants> <nf:constant> <nf:name>num_patterns</nf:name> <nf:description>Number of different test patterns</nf:description> <nf:value>5</nf:value> </nf:constant> </nf:constants> <nf:types> <nf:type xsi:type="nf:SimpleType"> <nf:name>phy_test_status</nf:name> <nf:description>Ethernet PHY test status</nf:description> <nf:width>32</nf:width> <nf:bitmask> <nf:name>busy</nf:name> <nf:description>Test in progress</nf:description> <nf:pos>0</nf:pos> </nf:bitmask> <nf:bitmask> <nf:name>done</nf:name> <nf:description>Test completed</nf:description> <nf:pos>4</nf:pos> </nf:bitmask> <nf:bitmask> <nf:name>good</nf:name> <nf:description>Test successful</nf:description> <nf:pos>8</nf:pos> </nf:bitmask> </nf:type> </nf:types> </nf:module>
Line 1 specifies that this is an XML file.
Line 2 declares that we're working with a project and specifies the XML schema that this file is based on.
Lines 3 and 6 specify the name of the module and a description. The name is used in the project.xml file when specifying the module instances in each memory region.
Line 4 specifies the prefix to attach to register names in the Verilog, C and Perl files. In this example, the name and prefix are identical but they do not need to be.
Line 5 specifies which memory region the module can be instantiated in. Valid locations are "core", "udp", and "cpci". The location is checked when a module is instantiated in the project.xml file to ensure that the module is being instantiated in the correct memory region.
Line 7 specifies the block size of the module; this is the size of the address space allocated to that module, the maximum number of registers that can be instantiated is the block size divided by four (each register is 32 bits/4 bytes wide). Common sizes for udp blocks are 64, 256, and 1024; the only size supported for core blocks is 256k. See Register System for more informaiton.
Lines 8 -- 24 specify the registers in the module.
Lines 9 -- 13 specify the first register in the module. In this case, the module is named "status", the description is "Status of the test", and it's declared to be of type phy_test_status. The type is defined later in the XML file, although it is also possible to specify a width instead of a type. The register name generated in Verilog, C, and Perl files is the concatenation of the module prefix and the register name; in this instance the name would be PHY_TEST_STATUS.
Lines 14 -- 23 specify a register group containing a single register. Register Groups provide a mechanism to generate a repeated set of registers; in this case the register group is used to generate one set of registers per physical port.
In this example, the register group is named phy, there are four instances, and each instance contains a single register named tx_status. The register names for register groups differ slightly between the Verilog code and the C/Perl code, largely due to the use cases. The register names produced by this register group are: PHY_TEST_PHY_0_TX_STATUS_REG through PHY_TEST_PHY_3_TX_STATUS_REG. The name is a concatenation of the module's prefix, the register group name, the instance number, and the register name.
Lines 25 -- 31 specify constants.
Lines 26 -- 30 specify a single constant named num_patterns that represents the number of different test patterns. The value of this constant is specified as 5. Constants can be used anywhere that numerical values can used.
Lines 32 -- 53 specify types.
Lines 33 -- 52 specify a single type named phy_test_status. This type represents the status for the Ethernet PHY tests (as explained in description). The width attribute specifies the width of the type in bits. The bitmasks (lines 37 -- 51) specify the purpose of individual bits within the type; as an example bit 0 is named busy and represents whether a test is in progress. You can also experiment with multi-bit fields using the nf:pos_lo and nf:pos_hi xml tags.
Specifying types is not necessary but aids developers working with projects. The type information is incorporated in the Verilog, C, and Perl output to simplify the developers job; for example, the following constants are provided in the C header file produced by the register system:
// Type: phy_test_status // Description: Ethernet PHY test status // File: projects/selftest/include/phy_test.xml // Part 1: bit positions #define PHY_TEST_STATUS_BUSY_POS 0 #define PHY_TEST_STATUS_DONE_POS 4 #define PHY_TEST_STATUS_GOOD_POS 8 // Part 2: masks/values #define PHY_TEST_STATUS_BUSY 0x00000001 #define PHY_TEST_STATUS_DONE 0x00000010 #define PHY_TEST_STATUS_GOOD 0x00000100
The above example provides an overview module XML files. More detailed information is found on the Register System page.
The register system tool to perform register memory allocation is invoked automatically as part of every simulation and synthesis run. The tool can be invoked manually at any time with the nf_register_gen.pl command. Common command line options include:
- --project <project> -- specify a particular project (instead of using the current project specified via the NF_DESIGN_DIR variable).
Common backend utilities that a developer is likely to invoke include:
- nf_register_gen.pl :
- nf_run_tests.pl :
- nf_regress_tests.pl :
- nf_download :
- nf_info :
- cpci_reprogram.pl :