ValueError: embedded null byte while implementing DPR on ZCU216

Hi @marioruiz @briansune ,
I finally solved the problem! Simply put, there is a BUG in the source code of PYNQ 2.7:

Firstly, lets review the error:

ValueError                                Traceback (most recent call last)
<ipython-input-29-3b813cdecb5c> in <module>
     18 decouple.write(DATA_OFFSET, 0x0000_0001)
     19 pb = Bitstream("add_pblock_partial.bit", None, True)
---> 20 pb.download()
     21 decouple.write(DATA_OFFSET, 0x0000_0000)
     22 

/usr/local/share/pynq-venv/lib/python3.8/site-packages/pynq/bitstream.py in download(self, parser)
    185 
    186         """
--> 187         self.device.download(self, parser)
    188 
    189     def remove_dtbo(self):

/usr/local/share/pynq-venv/lib/python3.8/site-packages/pynq/pl_server/embedded_device.py in download(self, bitstream, parser)
    576         if parser is None:
    577             from .xclbin_parser import XclBin
--> 578             parser = XclBin(DEFAULT_XCLBIN)
    579 
    580         if not bitstream.binfile_name:

/usr/local/share/pynq-venv/lib/python3.8/site-packages/pynq/pl_server/xclbin_parser.py in __init__(self, filename, xclbin_data)
    369     def __init__(self, filename="", xclbin_data=None):
    370         self.ip_dict, self.mem_dict, self.clock_dict = \
--> 371             _xclbin_to_dicts(filename, xclbin_data)
    372         self.gpio_dict = {}
    373         self.interrupt_controllers = {}

/usr/local/share/pynq-venv/lib/python3.8/site-packages/pynq/pl_server/xclbin_parser.py in _xclbin_to_dicts(filename, xclbin_data)
    276 def _xclbin_to_dicts(filename, xclbin_data=None):
    277     if xclbin_data is None:
--> 278          with open(filename, 'rb') as f:
    279              xclbin_data = bytearray(f.read())
    280     sections, xclbin_uuid = parse_xclbin_header(xclbin_data)

ValueError: embedded null byte

It turns out, that an embedded null byte in the filename, and I found that this filename is actually DEFAULT_XCLBIN.

Somehow, in the PYNQ 2.7, the following line of code cannot execute correctly.

DEFAULT_XCLBIN = (Path(__file__).parent / 'default.xclbin').read_bytes()

Location:

/PYNQ-image_v2.7/pynq/pl_server/embedded_device.py

My Solution is, by using Method Overriding, I rewrite these Classes:

class DebugXclBin(XclBin):
class DebugBitstream(Bitstream):

Now my full_test code is:

from pynq import Overlay, Bitstream, allocate, GPIO, MMIO
import pynq.lib.dma
from pynq.lib.dma import *
import numpy as np

######### Method Overriding #########
from pynq.pl_server.embedded_device import EmbeddedDevice, DEFAULT_XCLBIN, _get_bitstream_handler
from pynq.pl_server.xclbin_parser import XclBin, _xclbin_to_dicts


class DebugXclBin(XclBin):
    def __init__(self, filename="", xclbin_data=None):
        super().__init__(filename, xclbin_data)
        self.xclbin_data = xclbin_data  

class DebugBitstream(Bitstream):
    def download(self, parser=None):
        if parser is None:
            bitfile_path = self.bitfile_name
            
            # Create the bitstream handler
            bitstream_handler = _get_bitstream_handler(bitfile_path)

            # Get parser without partial
            parser = bitstream_handler.get_parser()
            if parser is None:
                parser = DebugXclBin(xclbin_data=DEFAULT_XCLBIN)
        
        if not hasattr(parser, 'xclbin_data'):
            raise AttributeError("Parser object has no attribute 'xclbin_data'")
        if parser.xclbin_data is None:
            raise ValueError("Parser object has xclbin_data set to None")
        
        super().download(parser)
        
######### Method Overriding #########

DATA_OFFSET = 0x0000 

overlay = Overlay("dpr.bit") 

decouple = MMIO(0xA000_0000, 0x1000)
decouple_status = MMIO(0xA001_0000, 0x1000)

dma_in1 = overlay.dma_in1
dma_in2 = overlay.dma_in2
dma_out = overlay.dma_out

decouple.write(DATA_OFFSET, 0x0000_0001)
pb = DebugBitstream("add_pblock_partial.bit", None, True)
pb.download()
decouple.write(DATA_OFFSET, 0x0000_0000)

in1_data = allocate(shape=(4,), dtype=np.uint32)
in2_data = allocate(shape=(4,), dtype=np.uint32)
out_data = allocate(shape=(4,), dtype=np.uint32)

in1_data[:] = np.array([2, 4, 6, 100], dtype=np.uint32)
in2_data[:] = np.array([1, 2, 3, 70], dtype=np.uint32)

dma_in1.sendchannel.transfer(in1_data)
dma_in2.sendchannel.transfer(in2_data)
dma_in1.sendchannel.wait()
dma_in2.sendchannel.wait()  
dma_out.recvchannel.transfer(out_data)
dma_out.recvchannel.wait()
print(out_data)

decouple.write(DATA_OFFSET, 0x0000_0001)
pb = DebugBitstream("sub_pblock_partial.bit", None, True)
pb.download()
decouple.write(DATA_OFFSET, 0x0000_0000)

in1_data = allocate(shape=(4,), dtype=np.uint32)
in2_data = allocate(shape=(4,), dtype=np.uint32)
out_data = allocate(shape=(4,), dtype=np.uint32)

in1_data[:] = np.array([2, 4, 6, 100], dtype=np.uint32)
in2_data[:] = np.array([1, 2, 3, 70], dtype=np.uint32)

dma_in1.sendchannel.transfer(in1_data)
dma_in2.sendchannel.transfer(in2_data)
dma_in1.sendchannel.wait()
dma_in2.sendchannel.wait()  
dma_out.recvchannel.transfer(out_data)
dma_out.recvchannel.wait()
print(out_data)

The output is:

[  3   6   9 170]
[ 1  2  3 30]

Problem solved!

1 Like