1.原理
数据使能信号充当掩码的作用。1表示1字节就是8个位有效。
2.1 ram_ctrl.v
module ram_ctrl#(
parameter CNT_MAX=24'd9_999_999
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire wr_flag ,
input wire rd_flag ,
output reg wr_en ,
output reg [7:0] addr ,
output reg[7:0] wr_data ,
output reg rd_en
);
reg [23:0] cnt_200ms;
assign wr_data=(wr_en==1'b1)?(addr):1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
wr_en<=1'b0;
else if(addr==8'd255)
wr_en<=1'b0;
else if(wr_flag==1'b1)
wr_en<=1'b1;
else
wr_en<=wr_en;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
rd_en<=1'b0;
else if(wr_flag==1'b1)
rd_en<=1'b0;
else if((rd_flag==1'b1)&&(wr_en==1'b0))
rd_en<=1'b1;
else
rd_en<=rd_en;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
addr<=8'd0;
else if(((addr==8'd255)&&(wr_en==1'b1))||((addr==8'd255)&&(cnt_200ms==24'd255))||rd_flag==1'b1||wr_flag==1'b1)
addr<=8'd0;
else if((wr_en==1'b1)||((rd_en==1'b1)&&(cnt_200ms==CNT_MAX)))
addr<=addr+1'b1;
else
addr<=addr;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
cnt_200ms<=24'd0;
else if((wr_flag==1'b1)||(cnt_200ms==CNT_MAX)||(rd_flag==1'b1))
cnt_200ms<=24'd0;
else if(rd_en==1'b1)
cnt_200ms<=cnt_200ms+1'b1;
else
cnt_200ms<=24'd0;
endmodule
2.2 tb_ram_ctrl.v
`timescale 1ns/1ns
module tb_ram_ctrl();
reg sys_clk ;
reg sys_rst_n ;
reg wr_flag ;
reg rd_flag ;
wire wr_en ;
wire [7:0] addr ;
wire [7:0]wr_data ;
wire rd_en ;
wire [7:0] data_out ;
initial
begin
sys_clk=1'b1;
sys_rst_n<=1'b0;
wr_flag<=1'b0;
rd_flag<=1'b0;
#20
sys_rst_n<=1'b1;
#1000
//rd_flag
rd_flag<=1'b1;
#20
rd_flag<=1'b0;
#60000 //一个数据显示11个时钟周期,256个数据,256*11=2816个时钟周期,就是2816*20=56320
//wr_flag
wr_flag<=1'b1;
#20
wr_flag<=1'b0;
#60000 //20*256=5120
//rd_flag
rd_flag<=1'b1;
#20
rd_flag<=1'b0;
end
assign #10 sys_clk=~sys_clk;
ram_ctrl#(
.CNT_MAX (4'd10)
)
ram_ctrl_inst
(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n) ,
.wr_flag (wr_flag ) ,
.rd_flag (rd_flag ) ,
.wr_en (wr_en ) ,
.addr (addr ) ,
.wr_data (wr_data ) ,
.rd_en (rd_en )
);
ram_8x256_one ram_8x256_one_inst
(
.aclr (~sys_rst_n),
.address(addr),
.clock (sys_clk),
.data (wr_data),
.rden (rd_en),
.wren (wr_en),
.q (data_out)
);
endmodule
2.3 ram.v
module ram(
input wire sys_clk ,
input wire sys_rst_n ,
input wire wr_key ,
input wire rd_key ,
output wire ds ,
output wire oe ,
output wire shcp ,
output wire stcp
);
wire wr_flag;
wire rd_flag;
wire wr_en ;
wire [7:0]addr ;
wire [7:0]wr_data ;
wire rd_en ;
wire [7:0]data_out;
key_filter
#(
.CNT_MAX (20'd999_999)
)
key_filter_wr_inst
(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n ),
.key_in (wr_key ),
.key_flag (wr_flag )
);
key_filter
#(
.CNT_MAX (20'd999_999)
)
key_filter_rd_inst
(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n ),
.key_in (rd_key ),
.key_flag (rd_flag )
);
ram_ctrl #(
.CNT_MAX(24'd9_999_999)
)
(
.sys_clk (sys_clk) ,
.sys_rst_n (sys_rst_n) ,
.wr_flag (wr_flag) ,
.rd_flag (rd_flag) ,
.wr_en (wr_en ) ,
.addr (addr ) ,
.wr_data (wr_data) ,
.rd_en ( rd_en )
);
ram_8x256_one ram_8x256_one_inst
(
.aclr (~sys_rst_n),
.address(addr),
.clock (sys_clk),
.data (wr_data),
.rden (rd_en),
.wren (wr_en),
.q (data_out)
);
seg_595_dynamic(
.sys_clk (sys_clk) ,
.sys_rst_n (sys_rst_n) ,
.data ({12'b0,data_out}) ,
.point (6'b000_000) ,
.sign (1'b0) ,
.seg_en (1'b1) ,
.ds (ds ) ,
.oe (oe ) ,
.shcp (shcp) ,
.stcp (stcp)
);
endmodule
2.4 tb_ram.v
`timescale 1ns/1ns
module tb_ram();
reg sys_clk ;
reg sys_rst_n ;
reg wr_key ;
reg rd_key ;
wire ds ;
wire oe ;
wire shcp ;
wire stcp ;
initial
begin
sys_clk=1'b1;
sys_rst_n<=1'b0;
wr_key=1'b1;
rd_key=1'b1;
#20
sys_rst_n<=1'b1;
#1000
//读操作rd_key
//模拟产生读操作按键前抖动
rd_key=1'b0;
#20
rd_key=1'b1;
#20
rd_key=1'b0;
#20
rd_key=1'b1;
#20
//模拟产生的稳定状态
rd_key=1'b0;
#200
//模拟产生按键信号的后抖动
rd_key=1'b1;
#20
rd_key=1'b0;
#20
rd_key=1'b1;
#20
rd_key=1'b0;
#20
rd_key=1'b1;
//此时就会读出在ip核事先初始化的数据
#200000
//模拟读数据的过程
//
wr_key=1'b0;
#20
wr_key=1'b1;
#20
wr_key=1'b0;
#20
wr_key=1'b1;
#20
//模拟稳定状态
wr_key=1'b0;
#200
//后抖动
wr_key=1'b1;
#20
wr_key=1'b0;
#20
wr_key=1'b1;
#20
wr_key=1'b0;
#20
wr_key=1'b1;
#1000
//rd_key
rd_key=1'b0;
#20
rd_key=1'b1;
#20
rd_key=1'b0;
#20
rd_key=1'b1;
#20
rd_key=1'b0;
#200
rd_key=1'b1;
#20
rd_key=1'b0;
#20
rd_key=1'b1;
#20
rd_key=1'b0;
#20
rd_key=1'b1;
#200000
//在读数据的过程中再次按下读操作按键
rd_key=1'b0;
#20
rd_key=1'b1;
#20
rd_key=1'b0;
#20
rd_key=1'b1;
#20
rd_key=1'b0;
#200
rd_key=1'b1;
#20
rd_key=1'b0;
#20
rd_key=1'b1;
#20
rd_key=1'b0;
#20
rd_key=1'b1;
#200000
end
always #10 sys_clk=~sys_clk;
defparam ram_inst.key_filter_wr_inst.CNT_MAX=9;
defparam ram_inst.key_filter_wr_inst.CNT_MAX=9;
defparam ram_inst.ram_ctrl_inst.CNT_MAX=99;
ram ram_inst(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n) ,
.wr_key (wr_key ) ,
.rd_key (rd_key ) ,
.ds (ds ) ,
.oe (oe ) ,
.shcp (shcp ) ,
.stcp (stcp )
);
endmodule
对顶层模块的仿真主要是查看各个模块之间的信号传递是否正确,因为之前各个模块已经仿真过了。
总的过程就是刚开始读初始化的数据,然后再次读一次发现还是从0地址开始读,然后在读的过程中按下写的按钮,此时就不再读了,数据定格在最后的一瞬间,再次按下读按钮,又从0地址开始读写入的数据。