01 |
什么是接口? |
SystemVerilog 接口的開發旨在讓設計中層級之間的連接變得更加輕松容易。 您可以把這類接口看作是多個模塊共有的引腳集合。與必須在每個模塊上定義多個引腳不同的是,您只需在接口中對引腳定義一次,之后只需在模塊上定義接口即可。 如果稍后接口中涉及的信號被更改,則僅需更改接口即可。
這樣就可以將大量信息壓縮到較少代碼行,但第一次寫接口可能會有點困難。在第一次看別人寫的接口時,也可能會很難進行解讀。 本文將介紹接口的基礎知識以及如何在 Vivado 中正確使用接口。
我們將把一個沒有接口的小型測試用例轉換為使用接口的測試用例。 這個測試用例的示例 RTL 代碼將在本文的最后一節中介紹。
此原始測試用例的原理圖如下所示:
原始測試用例
02 |
定義接口 |
首先,必須先定義接口。 所需要的只是將被接口替換的多個模塊共有的信號名稱。 知道該列表后,接口聲明如下:
interface my_int;
logic sel;
logic [9:0] data1, data2, result;
endinterface : my_int
上面的代碼聲明了一個名為“my_int”的接口。 它還聲明了四個信號,一個稱為“sel”和三個稱為“data1”、“data2”和“result”的 10 位寬總線。這些是將被接口替換的模塊的引腳。請注意,即使在兩個模塊中都使用“clk”信號,此處接口也沒使用 clk 信號。 將控制信號放在接口中是可以的,但這是個人偏好的問題。本文作者更喜歡將時鐘信號與接口分開。
03 |
使用接口 |
一旦聲明了接口,就可以象使用模塊的任何端口一樣使用此接口。在下級模塊中將使用接口替換端口,編碼樣式應更改如下:
原始版本:
module bottom2(
input clk,
input sel,
input [9:0] data1, data2,
output logic [9:0] result);
替換后版本:
module bottom2(
my_int int1,
input clk);
請注意,與將端口聲明為輸入或輸出不同的是,接口會被聲明為“my_int”(這是給接口指定的名稱)的類型, 而且還為其指定了一個實例名稱“int1”。
由于下級模塊的引腳已被移除,因此不能再以相同方式引用。 與直接引用引腳不同的是,他們需要基于接口名稱引用。
其語法是“
always@(posedge clk) begin
if (sel == 1)
result <= data1;
else
result <= data2;
end
現在,需要將其更改為以下內容:
always@(posedge clk) begin
if (int1.sel == 1)
int1.result <= int1.data1;
else
int1.result <= int1.data2;
end
在下級模塊中將引腳更改為接口之后,對這些引腳的引用已被更改為引用接口,還需要修改將這些模塊實例化的上級模塊。
在使用接口之前,頂層的模塊引腳將連接到設計中聲明的信號。所以現在我們要連接接口,而不是要連接信號。首先需要做的事是聲明一個相同類型的接口。
my_int int3();
上面的代碼聲明了一個類型為“my_int”的接口,并為其指定了一個實例名稱“int3”。
和前面一樣,對此接口內的信號的所有引用都需要使用“
接下來,下級模塊實例化。
bottom2 u1(int3,clk)
上面的 RTL 會對“bottom2”模塊進行實例化,給它指定一個實例名稱“u1”。 在“bottom2”模塊中聲明的接口“int1”現在與已在上一層聲明的接口“int3”相關聯。 進行這些更改后,設計的原理圖如下所示:
轉換為接口后的設計
04 |
添加 Modport |
添加接口后,該工具已創建正確的連接,但您可能會注意到原理圖看起來有點奇怪。 來自兩個下級層次的“data1”和“data2”似乎正在驅動同一個網絡。如果您進入這些下級模塊,您會看到沒有多驅動問題,因為其中一個模塊將“data1”和“data2”視為輸入。
原理圖看起來奇怪的原因是創建的接口沒有告訴工具哪些引腳在充當輸入,哪些引腳在充當輸出。 當工具創建連接時,并明確知道如何連接引腳,因此它先建立了連接,然后在分析行為時才找出了引腳的方向。
雖然這樣可行,但還是強烈建議將接口的輸入/輸出信息提供給工具。這是通過使用 modport 來完成的。Modport 在接口內部進行聲明,告訴工具哪些信號是輸入,哪些是輸出。由于不同的模塊的引腳的方向各不相同,因此通常每個接口會聲明多個 modport。
modport 的語法是:
modport
例如,以下 RTL 創建了一個名為“b1”的 modport,并將 result 信號作為輸出,將其他信號都作為輸入信號。
modport b2 (input sel, data1, data2, output result)
然后,modport 被用于下層端口列表的接口聲明中。
module bottom2 (
my_int.b2 int1,
input clk);
上面的代碼告訴工具如下信息:
-
“bottom2”將使用接口“my_int”,并為其指定名為“int1”的實例名稱
-
在此接口中,result 將是輸出
-
“sel”、“data1”和“data2”將是輸入。
更改完成后,新原理圖將如下所示:
添加 modport 后的設計
05 |
結論 |
編寫本文是為了說明接口在連接具有相似信號的邏輯時的用處,但這不是接口的唯一用途。 此外,接口可以使用包括任務和功能在內的許多特性,甚至可以進行參數化。
我們將在以后的文章中探討其他功能。
沒有接口的原始 RTL: |
module bottom1 (
input clk,
input [9:0] d1, d2,
input s1,
input [9:0] result,
output logic sel,
output logic [9:0] data1, data2,
output logic equal);
always@(posedge clk) begin
if (d1 == d2)
equal <= 1;
else
equal <= 0;
end
always@(posedge clk) begin
if (s1 == 1) begin
data1 <= d1;
end
else begin
data2 <= d2;
end
end
always@(posedge clk) begin
sel <= ^result;
end
endmodule
module bottom2 (
input clk,
input sel,
input [9:0] data1, data2,
output logic [9:0] result );
always@(posedge clk) begin
if (sel == 1)
result <= data1;
else
result <= data2;
end
endmodule
module top (
input clk,
input s1,
input [9:0] d1, d2,
output my_sel,
output equal);
logic [9:0] data1, data2, result;
logic sel;
assign my_sel = sel;
bottom1 u0 (.clk(clk), .d1(d1), .d2(d2), .s1(s1), .result(result), .sel(sel), .data1(data1), .data2(data2), .equal(equal));
bottom2 u1 (.clk(clk), .sel(sel), .data1(data1), .data2(data2), .result(result));
endmodule
第一次添加接口的設計: |
interface my_int;
logic sel;
logic [9:0] data1, data2, result;
endinterface : my_int
module bottom1 (
my_int int1,
input clk,
input [9:0] d1, d2,
input s1,
output logic equal);
always@(posedge clk) begin
if (d1 == d2)
equal <= 1;
else
equal <= 0;
end
always@(posedge clk) begin
if (s1 == 1) begin
int1.data1 <= d1;
end
else begin
int1.data2 <= d2;
end
end
always@(posedge clk) begin
int1.sel <= ^int1.result;
end
endmodule
module bottom2 (
my_int int1,
input clk);
always@(posedge clk) begin
if (int1.sel == 1)
int1.result <= int1.data1;
else
int1.result <= int1.data2;
end
endmodule
module top (
input clk,
input s1,
input [9:0] d1, d2,
output my_sel,
output equal);
logic [9:0] data1, data2, result;
logic sel;
my_int int3();
assign my_sel = int3.sel;
bottom1 u0 (int3, clk, d1, d2, s1, equal);
bottom2 u1 (int3, clk);
endmodule
使用modports進行設計: |
interface my_int;
logic sel;
logic [9:0] data1, data2, result;
modport b1 (input result, output sel, data1, data2);
modport b2 (input sel, data1, data2, output result);
endinterface : my_int
module bottom1 (
my_int.b1 int1,
input clk,
input [9:0] d1, d2,
input s1,
output logic equal);
always@(posedge clk) begin
if (d1 == d2)
equal <= 1;
else
equal <= 0;
end
always@(posedge clk) begin
if (s1 == 1) begin
int1.data1 <= d1;
end
else begin
int1.data2 <= d2;
end
end
always@(posedge clk) begin
int1.sel <= ^int1.result;
end
endmodule
module bottom2 (
my_int.b2 int1,
input clk);
always@(posedge clk) begin
if (int1.sel == 1)
int1.result <= int1.data1;
else
int1.result <= int1.data2;
end
endmodule
module top (
input clk,
input s1,
input [9:0] d1, d2,
output my_sel,
output equal);
logic [9:0] data1, data2, result;
logic sel;
my_int int3();
assign my_sel = int3.sel;
bottom1 u0 (int3, clk, d1, d2, s1, equal);
bottom2 u1 (int3, clk);
endmodule
原文標題:設計技巧:在 Vivado Synthesis 中使用 SystemVerilog 接口連接邏輯
文章出處:【微信公眾號:賽靈思】歡迎添加關注!文章轉載請注明出處。
-
賽靈思
+關注
關注
32文章
1794瀏覽量
131246 -
Vivado
+關注
關注
19文章
812瀏覽量
66471
發布評論請先 登錄
相關推薦
評論