赞
踩
在创建工程项目后,代码页面会自动生成如下语句(工程的创建及测试testbench等博主闲了再出教程敷衍大家)
module csdn(
//括号内为端口列表
);
//此处为I/O说明
//内部信号声明(也可理解为中间变量声明)
//主要的代码功能定义
endmodule
我们的代码内容写在module…endmodule中,对于括号内应进行输入输出端口的定义,该定义和测试testbench中相对应。
括号外则进行变量的声明及相关代码的撰写。(具体内容如下例1.2)
module csdn(
input a,
input b,
output [5:0] y
//此处定义三个端口,a,b为两个一位的输入端口,y为一个六位的输出端口
//未定义位数则自动按一位
);
assign y[0] = a & b;
assign y[1] = ~(a & b);
assign y[2] = a | b;
assign y[3] = ~(a | b);
assign y[4] = a ^ b;
assign y[5] = a ~^ b;
//此处assign声明语句
//此处为a,b的与 或 非 异或运算赋值到y的各个位中
endmodule
此程序为我接触verilog语言学习的第一个程序,很适合新手去当做入门仿真的练习。接下来还有一个程序,则为我的项目所涉及到的部分代码,此程序更偏向于应用,且更符合第一部分介绍的基本代码结构
如下图,是为了方便讲解而手绘的简易六位线性反馈移位寄存器。其寄存器在每个时钟周期右移一位,即寄存器R0的1-5位移到2-6位,寄存器R0的第一位赋值为反馈值,该反馈值为寄存器第三位和第六位的异或值。其第六位在每个周期输出一次,该值记为code。其输入初值为L1C,该初值在程序开始时对寄存器R0进行赋值。
该线性反馈移位寄存器实现代码如下:(预告:接下来的程序测试testbench可能用这个程序来讲解)
module L1C(
clk,
work,
l1c,
code
//端口列表
);
input clk;
input work;
input [5:0]l1c;
output code;
wire code;
//I/O端口说明
//此处的input output也可以写到括号内,看个人习惯,我习惯括号内声明端口,然后再去对I/O进行具体的说明
reg [5:0]r0; //寄存器RO
wire feedback; //反馈值
//中间变量定义
// -----------------------------------------------------------------------------------------------------
// ------------------------------Code Generator Part ---------------------------------------------------
// -----------------------------------------------------------------------------------------------------
always @(posedge clk) //此语句用法下文会讲,在这里主要看代码的结构
begin
if(!work)
begin
r0 <= l1c;
//对寄存器r0赋初值,初值l1c在testbench中会讲到
end else
begin
r0 <= {r0[4:0],feedback};
//此处为上文讲解的移位和反馈操作
end
end
assign feedback = r0[2] ^ r0[5]; //反馈值
assign code = r0[5]; //输出值
endmodule
此程序如果有一定的基础,应该很简单,如果没有基础,则可以忽略其中的语法,继续往下看,下面将具体讲解其中always和begin…end的用法,而这里主要看代码的结构,其结构主要包括的即为1.1中所介绍的。
注:程序中的input值在testbench中输入。对于c、matlab中一般都直接赋值,或者通过读取指令进行赋值。此处可当做其需要读取,但其实际赋值过程在testbench中进行。
此语句对于初学者可能是个麻烦,但其所完成的操作其实很简单,相当于一个判断语句,其可类比我们所熟悉的if语句,在if()语句中,其括号内的值为1(真)则执行其下面的语句。而对于always而言,其主要针对的是时钟,在硬件中,一般通过设置时钟进行操作,always则是判断你所设置的时钟,在时钟的上升沿或者下降沿进行其下面的语句。
always @()
对于always而言最常用到的莫过于下面语句
always @(posedge clk or negedge rst)
//异步复位 clk上升沿,rst下降沿 满足其中一个条件即开始执行
begin
end
具体clk及rst的值可在测试端testbench中设定,testbench后续会教大家怎么创建
begin…end其实很好理解,在此语句中的程序顺序执行(begin语句算是verilog语言的一个习惯,在每个执行的语句前加上,养成好的习惯)
如果没有begin…end则对于多个语句而言,只会执行一个(相当于一个框,对于判断语句而言,框到的地方即为需要执行的地方)
具体如下
always @(posedge clk) //通过判断clk上升沿执行以下操作
begin
r0 <= l1c;
r1 <= l1c;
end
//在此语句中r0和r1的值都会随着l1c在不同的clk上升沿值变
always @(posedge clk)
r0 <= l1c;
r1 <= l1c;
//如果没有begin...end限制,则通过always判断后,只执行其下面一个语句
//当然在实际操作中这样肯定会报错,博主想表达的意思为,没有begin...end限制,其r1 <= l1c就不属于always中的语句了
//而普通的等式则需要用assign去定义,r1 <= l1c则可变成assign r1 = l1c
我们用到的程序是1.2.2中我自己写的一个比较简单的反馈移位寄存器具体操作部分
always @(posedge clk)
//clk上升沿执行always对应的下面begin...end中的语句
begin //此处begin对应最末尾的end
if(!work) //如果work为0,则开始执行其begin...end中的语句,对r0进行赋值
begin
r0 <= l1c;//初值l1c在testbench中会讲到
end else //如果work为1则执行else下面的begin语句
begin
r0 <= {r0[4:0],feedback};//此处为移位反馈操作
//r0的0-4位放在高位,r0的最低位为feedback值
end
end
每个begin对应一个end,相距最近的begin和end为一对,其程序的执行在一对begin…end中顺序执行
硬件语言和软件语言大体差不多,如果认真学习过一门语言,我觉得想上手其他的语言将会非常简单,只是其定义和语法可能有一些差异。我对于verilog语言的学习源自于老板直接扔给我几千行的代码让我看,其代码很好懂,但仿真折磨了我许久。之后我会继续把仿真testbench过程做一个详细的讲解,但在仿真之前最好把1.2.2的线性反馈移位寄存器看懂(虽然不看懂也没啥影响,看懂的话可以明白其仿真中各个信号波形的含义)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。