David,
This is great work. Thanks.
Since I believe the fpga manager stuff is really an attribute of later
linux kernels, I don't think it is really a ZynqMP thing, but just a
later linux kernel thing.
I am currently bringing up the quite ancient zedboard using the latest
Vivado and Xilinx linux and will try to use this same code.
There are two thinigs I am looking into, now that you have done the hard
work of getting to a working solution:
1. The bit vs bin thing existed with the old bitstream loader, but I
think we were converting on the fly, so I will try that here.
(To avoid the bin format altogether).
2. The fpga manager has entry points from kernel mode that allow you to
inject the bitstream without making a copy in /lib/firmware.
Since we already have a kernel driver, I will try to use that to avoid
the whole /lib/firmware thing.
So if those two things can work (no guarantees), the difference between
old and new bitstream loading (and building) can be minimized and
the loading process faster and requiring no extra file system space.
This will make merging easier too.
We'll see. Thanks again to you and Geon for this important contribution.
Jim
On 2/1/19 3:12 PM, David Banks wrote:
> 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:27:51 CST