9.10数字逻辑

基础内容

module 模块名(【端口列表】)

端口信号声明

信号数据类型有wire,reg

信号位宽

模块把输入的input转化为output

数据类型默认为wire,wire表电路间的连线

assign赋值目标必须是wire,始终激活,连续赋值语句

过程赋值语句,always赋值目标必须是reg型

激活条件由敏感信号条件表决定,当敏感条件满足时,过程块被激活

有两种,一种是边沿敏感,一种是电平敏感

边沿敏感,posedge 信号名,信号上升沿到来,negedge,信号下降沿到来

电平敏感,信号列表中任一个信号有变化(a,b,c)

上升沿0->1,

always@(posedge CLK)

Q=D;

当CLK上升时,把D赋值给Q,这样Q始终为D的MAX

always@(D)

Q=D

只要D发生改变,Q就被赋值为D,即Q与D始终相同

=为阻塞赋值,是计算完后立即赋值,对后续赋值结果产生影响

>=为非阻塞赋值,是全部计算完后再赋值,计算时用的都是老数据

设计组合电路时常用阻塞赋值

时序电路常用非阻塞赋值

一个always中只能用一种赋值方式

always中开始赋值时要用Begin,end包起来

内部信号声明类型

数据类型 位宽 信号类型 元素个数

reg [3:0] Q

output [3:0]Q1

门原语调用,输出在前,输入在后

input型信号必为wire

output可为reg或wire

<位宽>`<进制><数字>

2` b00

5` d8

o八进制b二进制h十六进制d十进制

有符号数为,第一位为符号位

8` sb1 011 1011

RST表复位信号

没有定义位数时,都是wire,即默认类型都是wire一位,0或1

只有定义为reg[],才会有多位数

{s1,s0}表把s1,s0两个一位的wire型,拼接为两位的二进制数


module pratice1(a,b,c,d,s1,s0,y);
input a,b,c,d,s1,s0;
output reg y;
always@(a,b,c,d,s1,s0,y)
begin
    case({s1,s0})
        2`b00 : y=a;
        2`b01 : y=b;
        2`b10 :y=c;
        2`b11:y=d;
        default:y=0;
    endcase
end
endmodule

begin,end就像左右括号,if,else,等都要用  

 题

信号顺序调整

一个16位信号in包含四个四位数[3:0]a[3:0]b[3:0]c[3:0]d,将它们顺序倒置为dcba输出,输出out

`timescale 1ns/1ns

module top_module(
    input [15:0]in,
    output [15:0]out
);
wire[3:0]a,b,c,d;
assign {a,b,c,d}=in;
assign out={d,c,b,a};
endmodule

位运算与逻辑运算

1

2

3

4

5

6

7

8

9

10

11

12

`timescale 1ns/1ns

module top_module(

    input [2:0] a,

    input [2:0] b,

    output [2:0] c,

    output d

);

    assign c = a |  b;

    assign d = a || b;

endmodule

与:& 按位与;&& 逻辑与;

或:|  按位或;||    逻辑或;

非:~ 按位非;!  逻辑非;

#对信号按位操作#

1

2

3

4

5

6

7

8

9

10

11

12

13

`timescale 1ns/1ns

module top_module(

    input [4:0] in,

    output out_and,

    output out_or,

    output out_xor

);

    assign out_and  = &in[4:0];

    assign out_or   = |in[4:0];

    assign out_xor  = ^in[4:0];

    //&in[4:0] 等同于 in[4]&in[3]&in[2]&in[1]&in[0]  |和^同理

endmodule

 信号级联合并

将6个输入信号串联转为四个信号输出,输入信号为[4:0] a[4:0] b[4:0]c [4:0]d [4:0]e [4:0]f,末尾增加一个宽度为两位的3,形成32位长度后,按照从前到后的顺序输出[7:0]w [7:0]x [7:0]y [7:0]z 

`timescale 1ns/1ns

module top_module(
    input [4:0] a, b, c, d, e, f,
    output [7:0] w, x, y, z );
   // wire [31:0]data;
    assign {w,x,y,z}={a,b,c,d,e,f,2'b11};
endmodule

#信号反转输出#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

`timescale 1ns/1ns

module top_module(

    input [15:0] in,

    output [15:0] out

); 

    genvar i ;

    generate

        for (i=0 ;i <= 15 ; i = i + 1)

        begin: loop //这里一定要打标签

           assign out[i] = in[15-i];

        end

    endgenerate

     

/*assign out = {in[0],in[1],in[2],in[3],in[4],in[5],in[6],in[7],in[8],in[9],in[10],in[11],in[12],

    in[13],in[14],in[15]};*/ //这是一种笨方法,我们通过对内部的信号进行人为的交换顺序而成,那么自然就想到了

    //generate for 语法,可以进行批量的例化 。

endmodule

多位信号异或 

给定五个1bit信号(a、b、c、d 和 e),生成两种25位的数据: 一种是将信号复制五次后连接起来aaaaabbbbb...,一种是将信号连接起来复制五次成为abcdeabcde... 。比较两个25位信号,如果两个信号的同样位置的位相等,则输出1。

`timescale 1ns/1ns

module top_module(
    input a, b, c, d, e,
	output [24:0] out
);
wire [24:0] data1,data2;
assign data1={{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}};
assign data2={5{a,b,c,d,e}};
genvar i;
generate 
    for(i=0;i<=24;i=i+1)
    begin:loop
        assign out[i]=(data1[i]==data2[i])?1'b1:1'b0;
    end
endgenerate
endmodule

 制作一个四选一的多路选择器,要求输出定义上为线网类型

`timescale 1ns/1ns
module mux4_1(
input [1:0]d1,d2,d3,d0,
input [1:0]sel,
output[1:0]mux_out
);
//*************code***********//
reg[1:0]mux_out_tmp;
always@(*)begin
    case(sel)
        2'b00:mux_out_tmp=d3;
        2'b01:mux_out_tmp=d2;
        2'b10:mux_out_tmp=d1;
        2'b11:mux_out_tmp=d0;
    endcase
end
assign mux_out=mux_out_tmp;

//*************code***********//
endmodule
`timescale 1ns/1ns
module mux4_1(
input [1:0]d1,d2,d3,d0,
input [1:0]sel,
output[1:0]mux_out
);
    assign mux_out = sel[0]?(sel[1]?d0:d2):(sel[1]?d1:d3);
    
endmodule

思考

always与assign

always里赋值的必须为reg型,而不能是wire型,需要满足条件才会触发,

相当于寄存器,如果不用reg,修改的值出always就被消了,只有reg才能记忆保存

assign里赋值的必须是wire型,始终触发并赋值

reg与wire


 

本质上为什么要有reg和wire,因为电路需要有记忆性的单元(比如FF)以及无记忆性的单元(比如导线)。

reg a ;
reg b;
always@ (*) begin

if ()
a = tmp ;
b = a ;

end
在这段代码中a是不会综合出寄存器的,而b却会,原因在于a是中间变量,就是一条线,所以综合出来的不是寄存器,而是一条线。而在condtion不满足的情况下b要保值,所以b会综合成寄存器。绝不是 综合工具对代码描述的硬件行为的一种解读。

Verilog作为一门行为描述语言,你可以把每一段程序都理解为“用语言描述一个模块”,而实际上,一个模块的组成无非就是“引脚”+“内部的各种电路”。
有个这种准备之后就好理解wire 和 reg 了。Verilog中,把没有定义类型的信号默认设置为wire,除非特殊声明一次。如:
input[7:0] a, b;
reg [7:0] a;
以上例子,由于“input”就是模块管脚的声明,他有两个管脚a,b,用作输入。而再把a定义成寄存器类型,方便功能定义中进行操作。所以此时a 为reg型 b 为 默认wire 型。
所以说,可以粗略地把wire型理解为“从管脚输入的、原始的信号序列”,他在导体上以电信号的形式流动,而把reg型理解为“用寄存器存着从管脚输入的信号”,因为之后在寄存器中存住的数字信息,才能进行诸如移位、赋值等操作。

很经典的解读:

wire表示直通,即输入有变化,输出马上无条件地反映(如与、非门的简单连接)。

reg表示一定要有触发,输出才会反映输入的状态。

reg相当于存储单元,wire相当于物理连线。reg表示一定要有触发,没有输入的时候可以保持原来的值,但不直接实际的硬件电路对应。

      两者的区别是:寄存器型数据保持最后一次的赋值,而线型数据需要持续的驱动。wire使用在连续赋值语句中,而reg使用在过程赋值语句(initial ,always)中。wire若无驱动器连接,其值为z,reg默认初始值为不定值 x 。

      在连续赋值语句中,表达式右侧的计算结果可以立即更新表达式的左侧。在理解上,相当于一个逻辑之后直接连了一条线,这个逻辑对应于表达式的右侧,而这条线就对应于wire。在过程赋值语句中,表达式右侧的计算结果在某种条件的触发下放到一个变量当中,而这个变量可以声明成reg类型的。根据触发条件的不同,过程赋值语句可以建模不同的硬件结构:如果这个条件是时钟的上升沿或下降沿,那么这个硬件模型就是一个触发器;如果这个条件是某一信号的高电平或低电平,那么这个硬件模型就是一个锁存器;如果这个条件是赋值语句右侧任意操作数的变化,那么这个硬件模型就是一个组合逻辑。

      对组合逻辑输出变量,可以直接用assign。即如果不指定为reg类型,那么就默认为1位wire类型,故无需指定1位wire类型的变量。当然专门指定出wire类型,可能是多位或为使程序易读。wire只能被assign连续赋值,reg只能在initial和always中赋值。

      输入端口可以由wire/reg驱动,但输入端口只能是wire;输出端口可以是wire/reg类型,输出端口只能驱动wire;若输出端口在过程块中赋值则为reg型,若在过程块外赋值则为net型(wire/tri)。用关键词inout声明一个双向端口, inout端口不能声明为reg类型,只能是wire类型。

      默认信号是wire类型,reg类型要申明。这里所说的默认是指输出信号申明成output时为wire。如果是模块内部信号,必须申明成wire或者reg.

      对于always语句而言,赋值要申明成reg,连续赋值assign的时候要用wire。

模块调用时 信号类型确定方法总结如下:

•信号可以分为端口信号和内部信号。出现在端口列表中的信号是端口信号,其它的信号为内部信号。

•对于端口信号,输入端口只能是net类型。输出端口可以是net类型,也可以是register类型。若输出端口在过程块中赋值则为register类型;若在过程块外赋值(包括实例化语句),则为net类型。

•内部信号类型与输出端口相同,可以是net或register类型。判断方法也与输出端口相同。若在过程块中赋值,则为register类型;若在过程块外赋值,则为net类型。

•若信号既需要在过程块中赋值,又需要在过程块外赋值。这种情况是有可能出现的,如决断信号。这时需要一个中间信号转换。

下面所列是常出的错误及相应的错误信息(error message)

•用过程语句给一个net类型的或忘记声明类型的信号赋值。

           信息:illegal …… assignment.

•将实例的输出连接到声明为register类型的信号上。

           信息: has illegal output port specification.

•将模块的输入信号声明为register类型。

           信息:incompatible declaration,  

……

你可能感兴趣的:(fpga开发)