OpenCPI users interested in ZynqMP fpga_manager,
I know some users are interested in the OpenCPI's bitstream loading for
ZynqMP/UltraScale+ using "*fpga_manager*". In general, we followed the
instructions at
https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841847/Solution+ZynqMP+PL+Programming#SolutionZynqMPPLProgramming-StepsforprogrammingtheFullBitstream.
I will give a short explanation here:
Reminder: All ZynqMP/UltraScale+ changes are located at
https://github.com/Geontech/opencpi.git in release_1.4_zynq_ultra branch.
Firstly, all *fpga_manager *code is located in
*runtime/hdl/src/HdlBusDriver.cxx*. There were also changes in
r*untime/hdl-support/xilinx/vivado.mk
<
http://vivado.mk>* to generate a bitstream in the correct *.bin format. To
see the changes made to these files for ZynqMP, you can diff them between
*release_1.4* and *release_1.4_zynq_ultra*:
$ git clone
https://github.com/Geontech/opencpi.git --branch
release_1.4_zynq_ultra;
$ cd opencpi;
$ git fetch origin release_1.4:release_1.4;
$ git diff release_1.4 -- runtime/hdl/src/HdlBusDriver.cxx
runtime/hdl-support/xilinx/vivado.mk;
The directly relevant functions are *load_fpga_manager()* and i
*sProgrammed()*.
load_fpga_manager() ensures that /lib/firmware exists, reads the *.bin
bitstream file and writes its contents to /lib/firmware/opencpi_temp.bin.
It then writes "0" to /sys/class/fpga_manager/fpga0/flags and the the
filename "opencpi_temp.bin" to /sys/class/fpga_manager/fpga0/firmware.
Finally, the temporary opencpi_temp.bin bitstream is removed and the state
of the fpga_manager (/sys/class/fpga_manager/fpga0/state) is confirmed to
be "operating" in isProgrammed().
fpga_manager requires that bitstreams be in *.bin in order to write them to
the PL. So, some changes were made to vivado.mk to add a make rule for the
*.bin file. This make rule (*BinName*) uses Vivado's "*bootgen*" to convert
the bitstream from *.bit to *.bin.
Most of the relevant code is pasted or summarized below:
*load_fpga_manager*(const char *fileName, std::string &error) {
if (!file_exists("/lib/firmware")){
mkdir("/lib/firmware",0666);
}
int out_file = creat("/lib/firmware/opencpi_temp.bin", 0666);
gzFile bin_file;
int bfd, zerror;
uint8_t buf[8*1024];
if ((bfd = ::open(fileName, O_RDONLY)) < 0)
OU::format(error, "Can't open bitstream file '%s' for reading:
%s(%d)",
fileName, strerror(errno), errno);
if ((bin_file = ::gzdopen(bfd, "rb")) == NULL)
OU::format(error, "Can't open compressed bin file '%s' for :
%s(%u)",
fileName, strerror(errno), errno);
do {
uint8_t *bit_buf = buf;
int n = ::gzread(bin_file, bit_buf, sizeof(buf));
if (n < 0)
return true;
if (n & 3)
return OU::eformat(error, "Bitstream data in is '%s' not a
multiple of 3 bytes",
fileName);
if (n == 0)
break;
if (write(out_file, buf, n) <= 0)
return OU::eformat(error,
"Error writing to /lib/firmware/opencpi_temp.bin for bin
loading: %s(%u/%d)",
strerror(errno), errno, n);
} while (1);
close(out_file);
std::ofstream fpga_flags("/sys/class/fpga_manager/fpga0/flags");
std::ofstream
fpga_firmware("/sys/class/fpga_manager/fpga0/firmware");
fpga_flags << 0 << std::endl;
fpga_firmware << "opencpi_temp.bin" << std::endl;
remove("/lib/firmware/opencpi_temp.bin");
return isProgrammed(error) ? init(error) : true;
}
The isProgrammed() function just checks whether or not the fpga_manager
state is 'operating' although we are not entirely confident this is a
robust check:
*isProgrammed*(...) {
...
const char *e = OU::file2String(val,
"/sys/class/fpga_manager/fpga0/state", '|');
...
return val == "operating";
}
vivado.mk's *bin make-rule uses bootgen to convert bit to bin. This is
necessary in Vivado 2018.2, but in later versions you may be able to
directly generate the correct *.bin file via an option to write_bitstream:
$(call *BinName*,$1,$3,$6): $(call BitName,$1,$3)
$(AT)echo -n For $2 on $5 using config $4: Generating Xilinx Vivado
bitstream file $$_at_ with BIN extension using "bootgen".
$(AT)echo all: > $$(call BifName,$1,$3,$6); \
echo "{" >> $$(call BifName,$1,$3,$6); \
echo " [destination_device = pl] $(notdir $(call
BitName,$1,$3,$6))" >> $$(call BifName,$1,$3,$6); \
echo "}" >> $$(call BifName,$1,$3,$6);
$(AT)$(call DoXilinx,*bootgen*,$1,-image $(notdir $(call
BifName,$1,$3,$6)) -arch $(BootgenArch) -o $(notdir $(call
BinName,$1,$3,$6)) -w,bin)
Hope this is useful!
Regards,
David Banks
dbanks_at_geontech.com
Geon Technologies, LLC
Received on Fri Feb 01 2019 - 20:12:23 CST