警告:這篇文章可以做為專業(yè)人士飯后甜點,但是非專業(yè)人士請火速撤離,以免造成永久性大腦皮層損傷。
在PYNQ的base overlay 中添加了MicroBlaze,通過MicroBlaze 來配置PMOD 和ardonio 接口并驅(qū)動外部設(shè)備。但是平常我們對MicroBlaze 編程都是將MicroBlaze 的代碼文件被硬件的bitstream文件融合成一個文件下載到FPGA里面去執(zhí)行。但是,在PYNQ里面顯然不是這樣的。PYNQ的邏輯部分也就是Overlay都是在系統(tǒng)起來后動態(tài)加載的,再啟動MicroBlaze里面的程序。那么這一切都是如何實現(xiàn)的呢?
首先在PYNQ的overlay里面的MicroBlaze使用的是雙端口Block RAM,PS端可以對這個RAM進(jìn)行讀寫,那么問題就簡單了,等overlay配置完成,PS端再將二進(jìn)制程序文件吸入的到MicroBlaze指令存儲器里面,再復(fù)位MicroBlaze就可以了。
這一過程設(shè)計復(fù)雜的文件調(diào)用和地址映射。首先來看一下這一功能在Python里面實現(xiàn)的。
首先我們看一個使用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)
先調(diào)用base overlay,這個不用說。接下來使用的一個Pmod_ADC函數(shù)指定Pmod接口是A還是B。這個函數(shù)在pmod_adc.py文件里,讓我們進(jìn)如pmod_adc.py看一下這個函數(shù):
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函數(shù)指定了所使用的程序文件,也就是pmod_adc.bin。這程序是自己寫的MicroBlaze程序編譯生成的,可以在SDK里面完成程序并編譯得到.bin文件。
在pmod.py文件里面我們可以看到Pmod函數(shù)通過super()函數(shù)調(diào)用父PynqMicroblaze里面初始化函數(shù)。關(guān)于super()函數(shù)的使用自行谷歌。
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函數(shù)來載入我們的二進(jìn)制程序文件。并在載入完成后使用了run()函數(shù),在run()函數(shù)里面復(fù)位了MicroBlaze。
class PynqMicroblaze:
def run(self):
self.state = ‘RUNNING’
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()
讓我們再進(jìn)入pl.py,會發(fā)現(xiàn) load_ip_data函數(shù)使用MMIO接口函數(shù)寫入了程序文件。
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][‘a(chǎn)ddr_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程序文件的加載過程就已經(jīng)講完了。
還有些細(xì)節(jié)問題在后面的文章里面再寫吧。
評論
查看更多