axi时序图_深入 AXI4总线(E3)实战:制作一个 AXI 接口 IP
在本系列先前的文章中,我們首先通過協(xié)議 specification 了解協(xié)議的接口與機(jī)制,并通過操作一個(gè) AXI 接口的 RAM IP 進(jìn)行了一番實(shí)戰(zhàn)。
從協(xié)議機(jī)制上來說,協(xié)議的制定者權(quán)衡協(xié)議的使用場景,主從機(jī)接口,性能等各方面的需求與限制以及實(shí)現(xiàn)的難度制定了這些規(guī)則。從筆者個(gè)人的經(jīng)驗(yàn)來說,對于一個(gè)協(xié)議:
把手冊打印出來 -> 翻爛 -> 沒人比我更懂這個(gè)協(xié)議了(誤)翻爛可不是了解一個(gè)協(xié)議最有效的手段,最重要的還是針對協(xié)議的實(shí)踐。通過操作 AXI 接口的 IP 可以熟悉協(xié)議的接口。而通過實(shí)現(xiàn)一個(gè)協(xié)議的接口模塊,可以更深入地了解協(xié)議。本文將借助 Xilinx 提供的 AXI 接口代碼,實(shí)現(xiàn)一個(gè) AXI-lite 接口模塊,了解協(xié)議接口機(jī)制的實(shí)現(xiàn)。
Vivado 提供的接口代碼
在 Vivado 中使用 IP 編輯器創(chuàng)建一個(gè) AXI 接口的 IP,就可以獲取到 Xilinx 在創(chuàng)建模板中提供的接口代碼,這里簡單地紀(jì)錄下創(chuàng)建過程。
首先在 Tools 中選擇 創(chuàng)建打包新 IP 菜單,選擇建立一個(gè) AXI4 外設(shè)。
在接口界面,添加 AXI 接口。這里的接口可選作為主機(jī)或者從機(jī)的 AXI-Full,AXI-Lite 或者 AXI-Stream 協(xié)議,本文選擇 32 位 AXI-Lite 從機(jī)作為例子。位寬按照協(xié)議規(guī)定,可以在 32 位和 64 位之間進(jìn)行選擇。
在創(chuàng)建完 IP 核后.....沒錯(cuò),就是什么都不會發(fā)生。如果要編輯 IP 核或者像本文要做的那樣查看 IP 的 RTL 代碼,那么在 IP catalog 選項(xiàng)中找到剛剛新建的 IP 核,一般在 User Repository 選項(xiàng)下可以找到。右鍵-在 IP Packager 中編輯。
使用 IP Packager 編輯會打開一個(gè)新的基于 創(chuàng)建的 IP 核的 Vivado 工程,在這個(gè)工程中可以修改 IP 的信息,參數(shù),接口以及 RTL 代碼。在 source 中有一個(gè) IP 核的頂層模塊以及其下的 AXI-Lite 接口模塊,這就是我們要學(xué)習(xí)的接口實(shí)現(xiàn) demo 了。
AXI-Lite 接口模塊信號列表
Xilinx 提供的代碼是非常好的學(xué)習(xí)材料,編碼規(guī)范并提供了詳細(xì)的注釋。首先可以學(xué)習(xí)的是參數(shù)化的設(shè)計(jì),在 IP 核代碼中,很多的參數(shù)經(jīng)常需要變化,比如在 GUI 界面中修改數(shù)據(jù)寬度等等,這就需要完善的參數(shù)化設(shè)計(jì)。
在聲明端口之前可以使用#( )聲明模塊中的參數(shù)變量,這里起到兩個(gè)作用,一是聲明了參數(shù)a,b,二是賦予它們的默認(rèn)值。注意一個(gè)以上參數(shù)的聲明方式,不同參數(shù)之間用 "," 分隔,這和聲明端口的語法是一致的。但每個(gè)參數(shù)之前的 parameter 是不可以共用的。
module my_module #( parameter a = 1, parameter b = 2 ) ( 端口聲明 )在實(shí)例化模塊時(shí),可以指定傳入模塊參數(shù)的值,如下方實(shí)例化 my_module ,模塊命名為 m ,在 #( ) 中向模塊的參數(shù)傳入數(shù)值,模塊中的參數(shù) a,b 得到新的數(shù)值 10,20 。如果沒有傳值操作,那么模塊中參數(shù) a,b 使用默認(rèn)值 1,2。(這里注意實(shí)例名 m 的位置)
//實(shí)例化 my_module my_module #( .a(10), .b(20) ) m//實(shí)例名 ( 端口連接 )在 AXI-Lite 模塊中定義了兩個(gè)參數(shù),數(shù)據(jù)總線的寬度以及地址總線的寬度。在后續(xù)的端口寬度定義中使用了這些參數(shù)。關(guān)于地址總線寬度為什么這里會是 4 將在后文中具體討論。
AXI-Lite 相比完整的 AXI 協(xié)議,側(cè)重于配置與狀態(tài)信號傳輸,不支持突發(fā)傳輸,并在裁剪了用于內(nèi)存訪問的控制信號后,大幅減少了端口數(shù)量,便于集成。端口列表如下,在代碼中對每個(gè)端口的作用也有注釋說明。
AXI-Lite 接口信號列表CSR 寄存器
所以系統(tǒng)中集成 AXI-Lite 接口模塊的作用一般是什么?
在一個(gè) SoC 系統(tǒng)中,處理器需要配置大量的外設(shè)配置寄存器,并從外設(shè)的狀態(tài)寄存器中讀取外設(shè)的狀態(tài),進(jìn)行初始化完成的判斷等操作。AXI-Lite 總線就在 Configure & Status Report 階段作為主機(jī)和外設(shè)之間的橋梁。
AXI 接口模塊會將來自主機(jī),一般是處理器的 AXI 數(shù)據(jù)鎖存到寄存器中,將數(shù)值轉(zhuǎn)為為邏輯電平信號輸出給外設(shè)模塊。將來自外設(shè)的電平信號也鎖存到寄存器中,在主機(jī)發(fā)出讀取請求時(shí),將狀態(tài)寄存器的數(shù)值以 AXI 讀數(shù)據(jù)的形式發(fā)給主機(jī)。 AXI 接口模塊在系統(tǒng)中起到配置寄存器的配置輸入和狀態(tài)寄存器的狀態(tài)上報(bào)這兩方面的作用。
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1;自然而然,寄存器就是接口模塊中的重要組成部分。在本模塊中,設(shè)定有 4 個(gè)寄存器,每個(gè)寄存器位寬 32 位。寄存器的數(shù)量和位寬決定了地址總線的寬度。在計(jì)算機(jī)系統(tǒng)中,地址以字節(jié)為單位,4 個(gè)寄存器共有 16 個(gè)字節(jié),所以地址總線的寬度為:
Waddr = log2(16) = 4 bit總線操作中片選讀寫寄存器是以寄存器而不是字節(jié)為單位,所以在通過地址判斷所要讀寫的寄存器時(shí),只需要判斷地址的高 2 bit,片選出 4 個(gè)寄存器。在選擇了寄存器之后,也可以借助 WSTRB 字段控制對寄存器中的指定字節(jié)進(jìn)行寫操作,這部分會在后文解析協(xié)議實(shí)現(xiàn)時(shí)詳細(xì)討論。(WSTRB 信號只是指示從機(jī)屏蔽指定字節(jié),實(shí)際上這部分?jǐn)?shù)據(jù)也是傳輸?shù)?#xff0c;協(xié)議規(guī)定傳輸必須以 32/64 位進(jìn)行)
配置與狀態(tài)寄存器可以分為只讀,只寫,可讀可寫三類。本文先討論比較簡單的只讀,只寫情況,即將整個(gè)32 bit 寬的寄存器從讀/寫功能上劃分為兩類,所有 bit 對于主機(jī)而言,全部為只讀或者全部為只寫。
如何實(shí)現(xiàn)只寫/只讀寄存器,假設(shè)寄存器 0 是一個(gè)只寫寄存器,寄存器 1 是一個(gè)只讀寄存器:
首先在接口模塊上定義輸入輸出端口,進(jìn)行寄存器和電平信號的轉(zhuǎn)換。在輸出端口上輸出內(nèi)部存儲器的內(nèi)容,或者將外部輸入的邏輯電平賦予內(nèi)部寄存器。
總線接口實(shí)現(xiàn)邏輯會在主線產(chǎn)生讀寫請求時(shí),接口模塊會將只寫寄存器用總線數(shù)據(jù)更新或者將只讀寄存器的數(shù)據(jù)更新到總線上,實(shí)現(xiàn)寄存器信息的更新。
output [31:0] reg0_out; input [31:0] reg1_in; assign reg0_out = slv_reg0; always @(posedge clk)slv_reg1 <= reg1_in;接口時(shí)序?qū)崿F(xiàn)
AXI-Lite 協(xié)議同完整的 AXI 協(xié)議一樣有 5 個(gè)獨(dú)立的通道,但由于不支持長度超過 1 的突發(fā)傳輸。Lite 協(xié)議中地址控制信息通道和數(shù)據(jù)通道嚴(yán)格滿足一對一的關(guān)系。比如寫地址通道寫入地址以及控制信息后,寫數(shù)據(jù)通道只在下一有效時(shí)鐘沿進(jìn)行一次數(shù)據(jù)傳輸。地址信號傳輸完成信號作為下一時(shí)刻寫數(shù)據(jù)的使能信號。下圖表示了地址和數(shù)據(jù)流向,代碼也反映了這一時(shí)序關(guān)系。
數(shù)據(jù)流向圖AXI-Lite 協(xié)議上并沒有特別定義傳輸?shù)男盘枙r(shí)序,時(shí)序與 AXI-Full 協(xié)議 Burst 長度為 1 的情況相同。
我們首先關(guān)注地址通道的邏輯,讀寫地址通道的邏輯類似,這里以稍復(fù)雜些的寫地址通道為例。
上述代碼塊通過控制 awready 信號完成了一次地址通道傳輸。邏輯檢測 awvalid,wvalid信號的電平,當(dāng)主機(jī)在寫地址以及寫數(shù)據(jù)通道上就緒時(shí),從機(jī)置高 awready 信號,完成一次地址傳輸。與上 ~awready 是因?yàn)閭鬏斨恍枰谝淮螘r(shí)鐘上升沿 valid,ready 信號同時(shí)置高即可,在下一個(gè)周期,從機(jī)需要負(fù)責(zé)將 awready 信號置低,主機(jī)一般也會將 awvalid 信號置低,不過這和從機(jī)就不相干了。
在置高 awready 信號的條件中與上了 aw_en 變量,這是為了使從機(jī)有控制地址通道傳輸?shù)哪芰ΑT谡麄€(gè)寫傳輸周期中,即地址-數(shù)據(jù)-寫回復(fù)信號傳輸持續(xù)期間,如果主機(jī)又發(fā)起了一次新的寫傳輸請求,置高 awvalid,wvalid信號,那么此時(shí) aw_en 信號為低,從機(jī)將不會響應(yīng)直至從機(jī)完成寫回復(fù),結(jié)束本次傳輸后,才回去響應(yīng)下一次傳輸。
AXI 寫通道從機(jī)的守則根據(jù)上述協(xié)議中守則,從機(jī)可以等待 AWVALID 或者 WVALID,也可以等兩者都就緒后,再置起 AWREADY,那么本實(shí)現(xiàn)中等待的就是兩者都置起。也就是說雖然數(shù)據(jù)在地址后一周期傳輸,但是在地址傳輸時(shí),數(shù)據(jù)已經(jīng)就緒。
在從機(jī)置起 awready 信號完成地址通道傳輸?shù)耐瑫r(shí),從機(jī)也會從寫地址上鎖存當(dāng)前的寫地址。鎖存的寫地址會用于其后一個(gè)周期時(shí)刻來判斷待寫入的寄存器。
有趣的是鎖存地址的過程塊可以合并到上述產(chǎn)生 awready 的過程塊中去,兩者的使能條件相同。但從 Verilog 的哲學(xué)來說,合則節(jié)省代碼行數(shù),分則使邏輯功能劃分更清楚。反正代碼已經(jīng)很多行了,如果分開寫能夠更好體驗(yàn)邏輯功能,那就分開寫吧。
接下來是寫數(shù)據(jù)通道的時(shí)序產(chǎn)生,同寫地址通道類似,從機(jī)的寫數(shù)據(jù)通道中的 wready 信號也根據(jù)主機(jī)的 wvalid 信號產(chǎn)生。當(dāng) wvalid 為高,則置高 wready 一個(gè)周期。因?yàn)楸緦?shí)現(xiàn)中寫地址通道和寫數(shù)據(jù)通道是嚴(yán)格一對一的關(guān)系,所以 wready 的信號的產(chǎn)生和 awready 信號在同一個(gè)周期中進(jìn)行,判斷 wvalid 與 awvalid 同時(shí)為高 。如果實(shí)現(xiàn)的是支持突發(fā)傳輸?shù)?AXI-Full 協(xié)議,那么寫數(shù)據(jù)將和寫地址就失去了這種一一對應(yīng)的關(guān)系。(一次地址傳輸對應(yīng)多次數(shù)據(jù)傳輸)
本實(shí)現(xiàn)中最為重量級的一個(gè)部分是寫數(shù)據(jù)的接收。首先判斷讀取寫數(shù)據(jù)的使能條件。如前文所說:寫地址傳輸?shù)暮笠粋€(gè)時(shí)刻為寫數(shù)據(jù)傳輸,寫地址的完成的信號即作為寫數(shù)據(jù)的使能信號。
當(dāng)寫使能有效后,邏輯首先根據(jù)寫地址判斷主機(jī)所要操作的寄存器。這里對寫地址進(jìn)行切片:
axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]ADDR_LSB 與寄存器地址寬度相關(guān):32 位時(shí)為 2 ,64 位時(shí)為 3 。選擇寄存器時(shí)不需要考慮地址的 [ADDR_LSB-1 : 0] 部分。
寄存器寬度為 32 位時(shí),每個(gè)寄存器 4 個(gè)字節(jié),選擇寄存器時(shí),不需要判斷地址低兩位,因?yàn)檫@是單個(gè)寄存器內(nèi)部的字節(jié)地址。
OPT_MEM_ADDR_BITS 與寄存器的數(shù)量有關(guān),2^(OPT_MEM_ADDR_BITS+1) = 寄存器數(shù)量。So:
地址線的位寬 = ADDR_LSB+OPT_MEM_ADDR_BITS + 1以 4 個(gè) 32 位寄存器為例,地址線的寬度 = log2(4*4) = 4 ,即 2 + 1 + 1、
#注:在根據(jù)地址選擇寄存器時(shí),當(dāng)然也可以對整個(gè)地址寬度進(jìn)行判斷,但這樣會造成資源的浪費(fèi)。
在完成寄存器的選擇后,將總線上已經(jīng)就緒的寫數(shù)據(jù)寫入寄存器。如果不使用 STRB 信號對某些字節(jié)進(jìn)行屏蔽,那么這樣就完事了: slv_reg0 <= S_AXI_WDATA;
STRB 信號的作用是屏蔽一些字節(jié)的寫入,比如某個(gè)寄存器只有 8 bit,或者 16 bit,但寄存器的寫入必須以 32 bit 為單位。完整寫入 32 bit 勢必會影響臨近的其他寄存器,此時(shí)可以使用 STRB 信號,指定要寫入的字節(jié)位置為 1,屏蔽字節(jié)位置寫 0 。
代碼中使用 for 循環(huán),以字節(jié)為單位,判斷 STRB 信號為 1,則進(jìn)行寫入,否則保持原寄存器值不變。
完成一次寫操作的最后一步,是由從機(jī)在寫回復(fù)通道上對此次傳輸進(jìn)行評價(jià)...啊不 響應(yīng)。
在完成傳輸,即寫數(shù)據(jù)/地址通道完成握手后的下一周期,從機(jī)置起 bvalid 信號,并在 bresp 信號上給出 'OK' 信號。在響應(yīng)通道完成握手后,置低 bvalid 完成響應(yīng)操作。
這里我們的從機(jī)要么不給,要就回復(fù) 'OK',那么就不會有錯(cuò)誤的情況發(fā)生么?
我的理解是在這個(gè)模塊中,和主機(jī)在芯片內(nèi)部通信,就隔幾個(gè)寄存器,幾個(gè) um 的距離,一般不會出現(xiàn)傳輸錯(cuò)誤的情況。再者說,出現(xiàn)了錯(cuò)誤,我們從機(jī)也不知道啊。(無辜.jpg)
筆者個(gè)人唯二遇到 AXI 回復(fù)錯(cuò)誤的情況分別發(fā)生在 interconnect 和 DataMover IP 上。一是在 DataMover 上向 IP 寫了錯(cuò)誤的 CMD,IP 回復(fù) Internal error;二是 interconnect 和從機(jī)的連接有問題,interconnect 無法轉(zhuǎn)發(fā)請求,回復(fù) decode error;這些錯(cuò)誤回復(fù)在開發(fā)階段對 Debug 是很有幫助的,但生產(chǎn)環(huán)境中,主機(jī)一般不會對這些錯(cuò)誤回復(fù)進(jìn)行處理。
主機(jī)可能是這樣一種佛系思想:
小錯(cuò)誤不影響功能,錯(cuò)了也就錯(cuò)了,不管Fatal 錯(cuò)誤,啊,我 dump 了,所以也不管
好了,后續(xù)的文章可能會對 response 做進(jìn)一步分析。
讀通道邏輯和寫通道類似,本文就不再做進(jìn)一步展開,讀者可以自行閱讀代碼。這里有一個(gè)建議,即使筆者在完成了這篇文章的寫作后,再通過仿真也解決了一些疑惑。所以這里建議讀者還是要親自仿真一下,獲得第一手感性認(rèn)識。
在設(shè)計(jì)中集成接口模塊
在開發(fā)完成了一個(gè)寄存器總線接口模塊后(假裝都是我們自己寫的),我們有兩種方式將其集成到頂層設(shè)計(jì)中。
結(jié)語
本文我們通過學(xué)習(xí) Xilinx 在 IP 接口中提供的 AXI-Lite 接口實(shí)現(xiàn)的模板,有 AXI 的實(shí)現(xiàn)有了更深入的了解,其實(shí)從 AXI-Lite 的角度來說,很簡單哈,這一部分也是 AXI 協(xié)議的基礎(chǔ)部分。在后續(xù)的文章中,我們將對 AXI 協(xié)議的實(shí)現(xiàn)做更深入的了解。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的axi时序图_深入 AXI4总线(E3)实战:制作一个 AXI 接口 IP的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php mysql 字段不为空_Thin
- 下一篇: android客户端cookies,an