This email address is being protected from spambots. You need JavaScript enabled to view it.

  • Home
  • Blog
  • Microchip Polarfire SoC series - #3 Custom IP

Microchip Polarfire SoC series - #3 Custom IP

Welcome to the blog post number 3 in the Microchip PolarFire SoC series! 

Today, we’re integrating a custom IP into the PolarFire SoC video kit’s base design, addressing a key aspect of practical FPGA development. We’re going to add the system version IP that I have created for the FPGA meets devops video series, but this time the bus interface is APB instead of AXI. A simple testbench written in Python and cocoTB is used to validate the IP. And we’re going to add the system version application to the Linux image with a custom meta layer.

In this blog post, I assume you’ve watched the first two videos of the Microchip Polarfire SoC series where I explained how to install the tools, build the Yocto image, etc.

Full disclaimer: this video is not sponsored by Microchip and the video kit has been bought by Starware Design.

Video

You can find this blog post in video format on YouTube (embedded below).

Custom IP

While I was doing some research for this blog post, I found out that it is not possible to package an IP core and add it to the vault. I hope this feature will be added to Libero soon. This is the article from microchip that confirms that.

What it is possible to do today is to take an HDL file and create a so called HDL+ core.

Checkout the IP core repo in the FPGA folder from the previous video.

git clone https://github.com/starwaredesign/ip_repo_microchip.git

Let’s add the system version verilog file to the project with File->Import->HDL source files. Then click on build hierarchy. 

Right click on the system version file and click on “create core from HDL”. We can see it parses the parameters and the module inputs and outputs. Now edit the interface so the APB port is recognised. Drag the core into the smart design and wire it to the rest of the design.

We also add the pin assignment constraints. To simulate the board type and revision, I soldered a bank of dip switches to an FMC board.

# DQ16 - H29 - HPC_LA24_N_B9 -
set_io -port_name {board_type[0]} \
-pin_name E15 \
-fixed true \
-io_std LVCMOS33 \
-RES_PULL UP \
-DIRECTION INPUT

# DQ17 - H31 - HPC_LA28_P_B9 -
set_io -port_name {board_type[1]} \
-pin_name D13 \
-fixed true \
-io_std LVCMOS33 \
-RES_PULL UP \
-DIRECTION INPUT

# DQ18 - H32 - HPC_LA28_N_B9 -
set_io -port_name {board_type[2]} \
-pin_name C13 \
-fixed true \
-io_std LVCMOS33 \
-RES_PULL UP \
-DIRECTION INPUT

# DQ19 - H34 - HPC_LA30_P_B9 -
set_io -port_name {board_type[3]} \
-pin_name F18 \
-fixed true \
-io_std LVCMOS33 \
-RES_PULL UP \
-DIRECTION INPUT

# DQ20 - H25 - HPC_LA30_N_B9 -
set_io -port_name {board_rev[0]} \
-pin_name F17 \
-fixed true \
-io_std LVCMOS33 \
-RES_PULL UP \
-DIRECTION INPUT

# DQ21 - H37 - HPC_LA32_P_B9 -
set_io -port_name {board_rev[1]} \
-pin_name F14 \
-fixed true \
-io_std LVCMOS33 \
-RES_PULL UP \
-DIRECTION INPUT

# DQ22 - H38 - HPC_LA32_N_B9 -
set_io -port_name {board_rev[2]} \
-pin_name E13 \
-fixed true \
-io_std LVCMOS33 \
-RES_PULL UP \
-DIRECTION INPUT

# DQ25 - G9 - HPC_LA03_P_B9 -
set_io -port_name {board_rev[3]} \
-pin_name E25 \
-fixed true \
-io_std LVCMOS33 \
-RES_PULL UP \
-DIRECTION INPUT

We can also add false path constraints on the board version and board type inputs.

# CDC constraints
set_false_path -from [get_ports {*board_type[*]}] 
set_max_delay 3 -from [get_pins {systemversion_0/board_type_d1[*]/CLK}] -to [get_pins {systemversion_0/board_type_d2[*]/D}] 
set_false_path -from [get_ports {*board_rev[*]}] 
set_max_delay 3 -from [get_pins {systemversion_0/board_rev_d1[*]/CLK}] -to [get_pins {systemversion_0/board_rev_d2[*]/D}]

Unfortunately, the toolchain doesn’t support data path only type of constraints nor tags like ASYNC_REG like in AMD Vivado.

Click on build component, build the bitstream and flash it to the board.

Simulation

Before we test the IP on the FPGA, let’s run a simple test bench for the system version IP. If you like more details about cocotb, the test runner, and the test case checkout episode 5 of the FPGA meets devops series.

We’re going to use the modelsim/questa simulator that is part of the standard installation of Libero SoC. We are also going to use an external cocotb library to get an APB driver and monitor.

python -m venv .venv
source .venv/bin/activate
pip install cocotb
pip install cocotbext-apb
pip install pytest

Export the Questa path:

export PATH=/usr/local/microchip/Libero_SoC_v2023.2/QuestaSim/linux_x86_64:$PATH
export LM_LICENSE_FILE=1702@localhost

Run the test bench with the following command line:

pytest -s -v  --log-level=INFO

Software

Now that we have the system version IP inside the FPGA fabric, how can we get access to it? We can re-use the system version application from the FPGA meets devops series. Since that application is written in C and interacts with the IP via UIO, we can re-use it as is without any modifications.

Checkout the meta-swd layer:

git clone https://github.com/starwaredesign/meta-swd.git

Add it to bitbake:

. ./meta-polarfire-soc-yocto-bsp/polarfire-soc_yocto_setup.sh
bitbake-layers add-layer ../meta-swd

And add the system version app to the image. Edit conf/local.conf and add

IMAGE_INSTALL:append = " python3-gpiod system-version"

Add the IP to the device tree using the same commands from the previous video:

export MACHINE=mpfs-video-kit 
devtool modify mpfs-linux
code workspace/sources/mpfs-linux

Add to the polarfire video kit dtsi (arch/riscv/boot/dts/microchip/mpfs-video-kit-fabric.dtsi) the following: 

 systemversion: systemversion0@40002000 {
                compatible = "generic-uio";
                status = "okay";
                reg = <0x0 0x40002000 0x0 0x1000>;
        };

The memory address is from Libero SoC.

Let’s build the kernel 

devtool build mpfs-linux

And build the image

devtool build-image mpfs-dev-cli

And now write the image

umount /media/matteo/boot
umount /media/matteo/root
sudo bmaptool copy tmp-glibc/deploy/images/mpfs-video-kit/mpfs-dev-cli-mpfs-video-kit.rootfs.wic /dev/sdc

Unmount the SD card and put the SD card into the video kit.

Testing

 Let’s start the board and connect to the console over the serial port. I have wired the dip switches to this FMC board that has two pin headers with easy access to the I/Os. Use print-systemversion to get the FPGA version, board type, and board revision. You should see something like this

root@mpfs-video-kit:~# print-systemversion 
********************************************************************************
Board type 15, board revision 15
********************************************************************************
FPGA version 0.1.0
********************************************************************************

Disclaimer

All trademarks, logos, and brand names shown on this video are the property of their respective owners. The use of these trademarks does not imply any affiliation with, or endorsement by, their owners. This blog post is intended for educational/entertainment/informational purposes only, and no copyright infringement is intended.

Tags: polarfire, microchip, cocotb, yocto, SoC, fpga

About us

Starware Design provides design and consulting services for FPGA, board-level, embedded software and edge AI projects.


Whether you need a consultant to be part of your team on-site or a turnkey solution, Starware Design has the capability to suit your requirements.