This is a walkthrough of the Microchip repo for building an FPGA image for the BeagleV-Fire
Polarfire fabric.
Environment Setup Link to heading
In repo, there is a script to export some environment variables used by other scripts:
- Libero
- SoftConsole (SC)
- License server
#!/bin/bash
#===============================================================================
# Edit the following section with the location where the following tools are
# installed:
# - SoftConsole (SC_INSTALL_DIR)
# - Libero (LIBERO_INSTALL_DIR)
# - Licensing daemon for Libero (LICENSE_DAEMON_DIR)
#===============================================================================
export SC_INSTALL_DIR=/home/$USER/Microchip/SoftConsole-v2022.2-RISC-V-747
export LIBERO_INSTALL_DIR=/home/$USER/Microchip/Libero_SoC_v2023.2
export LICENSE_DAEMON_DIR=/home/$USER/Microchip/Linux_Licensing_Daemon
export LICENSE_FILE_DIR=/home/$USER/Microchip/license
#===============================================================================
# The following was tested on Ubuntu 20.04 with:
# - Libero 2023.2
# - SoftConsole 2022.2
#===============================================================================
#
# SoftConsole
#
export PATH=$PATH:$SC_INSTALL_DIR/riscv-unknown-elf-gcc/bin
export FPGENPROG=$LIBERO_INSTALL_DIR/Libero/bin64/fpgenprog
#
# Libero
#
export PATH=$PATH:$LIBERO_INSTALL_DIR/Libero/bin:$LIBERO_INSTALL_DIR/Libero/bin64
export PATH=$PATH:$LIBERO_INSTALL_DIR/Synplify/bin
export PATH=$PATH:$LIBERO_INSTALL_DIR/Model/modeltech/linuxacoem
export LOCALE=C
export LD_LIBRARY_PATH=/usr/lib/i386-linux-gnu:$LD_LIBRARY_PATH
#
# Libero License daemon
#
export LM_LICENSE_FILE=1702@localhost
export SNPSLMD_LICENSE_FILE=1702@localhost
$LICENSE_DAEMON_DIR/lmgrd -c $LICENSE_FILE_DIR/License.dat -l $LICENSE_FILE_DIR/license.log
Software Link to heading
In repo, the top script build-bitstream.py
calls the flow to build both software then bitstream
virtualenv .venv
source .venv/bin/activate
python requests gitpython pyyaml
python build-bitstream.py ./build-options/default.yaml
I will try to break down the steps done in the each of scripts
default.yaml Link to heading
Starting with the default.yaml
passed to top script, where it has some configuration.
---
HSS:
type: git
link: https://openbeagle.org/beaglev-fire/hart-software-services.git
branch: main-beaglev-fire
board: bvf
gateware:
type: sources
unique-design-version: 2.0.4
MSS Link to heading
MSS is the microprocess sub-system in polarfire with riscv. mss_configurator
is passed MSS_Configuration.cfg
to generate memory and peripherals enabled in the design.
def make_mss_config(mss_configurator, config_file, output_dir):
print("================================================================================")
print(" Generating MSS configuration")
print("================================================================================\r\n", flush=True)
cmd = mss_configurator + ' -GENERATE -CONFIGURATION_FILE:' + config_file + ' -OUTPUT_DIR:' + output_dir
exe_sys_cmd(cmd)
mss_config_file_path = os.path.join(gateware_top_dir, "sources", "MSS_Configuration", "MSS_Configuration.cfg")
work_mss_dir = os.path.join("work", "MSS")
make_mss_config(mss_configurator, mss_config_file_path, os.path.join(os.getcwd(), work_mss_dir))
A snippet from MSS_Configuration.cfg
looks something as follows:
BANK2_VOLTAGE 3.3
BANK4_VOLTAGE 1.8
BANK5_VOLTAGE 3.3
CAN_0 FABRIC
CAN_0_TX_EBL_N FABRIC
CAN_1 FABRIC
CAN_1_TX_EBL_N FABRIC
CAN_CLK_FREQ 8
CAN_CLK_SOURCE MSS_PLL
CORE_UP UNUSED
CRYPTO UNUSED
CRYPTO_DLL_JITTER_TOLERANCE MEDIUM_LOW
CRYPTO_ENABLE_ALARM false
CRYPTO_ENABLE_BUSERROR false
CRYPTO_ENABLE_BUSY true
...
...
HSS Link to heading
HSS is the bootloader (Firmware to boot MSS) to init peripherals and start up payload. make_hss
eventually generates hex files
make_hss(sources["HSS"], yaml_input_file)
# Builds the HSS using a pre-defined config file using SoftConsole in headless mode
def make_hss(hss_source, yaml_input_file):
print("================================================================================")
print(" Build Hart Software Services (HSS)")
print("================================================================================\r\n", flush=True)
cwd = os.getcwd()
print("debug: cwd : ", cwd)
# Retrieve build target info from YAML file
with open(yaml_input_file) as f: # open the yaml file passed as an arg
data = yaml.load(f, Loader=yaml.FullLoader)
try:
target_board = data.get("HSS").get("board")
except:
target_board = "bvf"
f.close()
print("Target board: " + target_board)
# Update XML in HSS project
XML_file = "boards/" + target_board + "/soc_fpga_design/xml/PF_SOC_MSS_mss_cfg.xml"
XML_file_abs_path = os.path.join(hss_source, XML_file)
try:
os.remove(XML_file_abs_path)
except:
print("HSS target board does not have a default MSS XML configuration - not a problem.", flush=True)
shutil.copyfile("./work/MSS/PF_SOC_MSS_mss_cfg.xml", XML_file_abs_path)
# Select HSS configuration to build
def_config_file = os.path.join(hss_source, "boards/" + target_board + "/def_config")
shutil.copyfile(def_config_file, os.path.join(hss_source, "./.config"))
# Call HSS makefile
initial_directory = os.getcwd()
os.chdir(hss_source)
make_command = "make BOARD=" + target_board
exe_sys_cmd(make_command)
os.chdir(initial_directory)
# Check build was successful and copy the build artifact to the output directory
generated_hex_file = "./sources/HSS/Default/bootmode1/hss-envm-wrapper-bm1-p0.hex"
if os.path.isfile(generated_hex_file):
shutil.copyfile(generated_hex_file, "./work/HSS/hss-envm-wrapper-bm1-p0.hex")
else:
print("!!! Error: Hart Soft Service build failed !!!", flush=True)
exit()
Libero Link to heading
This call to libero passing the tcl file and the hex generated from HSS.
fpga_design_sources_path = os.path.join(gateware_top_dir, "sources", "FPGA-design")
generate_libero_project(libero, yaml_input_file, fpga_design_sources_path, build_dir)
def generate_libero_project(libero, yaml_input_file, fpga_design_sources_path, build_dir_path):
print("================================================================================")
print(" Generate Libero project")
print("================================================================================\r\n", flush=True)
# Execute the Libero TCL script used to create the Libero design
initial_directory = os.getcwd()
os.chdir(fpga_design_sources_path)
project_location = os.path.join("..", "..", build_dir_path, "work", "libero")
script = "BUILD_BVF_GATEWARE.tcl"
script_args = get_libero_script_args(yaml_input_file)
design_version = get_design_version(yaml_input_file)
hss_image_location = os.path.join("..", "..", "work", "HSS", "hss-envm-wrapper-bm1-p0.hex")
prog_export_path = os.path.join("..", "..", build_dir_path)
top_level_name = get_top_level_name()
print("top level name: ", top_level_name)
call_libero(libero, script, script_args, project_location, hss_image_location, prog_export_path, top_level_name, design_version)
os.chdir(initial_directory)
Hardware Link to heading
The next steps describe the important file (including verilog) to build fpga bitstream.
Specifications Link to heading
PolarFire SoC MSS Technical Reference Manual 9
How MSS and Fabric Talk Link to heading
In MSS simulation guide 8, Describes Fabric interface controller (FIC) as a way to address peripherals and memory in polarfire.
blinky Link to heading
Starting with template directory with gateware directory that can be used to build the fpga bitstream.
./sources/FPGA-design/script_support/components/CAPE/ROBOTICS/HDL/apb_rotary_enc.v
./sources/FPGA-design/script_support/components/CAPE/ROBOTICS/HDL/debounce.v
./sources/FPGA-design/script_support/components/CAPE/ROBOTICS/HDL/rotary_encoder.v
./sources/FPGA-design/script_support/components/CAPE/ROBOTICS/HDL/servos.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TEMPLATE/HDL/apb_ctrl_status.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TEMPLATE/HDL/CAPE.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TEMPLATE/HDL/P8_IOPADS.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TEMPLATE/HDL/P9_11_18_IOPADS.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TEMPLATE/HDL/P9_21_31_IOPADS.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TEMPLATE/HDL/P9_41_42_IOPADS.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TUTORIAL/HDL/apb_ctrl_status.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TUTORIAL/HDL/blinky.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TUTORIAL/HDL/CAPE.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TUTORIAL/HDL/P8_IOPADS.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TUTORIAL/HDL/P9_11_18_IOPADS.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TUTORIAL/HDL/P9_21_31_IOPADS.v
./sources/FPGA-design/script_support/components/CAPE/VERILOG_TUTORIAL/HDL/P9_41_42_IOPADS.v
./sources/FPGA-design/script_support/HDL/APB_arbiter/apb_arbiter.v
./sources/FPGA-design/script_support/HDL/AXI4_address_shim/AXI4_address_shim.v
./sources/FPGA-design/script_support/HDL/MIV_IHC/MIV_IHCC/miv_ihcc_ctrl.v
./sources/FPGA-design/script_support/HDL/MIV_IHC/MIV_IHCC/miv_ihcc_irqs.v
./sources/FPGA-design/script_support/HDL/MIV_IHC/MIV_IHCC/miv_ihcc_mem.v
./sources/FPGA-design/script_support/HDL/MIV_IHC/MIV_IHCC/miv_ihcc.v
./sources/FPGA-design/script_support/HDL/MIV_IHC/MIV_IHCIA/miv_ihcia.v
./sources/FPGA-design/script_support/HDL/XCVR_LOOPBACK/pattern_chk.v
./sources/FPGA-design/script_support/HDL/XCVR_LOOPBACK/pattern_gen.v
./sources/FPGA-design/script_support/HDL/XCVR_LOOPBACK/startup.v
The interesting one is blinky
as it has top level user logic
repos/gateware/sources/FPGA-design/script_support/components/CAPE/VERILOG_TUTORIAL/HDL/blinky.v
`timescale 1ns/100ps
module blinky(
input clk,
input resetn,
output blink
);
reg [22:0] counter;
assign blink = counter[22];
always@(posedge clk or negedge resetn)
begin
if(~resetn)
begin
counter <= 16'h0000;
end
else
begin
counter <= counter + 1;
end
end
endmodule
The CAPE.v
is the top level for bitstream that instantiates blinky module with pads to conntect it to external pins.
gateware/sources/FPGA-design/script_support/components/CAPE/VERILOG_TUTORIAL/HDL/CAPE.v
blinky blinky_0(
.clk ( PCLK ),
.resetn ( PRESETN ),
.blink ( BLINK )
);
assign GPIO_OUT_net_0 = { 16'h0000 , GPIO_OUT[27:6], BLINK, GPIO_OUT[4:0] };
P8_IOPADS P8_IOPADS_0(
// Inputs
.GPIO_OE ( GPIO_OE_net_0 ),
.GPIO_OUT ( GPIO_OUT_net_0 ),
// Outputs
.GPIO_IN ( GPIO_IN_net_2 ),
// Inouts
.P8_3 ( P8_3 ),
.P8_4 ( P8_4 ),
.P8_5 ( P8_5 ),
.P8_6 ( P8_6 ),
.P8_7 ( P8_7 ),
.P8_8 ( P8_8 ),
There was apb controller to interface with processing unit.
apb_ctrl_status apb_ctrl_status_0(
// Inputs
.presetn ( PRESETN ),
.pclk ( PCLK ),
.psel ( APB_SLAVE_SLAVE_PSEL ),
.penable ( APB_SLAVE_SLAVE_PENABLE ),
.pwrite ( APB_SLAVE_SLAVE_PWRITE ),
.paddr ( APB_SLAVE_SLAVE_PADDR_0 ),
.pwdata ( APB_SLAVE_SLAVE_PWDATA ),
.status ( apb_ctrl_status_0_control ),
// Outputs
.prdata ( APB_SLAVE_PRDATA ),
.control ( apb_ctrl_status_0_control )
);
Logging into the apb_ctrl_status
where it has register read/write logic.
repos/gateware/sources/FPGA-design/script_support/components/CAPE/VERILOG_TEMPLATE/HDL/apb_ctrl_status.v
reg [31:0] control_value;
wire rd_enable;
wire wr_enable;
assign wr_enable = (penable && pwrite && psel);
assign rd_enable = (!pwrite && psel);
always@(posedge pclk or negedge presetn)
begin
if(~presetn)
begin
prdata <= 'b0;
control_value <= 32'h00000000;
control <= 32'h00000000;
end
else
begin
case(paddr[7:0])
STATUS:
begin
if (rd_enable)
begin
prdata <= status;
end
end
CONTROL_0:
begin
if (rd_enable)
begin
prdata <= 32'hdeadbeef;
control <= 32'hdeadbeef;
end
end
CONTROL_1:
begin
if (rd_enable)
begin
prdata <= control_value;
control <= control_value;
end
else if (wr_enable)
begin
control_value <= pwdata;
end
end
default:
begin
prdata <= 32'b0;
end
endcase
end
end
endmodule
TCL Link to heading
To link this that to the libero tcl files, ADD_CAPE.tcl
is sourced based on cape_option
repos/gateware/sources/FPGA-design/script_support/components/CAPE/VERILOG_TUTORIAL/ADD_CAPE.tcl
create_hdl_core -file $project_dir/hdl/CAPE.v -module {CAPE} -library {work} -package {}
hdl_core_add_bif -hdl_core_name {CAPE} -bif_definition {APB:AMBA:AMBA2:slave} -bif_name {BIF_1} -signal_map {}
hdl_core_assign_bif_signal -hdl_core_name {CAPE} -bif_name {BIF_1} -bif_signal_name {PADDR} -core_signal_name {APB_SLAVE_SLAVE_PADDR}
hdl_core_assign_bif_signal -hdl_core_name {CAPE} -bif_name {BIF_1} -bif_signal_name {PSELx} -core_signal_name {APB_SLAVE_SLAVE_PSEL}
hdl_core_assign_bif_signal -hdl_core_name {CAPE} -bif_name {BIF_1} -bif_signal_name {PENABLE} -core_signal_name {APB_SLAVE_SLAVE_PENABLE}
hdl_core_assign_bif_signal -hdl_core_name {CAPE} -bif_name {BIF_1} -bif_signal_name {PWRITE} -core_signal_name {APB_SLAVE_SLAVE_PWRITE}
hdl_core_assign_bif_signal -hdl_core_name {CAPE} -bif_name {BIF_1} -bif_signal_name {PRDATA} -core_signal_name {APB_SLAVE_SLAVE_PRDATA}
hdl_core_assign_bif_signal -hdl_core_name {CAPE} -bif_name {BIF_1} -bif_signal_name {PWDATA} -core_signal_name {APB_SLAVE_SLAVE_PWDATA}
hdl_core_rename_bif -hdl_core_name {CAPE} -current_bif_name {BIF_1} -new_bif_name {APB_TARGET}
The file is parsed from the yaml file. In this case, it’s VERILOG_TUTORIAL
repos/gateware/sources/FPGA-design/script_support/components/BVF_GATEWARE.tcl
source script_support/components/CAPE/$cape_option/ADD_CAPE.tcl
From repos/gateware/custom-fpga-design/my_custom_fpga_design.yaml
---
HSS:
type: git
link: https://openbeagle.org/beaglev-fire/hart-software-services.git
branch: main-beaglev-fire
board: bvf
gateware:
type: sources
build-args: "M2_OPTION:NONE CAPE_OPTION:VERILOG_TUTORIAL"
From the top, repos/gateware/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl
safe_source ./script_support/B_V_F_recursive.tcl
repos/gateware/sources/FPGA-design/script_support/B_V_F_recursive.tcl
::safe_source script_support/components/BVF_GATEWARE.tcl