美文网首页PYNQ
PYNQ中MicroBlaze程序是如何加载的

PYNQ中MicroBlaze程序是如何加载的

作者: IEEE1364 | 来源:发表于2018-12-19 17:20 被阅读29次

    警告:这篇文章可以做为专业人士饭后甜点,但是非专业人士请火速撤离,以免造成永久性大脑皮层损伤。

    在PYNQ的base overlay 中添加了MicroBlaze,通过MicroBlaze 来配置PMOD 和ardonio 接口并驱动外部设备。但是平常我们对MicroBlaze 编程都是将MicroBlaze 的代码文件被硬件的bitstream文件融合成一个文件下载到FPGA里面去执行。但是,在PYNQ里面显然不是这样的。PYNQ的逻辑部分也就是Overlay都是在系统起来后动态加载的,再启动MicroBlaze里面的程序。那么这一切都是如何实现的呢?

    首先在PYNQ的overlay里面的MicroBlaze使用的是双端口Block RAM,PS端可以对这个RAM进行读写,那么问题就简单了,等overlay配置完成,PS端再将二进制程序文件吸入的到MicroBlaze指令存储器里面,再复位MicroBlaze就可以了。
    这一过程设计复杂的文件调用和地址映射。首先来看一下这一功能在Python里面实现的。

    首先我们看一个使用MicroBlaze的例子,以Pmod ADC为例。测试代码如下:

    from pynq.overlays.base import BaseOverlay
    from pynq.lib import Pmod_ADC
    
    base = BaseOverlay("base.bit")
    
    if_id = input("Type in the interface ID used (PMODA or PMODB): ")
    if if_id.upper()=='PMODA':
        adc = Pmod_ADC(base.PMODA)
    else:
        adc = Pmod_ADC(base.PMODB)
    

    先调用base overlay,这个不用说。接下来使用的一个Pmod_ADC函数指定Pmod接口是A还是B。这个函数在pmod_adc.py文件里,让我们进如pmod_adc.py看一下这个函数:

    PMOD_ADC_PROGRAM = "pmod_adc.bin"
    
    class Pmod_ADC(object):
        def __init__(self, mb_info):
            self.microblaze = Pmod(mb_info, PMOD_ADC_PROGRAM)
            self.log_running = 0
    

    这里面使用一个Pmod函数指定了所使用的程序文件,也就是pmod_adc.bin。这程序是自己写的MicroBlaze程序编译生成的,可以在SDK里面完成程序并编译得到.bin文件。
    在pmod.py文件里面我们可以看到Pmod函数通过super()函数调用父PynqMicroblaze里面初始化函数。关于super()函数的使用自行谷歌。

    from pynq.lib import PynqMicroblaze
    
    class Pmod(PynqMicroblaze):
        def __init__(self, mb_info, mb_program):
            if not os.path.isabs(mb_program):
                mb_program = os.path.join(BIN_LOCATION, mb_program)
    
            super().__init__(mb_info, mb_program)
    

    在 PynqMicroblaze里面,使用了PL.load_ip_data函数来载入我们的二进制程序文件。并在载入完成后使用了run()函数,在run()函数里面复位了MicroBlaze。

    class PynqMicroblaze:
        def run(self):
            self.state = 'RUNNING'
            self.reset_pin.write(0)
    
        def program(self):
            self.reset()
            PL.load_ip_data(self.ip_name, self.mb_program, zero=True)
            if self.interrupt:
                self.interrupt.clear()
            self.run()
    

    让我们再进入pl.py,会发现 load_ip_data函数使用MMIO接口函数写入了程序文件。

        def load_ip_data(cls, ip_name, data, zero=False):
            cls.client_request()
            with open(data, 'rb') as bin_file:
                size = os.fstat(bin_file.fileno()).st_size
                target_size = cls._ip_dict[ip_name]['addr_range']
                if size > target_size:
                    raise RuntimeError("Binary file too big for IP")
                mmio = MMIO(cls._ip_dict[ip_name]['phys_addr'], target_size)
                buf = bin_file.read(size)
                mmio.write(0, buf)
                if zero and size < target_size:
                    mmio.write(size, b'\x00' * (target_size - size))
    
            cls._ip_dict[ip_name]['state'] = data
            cls.server_update()
    

    到此整个MicroBlaze程序文件的加载过程就已经讲完了。
    还有些细节问题在后面的文章里面再写吧。

    相关文章

      网友评论

        本文标题:PYNQ中MicroBlaze程序是如何加载的

        本文链接:https://www.haomeiwen.com/subject/favkkqtx.html