Verilog代碼匯總
自己整理的verilog文件,方便后續查看。
因個人技術力低下,可能會出現錯誤,可以通過郵箱和我交流:jiaming_li@cqu.edu.cn
使用vivado軟件進行編寫,更改文件編輯器為VSC,安裝格式化插件verilog-format
xorgate
代碼傳送門:https://github.com/Geaming-CHN/Vivado/tree/main/_Digital logic/gates/xorgate
異或門的verilog實現:
熟悉大概格式
xorgate.v
module xorgate
#(parameter WIDTH = 8)
(
input[(WIDTH-1):0] a,
input[(WIDTH-1):0] b,
output[(WIDTH-1):0] c
);
assign c = a^b;
endmodule
1位4選1多路選擇器
代碼傳送門:https://github.com/Geaming-CHN/Vivado/tree/main/_Digital logic/Project3
邏輯表達式
\(\large e=a\bar{S_2}\bar{S_1}+b\bar{S_2}{S_1}+c{S_2}\bar{S_1}+d{S_2}{S_1}\)
手繪電路圖如下:
源代碼文件:
采用assign
module design_1
(
input [0:0] a,
input [0:0] b,
input [0:0] c,
input [0:0] d,
input [0:0] S1,
input [0:0] S2,
output [0:0] e
);
assign e = a&(~S2)&(~S1)|b&(~S2)&(S1)|c&(S2)&(~S1)|d&(S2)&(S1);
endmodule
采用always
module design_1
(
input [2:0]a,
input [2:0]b,
input [2:0]c,
input [2:0]d,
input [1:0]S,
output reg[2:0]e
);
always @(a,b,c,d,S)
begin
case(S[1:0])
2'b00: e = a;
2'b01: e = b;
2'b10: e = c;
2'b11: e = d;
default:e = 2'b00;
endcase
end
endmodule
仿真文件:
module design_1_sim_2();
parameter size = 10000;
reg a = 0;
reg b = 0;
reg c = 0;
reg d = 0;
reg S1 = 0;
reg S2 = 0;
wire e;
design_1 u(.a(a),.b(b),.c(c),.d(d),.S1(S1),.S2(S2),.e(e));
initial begin
a = 'd0;
b = 'd0;
c = 'd0;
d = 'd0;
S1 = 'd0;
S2 = 'd0;
repeat(size)
begin
#10
a = $random;
b = $random;
c = $random;
d = $random;
S1 = $random;
S2 = $random;
end
end
endmodule
數字鍾設計
代碼傳送門:https://github.com/Geaming-CHN/Vivado/tree/main/_Digital logic/project7
代碼當時沒有分模塊寫,所以一個代碼給完了。
內容
實現一個六十進制數字時鍾,秒到60則歸零重加,同時讓分加1,分加到60歸零重加,並讓小時加1,小時加到24歸零重加。
設計思路
首先將整個實驗分成三大部分,一是分頻模塊,二是計數模塊,三是顯示模塊。
分頻:
- 因為代碼中的時鍾信號clk頻率過高,與數字時鍾的要求不匹配。在代碼中采用設置parameter分頻獲得clk2,計數時以clk2為時鍾信號進行計算。
計數:
- 計數模塊鍾分別設計一個60進制和24進制的計數器,用來計算時分秒及其進位。為方便顯示模塊使用,
- 將秒拆分為Second_2,Second_1;
- 將分拆分為Minute_2,Minute_1;
- 將時拆分為Hour_2,Hour_1;
- 則Second_1,Minute_1為十進制計數器,Second_2,Minute_2為六進制計數器,Hour_2為3進制計數器,Hour_1為10進制計數器(最后為5進制計數器,特殊情況:23:59:59)
顯示:
使用七段數碼管進行顯示。
其中低電平為有效。為了實現4個數碼管顯示不同內容,利用人眼的視覺暫留,對4個氣短數碼管進行分時復用。當數碼管的刷新頻率高於人眼的視覺暫留時,人眼就無法察覺數碼管信息的改變。
reg[10:0] display
使用11位的display對數碼管進行輸出,前4位為使能端,后七位與七段數碼管相對應。
- Hour_1為10進制計數器(最后為5進制計數器,特殊情況:23:59:59)
module clock(
input clk,rst,second_select,
output reg[10:0] display
);
reg[3:0] Hour_2,Hour_1,Minute_2,Minute_1,Second_2,Second_1;
reg[26:0] count = 0;
reg[15:0] count2 = 0;
reg[2:0] sel = 0;
parameter T = 10000000;
parameter T2 = 50000;
reg clk2 = 1'b0;
//時間
always @(posedge clk) begin
if(rst)
count<='b0;
else if(count == T)
begin
clk2 <= ~clk2;
count <= 0;
end
else count <= count + 'b1;
end
//Second_1 % 10
always @(posedge clk2) begin
//rst
if(rst)
Second_1 <= 4'b0000;
//進位
else if(Second_1==4'b1001)
Second_1 <= 4'b0000;
else
Second_1 <= Second_1 + 4'b0001;
end
//Second_2 % 6
always @(posedge clk2) begin
//rst
if(rst)
Second_2 <= 4'b0000;
//進位
else if(Second_1==4'b1001)//Second_1進位
begin
if(Second_2 == 4'b0101)//Second_2==5
Second_2<=4'b0000;
else
Second_2<=Second_2+4'b0001;
end
end
//Minute_1 % 10
always @(posedge clk2) begin
if(rst)
Minute_1 <= 4'b0000;
else if(Second_2 == 4'b0101&&Second_1==4'b1001)
begin
if(Minute_1==4'b1001)
Minute_1 <= 4'b0000;
else
Minute_1 <= Minute_1+4'b0001;
end
end
//Minute_2 % 6
always @(posedge clk2) begin
if(rst)
Minute_2 <= 4'b0000;
else if(Second_2 == 4'b0101&&Second_1==4'b1001)
begin
if(Minute_1==4'b1001)
begin
if(Minute_2==4'b0101)
Minute_2<=4'b0000;
else
Minute_2 <= Minute_2+4'b0001;
end
end
end
//Hour_1 % 10 最后為4
always @(posedge clk2) begin
if(rst)
Hour_1 <= 4'b0000;
else if(Second_2 == 4'b0101&&Second_1==4'b1001&&Minute_2==4'b0101&&Minute_1==4'b1001)
begin
if(Hour_2==4'b0010&&Hour_1==4'b0011)//23:59:59
Hour_1 <= 4'b0000;
else if(Hour_1 == 4'b1001)
Hour_1 <= 4'b0000;
else
Hour_1 <= Hour_1 + 4'b0001;
end
end
//Hour_2 % 3
always @(posedge clk2) begin
if(rst)
Hour_2 <= 4'b0000;
else if(Second_2 == 4'b0101&&Second_1==4'b1001&&Minute_2==4'b0101&&Minute_1==4'b1001)
begin
if(Hour_2==4'b0010&&Hour_1==4'b0011)//23:59:59
Hour_2 <= 4'b0000;
else if(Hour_1 == 4'b1001)
Hour_2 <= Hour_2+4'b0001;
end
end
//顯示
always @(posedge clk) begin
if(rst)
count2<='b0;
else if(count2==T2)
begin
count2<=0;
sel<=sel+1;
if(sel==4)
sel<=0;
end
else
count2 <=count2+1;
end
always @(posedge clk) begin
//顯示秒
if(second_select)
begin
case(sel)
//Second_1 0~9
0,1: begin
case(Second_1)
4'b0000:display = 11'b1110_0000001;
4'b0001:display = 11'b1110_1001111;
4'b0010:display = 11'b1110_0010010;
4'b0011:display = 11'b1110_0000110;
4'b0100:display = 11'b1110_1001100;
4'b0101:display = 11'b1110_0100100;
4'b0110:display = 11'b1110_0100000;
4'b0111:display = 11'b1110_0001111;
4'b1000:display = 11'b1110_0000000;
4'b1001:display = 11'b1110_0000100;
endcase
end
//Second_2 0~5
2,3:begin
case(Second_2)
4'b0000:display = 11'b1101_0000001;
4'b0001:display = 11'b1101_1001111;
4'b0010:display = 11'b1101_0010010;
4'b0011:display = 11'b1101_0000110;
4'b0100:display = 11'b1101_1001100;
4'b0101:display = 11'b1101_0100100;
endcase
end
endcase
end
//顯示小時和分鍾
else
begin
case(sel)
//Minute_1 0~9
0:begin
case(Minute_1)
4'b0000:display = 11'b1110_0000001;
4'b0001:display = 11'b1110_1001111;
4'b0010:display = 11'b1110_0010010;
4'b0011:display = 11'b1110_0000110;
4'b0100:display = 11'b1110_1001100;
4'b0101:display = 11'b1110_0100100;
4'b0110:display = 11'b1110_0100000;
4'b0111:display = 11'b1110_0001111;
4'b1000:display = 11'b1110_0000000;
4'b1001:display = 11'b1110_0000100;
endcase
end
//Minute_2 0~5
1:begin
case(Minute_2)
4'b0000:display = 11'b1101_0000001;
4'b0001:display = 11'b1101_1001111;
4'b0010:display = 11'b1101_0010010;
4'b0011:display = 11'b1101_0000110;
4'b0100:display = 11'b1101_1001100;
4'b0101:display = 11'b1101_0100100;
endcase
end
//Hour_1 0~9
2:begin
case(Hour_1)
4'b0000:display = 11'b1011_0000001;
4'b0001:display = 11'b1011_1001111;
4'b0010:display = 11'b1011_0010010;
4'b0011:display = 11'b1011_0000110;
4'b0100:display = 11'b1011_1001100;
4'b0101:display = 11'b1011_0100100;
4'b0110:display = 11'b1011_0100000;
4'b0111:display = 11'b1011_0001111;
4'b1000:display = 11'b1011_0000000;
4'b1001:display = 11'b1011_0000100;
endcase
end
//Hour_2
3:begin
case(Hour_2)
4'b0000:display = 11'b0111_0000001;
4'b0001:display = 11'b0111_1001111;
4'b0010:display = 11'b0111_0010010;
endcase
end
endcase
end
end
endmodule
單端口RAM
代碼傳送門:https://github.com/Geaming-CHN/Vivado/tree/main/_Digital logic/Project14
內容
利用BASYS3片內存儲器單元實現單端口RAM設計(帶異步讀和同步讀兩種模式),在時鍾(clk)上升沿,采集地址addr)、輸入數據data_in)、執行相關控制信息。當寫使能(we)有效,則執行寫操作,否則執行讀取操作。同步與異步設計僅針對讀操作:對於異步RAM而言,讀操作為異步,即地址信號有效時,控制器直接讀取RAM陣列;對於同步RAM而言,地址信號在時鍾上升沿被采集。並保存在寄存器中,然后使用該地址信號讀取RAM陣列。
設計思路
單端口RAM設計(帶異步讀和同步讀兩種模式),在時鍾(clk)上沿采集地址(addr)、輸入數據data_in)、執行相關控制信息。當寫使能we有效,則執行寫操作,否則執行讀取操作。同步與異步設計僅針對讀操作:對於異步RAM而言,讀操作為異步,即地址信號有效時,控制器直接讀取RAM陣列;對於同步RAM而言,地址信號在時鍾上升沿被采集並保存在寄存器中,然后使用該地址信號讀取RAM陣列。(額外添加了讀使能oe)

單端口同步RAM
-
頂層模塊
-
divider:為七段數碼管提供分頻后的clk;
-
Syn_SinglePortRAM:單端口同步RAM;
-
transformer:移位加三法,輸入至七段數碼管進行顯示功能的實現;
-
display7seg:七段數碼管顯示模塊;
top_Syn_SinglePortRAM
module top_Syn_SinglePortRAM#(parameter DATA_WIDTH = 4,parameter ADDR_DEPTH = 4)(
input clk,rst,
input [ADDR_DEPTH-1:0]addr,
input [DATA_WIDTH-1:0]data_in,
input we,oe,
output wire[3:0]an,
output wire[6:0]display
);
wire[DATA_WIDTH-1:0]data_out;
wire clk_div;
reg [25:0]target = 50000;
wire [15:0]BCD;
//divider
divider d(.clk(clk),.rst(rst),.target(target),.clk_div(clk_div));
//Syn_SinglePortRAM
Syn_SinglePortRAM S(.clk(clk),.rst(rst),.addr(addr),.data_in(data_in),.we(we),.oe(oe),.data_out(data_out));
//transformer
transformer t(.data(data_out),.BCD(BCD));
//display7seg
display7seg dis(.clk(clk_div),.data3(BCD[15:12]),.data2(BCD[11:8]),.data1(BCD[7:4]),.data0(BCD[3:0]),.an(an),.display(display));
endmodule
divider
module divider(
input clk,rst,
input [15:0] target,
output reg clk_div
);
reg [15:0] counter;
always @(posedge clk) begin
if(rst)
begin
counter <= 0;
clk_div <= 0;
end
else if(counter==target)
begin
counter <= 0;
clk_div <= ~clk_div;
end
else
counter <= counter+1;
end
endmodule
Syn_SinglePortRAM
module Syn_SinglePortRAM#(parameter DATA_WIDTH = 4,parameter ADDR_DEPTH = 4)(
input clk,rst,
input [ADDR_DEPTH-1:0]addr,
input [DATA_WIDTH-1:0]data_in,
input we,
input oe,
output reg[DATA_WIDTH-1:0]data_out
);
reg [DATA_WIDTH-1:0] RAM[(1<<ADDR_DEPTH)-1:0];
//write
always @(posedge clk)
begin
if(rst)
begin:init_RAM
integer i;//必須聲明在有名字的塊中,或寫在外面
for(i=0;i<(1<<ADDR_DEPTH);i = i+1)
begin
RAM[i] <= 0;
end
end
else if(we)
begin
RAM[addr] <= data_in;
end
end
//syn_read
always @(posedge clk) begin
if(rst)
begin
data_out <= 0;
end
else if(!we && oe)
begin
data_out <= RAM[addr];
end
else
data_out <= 0;
end
endmodule
transformer
module transformer(
input [3:0] data,
output [15:0]BCD//四位,方便輸入至數碼管
);
//移位加3,轉換成BCD
reg [19:0] transfor_data;
always @(*)
begin
transfor_data = 16'b0;
transfor_data[3:0] = data;
repeat(4)
begin
if(transfor_data[19:16]>4)
transfor_data[19:16] = transfor_data[19:16]+2'b11;
if(transfor_data[15:12]>4)
transfor_data[15:12] = transfor_data[15:12]+2'b11;
if(transfor_data[11:8]>4)
transfor_data[11:8] = transfor_data[11:8]+2'b11;
if(transfor_data[7:4]>4)
transfor_data[7:4] = transfor_data[7:4]+2'b11;
transfor_data[19:1] = transfor_data[18:0];
end
end
assign BCD = transfor_data[19:4];
endmodule
display7seg
module display7seg(
input clk,
input [3:0]data3,data2,data1,data0,
output reg[3:0]an,
output reg[6:0]display
);
reg [1:0] count;
always @(posedge clk) begin
if(count == 'b11)
count <= 0;
else
count <= count +'b1;
end
always @(posedge clk) begin
case(count)
2'b00: an <= 4'b1110;
2'b01: an <= 4'b1101;
2'b10: an <= 4'b1011;
2'b11: an <= 4'b0111;
endcase
end
always @(posedge clk) begin
case(count)
2'b00:
case (data0)
4'b0000:display = 7'b0000001;
4'b0001:display = 7'b1001111;
4'b0010:display = 7'b0010010;
4'b0011:display = 7'b0000110;
4'b0100:display = 7'b1001100;
4'b0101:display = 7'b0100100;
4'b0110:display = 7'b0100000;
4'b0111:display = 7'b0001111;
4'b1000:display = 7'b0000000;
4'b1001:display = 7'b0000100;
endcase
2'b01:
case (data1)
4'b0000:display = 7'b0000001;
4'b0001:display = 7'b1001111;
4'b0010:display = 7'b0010010;
4'b0011:display = 7'b0000110;
4'b0100:display = 7'b1001100;
4'b0101:display = 7'b0100100;
4'b0110:display = 7'b0100000;
4'b0111:display = 7'b0001111;
4'b1000:display = 7'b0000000;
4'b1001:display = 7'b0000100;
endcase
2'b10:
case (data2)
4'b0000:display = 7'b0000001;
4'b0001:display = 7'b1001111;
4'b0010:display = 7'b0010010;
4'b0011:display = 7'b0000110;
4'b0100:display = 7'b1001100;
4'b0101:display = 7'b0100100;
4'b0110:display = 7'b0100000;
4'b0111:display = 7'b0001111;
4'b1000:display = 7'b0000000;
4'b1001:display = 7'b0000100;
endcase
2'b11:
case (data3)
4'b0000:display = 7'b0000001;
4'b0001:display = 7'b1001111;
4'b0010:display = 7'b0010010;
4'b0011:display = 7'b0000110;
4'b0100:display = 7'b1001100;
4'b0101:display = 7'b0100100;
4'b0110:display = 7'b0100000;
4'b0111:display = 7'b0001111;
4'b1000:display = 7'b0000000;
4'b1001:display = 7'b0000100;
endcase
endcase
end
endmodule
單端口異步RAM
- 頂層模塊
- Asy_SinglePortRAM:單端口異步RAM;
- 其余模塊功能同上;
top_Asy_SinglePortRAM
module top_Asy_SinglePortRAM#(parameter DATA_WIDTH = 4,
parameter ADDR_DEPTH = 4)
(input clk,
rst,
input [ADDR_DEPTH-1:0]addr,
input [DATA_WIDTH-1:0]data_in,
input we,
oe,
output wire[3:0]an,
output wire[6:0]display);
wire[DATA_WIDTH-1:0]data_out;
wire clk_div;
reg [25:0]target = 50000;
wire [15:0]BCD;
//divider
divider d(.clk(clk),.rst(rst),.target(target),.clk_div(clk_div));
//Syn_SinglePortRAM
Asy_SinglePortRAM S(.clk(clk),.rst(rst),.addr(addr),.data_in(data_in),.we(we),.oe(oe),.data_out(data_out));
//transformer
transformer t(.data(data_out),.BCD(BCD));
//display7seg
display7seg dis(.clk(clk_div),.data3(BCD[15:12]),.data2(BCD[11:8]),.data1(BCD[7:4]),.data0(BCD[3:0]),.an(an),.display(display));
endmodule
Asy_SinglePortRAM
module Asy_SinglePortRAM#(parameter DATA_WIDTH = 4,parameter ADDR_DEPTH = 4)(
input clk,rst,
input [ADDR_DEPTH-1:0]addr,
input [DATA_WIDTH-1:0]data_in,
input we,oe,
output reg[DATA_WIDTH-1:0]data_out
);
reg [DATA_WIDTH-1:0] RAM[(1<<ADDR_DEPTH)-1:0];
//write
always @(posedge clk)
begin
if(rst)
begin:init_RAM
integer i;//必須聲明在有名字的塊中,或寫在外面
for(i=0;i<(1<<ADDR_DEPTH);i = i+1)
begin
RAM[i] <= 0;
end
end
else if(we)
begin
RAM[addr] <= data_in;
end
end
//read
//asy
always @(addr)
begin
if(!we && oe)
data_out = RAM[addr];
else
begin
data_out = 0;
end
end
endmodule
雙端口RAM
代碼傳送門:https://github.com/Geaming-CHN/Vivado/tree/main/_Digital logic/Project14
內容
實現雙端口(同步與異步)RAM設計,相對於單端口RAM而言,雙端口RAM存在兩個存取端口,並且可獨立進行讀寫操作,具有自己的地址(addr_a、addr_b)、數據輸入din_a、din_b輸出端口(dout_a、dout_b以及控制信號。
設計思路
雙端口(同步與異步)RAM,相對於單端口RAM而言,雙端口RAM存在兩個存取端口,並且可獨立進行讀寫操作,具有自己的地址(addr_a、addr_b)、數據輸入(din_a、din_b)/輸出端口(dout_a、dout_b)以及控制信號。雙端口RAM常用於視頻/圖像處理設計中。(額外添加了讀使能oe_a,oe_b)
雙端口同步RAM
- 頂層模塊:
- Syn_DoublePortRAM:雙端口同步RAM;
- 其余模塊功能同上
top_Syn_DoublePortRAM
module top_Syn_DoublePortRAM#(parameter DATA_WIDTH = 4,
parameter ADDR_DEPTH = 3)
(input clk,
rst,
input [ADDR_DEPTH-1:0]addr_a,
addr_b,
input [DATA_WIDTH-1:0]din_a,
din_b,
input we_a,
we_b,
input oe_a,
oe_b,
output wire[3:0]an,
output wire[6:0]display,
output wire error);
wire[DATA_WIDTH-1:0]dout_a,dout_b;
wire clk_div;
reg [25:0]target = 50000;
wire [15:0]BCD_a;
wire [15:0]BCD_b;
//divider
divider d(.clk(clk),.rst(rst),.target(target),.clk_div(clk_div));
//Syn_DoublePortRAM
Syn_DoublePortRAM S(.clk(clk),.rst(rst),.addr_a(addr_a),.addr_b(addr_b),.din_a(din_a),.din_b(din_b),.we_a(we_a),.we_b(we_b),.oe_a(oe_a),.oe_b(oe_b),.dout_a(dout_a),.dout_b(dout_b),.error(error));
//transformer
transformer t_a(.data(dout_a),.BCD(BCD_a));
transformer t_b(.data(dout_b),.BCD(BCD_b));
//display7seg
display7seg dis(.clk(clk_div),.data3(BCD_a[7:4]),.data2(BCD_a[3:0]),.data1(BCD_b[7:4]),.data0(BCD_b[3:0]),.an(an),.display(display));
endmodule
Syn_DoublePortRAM
module Syn_DoublePortRAM#(parameter DATA_WIDTH = 4,
parameter ADDR_DEPTH = 3)
(input clk,
rst,
input [ADDR_DEPTH-1:0]addr_a,
addr_b,
input [DATA_WIDTH-1:0]din_a,
din_b,
input we_a,
we_b,
input oe_a,
oe_b,
output reg[DATA_WIDTH-1:0]dout_a,
dout_b,
output reg error);
reg [DATA_WIDTH-1:0] RAM[(1<<ADDR_DEPTH)-1:0];
//error
always @(posedge clk)
begin
if (rst)
begin
error <= 0;
end
else if (!we_a&&!we_b&&(addr_a == addr_b))//地址相同時只能進行read
error <= 0;
else if (addr_a! = addr_b)//地址不同
error <= 0;
else
error <= 1;//error指示燈亮
end
//write
integer i;
always @(posedge clk)
begin
if (rst)//init
begin
for(i = 0;i<(1<<ADDR_DEPTH);i = i+1)
begin
RAM[i] <= 0;
end
end
else if (we_a&&!we_b&&(addr_a! = addr_b))
RAM[addr_a] = din_a;
else if (!we_a&&we_b&&(addr_a! = addr_b))
RAM[addr_b] = din_b;
else if (we_a&&we_b&&(addr_a! = addr_b))
begin
RAM[addr_a] = din_a;
RAM[addr_b] = din_b;
end
end
//read
//syn_a
always @(posedge clk)
begin
if (rst)
begin
dout_a <= 0;
end
else if (!we_a && oe_a)
begin
dout_a <= RAM[addr_a];
end
else
dout_a <= 0;
end
always @(posedge clk)
begin
if (rst)
begin
dout_b <= 0;
end
else if (!we_b && oe_b)
begin
dout_b <= RAM[addr_b];
end
else
dout_b <= 0;
end
endmodule
雙端口異步RAM
-
頂層模塊:
-
Asy_DoublePortRAM:雙端口同步RAM;
-
其余模塊功能同上
top_Asy_DoublePortRAM
module top_Asy_DoublePortRAM#(parameter DATA_WIDTH = 3,
parameter ADDR_DEPTH = 3)
(input clk,
rst,
input [ADDR_DEPTH-1:0]addr_a,
addr_b,
input [DATA_WIDTH-1:0]din_a,
din_b,
input we_a,
we_b,
input oe_a,
oe_b,
output wire[3:0]an,
output wire[6:0]display,
output wire error);
wire[DATA_WIDTH-1:0]dout_a,dout_b;
wire clk_div;
reg [25:0]target = 50000;
wire [15:0]BCD_a;
wire [15:0]BCD_b;
//divider
divider d(.clk(clk),
.rst(rst),
.target(target),
.clk_div(clk_div));
//Syn_DoublePortRAM
Asy_DoublePortRAM S(.clk(clk),
.rst(rst),
.addr_a(addr_a),
.addr_b(addr_b),
.din_a(din_a),
.din_b(din_b),
.we_a(we_a),
.we_b(we_b),
.oe_a(oe_a),
.oe_b(oe_b),
.dout_a(dout_a),
.dout_b(dout_b),
.error(error));
//transformer
transformer t_a(.data(dout_a),.BCD(BCD_a));
transformer t_b(.data(dout_b),.BCD(BCD_b));
//display7seg
display7seg dis(.clk(clk_div),.data3(BCD_a[7:4]),.data2(BCD_a[3:0]),.data1(BCD_b[7:4]),.data0(BCD_b[3:0]),.an(an),.display(display));
endmodule
Asy_DoublePortRAM
module Asy_DoublePortRAM#(parameter DATA_WIDTH = 4,
parameter ADDR_DEPTH = 3)
(input clk,
rst,
input [ADDR_DEPTH-1:0]addr_a,
addr_b,
input [DATA_WIDTH-1:0]din_a,
din_b,
input we_a,
we_b,
input oe_a,
oe_b,
output reg[DATA_WIDTH-1:0]dout_a,
dout_b,
output reg error);
reg [DATA_WIDTH-1:0] RAM[(1<<ADDR_DEPTH)-1:0];
//error
always @(posedge clk)
begin
if (rst)
begin
error <= 0;
end
else if (!we_a&&!we_b&&(addr_a == addr_b))//地址相同時只能進行read
error <= 0;
else if (addr_a! = addr_b)//地址不同
error <= 0;
else
error <= 1;//error指示燈亮
end
//write
integer i;
always @(posedge clk)
begin
if (rst)//init
begin
for(i = 0;i<(1<<ADDR_DEPTH);i = i+1)
begin
RAM[i] <= 0;
end
end
else if (we_a&&!we_b&&(addr_a! = addr_b))
RAM[addr_a] = din_a;
else if (!we_a&&we_b&&(addr_a! = addr_b))
RAM[addr_b] = din_b;
else if (we_a&&we_b&&(addr_a! = addr_b))
begin
RAM[addr_a] = din_a;
RAM[addr_b] = din_b;
end
end
//read
//asy_a
always @(addr_a)
begin
if (!we_a && oe_a)
dout_a <= RAM[addr_a];
else
dout_a <= 0;
end
//asy_b
always @(addr_b)
begin
if (!we_b && oe_b)
dout_b <= RAM[addr_b];
else
dout_b <= 0;
end
endmodule
FIFO
代碼傳送門:https://github.com/Geaming-CHN/Vivado/tree/main/_Digital logic/Project14
內容
實現FIFO設計,FIFO由存儲單元隊列或陣列構成,和RAM不同的是FIFO沒有地址,第一個被寫入隊列的數據也是第一個從隊列中讀出的數據。
設計思路
FIFO 是一個先入先出的存儲隊列,和RAM 不同的是FIFO 沒有地址,第一個被寫入隊列的數據也是第一個從隊列中讀出的數據。FIFO 可以在輸入輸出速率不匹配時,作為臨時存儲單元;可用於不同時鍾域中間的同步;輸入數據路徑和輸出數據路徑之間數據寬度不匹配時,可用於數據寬度調整電路。
-
頂層模塊
-
debkey:消抖模塊;
-
FIFO:實現FIFO;
top_FIFO
module top_FIFO#(parameter DATA_WIDTH = 4,parameter ADDR_DEPTH = 4)(
input button,clk,rst,wr_en,rd_en,
input [DATA_WIDTH-1:0]data_in,
output empty,full,
output wire[3:0]an,
output wire[6:0]display
);
wire button_deb;
wire[DATA_WIDTH-1:0]data_out;
wire clk_div;
reg [25:0]target = 50000;
wire [15:0]BCD;
//divider
divider d(.clk(clk),.rst(rst),.target(target),.clk_div(clk_div));
//debkey
debkey deb(.clk(clk),.rst(rst),.key_in(button),.key_out(button_deb));
//FIFO
FIFO F(.clk(button_deb),.rst(rst),.wr_en(wr_en),.rd_en(rd_en),.data_in(data_in),.empty(empty),.full(full),.data_out(data_out));
//transformer
transformer t(.data(data_out),.BCD(BCD));
//display7seg
display7seg dis(.clk(clk_div),.data3(BCD[15:12]),.data2(BCD[11:8]),.data1(BCD[7:4]),.data0(BCD[3:0]),.an(an),.display(display));
endmodule
FIFO
module FIFO#(parameter DATA_WIDTH = 4,parameter ADDR_DEPTH = 4)(
input clk,rst,wr_en,rd_en,
input [DATA_WIDTH-1:0] data_in,
output reg empty,full,
output reg[DATA_WIDTH-1:0] data_out
);
reg [DATA_WIDTH-1:0] FIFO[(1<<ADDR_DEPTH) - 1:0];
reg [ADDR_DEPTH-1:0]head;
reg [ADDR_DEPTH-1:0]rear;
reg [ADDR_DEPTH:0]NUM;
//empty
always @(*) begin
if(NUM==0)
empty<=1;
else
empty<=0;
end
//full
always @(*) begin
if(NUM==(1<<ADDR_DEPTH))
full<=1;
else
full<=0;
end
//NUM
always @(posedge clk or posedge rst) begin
if(rst)
NUM<=0;
else if(!wr_en&&!rd_en)//no write no read
NUM<=NUM;
else if(wr_en&&!rd_en&&(NUM<(1<<ADDR_DEPTH)))//wirte no read
NUM<=NUM+'b1;
else if(!wr_en&&rd_en&&(NUM>0))//read no write
NUM<=NUM-'b1;
else if(wr_en&&rd_en)
NUM<=NUM;
end
//write
integer i;
always @(posedge clk or posedge rst) begin
if(rst)
begin
rear<='b0;
for(i=0;i<(1<<ADDR_DEPTH);i=i+1)
FIFO[i]<=0;
end
else if(wr_en&&(NUM<(1<<ADDR_DEPTH)))//not full
begin
FIFO[rear]<=data_in;
rear<=(rear+1)%(1<<ADDR_DEPTH);
end
else if(wr_en&&(NUM>(1<<ADDR_DEPTH)-1))//full
rear<=rear;
end
//read
always @(posedge clk or posedge rst) begin
if(rst)
begin
head<='b0;
data_out<=0;
end
else if(rd_en&&(NUM!=0))
begin
data_out<=FIFO[head];
head<=(head+1)%(1<<ADDR_DEPTH);
end
else if(NUM==0)
data_out<=0;
end
endmodule
debkey
module debkey(
input clk,
input rst,
input key_in,
output key_out
);
parameter T100Hz = 249999;
integer cnt_100Hz;
reg clk_100Hz;
always @(posedge clk) begin
if(rst)
cnt_100Hz<=32'b0;
else
begin
cnt_100Hz<=cnt_100Hz+1'b1;
if(cnt_100Hz==T100Hz)
begin
cnt_100Hz<=32'b0;
clk_100Hz<=~clk_100Hz;
end
end
end
reg[2:0]key_rrr,key_rr,key_r;
always @(posedge clk_100Hz) begin
if(rst)
begin
key_rrr<=1'b1;
key_rr<=1'b1;
key_r<=1'b1;
end
else
begin
key_rrr<=key_rr;
key_rr<=key_r;
key_r<=key_in;
end
end
assign key_out = key_rrr&key_rr&key_r;
endmodule