Verilog语法_2(case语法和task语法)

September 17, 2016
作者:dengshuai_super
出处:http://blog.csdn.net/dengshuai_super/article/details/52564050
声明:转载请注明作者及出处。


Verilog语法_2(case语法和task语法)_第1张图片
上图,是在Quartus II里显示的最底层,右上方表示一个reg。


Verilog语法_2(case语法和task语法)_第2张图片
上图,这一个小块叫一个LE,是FPGA的基本单元


Verilog语法_2(case语法和task语法)_第3张图片
上图,这一个大块叫LAB,是逻辑阵列块,里面包含了多个LE


Verilog语法_2(case语法和task语法)_第4张图片
上图,板面上包含了很多个LAB,每个LAB都有对应的坐标


时钟走的线是金线,延时相当小,并且到每一级寄存器的延时都保持一致;
如果我们用数据线,数据线是铜线,它的介质是不一样的,它的特性也不一样。
所以使得我们数据传输的时候出现时序违例。这就是posedge,negedge只用时钟信号而不用其他信号的原因。negedge a,就是指a从1跳变0的那一刻的状态(下降沿)。


Verilog语法_2(case语法和task语法)_第5张图片

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;

always @(posedge sclk or negedge rst_n)//case语句只能在always块里面,case语句是并行语句,没有先后
                if(rst_n == 1'b0)
                begin
                        o_data<=8'd0;
                        o_dv<=1'b0;
                end
                else begin
                            case(cnt_7)
                                    3'd0:begin
                                                    o_data<=3'd7;//当cnt_7等于3'd0执行此条语句,
                                                    o_dv<=1'b1;//reg的概念:上升沿前面的低电平把数据加载到D端,当上升沿来临的时候就把D端的数据呈现在Q端
                                             end
                                    3'd1:begin
                                                    o_data<=3'd0;//case语句相当于一个译码器,对应一个真值表(综合时生成LUT)
                                                    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
                            endcase
                end

//下列是组合逻辑实现
//消除锁存器:
//1.把敏感列表写全,case条件;赋值语句右边的变量;
//2.所有条件分支写全
//always @(cnt_7)//敏感列表是变量的时候是组合逻辑。是电平触发。敏感列表必须要完整,否则生成锁存器(只有电平触发的时候才有可能生成锁存器)。锁存器延迟的时间不固定还是电平触发,导致此路径不能参与到时序分析里边
//                          case(cnt_7)
//                                  3'd0:begin
//                                                  o_data<=3'd7;//当cnt_7等于3'd0执行此条语句
//                                                  o_dv<=1'b1;
//                                           end
//                                  3'd1:begin
//                                                  o_data<=3'd0;//case语句相当于一个译码器,对应一个真值表(综合时生成LUT(查找表就是把一些真值表存在里面),真值表的条件当地址,真值表的输出结果作为输出)
//                                                  o_dv<=1'b0;
//                                           end
//                                  3'd2:begin
//                                                  o_data<=3'd5;
//                                                  o_dv<=1'b1;
//                                           end
//                                  default:begin//可以直接加一个“;”结束
//                                                      o_data<=3'd0;
//                                                      0_dv<=1'b0;
//                                                  end
//                          endcase
endmodule
/*
wire和reg的具体区别
在RTL图里就可以看到:
wire就是一根线
reg就是一个D触发器,是一个硬件的元件(也可以理解为一个模块)
FPGA的基本单元是LE,一个LE里面会有寄存器
*/
`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;

end

initial begin
            i_data=0;
            i_addr=0;
            #500
            send_data(255);
end

always #10 sclk <=~sclk;//周期20ns的时钟

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);//任务名字和长度,任务的声明,类似C语言
       integer len,i;//变量声明区
       begin//必须加begin和end
                for(i=0;i1)//循环语句
                begin
                        @(posedge sclk);//for循环的时候一定要按照节拍来工作。如果注视掉本行,在波形图上i_data和i_addr都为零不动了。因为瞬间溢出成0
                        i_addr<=i[7:0];//可以用阻塞赋值也可以用非阻塞赋值。阻塞赋值就是直接赋过去,非阻塞赋值会延时一拍。
                        i_data<=i[7:0];//截取低8位
                        //用case语句产生一个协议,当地址为0时,i_data=0xff;
                        //当地址为1时,i_data=0x55;
                        //当地址为2时,i_data=0x00;
                        //其他地址全部保留赋值为0xff;
                end
                i_addr<=0;
            i_data<=0;
       end  
endtask
endmodule

/*
如果去描述一个ram,地址不要用case语句来描述,要用存储器变量,存储器变量使用reg来声明的。
单片机或arm这一类的芯片要和FPGA通信的时候,会有一个并行总线,并行总线给过来地址,可以用case来做
就相当于arm芯片来读取FPGA的一些寄存器的时候就可以用case语句来做
*/

来源:
https://ke.qq.com/user/index/index.html#cid=66019&term_id=100056181

你可能感兴趣的:(Verilog,fpga,FPGA)