【精品博文】学习FPGA第一天

用case语句实现一个计数器

module ex_case(
                       input wire rst_n,
        input wire sclk,
        output reg o_dv, //标志数据有效
        output reg [7:0] o_data, //用于数据输入
        input wire [9:0] i_data,
        input wire [7:0] i_addr
);
reg [2:0] cnt_7;
//不同功能的寄存器分开always块来写,这样代码的可维护性和可读性强.

always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_7 <= 3'd0;
    else
        cnt_7 <= cnt_7 + 1'b1; //溢出,低三位重新为0
always @(posedge sclk or negedge rst_n)
    if(rst_n == 1'b0)begin
        o_data<=8'd0;
        o_dv<=1'b0; //如果不赋初值,复位会接在o_dv使能端。
    end
    else begin
        case(cnt_7)
            3'd0:begin
                o_data<=3'd7; //当cnt_7等于3'd0时,执行此条语句。如果:后多条语句,加beginend
                o_dv<=1'b1;
               end
            3'd1:begin
                o_data<=3'd0; //case endcase 比if else 快.相当于译码器
                o_dv<=1'b0;
               end
            3'd2:begin
                o_data<=3'd5;
                o_dv<=1'b1;
               end
            default:begin
                o_data<=3'd0;
                o_dv<=1'b0;
            end //case语句一定要有default
        endcase //case语句只能在always块里,也是并行语句,满足case条件执行 
    end

endmodule

//在消除锁存器,锁存器在FPGA里不能用,延时无法时序分析,而且FPGA每一次综合布线是不固定的。 只有在电平触发时,case没有写全才会有锁存器出现。
//1、敏感列表写全,case条件,在赋值语句右边的变量也要加入敏感列表里.
//2、所有条件分支写全
//always @(cnt_7)
//                     case(cnt_7)
//          3'd0:begin
//                o_data<=3d'7;
//               o_dv<=1'b1;
//              end
//           3'd1:begin
//                o_data<=3d'0;
//                o_dv<=1'b0;
//              end
//           3'd2:begin
//                o_data<=3d'5;
//                o_dv<=1'b1;
//              end
//           default:begin
//               o_data<=3d'0;
//                o_dv<=1'b0;
//               end 
//          endcase 
testbench:

`timescale 1ns/1ns

module tb_ex_case;
reg sclk,rst_n;
wire [7:0] data;
wire dv;
reg [7:0] i_addr;
reg [9:0] i_data;
initial begin
      sclk =0;
      rst_n =0;
      #200
      rst_n =1;//不用设置位宽,tb因为不可综合
end

initial begin
      #500
      send(255);
end
always #10 sclk <= ~sclk;

ex_case ex_case_inst(
        .rst_n (rst_n),
        .sclk (sclk),
        .o_dv (dv),
        .o_data (data),
        .i_data (i_data),
        .i_addr (i_addr)
);
task send_data(len); //任务的声明,过程描述

integer len,i;
//变量声明区,在可综合模块不用integer 它指32位整型
    begin
        for(i=0;i<len;i=i+1)begin //循环语句
            @(posedge sclk);
            i_addr<=i[7:0];
            i_data<=i[7:0];

        end
        i_addr<=0;
        i_data<=0;
    end
endtask
endmodule

sclk和rst_n信号线都为金线,延时很短,而其它端口多为铜线,一般不用posedge、negedge来写。

在modelsim仿真时提示“len”信号already declared in this scope ,

task send_data(len); //任务的声明,过程描述

integer len,i;

于是交换顺序无报错:integer len,i;

      task send_data(len);

可能是modelsim有要求,在块里边出现之前,必须先做声明。(已经弄明白了task声明的要求)

测试后发现写的程序有问题,i_data和i_addr的波形图有问题:

将len加入波形,发现它一直是1,考虑到时位宽问题没有处理好,task send_data(len) len默认为1bit,代码改为:

task后变量的声明有顺序要求,任务使能语句中参数列表顺序应与之一直。新的波形图:

(0)

相关推荐