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