Creating a new IP#
Here is a quick start guide about creating a new IP. You can start from these
files and modify them as you need.
Here is the code for a fan control IP: library/axi_fan_control.
In this tutorial, we will make a led control IP, using AXI. In this case,
<module_name>
will be replaced in code with axi_led_control
for Xilinx
and axi_led_control_intel
for Intel.
Verilog File#
Lets say you want to make a new IP with the name <module_name>
.
You must edit the verilog file so that it has the same name (e.g. axi_led_control.v
).
After that, feel free to write the verilog code for your purpose.
You can also use other instances of modules, but be sure to include them after,
in the tcl file, under the <other_components>
list.
Register Map#
The register map is defined in a docs/regmap/adi_regmap_*.txt file and follows a special syntax.
One file can have more than one register map, and they are bounded by the header:
TITLE
[USING <regmap_to_inherit> ...]
<title> (<ip_name>)
<unique_id>
ENDTITLE
Example:
TITLE
SPI Engine (axi_spi_engine)
AXI_SPI_ENGINE
ENDTITLE
The USING
method is only present if the register map imports other register
maps for look-up.
The register and fields are defined with the following syntax:
REG
<address>
[WHERE n IS ...]
<name>
<description>
ENDREG
FIELD
[31:0] <default>
[WHERE n IS ...]
<description>
<access>
ENDFIELD
For example:
REG
0x00000001
VERSION
Version of the peripheral.
Follows semantic versioning. Current version 1.00.71.
ENDREG
FIELD
[31:16] 0x00000001
VERSION_MAJOR
RO
ENDFIELD
FIELD
[15:8] 0x00000001
VERSION_MINOR
RO
ENDFIELD
FIELD
[7:0] 0x00000071
VERSION_PATCH
RO
ENDFIELD
The WHERE
line is only present if using ranged register/fields.
Noticed that the description can be multi-line and can also include Sphinx syntax, parsed during build. The file content is always 90-columns wide. There are multiple ways to define the default value for a field. All parameter values used for defining or calculating the default value of a field must be a configuration parameter. In cases where expressions are used to calculate the field values, these must be compatible SystemVerilog, as the expressions are used in the simulation environment as well.
FIELD
[31:0]
SCRATCH
RO
Value of the Scratch field is undefined.
In a simulation environment this value appears as X for all bits.
ENDFIELD
FIELD
[31:0] 0x12345678
VERSION
RO
Value of the Version is hardcoded in the IP.
ENDFIELD
FIELD
[31:0] ID
PERIPHERAL_ID
RO
Value of the ID configuration parameter.
In case of multiple instances, each instance will have a unique ID.
ENDFIELD
FIELD
[31:0] SPECIAL = (VALUE1+(VALUE2-VALUE3)*VALUE4)/VALUE5
SPECIAL
RO
Value of the SPECIAL field is calculated using an expression.
Example of simple operations
ENDFIELD
FIELD
[31:0] SPECIAL = (VALUE1>VALUE2)?VALUE3:VALUE4
SPECIAL
RO
Value of the SPECIAL field is calculated using an expression.
Example of conditional calculation
ENDFIELD
FIELD
[31:0] SPECIAL = `MAX(VALUE1,`MIN(VALUE2,VALUE3))
SPECIAL
RO
Value of the SPECIAL field is calculated using an expression.
Example of min and max value calculation
ENDFIELD
FIELD
[31:0] SPECIAL = $clog2(VALUE1**VALUE2)
SPECIAL
RO
Value of the SPECIAL field is calculated using an expression.
Example of log2 and exponentiation calculation
ENDFIELD
Examples:
docs/regmap/adi_regmap_adc.txt, uses
WHERE
docs/regmap/adi_regmap_axi_ad3552r.txt, uses
USING
Importing with Using Method#
The USING
method allows to look-up a register map to import register and
fields.
A register map can look-up multiple register maps by repeating the method for
each register map, for example:
TITLE
USING COMMON_REGS
USING COMMON_REGS_EXTRA
My IP (my_ip)
MY_IP
ENDTITLE
If using the USING
method for look-up, registers and fields are imported
with the following syntax:
REG
<reg_to_import>
ENDREG
FIELD
[<field_to_import> ...]
ENDFIELD
That means, only include the register/field name, and nothing else. For example:
REG
CNTRL_1
ENDREG
FIELD
SDR_DDR_N
SYMB_8_16B
ENDFIELD
If inheriting registers from multiple register maps, consider explicitly setting the source register map:
REG
COMMON_EXTRA.CTRL
ENDREG
FIELD
SOME_FIELD
ENDFIELD
Some considerations:
Imported registers shall have non-imported fields, for example, when importing a register that is reserved for custom implementation.
Imported fields must be inside a imported register, since the field name is not unique.
Multiple fields can be imported from a single
FIELD
group.Multiple register maps can be used for lookup. Add each in a different
USING
method.
Ranged Registers and Fields#
Registers and fields can use a special n
variable and the WHERE
method
to define an incrementing/repeating register/field. There is an option increase
the address increment value by an additional parameter. This parameter must be
in hexadecimal format as well.
The syntax is WHERE n IS FROM <lower> TO <UPPER>
, for example, for registers:
REG
0x0102 + n
WHERE n IS FROM 0 TO 15
CHAN_CNTRLn_3
DAC Channel Control & Status (channel - 0)
ENDREG
REG
0x0102 + 0x16*n
WHERE n IS FROM 0 TO 15
CHAN_CNTRLn_3
DAC Channel Control & Status (channel - 0)
ENDREG
And for fields:
FIELD
[n]
WHERE n IS FROM 0 TO 31
ES_RESETn
RW
Controls the EYESCANRESET pin of the GTH/GTY transceivers for lane n.
ENDFIELD
To ease the process of creating a new regmap with imported registers you can use the generic adc/dac templates that include all available registers:
Xilinx#
TCL File#
The tcl file should be named <module_name_ip>.tcl
(ex: axi_led_control_ip.tcl
).
Here you should keep the two lines that source our scripts :
source ../scripts/adi_env.tcl
source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl
Then take a look at the commands
adi_ip_create <module_name>
adi_ip_files <module_name> [list <other_components>]
These commands create the IP and add the dependencies for it.
By <other_components>
we refer to the modules we were talking about above,
that must be included in the tcl file. Also, <other_components>
must include
the verilog file for the IP itself, named <module_name>.v
.
If your new IP uses AXI Lite for register control, then the next command is
adi_ip_properties <module_name>
It is used to initialize properties like memory and so on. If the IP does not use AXI, then you should use
adi_ip_properties_lite <module_name>
At the end of the file don’t forget to save the IP by using this command
ipx::save_core [ipx::currentcore]
If you need more help, here is an example of an IP called axi_led_control. You can open it side by side with the tcl file from the original axi_fan_control and apply the same logic to make your changes.
# ip
source ../scripts/adi_env.tcl
source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl
adi_ip_create axi_led_control
adi_ip_files axi_led_control [list \
"$ad_hdl_dir/library/common/up_axi.v" \
"axi_led_control.v"]
adi_ip_properties axi_led_control
set cc [ipx::current_core]
ipx::save_core $cc
Makefile#
In this file you will also have to change/add paths to every file in <other_components>
list, using GENERIC_DEPS.
Make sure to also change LIBRARY_NAME and XILINX_DEPS to match the name for the new IP.
If you need more help, here is an example of an IP called axi_led_control. You can open it side by side with the Makefile from the original axi_fan_control and apply the same logic to make your changes.
LIBRARY_NAME := axi_led_control
GENERIC_DEPS += ../common/up_axi.v
GENERIC_DEPS += axi_led_control.v
XILINX_DEPS += axi_led_control_ip.tcl
include ../scripts/library.mk
Now you can run the famous make
in command line from the IP directory.
After that, <module_name>
will be accessible within vivado for future integrations.
Intel#
TCL File#
The tcl file should be named <module_name_hw>.tcl (ex: axi_led_control_intel_hw.tcl) These first 4 lines of code you should keep:
package require qsys 14.0
package require quartus::device
source ../scripts/adi_env.tcl
source ../scripts/adi_ip_intel.tcl
After that, the next line creates the new IP:
ad_ip_create <module_name> {entity_name}.
The module_name is the name of the IP you are creating, but entity_name will be the one visible inside Quartus IP Catalogue.
Next, you must add the other components used for creating the IP. For this, we will use the ad_ip_files command:
ad_ip_files <module_name> [list <other_components>]
The <other_components>
list is referring to any other verilog file imported
or used.
It must also include the verilog file for the IP itself (<module_name>.v
).
Now let’s add an instance of AXI:
ad_ip_intf_s_axi s_axi_aclk s_axi_aresetn 10
This command instantiates an interface using axi. The parameters refer to the ports of the interface, while the number refers to the width of the data bus.
There should be added an interface for every port of the IP. In this example, there is only one port left: led_on. This port is also external, so that’s what conduit is there for.
add_interface led_on_if conduit end
add_interface_port led_on_if led_on data Output 1
The last line is related to the port in the verilog file. In this case, led_on.
The other parameters refer to <signal_type> <direction> <width_expression>
.
In Quartus there is no need to save the core or run make afterwards. It is smart enough to search for _hw.tcl in the library directory. Although, you might need to add the path to the new IP in the IP Catalogue.
If you want to see the whole file, here is an example named axi_led_control_intel.
package require qsys 14.0
package require quartus::device
source ../scripts/adi_env.tcl
source ../scripts/adi_ip_intel.tcl
ad_ip_create axi_led_control_intel {AXI LED CONTROL}
ad_ip_files axi_led_control_intel [list \
$ad_hdl_dir/library/common/up_axi.v \
axi_led_control_intel.v]
#axi4 subordinate
ad_ip_intf_s_axi s_axi_aclk s_axi_aresetn 10
#output led
add_interface led_on_if conduit end
add_interface_port led_on_if led_on data Output 1
Makefile#
You don’t need to run make for the IP to be visible in the Catalogue. Yet, here is the Makefile for the example mentioned before:
LIBRARY_NAME := axi_led_control_intel
GENERIC_DEPS += ../common/up_axi.v
GENERIC_DEPS += axi_led_control_intel.v
INTEL_DEPS += axi_led_control_intel_hw.tcl
include ../scripts/library.mk
This example was made starting from the axi_ad9361 IP found in our repo, under the library directory: ibrary/axi_ad9361.