Verilog基础(一)——数据类型、运算符

本文主要介绍verilog基础模块,主要讲述verilog语言中的数据类型、运算符。

1. 数据类型

1.1 常量

整数:整数可以用二进制b或B,八进制o或O,十进制d或D,十六进制h或 H表示,例如,8’b00001111 表示8位位宽的二进制整数,4’ha表示4位位宽的十六进制整数。

X和Z:X代表不定值,z代表高阻值,例如,5’b00x11,第三位不定值,3’b00z 表示最低位为高阻值。

下划线:在位数过长时可以用来分割位数,提高程序可读性,如8’b0000_1111

1.2 参数

参数 parameter:parameter可以用标识符定义常量,运用时只使用标识符即可,提高代码可读性及维护性,如定义parameter width = 8 ; 定义寄存器reg [width-1:0] a; 即定义了8位宽度的寄存器。

参数的传递:在一个模块中如果有定义参数,在其他模块调用此模块时可以传递参数,并可以修改参数,如下所示,在module后用#()表示。

1.3 传参示例

参数 parameter:parameter可以用标识符定义常量,运用时只使用标识符即可,提高代码可读性及维护性,如定义parameter width = 8 ; 定义寄存器reg [width-1:0] a; 即定义了8位宽度的寄存器。

module ROM
#(
    parameter depth =15,
    parameter width = 8
) 
(
    input [depth-1:0] addr,
    input [width-1:0] data,
    output result
) ;
endmodule

调用该ROM模块时,可以在调用时修改传参来修改参数。如下代码,在调用ROM模块时,将depth和width变量的位宽分布修改成了32位位宽和16位位宽。

module top() ;

wire [31:0] addr ;
wire [15:0] data ;
wire result ;

ROM
#(
    .depth(32),
    .width(16)
)
ROM1
( 
    .addr(addr) ,
    .data(data) ,
    .result(result)
) ;

endmodule

Parameter可以用于模块间的参数传递,而localparam仅用于本模块内使用,不能用于参数传递。Localparam多用于状态机状态的定义。

1.4 变量

变量是指程序运行时可以改变其值的量,下面主要介绍几个常用了变量类型。

1.4.1 Wire型

Wire 类型变量,也叫网络类型变量,用于结构实体之间的物理连接,如门与门之间,不能储存值,用连续赋值语句assign赋值,定义为wire [n-1:0] a ;其中n 代表位宽,如定义wire a ; assign a = b ;是将b的结点连接到连线a上。如下图所示,两个实体之间的连线即是wire类型变量。
在这里插入图片描述

1.4.2 Reg型

Reg类型变量,也称为寄存器变量,可用来储存值,必须在always语句里使用。其定义为reg [n-1:0] a ;表示n位位宽的寄存器,如reg [7:0] a;表示定义8位位宽的寄存器a。
如下所示定义了寄存器q,生成的电路为时序逻辑,下图为其结构,为D触发器。

module TOP
(
    input d,
    input clk,
    output reg q
) ;

always @(posedge clk)
begin
    q <= d ;
end
endmodule

在这里插入图片描述
也可以生成组合逻辑,如下面代码所示为一个数据选择器,敏感信号没有时钟,最终生成电路为组合逻辑。

module TOP
(
    input a,
    input b,
    input c,
    input d,
    input [1:0] sel,
    output reg Mux
) ;

always @(sel or a or b or c or d)
begin
    case(sel)
    2'b00 : Mux = a ;
    2'b01 : Mux = b ;
    2'b10 : Mux = c ;
    2'b11 : Mux = d ;
    endcase
end
endmodule

在这里插入图片描述

1.4.3 Memory型

可以用memory类型来定义RAM、ROM等存储器,其结构为reg [n-1:0]存储器名[m-1:0],意义为m个n位宽度的寄存器。例如,reg [7:0] ram [255:0]表示定义了256个8位寄存器,256也即是存储器的深度,8为数据宽度。

2. 运算符

运算符可分为以下几类:
(1)算术运算符(+,-,*,/,%)
(2)赋值运算符(=,<=)
(3)关系运算符(>,<,>=,<=,==,!=)
(4)逻辑运算符(&&,||,!)
(5)条件运算符(?:)
(6)位运算符(,|,^,&,^
(7)移位运算符(<<,>>)
(8)拼接运算符({ })
大部分运算符与C/C++语言中定义的运算符用法基本上一致,这里主要介绍几种与C/C++语言中差异较大的运算符。

2.1 赋值运算符

“=”为阻塞赋值,”<=”为非阻塞赋值。阻塞赋值为执行完一条赋值语句,再执行下一条,可理解为顺序执行,而且赋值是立即执行;非阻塞赋值可理解为并行执行,不考虑顺序,在always块语句执行完成后,才进行赋值。

2.1.1 阻塞赋值运算符

下面先介绍阻塞赋值,代码如下:

module TOP
(
    input din,
    input clk,
    output reg a,b,c
) ;

always @(posedge clk)
begin
    a = din;
    b = a;
    c = b;
end
endmodule

下面是上面模块对应的仿真代码(用于给上面模块提供时钟、激励信号用于仿真模块功能的正确性):

module SimFile ();

reg din ;
reg clk ;
wire a,b,c ;

initial
begin
    din = 0 ;
    clk = 0 ;
    forever
    begin
        #({$random}%100)	// 随机等待一段时间(0~99ns之间)
        din = ~din ;
    end
end

always #10 clk = ~clk ;

TOP TOP_i
(
    .clk(clk),
    .din(din),
    .a(a),
    .b(b),
    .c(c)
);

clk时钟的周期是20ns,从仿真结果可以看到,在clk的上升沿时,寄存器a的值等于输入din的值,并立即赋给寄存器b,b的值赋给c。
在这里插入图片描述
上面编写的阻塞赋值TOP模块在FPGA内部布局成的电路(RTL)如下图所示,由RTL可以明显看出,在每个时钟周期上沿到来时,寄存器a、b、c的值都被统一赋值成了输入din的值。
在这里插入图片描述

2.1.2 非阻塞赋值运算符

将上面编写TOP模块的赋值方式改为非阻塞赋值方式,代码如下:

module TOP
(
    input din,
    input clk,
    output reg a,b,c
) ;

always @(posedge clk)
begin
    a <= din;
    b <= a;
    c <= b;
end
endmodule

仿真代码仍然使用2.1.1节的仿真代码提供时钟和激励信号,仿真结果如下:
在这里插入图片描述
在每个时钟clk上升沿时,寄存器a的值没有立即赋值给b,b为a原来的值,同样,c为b原来的值。上面编写的非阻塞赋值TOP模块在FPGA内部布局成的电路(RTL)如下图所示。
在这里插入图片描述
一般情况下,在时序逻辑电路中使用非阻塞赋值,可避免出现竞争冒险现象。在组合逻辑中使用阻塞赋值,执行赋值语句后立即改变。在assign语句中必须用阻塞赋值。

2.2 位拼接运算符

“{ }”拼接运算符,将多个信号按位拼接,如{a[3:0], b[1:0]},将a的低4位,b的低2位拼接成6位数据。
{n{a[3:0]}}表示将n个a[3:0]拼接,{n{1’b0}}表示n位的0拼接。如{8{1’b0}}表示为8’b0000_0000。

2.3 运算符的优先级

各种运算符的优先级别如下图所示:
在这里插入图片描述

参考文献:
[1] http://www.alinx.com.cn/.

如果大家对我们的文章感兴趣,可以关注我们的公众号:“FpgaHome”:

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
序列检测器是一种电路,用于检测输入信号序列是否符合某种特定的模式。在Verilog HDL语言中,可以使用状态机来实现序列检测器。以下是一个简单的序列检测器的Verilog HDL代码示例: ```verilog module sequence_detector( input clk, // 时钟信号 input reset, // 复位信号 input data, // 输入数据信号 output reg match // 匹配信号 ); // 定义状态 typedef enum logic [1:0] { STATE_IDLE, // 空闲状态 STATE_S1, // 状态1 STATE_S2, // 状态2 STATE_S3 // 状态3 } state_t; // 定义状态转移表 parameter [3:0] TRANS_TABLE [0:3] = '{4'b0000, 4'b0001, 4'b0010, 4'b0100}; // 定义当前状态变量和下一个状态变量 reg [1:0] state, next_state; // 初始化状态为IDLE initial begin state = STATE_IDLE; end // 定义状态机逻辑 always @ (posedge clk, posedge reset) begin if (reset) begin state <= STATE_IDLE; end else begin state <= next_state; end end // 定义状态转移逻辑 always @ (*) begin case (state) STATE_IDLE: begin if (data) begin next_state = STATE_S1; end else begin next_state = STATE_IDLE; end end STATE_S1: begin if (!data) begin next_state = STATE_IDLE; end else if (data) begin next_state = STATE_S2; end end STATE_S2: begin if (!data) begin next_state = STATE_IDLE; end else if (data) begin next_state = STATE_S3; end end STATE_S3: begin if (!data) begin next_state = STATE_IDLE; match = 1; end else begin next_state = STATE_S3; end end endcase end endmodule ``` 这个序列检测器可以检测输入数据信号是否符合“1101”这个模式。输入数据信号通过data端口输入,匹配结果通过match端口输出。当输入数据信号符合“1101”这个模式时,match信号会被置为1。如果输入数据信号不符合模式,match信号会保持为0。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值