Verilog基本代码结构及常用语句always、begin...end解读


在老板的要求下,我开始学习接触FPGA相关内容。而我们所用到的FPGA综合开发软件为vivado,虽然还没练习时长两年半,但也有一定的经验,接下来我把学习中遇到的问题记录如下,希望能帮助到刚入门的萌新。如果有一定的语言基础(例如c、matlab、Python等等),则搞懂以下问题,对于verilog语言的学习就会非常简单。

1.1 基本代码结构

在创建工程项目后,代码页面会自动生成如下语句(工程的创建及测试testbench等博主闲了再出教程敷衍大家)

module csdn(
//括号内为端口列表
    );
//此处为I/O说明
//内部信号声明(也可理解为中间变量声明)
//主要的代码功能定义
endmodule

我们的代码内容写在module…endmodule中,对于括号内应进行输入输出端口的定义,该定义和测试testbench中相对应。

括号外则进行变量的声明及相关代码的撰写。(具体内容如下例1.2)

1.2 简例

1.2.1 简单的与或非运算

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语言学习的第一个程序,很适合新手去当做入门仿真的练习。接下来还有一个程序,则为我的项目所涉及到的部分代码,此程序更偏向于应用,且更符合第一部分介绍的基本代码结构

1.2.2 线性反馈移位寄存器(此部分可在看懂always和begin后详细了解)

如下图,是为了方便讲解而手绘的简易六位线性反馈移位寄存器。其寄存器在每个时钟周期右移一位,即寄存器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中进行。

2.1 always 常用结构

此语句对于初学者可能是个麻烦,但其所完成的操作其实很简单,相当于一个判断语句,其可类比我们所熟悉的if语句,在if()语句中,其括号内的值为1(真)则执行其下面的语句。而对于always而言,其主要针对的是时钟,在硬件中,一般通过设置时钟进行操作,always则是判断你所设置的时钟,在时钟的上升沿或者下降沿进行其下面的语句。

always @()    

对于always而言最常用到的莫过于下面语句

always @(posedge clk or negedge rst)    
//异步复位 clk上升沿,rst下降沿 满足其中一个条件即开始执行
begin 
end

具体clk及rst的值可在测试端testbench中设定,testbench后续会教大家怎么创建

3.1 begin…end 用法解读

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

3.2 简例

我们用到的程序是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的线性反馈移位寄存器看懂(虽然不看懂也没啥影响,看懂的话可以明白其仿真中各个信号波形的含义)

  • 32
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: Verilog 中的 beginend 是用来定义一段代码块的。它们用来定义该代码块中的语句应该如何按顺序执行。begin代码块的开始标记,end代码块的结束标记。例如: ``` begin // some statements end ``` 这段代码中的语句将按顺序执行。 ### 回答2: 在Verilog中,“begin”和“end”是用于定义代码块的关键字。Verilog中begin end的用法可以分为两个方面:模块块和组合逻辑块。 在模块块中,begin end的用法是用来定义模块块内的语句块,例如:输入输出端口、寄存器、赋值等。在模块块中使用begin end可以让不同的语句块归入同一个block内,当需要被快速 reference或者command时可以很方便的进行操作。 在组合逻辑块中,begin end的用法用来定义组合逻辑块内的语句块,例如:组合逻辑的判断和运算等。每个begin都应有至少一个end与之对应,确保代码块正确执行,防止意外和逻辑错误。在应用程序中执行判断,处理和运算等的时候,在begin end组合内使用可以有效地分组操作,加强程序的可读性和可维护性。 总之,begin endVerilog中的关键字,可以用来定义不同的代码块,从而加强程序的可读性和可维护性。在编写Verilog程序的时候,使用beginend来组织代码,可以使代码更加规范和易于理解,减少错误的发生,提高代码的可维护性和可扩展性。 ### 回答3: verilog中的beginend是用来标识代码进行块式编程的语句。它们包含了一个或多个语句,可以组成顺序结构、分支结构或循环结构。 在verilog中,beginend常用于组织一个复杂的语句块,因为使用beginend可以更好地清晰地定义时序逻辑和组合逻辑。例如,beginend可以用来分组always语句、initial语句、模块的顶层和任务等。 beginend的语法格式如下: begin [语句1]; [语句2]; [语句3]; ... end beginend必须成对出现,且内部语句可以为空。多个beginend也可以嵌套使用,但是必须保证嵌套的beginend成对匹配。在一个beginend块中的语句可以是单一语句、复合语句或者另一个嵌套的beginend语句块。 需要注意的是,每个语句后必须使用分号(;)分隔。如果忘记了在语句后面加上分号,编译器会提示语法错误。因此,在编写verilog代码时,应该注意精确地书写分号。 总的来说,beginend的使用是verilog中非常重要的一种语句块,它们用于组织逻辑、维护代码结构和功能实现。无论在何种场景中,程序员都应该根据实际情况嵌套使用,并书写清晰易懂的代码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木彡886

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值