【轉(zhuǎn)】RTL概念與常用RTL建模
RTL概念與常用RTL建模

? ? ? ? ? ? ? ? ? ?
lzhang97 ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ?于?2021-06-11 16:00:15?發(fā)布 ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ?30756 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?收藏 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?366 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
分類(lèi)專(zhuān)欄: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Verilog學(xué)習(xí)筆記 ? ? ? ? ? ? ? ? ? ? ? ? ? ?文章標(biāo)簽: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?fpga ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?verilog ? ? ? ? ? ? ? ? ? ?
版權(quán) ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Verilog學(xué)習(xí)筆記 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?專(zhuān)欄收錄該內(nèi)容 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
7 篇文章 ? ? ? ? ? ? ? ? ? ? ? ?19 訂閱
訂閱專(zhuān)欄 ? ? ? ? ? ? ? ? ? ?
RTL和綜合的概念
RTL(Register Transfer Level,寄存器傳輸級(jí))指:不關(guān)注寄存器和組合邏輯的細(xì)節(jié)(如使用了多少邏輯門(mén),邏輯門(mén)之間的連接拓?fù)浣Y(jié)構(gòu)等),通過(guò)描述寄存器到寄存器之間的邏輯功能描述電路的HDL層次。RTL級(jí)是比門(mén)級(jí)更高的抽象層次,使用RTL級(jí)語(yǔ)言描述硬件電路一般比門(mén)級(jí)描述簡(jiǎn)單高效得多。
RTL級(jí)語(yǔ)言的最重要的特性是:RTL級(jí)描述是可綜合的描述層次。
綜合(Synthesize)是指將HDL語(yǔ)言、原理圖等設(shè)計(jì)輸入翻譯成由與、或、非門(mén)等基本邏輯單元組成的門(mén)級(jí)連接(網(wǎng)表),并根據(jù)設(shè)計(jì)目標(biāo)與要求(約束條件)優(yōu)化所生成的邏輯連接,輸出門(mén)級(jí)網(wǎng)表文件。RTL級(jí)綜合指將RTL級(jí)源碼翻譯并優(yōu)化為門(mén)級(jí)網(wǎng)表。
RTL級(jí)的基本要素和設(shè)計(jì)步驟
典型的RTL設(shè)計(jì)包含一下3個(gè)部分
時(shí)鐘域描述:描述所使用的所有時(shí)鐘,時(shí)鐘之間的主從與派生關(guān)系,時(shí)鐘域之間的轉(zhuǎn)換;
時(shí)序邏輯描述(寄存器描述):根據(jù)時(shí)鐘沿的變換,描述寄存器之間的數(shù)據(jù)傳輸方式;
組合邏輯描述:描述電平敏感信號(hào)的邏輯組合方式與邏輯功能。
書(shū)中推薦的設(shè)計(jì)步驟:
功能定義與模塊劃分:根據(jù)系統(tǒng)功能的定義和模塊劃分準(zhǔn)則劃分各個(gè)功能模塊;
定義所有模塊的接口:首先清晰定義每個(gè)模塊的接口,完成每個(gè)模塊的信號(hào)列表,這種思路與Modular Design(模塊化設(shè)計(jì)方法)一致,利于模塊重用、調(diào)試、修改;
設(shè)計(jì)時(shí)鐘域:根據(jù)設(shè)計(jì)的時(shí)鐘復(fù)雜程度定義時(shí)鐘之間的派生關(guān)系,分析設(shè)計(jì)中有哪些時(shí)鐘域,是否存在異步時(shí)鐘域之間的數(shù)據(jù)交換;對(duì)于PLD器件設(shè)計(jì),還需要確認(rèn)全局時(shí)鐘是否使用PLL/DLL完成時(shí)鐘的分頻、倍頻、移相等功能,哪些時(shí)鐘使用全局時(shí)鐘資源布線,哪些時(shí)鐘使用第二全局時(shí)鐘資源布線;全局時(shí)鐘的特點(diǎn)是:幾乎沒(méi)有Clock Skew(時(shí)鐘傾斜),有一定的Clock Delay(時(shí)鐘延遲),驅(qū)動(dòng)能力最強(qiáng);第二全局時(shí)鐘的特點(diǎn)是:有較小的Clock Shew,較小的Clock Delay,時(shí)鐘驅(qū)動(dòng)能力較強(qiáng);
補(bǔ)充:時(shí)鐘抖動(dòng)(Clock Jitter):指芯片的某一個(gè)給定點(diǎn)上時(shí)鐘周期發(fā)生暫時(shí)性變化,使得時(shí)鐘周期在不同的周期上可能加長(zhǎng)或縮短。時(shí)鐘偏移(Clock Skew):是由于布線長(zhǎng)度及負(fù)載不同引起的,導(dǎo)致同一個(gè)時(shí)鐘信號(hào)到達(dá)相鄰兩個(gè)時(shí)序單元的時(shí)間不一致。區(qū)別:Jitter是在時(shí)鐘發(fā)生器內(nèi)部產(chǎn)生的,和晶振或者PLL內(nèi)部電路有關(guān),布線對(duì)其沒(méi)有影響。Skew是由不同布線長(zhǎng)度導(dǎo)致的不同路徑的時(shí)鐘上升沿到來(lái)的延時(shí)不同。
考慮設(shè)計(jì)的關(guān)鍵路徑:關(guān)鍵路徑是指設(shè)計(jì)中時(shí)序要求最難以滿足的路徑,設(shè)計(jì)的時(shí)序要求主要體現(xiàn)在頻率、建立時(shí)間、保持時(shí)間等時(shí)序指標(biāo)上,;在設(shè)計(jì)初期,設(shè)計(jì)者可以根據(jù)系統(tǒng)的頻率要求,粗略的分析出設(shè)計(jì)的時(shí)序難點(diǎn)(如最高頻率路徑、計(jì)數(shù)器的最低位、包含復(fù)雜組合邏輯的時(shí)序路徑等),通過(guò)一些時(shí)序優(yōu)化手段(如Pipeline、Retiming、邏輯復(fù)制等)從代碼上緩解設(shè)計(jì)的時(shí)序壓力,這種方法以但依靠綜合與布線工具的自動(dòng)優(yōu)化有效的多;
頂層設(shè)計(jì):RTL設(shè)計(jì)推薦使用自頂而下的設(shè)計(jì)方法,因?yàn)檫@種設(shè)計(jì)方法與模塊規(guī)劃的順序一致,而且更有利于進(jìn)行Modular Design,可以并行開(kāi)展設(shè)計(jì)工作,提高模塊復(fù)用率;
FSM設(shè)計(jì):FSM是邏輯設(shè)計(jì)最重要的內(nèi)容之一;
時(shí)序邏輯設(shè)計(jì):首先根據(jù)時(shí)鐘域規(guī)劃好寄存器組,然后描述各個(gè)寄存器組之間的數(shù)據(jù)傳輸方式;
組合邏輯設(shè)計(jì):一般來(lái)說(shuō),大段的組合邏輯最好與時(shí)序邏輯分開(kāi)描述,這樣更有利于時(shí)序約束和時(shí)序分析,使綜合器和布局布線器達(dá)到更好的優(yōu)化效果。
常用RTL級(jí)建模
非阻塞賦值、阻塞賦值、連續(xù)賦值
對(duì)于時(shí)序邏輯,即always塊的敏感信號(hào)列表為邊沿敏感信號(hào),統(tǒng)一使用非阻塞賦值“<=”;
對(duì)于always塊敏感信號(hào)列表為電平敏感的組合邏輯,統(tǒng)一使用阻塞賦值“=”;
對(duì)于assign關(guān)鍵字描述的組合邏輯,統(tǒng)一使用阻塞賦值“=”,變量被定義為wire型信號(hào)。
寄存器電路建模
寄存器和組合邏輯是數(shù)字邏輯電路的兩大基本要素,寄存器一般和同步時(shí)序邏輯關(guān)聯(lián),其特點(diǎn)是僅當(dāng)時(shí)鐘的邊沿到達(dá)時(shí),才有可能發(fā)生輸出的改變。
寄存器變量聲明:寄存器定義為reg型,但要注意的是,反之不一定成立;
時(shí)鐘輸入:在每個(gè)時(shí)鐘的正沿或負(fù)沿對(duì)數(shù)據(jù)從進(jìn)行處理。
異步復(fù)位/置位:絕大多數(shù)目標(biāo)器件的寄存器模型都包含異步復(fù)位/置位端;
同步復(fù)位/置位:任何寄存器都可以實(shí)現(xiàn)同步復(fù)位/置位功能;
同時(shí)使用時(shí)鐘上升沿和下降沿的問(wèn)題:有時(shí)因?yàn)閿?shù)據(jù)采樣或者調(diào)整數(shù)據(jù)相位等需求,設(shè)計(jì)者會(huì)在一個(gè)always的敏感信號(hào)列表中同時(shí)使用時(shí)鐘的posedge和negedge,或者在兩個(gè)always的敏感信號(hào)列表中分別使用posedge和nesedge對(duì)某個(gè)寄存器電路操作;這兩種描述下,時(shí)鐘上升沿和下降沿到來(lái)時(shí),寄存器電路都會(huì)做相應(yīng)的操作,這個(gè)雙邊沿電路等同于使用了原來(lái)時(shí)鐘的倍頻時(shí)鐘的單邊沿操作電路,這種操作是不推薦的;芯片內(nèi)部的PLL/DLL和一些時(shí)鐘電路往往只能對(duì)一個(gè)邊沿有非常好的指標(biāo),而另一個(gè)沿的抖動(dòng)、偏移、斜率等指標(biāo)不見(jiàn)得非常優(yōu)化,有時(shí)同時(shí)使用時(shí)鐘的正負(fù)邊沿會(huì)因?yàn)闀r(shí)鐘的抖動(dòng)、偏斜、占空比、斜率等問(wèn)題造成一定的性能惡化;一般推薦將原時(shí)鐘通過(guò)PLL/DLL倍頻,然后使用倍頻時(shí)鐘的單邊沿進(jìn)行操作。
組合邏輯建模
always 模塊的敏感信號(hào)列表為電平敏感信號(hào)的組合邏輯電路
always模塊的敏感信號(hào)列表為所有判定條件和輸入信號(hào),在使用這種結(jié)構(gòu)描述組合邏輯時(shí)一定要將敏感列表列寫(xiě)完整。在always塊中可以使用高級(jí)編程語(yǔ)言,使用阻塞賦值“=”,雖然信號(hào)被定義位reg型,但最終綜合實(shí)現(xiàn)結(jié)果并不是寄存器,而是組合邏輯,定義為reg型是純語(yǔ)法需要。
assign 等語(yǔ)句描述的組合邏輯電路
這種形式描述組合邏輯電路適用于描述那些相對(duì)簡(jiǎn)單的組合邏輯,信號(hào)一般被定義位wire型。
雙向端口與三態(tài)信號(hào)建模
所有的雙向總線應(yīng)該在頂層模塊定義為三態(tài)信號(hào),禁止在頂層以外的其他子層次定義雙向端口。為了避免仿真和綜合實(shí)現(xiàn)結(jié)果不一致,并便于維護(hù),強(qiáng)烈建議僅在頂層定義雙向總線和例化三態(tài)信號(hào),禁止在除頂層以外的其他層次賦值高阻態(tài)"Z",在頂層將雙向信號(hào)分為輸入和輸出信號(hào)兩種類(lèi)型,然后根據(jù)需要分別傳遞到不同的子模塊中,這樣做的另一個(gè)好處是便于描述仿真激勵(lì)。
module bibus (clk, rst, sel, data_bus, addr);
input ? ? ? clk, rst, sel;
input [7:0] addr;
inout [7:0] data_bus;
wire [7:0] data_in, data_out;
assign data_in = data_bus;
assign data_bus = (sel) ? data_out : 8'bZ;
decode decode_inst (.clock (clk),
? ? ? ? ? ? ? ? ? ?.reset (rst),
? ? ? ? ? ? ? ? ? ?.data_bus_in (data_in),
? ? ? ? ? ? ? ? ? ?.addr_bus (addr),
? ? ? ? ? ? ? ? ? ?.data_bus_out (data_out)
? ? ? ? ? ? ? ? ? ?);
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
如果三態(tài)總線的使能關(guān)系比較復(fù)雜,不是單一信號(hào),此時(shí)可以使用嵌套的問(wèn)號(hào)表達(dá)式,或者使用case語(yǔ)句描述。
嵌套的問(wèn)號(hào)表達(dá)式
module complex_bibus (clk, rst, sel1, sel2, sel3, data_bus, addr);
input ? ? ? clk, rst;
input ? ? ? sel1, sel2, sel3;
input [7:0] addr;
inout [7:0] data_bus;
wire [7:0] data_in;
//wire [7:0] data_out; //use wire type
wire [7:0] decode_out;
wire [7:0] cnt_out;
assign data_in = data_bus;
assign data_bus = (sel1)? decode_out : ((sel2)? cnt_out : ((sel3)? 8'b11111111: 8'bZZZZZZZZ));
decode decode_inst (.clock (clk),
? ? ? ? ? ? ? ? ? ?.reset (rst),
? ? ? ? ? ? ? ? ? ?.data_bus_in (data_in),
? ? ? ? ? ? ? ? ? ?.addr_bus (addr),
? ? ? ? ? ? ? ? ? ?.data_bus_out (decode_out)
? ? ? ? ? ? ? ? ? ?);
? ? ? ? ? ? ? ? ? ?
counter counter_inst (.clock (clk),
? ? ? ? ? ? ? ? ? ?.reset (rst),
? ? ? ? ? ? ? ? ? ?.data_bus_in (data_in),
? ? ? ? ? ? ? ? ? ?.cnt_out (cnt_out)
? ? ? ? ? ? ? ? ? ?); ? ? ? ? ? ?
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
case語(yǔ)句(如果使能情況比較復(fù)雜,通過(guò)case進(jìn)行羅列,更清晰)
input sel1, sel2, sel3;
input [7:0] addr;
inout [7:0] data_bus;
wire [7:0] data_in;
reg ?[7:0] data_out; //use reg type, but not registers
wire [7:0] decode_out;
wire [7:0] cnt_out;
assign data_in = data_bus;
decode decode_inst (.clock (clk),
? ? ? ? ? ? ? ? ? ?.reset (rst),
? ? ? ? ? ? ? ? ? ?.data_bus_in (data_in),
? ? ? ? ? ? ? ? ? ?.addr_bus (addr),
? ? ? ? ? ? ? ? ? ?.data_bus_out (decode_out)
? ? ? ? ? ? ? ? ? ?);
? ? ? ? ? ? ? ? ? ?
counter counter_inst (.clock (clk),
? ? ? ? ? ? ? ? ? ?.reset (rst),
? ? ? ? ? ? ? ? ? ?.data_bus_in (data_in),
? ? ? ? ? ? ? ? ? ?.cnt_out (cnt_out)
? ? ? ? ? ? ? ? ? ?);
? ? ? ? ? ? ? ? ? ?
always @ (decode_out or cnt_out or sel1 or sel2 or sel3)
? ?begin
? ? ? case ({sel1, sel2, sel3})
? ? ? ? 3'b100: ?data_out = decode_out;
? ? ? ? 3'b010: ?data_out = cnt_out;
? ? ? ? 3'b001: ?data_out = 8'b11111111;
? ? ? ? default: data_out = 8'bZZZZZZZZ;
? ? ? endcase
? ?end
assign data_bus = data_out; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
mux 建模
簡(jiǎn)單的使用assign和?,相對(duì)復(fù)雜的使用always和if…else、case等條件判斷語(yǔ)句建模。
存儲(chǔ)器建模
邏輯電路設(shè)計(jì)經(jīng)常使用一些單口RAM、雙口RAM和ROM等存儲(chǔ)器。Verilog 語(yǔ)法中基本的存儲(chǔ)單元定義格式為:
reg [datawidth] MemoryName [addresswidth]
1
如定義一個(gè)數(shù)據(jù)位寬為8bit,地址為63為的RAM8x64:
reg [7:0] RAM8x64 [0:63];
1
在使用存儲(chǔ)單元時(shí),不能直接操作存儲(chǔ)器某地址的某位,需要先將存儲(chǔ)單元賦值給某個(gè)寄存器,然后再對(duì)該存儲(chǔ)器的某位進(jìn)行相關(guān)操作。
module ram_basic (clk, CS, WR, addr, data_in, data_out, en);
input ? ? ? ? clk;
input ? ? ? ? CS; ?//CS = 1, RAM enable
input ? ? ? ? WR; ?//WR =1 then WRite enable; WR = 0 then read enable
input ? ? ? ? en; ?//data_out enable, convert the data sequency
input ?[5:0] ?addr;
input ?[7:0] ?data_in;
output [7:0] ?data_out;
reg [7:0] RAM8x64 [0:63];
reg [7:0] mem_data;
always @ (posedge clk)
? ?if (WR && CS) //WRite
? ? ? ?RAM8x64 [addr] <= data_in [7:0];
? ?else if (~WR && CS ) // read
? ? ? ?mem_data <= RAM8x64 [addr];
? ? ? ?
assign data_out = (en)? mem_data[7:0] : {~mem_data[7], mem_data[6:0]};
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
FPGA中內(nèi)嵌的RAM資源分為兩類(lèi):塊RAM(Block RAM)資源和分布式RAM(Distributed RAM)資源,BRAM作為FPGA內(nèi)部硬件資源,使用時(shí)不會(huì)占用其他邏輯資源,分布式RAM是通過(guò)查找表和觸發(fā)器實(shí)現(xiàn)的RAM結(jié)構(gòu)。
使用RAM等資源時(shí)通常不使用這種Verilog語(yǔ)言進(jìn)行建模,一般使用廠商提供IP核通過(guò)GUI完成相關(guān)參數(shù)配置,并生成相關(guān)IP。
簡(jiǎn)單的時(shí)鐘分頻電路
偶數(shù)分頻十分簡(jiǎn)單,只需要用高速時(shí)鐘驅(qū)動(dòng)一個(gè)同步計(jì)數(shù)器;
module clk_div_phase (rst, clk_200K, clk_100K, clk_50K, clk_25K);
input ? ? ? ?clk_200K;
input ? ? ? ?rst;
output ? ? ? clk_100K, clk_50K, clk_25K;
wire ? ? ? ? clk_100K, clk_50K, clk_25K;
reg [2:0] cnt; ?
always @ (posedge clk_200K or negedge rst)
? if (!rst)
? ? ?cnt <= 3'b000;
? else
? ? ?cnt <= cnt + 1;
assign clk_100K = ~cnt [0];//2分頻
assign clk_50K ?= ~cnt [1];//4分頻
assign clk_25K ?= ~cnt [2];//8分頻
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
上例通過(guò)對(duì)計(jì)數(shù)器每個(gè)bit的反向,完成了所有分頻后的時(shí)鐘調(diào)整,保證了3個(gè)分頻后時(shí)鐘的相位嚴(yán)格同相,也與源時(shí)鐘同相,有共同的上升沿。
奇數(shù)分頻
module clk_3div (clk,reset,clk_out);
input clk, reset;
output clk_out;
reg[1:0] state;
reg clk1;
always @(posedge clk or negedge reset)
if(!reset)
? ?state<=2'b00;
else
? ?case(state)
? ? ? ?2'b00:state<=2'b01;
? ? ? ?2'b01:state<=2'b11;
? ? ? ?2'b11:state<=2'b00;
? ? ? ?default:state<=2'b00;
? ?endcase
always @(negedge clk or negedge reset)
? ?if(!reset)
? ? ? ?clk1<=1'b0;
? ?else
? ? ? ?clk1<=state[0];
assign clk_out=state[0]&clk1;
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
串/并轉(zhuǎn)換建模
根據(jù)數(shù)據(jù)的排序和數(shù)量的要求,可以選用移位寄存器、RAM等實(shí)現(xiàn);對(duì)于數(shù)量比較小的設(shè)計(jì)可以采用移位寄存器完成串/并轉(zhuǎn)換(串轉(zhuǎn)并:先移位,再并行輸出;并轉(zhuǎn)串:先加載并行數(shù)據(jù),再移位輸出);對(duì)于排列順序有規(guī)律的串/并轉(zhuǎn)換,可以使用case語(yǔ)句進(jìn)行判斷實(shí)現(xiàn);對(duì)于復(fù)雜的串/并轉(zhuǎn)換,還可以用狀態(tài)機(jī)實(shí)現(xiàn)。
同步復(fù)位與異步復(fù)位
同步復(fù)位
建模
module syn_rst (clk, rst_, cnt1, cnt2);
input ? ? ? ?clk;
input ? ? ? ?rst_;
output [4:0] cnt1 , cnt2;
reg ? ?[4:0] cnt1 , cnt2;
always @ (posedge clk)
? if (!rst_)
? ? ?begin
? ? ? ?cnt1 <= 4'b0;
? ? ? ?cnt2 <= 4'b0;
? ? ?end
? else
? ? ?begin
? ? ? ?if (cnt1 < 2'b11)
? ? ? ? ? ?cnt1 <= cnt1 + 1;
? ? ? ?else
? ? ? ? ? ?cnt1 <= cnt1; ? ? ? ? ? ? ? ?
? ? ? ?cnt2 <= cnt1 - 1; ? ? ?
? ? ?end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
很多目標(biāo)器件的觸發(fā)器本身本身并不包含同步復(fù)位端口,則同步復(fù)位可以通過(guò)下圖結(jié)構(gòu)實(shí)現(xiàn):


優(yōu)點(diǎn)
同步復(fù)位利于基于周期機(jī)制的仿真器仿真;
使用同步復(fù)位可以設(shè)計(jì)100%的同步時(shí)序電路,利于時(shí)序分析,其綜合結(jié)果的頻率往往更高;
同步復(fù)位僅在時(shí)鐘的上升沿生效,可以有效的避免因復(fù)位電路毛刺造成的亞穩(wěn)態(tài)和錯(cuò)誤;在進(jìn)行復(fù)位和釋放復(fù)位信號(hào)時(shí),都是僅當(dāng)時(shí)鐘沿采到復(fù)位電平變化時(shí)才進(jìn)行相關(guān)操作,如果復(fù)位信號(hào)樹(shù)的組合邏輯出現(xiàn)了某些毛刺,此時(shí)時(shí)鐘邊沿采集到毛刺的概率非常低,通過(guò)時(shí)鐘沿采樣,可以十分有效地過(guò)濾復(fù)位電路的組合邏輯毛刺,增強(qiáng)電路的穩(wěn)定性。
缺點(diǎn)
很多目標(biāo)器件的觸發(fā)器本身不包含同步復(fù)位端口,使用同步復(fù)位會(huì)增加很多邏輯資源;
同步復(fù)位的最大問(wèn)題在于必須保證復(fù)位信號(hào)的有效時(shí)間足夠長(zhǎng),才能保證所有觸發(fā)器都有效復(fù)位,所以同步復(fù)位信號(hào)的持續(xù)時(shí)間必須大于設(shè)計(jì)的最長(zhǎng)時(shí)鐘周期,以保證所有時(shí)鐘的有效沿都能采樣到同步復(fù)位信號(hào)。
其實(shí)僅僅保證同步復(fù)位信號(hào)的持續(xù)時(shí)間大于最慢的時(shí)鐘周期還是不夠的,設(shè)計(jì)中還要考慮到同步復(fù)位信號(hào)樹(shù)通過(guò)所有組合邏輯路徑的延時(shí)以及由于時(shí)鐘布線產(chǎn)生的偏斜(skew),只有同步復(fù)位大于時(shí)鐘最大周期加上同步信號(hào)穿過(guò)的組合邏輯路徑延時(shí)加上時(shí)鐘偏斜時(shí),才能保證同步復(fù)位可靠、徹底。

上圖中,假設(shè)同步復(fù)位邏輯樹(shù)組合邏輯的延時(shí)為t1,復(fù)位信號(hào)傳播路徑的最大延遲為t2,最慢時(shí)鐘的周期為Period max,時(shí)鐘的skew為clk2-clk1,則同步復(fù)位的周期Tsys_rst應(yīng)滿足:Tsys_rst > Period max + (clk2-clk1) + t1 + t2;
異步復(fù)位
建模
module asyn_rst (clk, rst_, cnt1, cnt2);
input ? ? ? ?clk;
input ? ? ? ?rst_;
output [4:0] cnt1 , cnt2;
reg ? ?[4:0] cnt1 , cnt2;
always @ (posedge clk or negedge rst_)
? if (!rst_)
? ? ?begin
? ? ? ?cnt1 <= 4'b0;
? ? ? ?cnt2 <= 4'b0;
? ? ?end
? else
? ? ?begin
? ? ? ?if (cnt1 < 2'b11)
? ? ? ? ? ?cnt1 <= cnt1 + 1;
? ? ? ?else
? ? ? ? ? ?cnt1 <= cnt1; ? ? ? ? ? ? ? ?
? ? ? ?cnt2 <= cnt1 - 1; ? ? ?
? ? ?end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
優(yōu)點(diǎn)
多數(shù)器件包含異步復(fù)位端口,異步復(fù)位會(huì)節(jié)約邏輯資源;
異步復(fù)位設(shè)計(jì)簡(jiǎn)單;
大多數(shù)FPGA,都有專(zhuān)用的全局復(fù)位/置位資源(GSR,Globe Set Reset),使用GSR資源,異步復(fù)位達(dá)到所有寄存器的偏斜(skew)最小。
缺點(diǎn)
異步復(fù)位的作用和釋放與時(shí)鐘沿沒(méi)有直接關(guān)系,在異步復(fù)位神效時(shí)問(wèn)題并不明顯,但當(dāng)異步復(fù)位釋放時(shí),如果異步復(fù)位釋放時(shí)間和時(shí)鐘的有效沿到達(dá)時(shí)間幾乎一致,則容易造成觸發(fā)器輸出亞穩(wěn)態(tài),造成邏輯錯(cuò)誤;
如果異步復(fù)位邏輯樹(shù)的組合邏輯產(chǎn)生了毛刺,則毛刺的有效沿會(huì)使觸發(fā)器誤復(fù)位,造成邏輯錯(cuò)誤。
推薦的復(fù)位電路設(shè)計(jì)方式——異步復(fù)位,同步釋放
推薦的復(fù)位電路設(shè)計(jì)方式是異步復(fù)位,同步釋放,這種方式可以有效的繼承異步復(fù)位設(shè)計(jì)簡(jiǎn)單的優(yōu)勢(shì),并克服異步復(fù)位的風(fēng)險(xiǎn)與缺陷;相較于純粹的異步復(fù)位,降低了異步復(fù)位信號(hào)釋放導(dǎo)致的亞穩(wěn)態(tài)的可能性,相較于同步復(fù)位,能夠識(shí)別到同步復(fù)位中檢測(cè)不到的復(fù)位信號(hào)。
在FPGA中使用異步復(fù)位,同步釋放可以節(jié)約器件資源,并獲得穩(wěn)定可靠的復(fù)位效果。
異步復(fù)位同步釋放,既能很快的檢測(cè)到復(fù)位信號(hào),不需要復(fù)位保持超過(guò)一個(gè)時(shí)鐘周期,又能解決釋放時(shí)的亞穩(wěn)態(tài)問(wèn)題(降低亞穩(wěn)態(tài)發(fā)生的概率)。

異步復(fù)位,同步釋放的具體設(shè)計(jì)方法很多,關(guān)鍵是如何保證同步地釋放復(fù)位信號(hào),本例舉例的方法是在復(fù)位信號(hào)釋放時(shí),用系統(tǒng)時(shí)鐘采樣后再將復(fù)位信號(hào)送到寄存器的異步復(fù)位端。
所謂“異步復(fù)位”是針對(duì)D觸發(fā)器的復(fù)位端口,它是異步的,但是設(shè)計(jì)中已經(jīng)同步了異步復(fù)位信號(hào),所以筆者(Crazybingo)認(rèn)為這只是某種意義上的“異步復(fù)位”。
所謂“同步釋放”,實(shí)際上是由于我們?cè)O(shè)計(jì)了同步邏輯電路,外部復(fù)位信號(hào)不會(huì)在出現(xiàn)釋放時(shí)與clk信號(hào)競(jìng)爭(zhēng),整個(gè)系統(tǒng)將與全局時(shí)鐘clk信號(hào)同步。
使用時(shí)鐘將外部輸入的異步復(fù)位信號(hào)寄存一個(gè)節(jié)拍后,再送到觸發(fā)器異步復(fù)位端口的設(shè)計(jì)方法的另一個(gè)好處在于:做STA(靜態(tài)時(shí)序分析)分析時(shí),時(shí)序工具會(huì)自動(dòng)檢查同步后的異步復(fù)位信號(hào)和時(shí)鐘的到達(dá)(Recovery)/撤銷(xiāo)(Removal)時(shí)間關(guān)系,如果因布線造成的skew導(dǎo)致該到達(dá)/撤銷(xiāo)時(shí)間不能滿足,STA工具會(huì)上報(bào)該路徑,幫助設(shè)計(jì)者進(jìn)一步分析問(wèn)題。
module system_ctrl ? ? //異步復(fù)位,同步釋放——by 特權(quán)同學(xué)
//==================<端口>==================================================
(
//globel clock ----------------------------------
input ?wire ? ? ? ? ? ? ? ? clk ? ? ? ? ? ? ? ? , //時(shí)鐘,50Mhz
input ?wire ? ? ? ? ? ? ? ? rst_n ? ? ? ? ? ? ? , //復(fù)位,低電平有效
//user interface --------------------------------
input ?wire ? ? ? ? ? ? ? ? a ? ? ? ? ? ? ? ? ? , //輸入信號(hào)
output reg ? ? ? ? ? ? ? ? ?b ? ? ? ? ? ? ? ? ? ? //輸出信號(hào)
);
//==========================================================================
//== ? ?異步復(fù)位的同步化設(shè)計(jì)
//==========================================================================
reg ? ? ? ?sys_rst_n_r;
reg ? ? ? ?sys_rst_n;
always @(posedge clk or negedge rst_n)
begin
? ?if(!rst_n) begin
? ? ? ?sys_rst_n_r <= 1'b0;
? ? ? ?sys_rst_n ? <= 1'b0;
? ?end
? ?else begin
? ? ? ?sys_rst_n_r <= 1'b1;
? ? ? ?sys_rst_n ? <= sys_rst_n_r; //注意這里的rst_sync_n才是我們真正對(duì)系統(tǒng)輸出的復(fù)位信號(hào)
? ?end
end
always @(posedge clk or negedge sys_rst_n) ? //注意這里將同步后的信號(hào)仍作為異步復(fù)位信號(hào)進(jìn)行處理,Altera推薦
begin
? ?if(!sys_rst_n)
? ? ? ?b <= 0;
? ?else
? ? ? ?b <= a;
end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

上圖是Altera推薦的異步復(fù)位,同步釋放示意圖
module reset_gen ( output rst_sync_n, input clk, rst_async_n); ?//此模塊對(duì)應(yīng)前一個(gè)黃框中的邏輯,輸出信號(hào)在后級(jí)電路中仍作為異步復(fù)位信號(hào)進(jìn)行處理
reg rst_s1, rst_s2;
wire rst_sync_n ;
always @ (posedge clk, posedge rst_async_n)
? ?if (rst_async_n)
? ? ? ? begin
? ? ? ? ? ?rst_s1 <= 1'b0;
? ? ? ? ? ?rst_s2 <= 1'b0;
? ? ? ?end
? ?else
? ? ? ?begin
? ? ? ? ? ?rst_s1 <= 1'b1; //針對(duì)Altera FPGA
? ? ? ? ? ?rst_s2 <= rst_s1;
? ? ? ?end
assign rst_sync_n = rst_s2; //注意這里的rst_sync_n才是我們真正對(duì)系統(tǒng)輸出的復(fù)位信號(hào)
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Xilinx
Xilinx的FPGA,高電平復(fù)位其Filp-Flop同時(shí)支持同步/異步復(fù)位,復(fù)位準(zhǔn)則:
盡量少使用復(fù)位,特別是少用全局復(fù)位,能不用復(fù)位就不用,一定要用復(fù)位的使用局部復(fù)位;
如果必須要復(fù)位,在同步和異步復(fù)位上,則盡量使用同步復(fù)位(BRAM DSP48不支持異步復(fù)位),一定要用異步復(fù)位的地方,采用“異步復(fù)位、同步釋放”;
復(fù)位電平選擇高電平復(fù)位;
只要存在復(fù)位都會(huì)增加布局布線的負(fù)擔(dān),因?yàn)閺?fù)位會(huì)像時(shí)鐘一樣連接到每一個(gè)寄存器上,是相當(dāng)復(fù)雜的工程,會(huì)增加時(shí)序收斂的難度。
對(duì)于同一個(gè)觸發(fā)器邏輯,因?yàn)橥瑫r(shí)支持異步和同步復(fù)位,所以異步復(fù)位并不會(huì)節(jié)省資源;對(duì)于其他的資源,比如 DSP48 等,同步復(fù)位更加節(jié)省資源。
首先,對(duì)于 DSP48,其內(nèi)部還帶有一些寄存器(只支持同步復(fù)位),如果使用異步復(fù)位,則會(huì)額外使用外部 Slice 中帶異步復(fù)位的寄存器,而使用同步復(fù)位時(shí),可以利用 DSP48 內(nèi)部的寄存器;Xilinx 的 FPGA,對(duì)于 DSP48、BRAM 資源,使用同步復(fù)位比異步復(fù)位更節(jié)省資源。
對(duì)于高電平復(fù)位,使用異步復(fù)位同步釋放,則第一個(gè)寄存器的 D 輸入是 0,這里使用了 4
個(gè)觸發(fā)器打拍同步。The number of flip-flops in the chain determines the minimum
duration of the reset pulse issued to the localized network.

always @(posedge clk or posedge rst_async)
begin
? ?if(rst_async == 1'b1) begin
? ? ? ?rst_sync_reg1 <= 1'b1; //Xilinx的FPGA高電平復(fù)位
? ? ? ?rst_sync_reg2 <= 1'b1;
? ? ? ?rst_sync_reg3 <= 1'b1;
? ? ? ?rst_sync_reg4 <= 1'b1;
? ?end
? ?else begin
? ? ? ?rst_sync_reg1 <= 1'b0;
? ? ? ?rst_sync_reg2 <= rst_sync_reg1;
? ? ? ?rst_sync_reg3 <= rst_sync_reg2;
? ? ? ?rst_sync_reg4 <= rst_sync_reg3;
? ?end
end ?
wire sys_rst;
assign sys_rst = rst_sync_reg4;
always @(posedge clk) ? ?//同步后的信號(hào)當(dāng)作同步復(fù)位信號(hào)處理
begin
? ?if(sys_rst == 1'b1) begin
? ? ? ?data_out_rst_async <= 1'b0;
? ?end
? ?else begin
? ? ? ?data_out_rst_async <= a & b & c & d;
? ?end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
同步后的信號(hào)如果作為同步復(fù)位信號(hào)進(jìn)行處理:
rst_async異步復(fù)位一旦給出,用于同步的4個(gè)寄存器rst_sync_reg1~4立刻輸出高電平“1”,在下一個(gè)時(shí)鐘上升沿檢測(cè)到同步復(fù)位并將輸出data_out_rst_async復(fù)位;
異步復(fù)位信號(hào)釋放后,經(jīng)過(guò)同步的sys_rst經(jīng)過(guò)一定周期后在時(shí)鐘邊沿同步釋放;
同步后的信號(hào)如果作為異步復(fù)位信號(hào)進(jìn)行處理:
區(qū)別在于異步復(fù)位信號(hào)rst_async一旦產(chǎn)生,輸出立刻復(fù)位,且同樣是同步釋放,好像這種處理才更符合異步復(fù)位、同步釋放。
那么為什么Xilinx白皮書(shū)還是將sys_rst按照同步復(fù)位去做的呢? 綜合考慮可能有這樣的因素:
當(dāng)作同步復(fù)位的差別只在于復(fù)位時(shí)間會(huì)稍晚一些,要在時(shí)鐘的下一個(gè)邊沿檢測(cè)到,但是還是能夠識(shí)別到輸入的rst_async異步復(fù)位信號(hào),所以從復(fù)位角度來(lái)說(shuō),都能夠后實(shí)現(xiàn)復(fù)位效果;
根據(jù)Xilinx復(fù)位準(zhǔn)則,我們知道同步復(fù)位相比異步復(fù)位有很多好處,具體參見(jiàn):Xilinx FPGA 復(fù)位策略白皮書(shū)(WP272) 公眾號(hào)-FPGA探索者做了翻譯可以參考,既然兩者對(duì)后級(jí)復(fù)位沒(méi)有功能上的差別,那么優(yōu)先選擇同步復(fù)位;
Xilinx 推薦的復(fù)位準(zhǔn)則:
盡量少使用復(fù)位,特別是少用全局復(fù)位,能不用復(fù)位就不用,一定要用復(fù)位的使用局部復(fù)位;
如果必須要復(fù)位,在同步和異步復(fù)位上,則盡量使用同步復(fù)位,一定要用異步復(fù)位的地方,采用“異步復(fù)位、同步釋放”;
復(fù)位電平選擇高電平復(fù)位;
Altera
Altera的FPGA,低電平復(fù)位,其觸發(fā)器只有異步復(fù)位端口,所以如果想要用同步復(fù)位,需要額外的資源來(lái)實(shí)現(xiàn),這也是“異步復(fù)位節(jié)省資源”這一說(shuō)法的原因。
具體電路及代碼見(jiàn)上文
用case和if…else建模
略
可綜合的Verilog語(yǔ)法子集
在RTL建模時(shí),使用可綜合的Verilog語(yǔ)法是整個(gè)Verilog語(yǔ)法中的非常小的一個(gè)子集。其實(shí)可綜合的Verilog常用關(guān)鍵字非常有限,這恰恰體現(xiàn)了Verilog語(yǔ)言是硬件描述語(yǔ)言的本質(zhì),Verilog作為HDL,其本質(zhì)在于把電路流暢、合理的轉(zhuǎn)換為語(yǔ)言形式,而使用較少的一些關(guān)鍵字就可以有效的將電路轉(zhuǎn)換到可綜合的RTL語(yǔ)言結(jié)構(gòu)。
常用的RTL語(yǔ)法結(jié)構(gòu)列舉:
模塊聲明:module…endmodule;
端口聲明:input、outpu、inout;
信號(hào)類(lèi)型:wire、reg、tri等,integer通常用于for語(yǔ)句中索引;
參數(shù)定義:parameter
運(yùn)算操作符:邏輯操作、移位操作、算術(shù)操作;
比較判斷:case…endcase(casex/casez)、if…else;
連續(xù)賦值:assign、問(wèn)號(hào)表達(dá)式
always模塊:建模時(shí)序和組合邏輯
語(yǔ)法分割符:begin…end
任務(wù)定義:task…endtask
循環(huán)語(yǔ)句:for
CPU讀/寫(xiě)PLD寄存器接口設(shè)計(jì)實(shí)例


CS:片選(低有效、input)
OE:輸出使能信號(hào)(低有效、input)
WR:讀/寫(xiě)指示,低-讀數(shù)據(jù),高-寫(xiě)數(shù)據(jù)(input)
Address:地址總線(input)
Data:雙向數(shù)據(jù)總線(inout)
地址譯碼器電路
module decode (CS_, OE_, WR_, Addr, my_wr, my_rd, CS_reg1, CS_reg2, CS_reg3);
input ? ? ? ?CS_, OE_, WR_;
input ?[7:0] Addr;
output ? ? ? my_wr, my_rd;
output ? ? ? CS_reg1, CS_reg2, CS_reg3;
reg ? ? ? ? ?CS_reg1, CS_reg2, CS_reg3;
assign my_wr = (!WR_) && (!CS_) && (!OE_);
assign my_rd = (WR_) ?&& (!CS_) && (!OE_);
always @ (Addr or CS_)
?if (!CS_)
? ? begin
? ? ? case (Addr)
? ? ? ? ?8'b 11110000: CS_reg1 <= 1'b1;
? ? ? ? ?8'b 00001111: CS_reg2 <= 1'b1;
? ? ? ? ?8'b 10100010: CS_reg3 <= 1'b1;
? ? ? ? ?default: ? ? begin
? ? ? ? ? ? ? ? ? ? ? ? ? CS_reg1 <= 1'b0;
? ? ? ? ? ? ? ? ? ? ? ? ? CS_reg2 <= 1'b0;
? ? ? ? ? ? ? ? ? ? ? ? ? CS_reg3 <= 1'b0;
? ? ? ? ? ? ? ? ? ? ? end
? ? ? endcase
? ? end
? ? ? ? ? ? ?
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
讀寄存器
module read_reg (clk, rst, data_out, ?my_rd, CS_reg1, CS_reg2, CS_reg3, reg1, reg2, reg3);
input ? ? ? ?clk, rst, my_rd, CS_reg1, CS_reg2, CS_reg3;
input ?[7:0] reg1, reg2, reg3;
output [7:0] data_out;
reg ? ?[7:0] data_out;
?always @ (posedge clk or negedge rst)
? ? ?if (!rst)
? ? ? ? data_out <= 8'b0;
? ? ?else
? ? ? ? begin
? ? ? ? ? ?if (my_rd)
? ? ? ? ? ? ? ?begin
? ? ? ? ? ? ? ? ? ? if (CS_reg1)
? ? ? ? ? ? ? ? ? ? ? ? data_out <= reg1;
? ? ? ? ? ? ? ? ? ? else if (CS_reg2)
? ? ? ? ? ? ? ? ? ? ? ? data_out <= reg2;
? ? ? ? ? ? ? ? ? ? else if (CS_reg3)
? ? ? ? ? ? ? ? ? ? ? ? data_out <= reg3;
? ? ? ? ? ? ? ?end
? ? ? ? ? ?else
? ? ? ? ? ? ? ?data_out <= 8'b0; ? ? ? ? ? ? ?
? ? ? ?
? ? ? ? end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
寫(xiě)寄存器
module write_reg (clk, rst, data_in, ?my_wr, CS_reg1, CS_reg2, CS_reg3, reg1, reg2, reg3);
input ? ? ? ?clk, rst, my_wr, CS_reg1, CS_reg2, CS_reg3;
input ?[7:0] data_in;
output [7:0] reg1, reg2, reg3;
reg ? ?[7:0] reg1, reg2, reg3;
?always @ (posedge clk or negedge rst)
? ? ?if (!rst)
? ? ? ? begin
? ? ? ? ? ? ?reg1 <= 8'b0;
? ? ? ? ? ? ?reg2 <= 8'b0;
? ? ? ? ? ? ?reg3 <= 8'b0; ? ? ? ?
? ? ? ? end
? ? ?else
? ? ? ? begin
? ? ? ? ? ?if (my_wr)
? ? ? ? ? ? ? ?begin
? ? ? ? ? ? ? ? ? ? if (CS_reg1)
? ? ? ? ? ? ? ? ? ? ? ? reg1 <= data_in;
? ? ? ? ? ? ? ? ? ? else if (CS_reg2)
? ? ? ? ? ? ? ? ? ? ? ? reg2 <= data_in;
? ? ? ? ? ? ? ? ? ? else if (CS_reg3)
? ? ? ? ? ? ? ? ? ? ? ? reg3 <= data_in;
? ? ? ? ? ? ? ?end
? ? ? ? ? ?else
? ? ? ? ? ? ? ?begin
? ? ? ? ? ? ? ? ? ? reg1 <= reg1;
? ? ? ? ? ? ? ? ? ? reg2 <= reg2;
? ? ? ? ? ? ? ? ? ? reg3 <= reg3;
? ? ? ? ? ? ? ?end ? ? ? ? ? ? ? ?
? ? ? ?
? ? ? ? end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
頂層
module top (clk_cpu, rst, CS_, OE_, WR_, Addr, data_bus);
input ? clk_cpu, rst;
input ? CS_, OE_, WR_;
input [7:0] Addr;
inout [7:0] data_bus;
wire [7:0] data_in;
wire [7:0] data_out;
wire ? ? ? my_wr, my_rd;
wire ? ? ? CS_reg1, CS_reg2, CS_reg3; // the register selection
wire [7:0] reg1, reg2, reg3; ? ? ? ? ?// the register to be read and written
assign data_in = data_bus;
assign data_bus = ((!CS_) && (!OE_))? data_out : 8'bZZZZZZZZ;
decode decode_u1 ?(.CS_(CS_),
? ? ? ? ? ? ? ? ? .OE_(OE_),
? ? ? ? ? ? ? ? ? .WR_(WR_),
? ? ? ? ? ? ? ? ? .Addr(Addr),
? ? ? ? ? ? ? ? ? .my_wr(my_wr),
? ? ? ? ? ? ? ? ? .my_rd(my_rd),
? ? ? ? ? ? ? ? ? .CS_reg1(CS_reg1),
? ? ? ? ? ? ? ? ? .CS_reg2(CS_reg2),
? ? ? ? ? ? ? ? ? .CS_reg3(CS_reg3)
? ? ? ? ? ? ? ? ? );
write_reg write_reg_u1 ( .clk(clk_cpu),
? ? ? ? ? ? ? ? ? ? ? ? .rst(rst),
? ? ? ? ? ? ? ? ? ? ? ? .data_in(data_in),
? ? ? ? ? ? ? ? ? ? ? ? .my_wr(my_wr),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg1(CS_reg1),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg2(CS_reg2),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg3(CS_reg3),
? ? ? ? ? ? ? ? ? ? ? ? .reg1(reg1),
? ? ? ? ? ? ? ? ? ? ? ? .reg2(reg2),
? ? ? ? ? ? ? ? ? ? ? ? .reg3(reg3)
? ? ? ? ? ? ? ? ? ? ? ? );
read_reg read_reg_u1 ?( .clk(clk_cpu),
? ? ? ? ? ? ? ? ? ? ? ? .rst(rst),
? ? ? ? ? ? ? ? ? ? ? ? .data_out(data_out),
? ? ? ? ? ? ? ? ? ? ? ? .my_rd(my_rd),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg1(CS_reg1),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg2(CS_reg2),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg3(CS_reg3),
? ? ? ? ? ? ? ? ? ? ? ? .reg1(reg1),
? ? ? ? ? ? ? ? ? ? ? ? .reg2(reg2),
? ? ? ? ? ? ? ? ? ? ? ? .reg3(reg3)
? ? ? ? ? ? ? ? ? ? ? ? );
? ? ? ? ? ? ? ? ? ?
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
使用OE/WR邊沿讀寫(xiě)
使用OE或WR的沿讀寫(xiě)寄存器的描述看起來(lái)比前面介紹的使用CPU時(shí)鐘同步讀寫(xiě)寄存器的描述簡(jiǎn)單,但是讀者必須明確這種方式正常工作有兩個(gè)前提條件:
OE的上升沿可以有效地采樣數(shù)據(jù)總線,即OE的上升沿采樣數(shù)據(jù)總線時(shí)Setup和Hold都能保證滿足;
WR和CS信號(hào)都比OE信號(hào)寬,即OE上升沿讀寫(xiě)寄存器時(shí),CS和WR信號(hào)始終保持有效。
只有這兩個(gè)條件同時(shí)滿足的前提下,才能保證使用OE的沿讀寫(xiě)PLD寄存器電路是可靠的。
/******************************************/
module decode (CS_, WR_, Addr, my_wr, my_rd, CS_reg1, CS_reg2, CS_reg3);
input ? ? ? ?CS_, WR_;
input ?[7:0] Addr;
output ? ? ? my_wr, my_rd;
output ? ? ? CS_reg1, CS_reg2, CS_reg3;
reg ? ? ? ? ?CS_reg1, CS_reg2, CS_reg3;
assign my_wr = (!WR_) && (!CS_);
assign my_rd = (WR_) ?&& (!CS_);
always @ (Addr or CS_)
?if (!CS_)
? ? begin
? ? ? case (Addr)
? ? ? ? ?8'b 11110000: CS_reg1 <= 1'b1;
? ? ? ? ?8'b 00001111: CS_reg2 <= 1'b1;
? ? ? ? ?8'b 10100010: CS_reg3 <= 1'b1;
? ? ? ? ?default: ? ? begin ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? CS_reg1 <= 1'b0; ?
? ? ? ? ? ? ? ? ? ? ? ? ? CS_reg2 <= 1'b0; ?
? ? ? ? ? ? ? ? ? ? ? ? ? CS_reg3 <= 1'b0; ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? end
? ? ? endcase
? ? end ? ? ? ? ? ? ?
endmodule
/******************************************/
module read_reg (OE_, rst, data_out, ?my_rd, CS_reg1, CS_reg2, CS_reg3, reg1, reg2, reg3);
input ? ? ? ?OE_, rst, my_rd, CS_reg1, CS_reg2, CS_reg3;
input ?[7:0] reg1, reg2, reg3;
output [7:0] data_out;
reg ? ?[7:0] data_out;
?always @ (posedge OE_ or negedge rst)
? ? ?if (!rst)
? ? ? ? data_out <= 8'b0;
? ? ?else
? ? ? ? begin
? ? ? ? ? ?if (my_rd)
? ? ? ? ? ? ? ?begin
? ? ? ? ? ? ? ? ? ? if (CS_reg1)
? ? ? ? ? ? ? ? ? ? ? ? data_out <= reg1;
? ? ? ? ? ? ? ? ? ? else if (CS_reg2)
? ? ? ? ? ? ? ? ? ? ? ? data_out <= reg2;
? ? ? ? ? ? ? ? ? ? else if (CS_reg3)
? ? ? ? ? ? ? ? ? ? ? ? data_out <= reg3;
? ? ? ? ? ? ? ?end
? ? ? ? ? ?else
? ? ? ? ? ? ? ?data_out <= 8'b0; ? ? ? ? ? ? ?
? ? ? ?
? ? ? ? end
endmodule
/******************************************/
module write_reg (OE_, rst, data_in, ?my_wr, CS_reg1, CS_reg2, CS_reg3, reg1, reg2, reg3);
input ? ? ? ?OE_, rst, my_wr, CS_reg1, CS_reg2, CS_reg3;
input ?[7:0] data_in;
output [7:0] reg1, reg2, reg3;
reg ? ?[7:0] reg1, reg2, reg3;
?always @ (posedge OE_ or negedge rst)
? ? ?if (!rst)
? ? ? ? begin
? ? ? ? ? ? ?reg1 <= 8'b0;
? ? ? ? ? ? ?reg2 <= 8'b0;
? ? ? ? ? ? ?reg3 <= 8'b0; ? ? ? ?
? ? ? ? end
? ? ?else
? ? ? ? begin
? ? ? ? ? ?if (my_wr)
? ? ? ? ? ? ? ?begin
? ? ? ? ? ? ? ? ? ? if (CS_reg1)
? ? ? ? ? ? ? ? ? ? ? ? reg1 <= data_in;
? ? ? ? ? ? ? ? ? ? else if (CS_reg2)
? ? ? ? ? ? ? ? ? ? ? ? reg2 <= data_in;
? ? ? ? ? ? ? ? ? ? else if (CS_reg3)
? ? ? ? ? ? ? ? ? ? ? ? reg3 <= data_in;
? ? ? ? ? ? ? ?end
? ? ? ? ? ?else
? ? ? ? ? ? ? ?begin
? ? ? ? ? ? ? ? ? ? reg1 <= reg1;
? ? ? ? ? ? ? ? ? ? reg2 <= reg2;
? ? ? ? ? ? ? ? ? ? reg3 <= reg3;
? ? ? ? ? ? ? ?end ? ? ? ? ? ? ? ?
? ? ? ?
? ? ? ? end
? ? ? ?
endmodule
/******************************************/
module top (rst, CS_, OE_, WR_, Addr, data_bus);
input ? ? ? rst;
input ? ? ? ?CS_, OE_, WR_;
input [7:0] Addr;
inout [7:0] data_bus;
wire [7:0] data_in;
wire [7:0] data_out;
wire ? ? ? my_wr, my_rd;
wire ? ? ? CS_reg1, CS_reg2, CS_reg3; // the register selection
wire [7:0] reg1, reg2, reg3; ? ? ? ? ?// the register to be read and written
assign data_in = data_bus;
assign data_bus = ((!CS_) && (!OE_))? data_out : 8'bZZZZZZZZ;
decode decode_u1 ?(.CS_(CS_),
? ? ? ? ? ? ? ? // ?.OE_(OE_),
? ? ? ? ? ? ? ? ? .WR_(WR_),
? ? ? ? ? ? ? ? ? .Addr(Addr),
? ? ? ? ? ? ? ? ? .my_wr(my_wr),
? ? ? ? ? ? ? ? ? .my_rd(my_rd),
? ? ? ? ? ? ? ? ? .CS_reg1(CS_reg1),
? ? ? ? ? ? ? ? ? .CS_reg2(CS_reg2),
? ? ? ? ? ? ? ? ? .CS_reg3(CS_reg3)
? ? ? ? ? ? ? ? ? );
write_reg write_reg_u1 ( .OE_(OE_),
? ? ? ? ? ? ? ? ? ? ? ? .rst(rst),
? ? ? ? ? ? ? ? ? ? ? ? .data_in(data_in), ?
? ? ? ? ? ? ? ? ? ? ? ? .my_wr(my_wr),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg1(CS_reg1),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg2(CS_reg2),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg3(CS_reg3),
? ? ? ? ? ? ? ? ? ? ? ? .reg1(reg1),
? ? ? ? ? ? ? ? ? ? ? ? .reg2(reg2),
? ? ? ? ? ? ? ? ? ? ? ? .reg3(reg3)
? ? ? ? ? ? ? ? ? ? ? ? );
read_reg read_reg_u1 ?( ?.OE_(OE_),
? ? ? ? ? ? ? ? ? ? ? ? .rst(rst),
? ? ? ? ? ? ? ? ? ? ? ? .data_out(data_out), ?
? ? ? ? ? ? ? ? ? ? ? ? .my_rd(my_rd),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg1(CS_reg1),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg2(CS_reg2),
? ? ? ? ? ? ? ? ? ? ? ? .CS_reg3(CS_reg3),
? ? ? ? ? ? ? ? ? ? ? ? .reg1(reg1),
? ? ? ? ? ? ? ? ? ? ? ? .reg2(reg2),
? ? ? ? ? ? ? ? ? ? ? ? .reg3(reg3)
? ? ? ? ? ? ? ? ? ? ? ? );
? ? ? ? ? ? ? ? ? ?
endmodule
/******************************************/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
如果譯碼電路是組合邏輯,則其譯碼結(jié)果就有可能帶有毛刺,另外由于CPU總線的時(shí)序在電壓、溫度、環(huán)境變化的情況下時(shí)序可能遭到破壞,造成OE,WR,CS等信號(hào)的時(shí)序余量惡化,如果此時(shí)使用譯碼結(jié)果的電平做電平敏感的always模塊,進(jìn)行讀寫(xiě)寄存器操作(如Example-4-21\ asyn_bad目錄下的read_reg.v和write_reg.v),則會(huì)因?yàn)槊毯湾e(cuò)誤電平造成讀寫(xiě)錯(cuò)誤。所以不同將OE或WR的電平作為敏感信號(hào)來(lái)進(jìn)行讀寫(xiě)。