一. 实验目的
熟练掌握时序逻辑电路的设计方法
掌握寄存器文件的实现原理掌握
数码管动态扫描实现方法
二. 实验内容
用模块化设计,实现 16*16bit 的寄存器文件
– 具备 2 组读端口及 1 组写端口
– 通过读端口可从 0~15 号的任意地址读取数据
– 通过写端口可向 0~15 号的任意地址写入数据
– 读写端口为“全双工”的工作方式
– 0~15 号寄存器的复位初值依次为:“0x0000,0x1100,0x2200,...,0xFF00”
– 通过 1 组读端口及写端口,所有寄存器的值每 0.5s 秒钟加 1
– 通过拨动开关做为另 1 组读端口地址输入,将读出结果以16 进制显示在七段数码管上
三.实验结果
1)编写 verilog代码
Top 模块
module regfile(
input clk,
input reset_n,
input [3:0]addr_a,
input [3:0]addr_b,
input [3:0]addr_c,
input [15:0]data_c,
input wen_c,
output reg[15:0]q_a,
output reg[15:0]q_b
);
reg[15:0] a0;reg[15:0] a1;reg[15:0] a2;
reg[15:0] a3;
reg[15:0] a4;
reg[15:0] a5;
reg[15:0] a6;
reg[15:0] a7;
reg[15:0] a8;
reg[15:0] a9;
reg[15:0] a10;
reg[15:0] a11;
reg[15:0] a12;
reg[15:0] a13;
reg[15:0] a14;
reg[15:0] a15;
always @(posedge clk or negedge reset_n)
if(~reset_n) //复位
begin
a0<=16'h0000;
a1<=16'h1100;
a2<=16'h2200;
a3<=16'h3300;
a4<=16'h4400;
a5<=16'h5500;
a6<=16'h6600;
a7<=16'h7700;
a8<=16'h8800;
a9<=16'h9900;
a10<=16'haa00;
a11<=16'hbb00;
a12<=16'hcc00;
a13<=16'hdd00;
a14<=16'hee00;
a15<=16'hff00;
end
else
begin
if(wen_c)
begin
case(addr_c)
4'b0000: a0<=data_c;
4'b0001: a1<=data_c;
4'b0010: a2<=data_c;
4'b0011: a3<=data_c;
4'b0100: a4<=data_c;
4'b0101: a5<=data_c;
4'b0110: a6<=data_c;
4'b0111: a7<=data_c;
4'b1000: a8<=data_c;
4'b1001: a9<=data_c;
4'b1010: a10<=data_c;
4'b1011: a11<=data_c;
4'b1100: a12<=data_c;
4'b1101: a13<=data_c;
4'b1110: a14<=data_c;
4'b1111: a15<=data_c;
default: a0<=0;
endcase
q_b[15:0]<=data_c;
end
else
begin
case(addr_b)
4'b0000: q_b[15:0]<=a0;
4'b0001: q_b[15:0]<=a1;
4'b0010: q_b[15:0]<=a2;
4'b0011: q_b[15:0]<=a3;
4'b0100: q_b[15:0]<=a4;
4'b0101: q_b[15:0]<=a5;
4'b0110: q_b[15:0]<=a6;
4'b0111: q_b[15:0]<=a7;
4'b1000: q_b[15:0]<=a8;
4'b1001: q_b[15:0]<=a9;
4'b1010: q_b[15:0]<=a10;
4'b1011: q_b[15:0]<=a11;
4'b1100: q_b[15:0]<=a12;
4'b1101: q_b[15:0]<=a13;
4'b1110: q_b[15:0]<=a14;
4'b1111: q_b[15:0]<=a15;
default: q_b[15:0]<=16'h0000;
endcase
end
end
always@(posedge clk or negedge reset_n)
if(~reset_n)
q_a[15:0]<=16'h0000;
else
case(addr_a)
4'b0000: q_a[15:0]<=a0;
4'b0001: q_a[15:0]<=a1;
4'b0010: q_a[15:0]<=a2;
4'b0011: q_a[15:0]<=a3;
4'b0100: q_a[15:0]<=a4;
4'b0101: q_a[15:0]<=a5;
4'b0110: q_a[15:0]<=a6;
4'b0111: q_a[15:0]<=a7;
4'b1000: q_a[15:0]<=a8;
4'b1001: q_a[15:0]<=a9;
4'b1010: q_a[15:0]<=a10;
4'b1011: q_a[15:0]<=a11;
4'b1100: q_a[15:0]<=a12;
4'b1101: q_a[15:0]<=a13;
4'b1110: q_a[15:0]<=a14;
4'b1111: q_a[15:0]<=a15;
default: q_a[15:0]<=16'h0000;
endcase
endmodule
module inc( input clk, input reset_n, input [15:0]q_b, output reg[3:0] addr_b, output reg[3:0] addr_c, output reg[15:0] data_c, output reg wen_c
); reg [29:0]cnt; reg clk0; always@(posedge clk or negedge reset_n) if(~reset_n) cnt<=0; else begin cnt<=cnt+1; if(cnt==100000-1)
clk0<=1;
else if(cnt==1000000-1) begin clk0<=0; cnt<=0; end end
always@(posedge clk0 or negedge reset_n)
if(~reset_n) begin
wen_c<=0; addr_b<=0; addr_c<=0; data_c<=0;
end else
begin if(wen_c)
begin wen_c<=~wen_c; addr_b<=addr_b; if(addr_c>=4'b1111) addr_c<=4'b0000;
else
addr_c<=addr_c+1; data_c<=data_c;
end else begin
wen_c<=~wen_c; if(addr_b>=4'b1111) addr_b<=4'b0000;
else
addr_b<=addr_b+1; data_c<=q_b+1'b1;
end end
endmodule
module seg( input clk, input reset_n, input [15:0]q_a, output reg[7:0]data, output reg[3:0]sel
); reg [29:0]cnt; reg [1:0]scn_cnt; reg clk0; always@(posedge clk or negedge reset_n)
if(~reset_n)
cnt<=0; else begin
cnt<=cnt+1;
if(cnt==10000-1) clk0<=1;
else if(cnt==100000-1)
begin clk0<=0; cnt<=0; end
end
always@(posedge clk0 or negedge reset_n) if(~reset_n) scn_cnt<=2'b00; else begin
if(scn_cnt==2'b11) scn_cnt<=2'b00; else
scn_cnt<=scn_cnt+1'b1;
end
always@(posedge clk0 or negedge reset_n) if(~reset_n) sel<=4'b1111; else
case(scn_cnt) 2'b00: sel<=4'b1110;
2'b01: sel<=4'b1101;
2'b10: sel<=4'b1011; 2'b11: sel<=4'b0111; default: sel<=4'b1111; endcase
always @(posedge clk0 or negedge reset_n) if(~reset_n) data=8'b11111111; else
begin
if(sel==4'b0111) begin
case(q_a[15:12]) 4'h0: data=8'b00000011;
4'h1: data=8'b10011111;
4'h2: data=8'b00100101;
4'h3: data=8'b00001101;
4'h4: data=8'b10011001;
4'h5: data=8'b01001001; 4'h6: data=8'b01000001; 4'h7: data=8'b00011111;
4'h8: data=8'b00000001;
4'h9: data=8'b00001001; 4'ha: data=8'b00010001;
4'hb: data=8'b11000001;
4'hc: data=8'b01100011;
4'hd: data=8'b10000101;
4'he: data=8'b01100001; 4'hf: data=8'b01110001; default: data=8'b11111111;
endcase end
else if(sel==4'b1011)
begin
case(q_a[11:8]) 4'h0: data=8'b00000011;
4'h1: data=8'b10011111;
4'h2: data=8'b00100101;
4'h3: data=8'b00001101;
4'h4: data=8'b10011001;
4'h5: data=8'b01001001;
4'h6: data=8'b01000001;
4'h7: data=8'b00011111;
4'h8: data=8'b00000001;
4'h9: data=8'b00001001; 4'ha: data=8'b00010001; 4'hb: data=8'b11000001;
4'hc: data=8'b01100011;
4'hd: data=8'b10000101; 4'he: data=8'b01100001; 4'hf: data=8'b01110001; default: data=8'b11111111;
endcase end
else if(sel==4'b1101) begin
case(q_a[7:4]) 4'h0: data=8'b00000011;
4'h1: data=8'b10011111;
4'h2: data=8'b00100101;
4'h3: data=8'b00001101;
4'h4: data=8'b10011001;
4'h5: data=8'b01001001; 4'h6: data=8'b01000001; 4'h7: data=8'b00011111;
4'h8: data=8'b00000001;
4'h9: data=8'b00001001; 4'ha: data=8'b00010001;
4'hb: data=8'b11000001;
4'hc: data=8'b01100011;
4'hd: data=8'b10000101;
4'he: data=8'b01100001; 4'hf: data=8'b01110001; default: data=8'b11111111;
endcase end
else begin
case(q_a[3:0]) 4'h0: data=8'b00000011;
4'h1: data=8'b10011111;
4'h2: data=8'b00100101;
4'h3: data=8'b00001101;
4'h4: data=8'b10011001;
4'h5: data=8'b01001001;
4'h6: data=8'b01000001;
4'h7: data=8'b00011111;
4'h8: data=8'b00000001;
4'h9: data=8'b00001001; 4'ha: data=8'b00010001; 4'hb: data=8'b11000001;
4'hc: data=8'b01100011;
4'hd: data=8'b10000101; 4'he: data=8'b01100001; 4'hf: data=8'b01110001; default: data=8'b11111111;
endcase end end endmodule
2) Ucf 文件设置
四.实验分析
1.本实验主要分为三个部分,寄存器文件,数码管的控制,以及加一运算实现这三个模块
2..寄存器文件本质为一状态机
3.对于时间上地要求,0.5s 采用统计地方式实现,达到一定地周期数后产生脉冲
在同一时刻对同一地址进行读写,会有何结果?会将时钟上升沿之前的内容读出,然后将新内容写进覆盖原先内容,因为在reg 模块中可见采用的是非阻塞赋值的方式,读写同时进行不存在先后