//原程序
//3——9——2
module device_regs_withfunction(
input [3:0] address,
input write_en,
input read_en,
input [7:0] data_in,
output reg [7:0] read_data,
input clk,
input resetb
);
reg[7:0] reg0,reg1,reg2,reg3;
reg[7:0] read_data_nxt;
function [7:0] dev_reg_nxt;
input [3:0] address;
input [3:0] reg_offset;
input write_en;
input [7:0] data_in;
input [7:0] dev_reg;
begin
dev_reg_nxt = ((address == reg_offset)&&write_en)?data_in:dev_reg;
end
endfunction
always @(posedge clk or negedge resetb)begin
if(!resetb)begin
reg0 <= 'd0;
reg1 <= 'd0;
reg2 <= 'd0;
reg3 <= 'd0;
read_data <= 'd0;
end
else begin
reg0 <= dev_reg_nxt(address,4'b0000,write_en,data_in,reg0);
reg1 <= dev_reg_nxt(address,4'b0001,write_en,data_in,reg1);
reg2 <= dev_reg_nxt(address,4'b0010,write_en,data_in,reg2);
reg3 <= dev_reg_nxt(address,4'b0011,write_en,data_in,reg3);
read_data <= read_data_nxt;
end
end
always @(*)begin
read_data_nxt = read_data;
if(read_en)begin
case(1'b1)
(address == 4'b0000):read_data_nxt = reg0;
(address == 4'b0001):read_data_nxt = reg1;
(address == 4'b0010):read_data_nxt = reg2;
(address == 4'b0011):read_data_nxt = reg3;
endcase
end
end
endmodule
//--------------------------------------仿真程序-----------------------------------------------------
//一个简单的testbench
//4_7与3——9——2联合使用
`timescale 1ns/10ps
module testbench_top();
reg [3:0] address_tb;
reg [7:0] wrdata_tb;
reg write_en_tb,read_en_tb;
reg clk_tb,resetb;
wire [7:0] rddata_tb;
//*******************************************************
parameter CLKTB_HALF_PERIOD = 5;
parameter RST_DEASSERT_DLY = 100;
parameter REG0_OFFSET =4'b0000;
parameter REG1_OFFSET =4'b0001;
parameter REG2_OFFSET =4'b0010;
parameter REG3_OFFSET =4'b0011;
//generate clk_tb
initial begin
clk_tb = 1'b0;
forever begin
#CLKTB_HALF_PERIOD clk_tb = ~clk_tb;
end
end
//generate resetb
initial begin
resetb = 1'b0;
#RST_DEASSERT_DLY resetb = 1'b1;
end
initial begin
address_tb = 'b0;
wrdata_tb = 'b0;
write_en_tb = 1'b0;
read_en_tb = 1'b0;
end
device_regs_withfunction device_regs_withfunction_0
(
.clk(clk_tb),
.resetb(resetb),
.address(address_tb),
.write_en(write_en_tb),
.read_en(read_en_tb),
.data_in(wrdata_tb),
.read_data(rddata_tb)
);
task reg_write;
input [3:0] address_in;
input [7:0] data_in;
begin
@(posedge clk_tb);
#1 address_tb = address_in;
@(posedge clk_tb);
#1 write_en_tb = 1'b1;
wrdata_tb = data_in;
@(posedge clk_tb);
#1;
write_en_tb = 1'b0;
address_tb = 4'hF;
wrdata_tb = 4'h0;
end
endtask
task reg_read;
input [3:0] address_in;
input [7:0] expected_data;
begin
@(posedge clk_tb);
#1 address_tb = address_in;
@(posedge clk_tb);
#1 read_en_tb = 1'b1;
@(posedge clk_tb);
#1;
read_en_tb = 1'b0;
address_tb = 4'hF;
@(posedge clk_tb);
if(expected_data == rddata_tb)
$display ("data matches:expected_data = %h,actual data = %h",expected_data,rddata_tb);
else
$display ("ERROR:data mismatch:expected_data = %h,actual_data = %h",expected_data,rddata_tb);
end
endtask
initial begin
#1000;
reg_write (REG0_OFFSET,8'hA5);
reg_read(REG0_OFFSET,8'hA5);
reg_write(REG1_OFFSET,8'hA6);
reg_read(REG1_OFFSET,8'hA6);
reg_write(REG2_OFFSET,8'hA7);
reg_read(REG2_OFFSET,8'hA7);
reg_write(REG3_OFFSET,8'hA8);
reg_read(REG3_OFFSET,8'hA8);
#1000;
$stop;
end
endmodule
//仿真图像
以上两个文件是可以直接仿真的,实现一个读写寄存器的功能,该程序使用语法比较丰富,包含代码里可综合的逻辑用function,仿真文件中使用task,是一个很好的初学模仿使用教程
initial begin
r_period_cnt <= 13'd0;
for(s=1;s<=30000;s=s+1)begin
@(posedge r_clk_1M)begin
r_ad_data_buf <= ad_data_txt[r_period_cnt];
r_period_cnt <= r_period_cnt+1'b1;
r_ad_data_valid <= 1'b1;
#10;
r_ad_data_valid <= 1'b0;
end
end
end
记录仿写的一段程序,使用了for循环在initial里,这段是为了直接实现10M的AD采样下,100M的valid指示信号的变化,这样写的好处是实现了一个时钟,两个不同时钟域变化的信号的仿写。
接上再更新一段仿真的写法
always @(posedge fetch_data)begin
@(posedge clk2x);
@(posedge clk2x);
#1
ack_fetch_data = 1'b1;
@(posedge clk2x);
#1
ack_fetch_data = 1'b0;
end
这个仿真的写法真的与可综合的always块的写法有所不同了,值得尝试