用Python給Verilog設(shè)計(jì)自仿(五):阻塞與隊(duì)列,如何實(shí)現(xiàn)FPGA仿真高吞吐數(shù)據(jù)校驗(yàn)
掃描二維碼
隨時(shí)隨地手機(jī)看文章
1前言
對(duì)于許多FPGA/IC工程師而言,設(shè)計(jì)實(shí)現(xiàn)游刃有余,驗(yàn)證仿真卻常成短板——傳統(tǒng)驗(yàn)證方法面臨兩難困局:學(xué)習(xí)UVM需投入大量時(shí)間成本,而純Verilog自仿又會(huì)陷入重復(fù)造輪子的低效循環(huán)。以通信協(xié)議仿真為例,僅報(bào)文解析就需要重寫整套解析邏輯,相當(dāng)于用Verilog再實(shí)現(xiàn)一次協(xié)議棧,耗時(shí)費(fèi)力。
此時(shí),Python的生態(tài)優(yōu)勢便鋒芒盡顯。其豐富的字符串處理庫可直接解析報(bào)文,配合Cocotb框架,僅需少量Python代碼即可構(gòu)建高效測試平臺(tái),將驗(yàn)證工作量壓縮70%以上。Cocotb的獨(dú)特價(jià)值正在于此:用Python解放驗(yàn)證生產(chǎn)力,讓工程師專注于設(shè)計(jì)創(chuàng)新而非重復(fù)勞動(dòng)。
2阻塞與非阻塞
在cocotb中阻塞操作需要使用await,而非阻塞隊(duì)列操作則不需要,如果阻塞不使用await,協(xié)程則會(huì)一直暫停,直到條件滿足,我們可以類比為await操作相當(dāng)于Verilog中的阻塞賦值=,而不使用await則類似于Verilog中的非阻塞賦值<=。當(dāng)我們在cocotb中執(zhí)行阻塞隊(duì)列操作時(shí),協(xié)程會(huì)在執(zhí)行到隊(duì)列操作時(shí)暫停,直到特定條件被滿足為止,這時(shí)需要使用await來使協(xié)程等待。例如,await queue.get()會(huì)阻塞當(dāng)前協(xié)程,直到隊(duì)列中有數(shù)據(jù)可供獲取。而如果沒有使用await,協(xié)程將會(huì)一直停留在這個(gè)位置,無法繼續(xù)執(zhí)行后續(xù)操作,直到條件滿足??梢灶惐葹閂erilog中的阻塞賦值=,即當(dāng)某個(gè)操作完成之前,后續(xù)的語句都無法繼續(xù)執(zhí)行。
//Verilog中的阻塞賦值 always @(*)begin b = a; c = b; end //Verilog中的非阻塞賦值 always @(posedge clk)begin b <= a; c <= b; end
#python 阻塞 asyncdefassign_testa: b = a asyncdefassign_testb: c = b await assign_testa #等待testa執(zhí)行完,再執(zhí)行testb await assign_testa #python 非阻塞 task1 = asyncio.create_task(assign_testa()) # 不會(huì)阻塞,馬上開始 assign_testa task2 = asyncio.create_task(assign_testb()) # 不會(huì)阻塞,馬上開始 assign_testb
3Cocotb-Queue
我們可以把Queue類比為硬件中的FIFO,也是先進(jìn)先出的結(jié)構(gòu)。
Cocotb 提供了幾種隊(duì)列類型,用于協(xié)同多個(gè)生產(chǎn)者和消費(fèi)者協(xié)程的操作。它們是基于 asyncio 的Queue類,具有異步操作特性,并且可以幫助你在測試中同步不同的協(xié)程之間的通信。
class cocotb.queue.Queue(maxsize=0)
maxsize:指定隊(duì)列的最大容量。如果 maxsize 小于或等于 0,則隊(duì)列大小無限制。如果 maxsize 大于 0,當(dāng)隊(duì)列達(dá)到該大小時(shí),put() 方法會(huì)阻塞,直到有空間。
我們在使用隊(duì)列時(shí),需要首先定義一個(gè)Queue類
from cocotb.queue import Queue rx_queue = Queue()
主要方法
async put(item)
將 item 放入隊(duì)列。
如果隊(duì)列已滿,則會(huì)等待直到有空間可用。
put_nowait(item)
將 item 放入隊(duì)列,不會(huì)阻塞。
如果隊(duì)列已滿,立即拋出 QueueFull 異常。
async get()
從隊(duì)列中移除并返回一個(gè)項(xiàng)。
如果隊(duì)列為空,會(huì)等待直到有項(xiàng)可以取出。
get_nowait()
從隊(duì)列中移除并返回一個(gè)項(xiàng)。
如果隊(duì)列為空,立即拋出 QueueEmpty 異常。
qsize()
返回隊(duì)列中當(dāng)前項(xiàng)的數(shù)量。
empty()
如果隊(duì)列為空,返回 True,否則返回 False。
full()
如果隊(duì)列已滿,返回 True,否則返回 False。
4Queue有什么用
其實(shí)他類似于硬件FIFO中的功能
生產(chǎn)者(例如monitor)負(fù)責(zé)從硬件或仿真環(huán)境中接收數(shù)據(jù),并將這些數(shù)據(jù)放入隊(duì)列中。消費(fèi)者(例如校驗(yàn)器)則從隊(duì)列中取出數(shù)據(jù)進(jìn)行處理。這個(gè)過程的關(guān)鍵在于隊(duì)列的使用,它能夠確保生產(chǎn)者和消費(fèi)者之間不會(huì)直接依賴于對(duì)方的執(zhí)行進(jìn)度,從而避免了一個(gè)操作(如生產(chǎn)者)阻塞整個(gè)協(xié)程的情況。
如果沒有隊(duì)列,消費(fèi)者需要直接等待生產(chǎn)者生成數(shù)據(jù),這就意味著消費(fèi)者的協(xié)程會(huì)一直被阻塞,直到生產(chǎn)者完成數(shù)據(jù)的生成。而使用隊(duì)列后,即使生產(chǎn)者暫時(shí)沒有數(shù)據(jù)可供消費(fèi),消費(fèi)者仍然可以繼續(xù)執(zhí)行其他操作,只有在隊(duì)列中有數(shù)據(jù)時(shí),消費(fèi)者才會(huì)從隊(duì)列中取出并進(jìn)行處理。這種解耦使得系統(tǒng)的執(zhí)行更為靈活和高效。
在cocotb仿真過程中,如果要校驗(yàn)的數(shù)據(jù)數(shù)據(jù)量很大,建議使用Queue來完成校驗(yàn)數(shù)據(jù)的存取。我們通過receiver_monitor來入隊(duì)響應(yīng)報(bào)文,通過data_validator來出隊(duì)響應(yīng)報(bào)文,并校驗(yàn)報(bào)文是否正確
async def receiver_monitor(dut: SimHandle, sink: AxiStreamSink) -> None: """異步接收協(xié)程""" while True: try: frame = await sink.recv() # 阻塞式接收 # rx_queue.put_nowait(frame) # 非阻塞入隊(duì) await rx_queue.put(frame) # 阻塞入隊(duì) except Exception as e: dut._log.error(f"queue error: {e}") raise errors = [] async def data_validator(dut: SimHandle, frame_count: int) -None: result = 0 while(result < frame_count): frame = await rx_queue.get() # 阻塞式出隊(duì) data = (int.from_bytes(frame.tdata, byteorder='little')) if data != result: errors.append(f"CHECK ERROR, got {data},the result is {hex(result)}") dut._log.error(f"verilate fail :{data},the result is {hex(result)}") else: dut._log.info(f"CHECK PASS receive data is :{data}") result = result + 1 @cocotb.test() async def axis_simple_test(dut: SimHandle): ...... assert len(errors) == 0,"TEST FAIL"
5寫在最后
本文為原創(chuàng)Cocotb技術(shù)專欄,歡迎工程師伙伴們留言討論或交流,共同學(xué)習(xí)。若想第一時(shí)間獲取更新,可點(diǎn)擊下方「關(guān)注」或訂閱Cocotb專題。





