1.為什么是RTL
在數字前端領域,RTL幾乎與“設計代碼”概念相同。RTL的英文全稱為Register Transfer Level,中文一般翻譯為寄存器傳輸級,原本是HDL建模的一種層次。以Verilog HDL為例,其建模層次包括系統級、算法級、RTL級、門級和開關級,其中:
*系統級和算法級:描述層次較高,較多的忽略細節時序,設計精度低,但開發容易,設計難度低
*門級和開關級:描述層次較低,設計難度很大,但設計精細度很高
*RTL級:設計難度和設計精度的trade off,同時也是EDA工具能較好處理的最高層級
這里舉出一個乘加器的RTL例子,代碼如下所示:
reg [7:0] a_reg;
reg [7:0] b_reg;
reg [15:0] mul_reg;
reg [15:0] c_reg;
reg [16:0] result_reg;
always @ (posedge clk)
mul_reg <= a_reg * b_reg;
always @ (posedge clk)
result_reg <= c_reg + mul_reg;
這段代碼中涉及5個寄存器,以及寄存器之間的關系,例如mul_reg就等于a_reg和b_reg的乘積,RTL級的描述就是以寄存器為基點(例如a_reg
、b_reg
、mul_reg
),描述寄存器之間的關系(例如mul_reg=a_reg*b_reg
)的建模層次。
2.RTL拆解
2.1.R(Reg)
RTL首先為R,即寄存器,在RTL級中的寄存器為一種理想寄存器,其具有以下幾種特征:
*存儲:寄存器具有存儲特性,在不復位和賦值的情況下會一直保持當前的值
*延遲:由于寄存器是邊沿敏感器件,僅能在時鐘上升沿(一般不使用下降沿)可以被賦值,因此輸入的數據延遲一個cycle才能在輸出上體現
*時鐘:寄存器具有時鐘輸入端口,賦值的條件時時鐘邊沿+復位無效+有效信號(若有)
*復位:寄存器可以具有同步或異步復位端口,也可以沒有復位端口,復位是優先級最高的賦值端口,會將寄存器輸出變為復位值,且異步復位是立即有效的
對于Reg,可以分為以下幾種類型:
*存儲:用于保存當前的值供下次調用,使用了寄存器的存儲特性,為了滿足功能要求添加,在更上層的建模中可見
*打拍:用于打斷組合邏輯路徑,為了滿足時序要求添加,刪除后(匹配控制路徑)對功能無影響,在更上層的建模中不可見
*狀態:用于保存狀態,以自身狀態為下一狀態的輸入,常見為狀態機、隱式狀態機和計數器幾種,是一條控制路徑或子控制類路徑的起點
根據Reg處于數據路徑還是控制路徑,常見的形態如下表所示:
可以使用下面的例子展示,這里的例子是一個以累加器結尾的流水線,上方是控制路徑,下方是數據路徑。控制路徑的起點是分類為狀態的寄存器,形式為狀態機,后續逐級對狀態信息打拍,這里的目的是為了匹配流水線的延遲,因此分類為打拍,最后將狀態存儲供后續使用,是為了功能添加,因此分類為存儲。數據路徑為流水線,添加流水線的目的是提高運行速率,為了匹配時序目標,因此第一、第二、第三級流水線的分類均為打拍,而最后一級寄存器是累加寄存器,添加的目的是為了保持數據,滿足累加的功能要求,因此分類為存儲:
最后,根據不同類型的寄存器,設計時需要考慮的問題都相對固定,首先分析寄存器是否有必要存在和基本的形式,分析的角度如下所示:
*狀態寄存器:當前設計是集中式控制還是分布式控制,若為集中式控制,狀態寄存器是否需要移動到控制模塊中;若為分布式控制,狀態寄存器的形態為計數器還是顯式狀態機。
*打拍寄存器:邏輯路徑是否過長,若過長,則添加在哪個點既能合理的分割邏輯路徑,又能使用較少bit的寄存器
*存儲寄存器:存儲的訪問方式,容量需求如何,是否需要靈活同時讀寫,是否可以用memory代替
隨后對于寄存器,有一些基本的設計要素,是每個寄存器都要考慮的,包括:
*工作在哪個時鐘域下,和輸入寄存器之間是否存在跨時鐘域的關系
*是否需要異步和同步復位信號,若需要,位于哪個復位域(和其他哪些寄存器能一起復位)
*是否需要用前清零和用后清零
*什么是否需要對其進行刷新,刷新是否需要有效信號(是否考慮自動門控)
對其復位、自動門控和復位的處理如下表所示,其中是否添加異步/同步復位和自動門控優先級主要與位置有關,復位處理主要與分類有關:
2.2.T(Transfer)
Transfer用于描述組合邏輯,即寄存器之間的連接關系,必須依附于寄存器(或端口)存在。Transfer可以用函數表示,描述其依附的Reg的值如何進行更新。以一個累加器為例,其代碼如下所示:
input [7:0] din;
input din_vld;
reg [7:0] dout;
wire dout_transfer;
assign dout_transfer = dout + din;
always @ (posedge clk or negedge rst_b) begin
if(~rst_b) begin
dout <= 8'b0;
end else if(din_vld) begin
dout <= dout_transfer;
end
end
其中dout
是數據路徑上的存儲寄存器,對應的transfer的函數表達式如下所示:
Transfer又可以分為兩類,分別是有狀態和無狀態:
*有狀態Transfer:其依附的寄存器的值作為transfor的輸入,如上面的例子就是一個有狀態的Transfor,一般來說,有狀態的Transfor只會依附在狀態寄存器、存儲寄存器(累運算)上
*無狀態Transfor:其依附的寄存器的值和transfor的輸入無關,一般依附在打拍寄存器和一部分存儲寄存器(純存儲)上
這兩種類型的Transfer的例子如下圖所示:
和Reg不同,Transfer的功能和基本實現模式由設計人員通過RTL代碼描述,而具體而細節的實現方式一般由綜合器確定(也可以由設計人員手工指定),綜合器主要會對Transfer進行優化,Transfer對應的變量可能在綜合后被重命名,按原有名稱在網表中可能無法找到。
2.3.L(Level)
Level就是層級,這里對R和T做一個總結,以R(和Port)為節點,以T為邊,可以構建一個有向、有環、帶自環邊的圖,如下圖所示:
圖中的節點分為寄存器、端口和常數值(一般忽略),而邊分為控制線和數據線,控制線負責管理刷新時刻,而數據線負責生成刷新值。按另一種說法,如果將一個寄存器的功能用一個或多個不包括分支的函數表示,則函數中的輸入值就都是數據線,其他信號就是控制線,
RTL代碼實質就是描述一張圖的關系,如下一段代碼:
input din_vld
reg cnt_en;
reg [7:0] cnt;
output dout_vld;
always @ (posedge clk or negedge rst_b) begin
if(~rst_b) begin
cnt_en <= 1'b0;
end else if(cnt == 8'd200) begin
cnt_en <= 1'b0; // 數據線f(x) = 0
end else if(din_vld) begin
cnt_en <= 1'b1; // 數據線f(x) = 1
end
always @ (posedge clk or negedge rst_b) begin
if(~rst_b) begin
cnt <= 8'b0;
end else if(din_vld) begin // 控制線
cnt <= 8'b0; // 數據線f(x) = 0
end else if(cnt_en) begin
cnt <= cnt + 1'b1; // 數據線f(x) = cnt + 1
end
assign dout_vld = (cnt > 8'd128); // 數據線f(x) = 0 和 f(x) = 1
這段代碼描述了一個計數器生成控制信號的過程,可以轉換為如下所示的圖。其中紅線為控制線,黑線為數據線,忽略了常數值:
3.RTL和Reg/Wire的關系
RTL中的Reg和Transfer與Verilog中常用的Reg和Wire的關系是一個老生常談的話題,這里直接給出結論:
*Verilog中的Reg類型可以建模RTL中的Reg(時序邏輯)和Transfer(組合邏輯),但RTL中的Reg只能用Verilog中的Reg類型建模
*Verilog中的Wire類型只能用來建模RTL中的Transfer(組合邏輯),但RTL中的Transfer(組合邏輯)既可以用Verilog中的Wire類型建模,也可以用Verilog中的Reg類型建模
-
寄存器
+關注
關注
31文章
5336瀏覽量
120230 -
EDA工具
+關注
關注
4文章
267瀏覽量
31785 -
RTL
+關注
關注
1文章
385瀏覽量
59759 -
狀態機
+關注
關注
2文章
492瀏覽量
27528 -
乘加器
+關注
關注
0文章
4瀏覽量
6017
發布評論請先 登錄
相關推薦
評論