初学者verilog中function,task的仿真使用了解

//原程序
//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块的写法有所不同了,值得尝试

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值