本文主要思路是建立一个4个8位寄存器,然后在顶层文件中对这四个寄存器写入数值,最后在四个存储器中读取数值。
其模块框图如下:
下面是verilog代码实现:
(1)存储器模块
module device_regs(clk,reset,data_in,data_adr,wr_en,rd_en,read_data);
input clk,reset;
input wr_en, rd_en;
input [7:0] data_in;
input [1:0] data_adr;
output [7:0] read_data;
reg [7:0] reg0,reg1,reg2,reg3;
wire [7:0] reg0_nxt,reg1_nxt,reg2_nxt,reg3_nxt;
reg[7:0] read_data,read_data_nxt;
wire reg_match0,reg_match1,reg_match2,reg_match3;
assign reg_match0 = (data_adr == 2'b00);
assign reg_match1 = (data_adr == 2'b01);
assign reg_match2 = (data_adr == 2'b10);
assign reg_match3 = (data_adr == 2'b11);
assign reg0_nxt = (reg_match0&&wr_en)? data_in:reg0;
assign reg1_nxt = (reg_match0&&wr_en)? data_in:reg1;
assign reg2_nxt = (reg_match0&&wr_en)? data_in:reg2;
assign reg3_nxt = (reg_match0&&wr_en)? data_in:reg3;
always@(posedge clk or negedge reset)begin
if(!reset)begin
reg0 <= 'd0;
reg1 <= 'd0;
reg2 <= 'd0;
reg3 <= 'd0;
read_data <= 4'b0000;
end
else begin
reg0 <= reg0_nxt;
reg1 <= reg1_nxt;
reg2 <= reg2_nxt;
reg3 <= reg3_nxt;
read_data <= read_data_nxt;
end
end
always@(*) begin
read_data_nxt = read_data;
if(rd_en)begin
case(1'b1)
reg_match0:read_data_nxt = reg0;
reg_match1:read_data_nxt = reg1;
reg_match2:read_data_nxt = reg2;
reg_match3:read_data_nxt = reg3;
endcase
end
end
endmodule
(2)测试文件,包括读写任务
`timescale 1ns/1ns
module testbench_top();
reg[1:0] address_tb;
reg[7:0] wrdata_tb;
wire[7:0] rddata_tb;
reg wr_en_tb,rd_en_tb;
reg clk_tb;
reg reset_tb;
parameter CLKTB_HALF_PERIOD = 5;
parameter RST_DEASSERT_DELAY = 100;
parameter REG0_OFFSET = 2'b00,
REG1_OFFSET = 2'b01,
REG2_OFFSET = 2'b10,
REG3_OFFSET = 2'b11;
initial begin
clk_tb = 0;
forever #CLKTB_HALF_PERIOD clk_tb = ~clk_tb;
end
//generate clk
initial begin
reset_tb = 1'b0;
#RST_DEASSERT_DELAY reset_tb= 1'b1;
end
//generate reset
initial begin
address_tb = 2'b00;
wrdata_tb = 'h0;
wr_en_tb = 1'b0;
rd_en_tb = 1'b0;
end
//initialize varible
device_regs device_regs_tb
(.clk(clk_tb),
.reset(reset_tb),
.data_in(wrdata_tb),
.data_adr(address_tb),
.wr_en(wr_en_tb),
.rd_en(rd_en_tb),
.read_data(rddata_tb));
//module example
task reg_write;
input [1:0] address_in;
input [7:0] data_in;
begin
@(posedge clk_tb);
#1 address_tb = address_in;
@(posedge clk_tb);
#1 wr_en_tb = 1'b1;
wrdata_tb = data_in;
@(posedge clk_tb);
#1;
address_tb = 2'b11;
wr_en_tb = 1'b0;
wrdata_tb = 8'h00;
end
endtask
//task write
task reg_read;
input address_in;
input expected_data;
begin
@(posedge clk_tb)
#1 address_tb = address_in;
@(posedge clk_tb)
#1 rd_en_tb = 1'b1;
@(posedge clk_tb)
#1 rd_en_tb = 1'b0;
address_tb = 2'b11;
@(posedge clk_tb);
$display("expected_data = %h,actual_data = %h",expected_data,rddata_tb);
end
endtask
//task read
initial begin
#1000;
reg_write(REG0_OFFSET,8'hA5);
reg_read(REG0_OFFSET,8'hA5);
reg_write(REG0_OFFSET,8'hA6);
reg_read(REG0_OFFSET,8'hA6);
reg_write(REG0_OFFSET,8'hA7);
reg_read(REG0_OFFSET,8'hA7);
reg_write(REG0_OFFSET,8'hA8);
reg_read(REG0_OFFSET,8'hA8);
end
endmodule
其仿真结果如下:
可以看到写入的A5,A6,A7,A8数据都读了出来
这是控制栏的显示