亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> Verilog

使用 Verilog always 块实现组合逻辑

Verilog always 块可用于时序和组合逻辑。前文用 assign 语句展示了几个设计示例。接下来用 always 块探索相同设计集。

示例 #1:简单组合逻辑

下面代码实现简单数字组合逻辑,输出信号 z 类型为 reg,在敏感列表中任一信号值变化时更新。敏感列表声明在 @ 运算符后的括号内。

module combo (
    input a, b, c, d, e,
    output reg z
);
always @ (a or b or c or d or e) begin
    z = ((a & b) | (c ^ d) & ~e);
end
endmodule

模块 combo 经综合工具展开为以下硬件原理图,可见组合逻辑用数字门实现。

建模组合逻辑时使用阻塞赋值

测试平台

测试平台用于仿真验证设计行为。使用 for 循环和 10 时间单位延迟驱动所有输入组合到设计模块。

module tb;
reg a, b, c, d, e;
wire z;
integer i;
combo u0 ( .a(a), .b(b), .c(c), .d(d), .e(e), .z(z));
initial begin
    a <= 0; b <= 0; c <= 0; d <= 0; e <= 0;
    $monitor ("a=%0b b=%0b c=%0b d=%0b e=%0b z=%0b", a, b, c, d, e, z);
    for (i = 0; i < 32; i = i + 1) begin
        {a, b, c, d, e} = i;
        #10;
    end
end
endmodule

仿真日志

ncsim> run
a=0 b=0 c=0 d=0 e=0 z=0
a=0 b=0 c=0 d=0 e=1 z=0
...
a=1 b=1 c=1 d=1 e=1 z=1
ncsim: *W,RNQUIE: Simulation is complete.

注意:assign 和 always 两种方法综合出相同硬件逻辑。

示例 #2:半加器

半加器模块接受两个标量输入 a、b,用组合逻辑驱动输出 sum 和进位 cout。sum 由 a 和 b 异或驱动,cout 由两者与运算得出。

module ha (
    input a, b,
    output sum, cout
);
always @ (a or b) begin
    {cout, sum} = a + b;
end
endmodule

测试平台

module tb;
reg a, b;
wire sum, cout;
integer i;
ha u0 ( .a(a), .b(b), .sum(sum), .cout(cout));
initial begin
    a <= 0; b <= 0;
    $monitor("a=%0b b=%0b sum=%0b cout=%0b", a, b, sum, cout);
    for (i = 0; i < 4; i = i + 1) begin
        {a, b} = i;
        #10;
    end
end
endmodule

仿真日志

ncsim> run
a=0 b=0 sum=0 cout=0
a=0 b=1 sum=1 cout=0
a=1 b=0 sum=1 cout=0
a=1 b=1 sum=0 cout=1
ncsim: *W,RNQUIE: Simulation is complete.

示例 #3:全加器

always 块可描述全加器行为驱动输出 sum 和 cout。

module fa (
    input a, b, cin,
    output reg sum, cout
);
always @ (a or b or cin) begin
    {cout, sum} = a + b + cin;
end
endmodule

测试平台

module tb;
reg a, b, cin;
wire sum, cout;
integer i;
fa u0 ( .a(a), .b(b), .cin(cin), .sum(sum), .cout(cout));
initial begin
    a <= 0; b <= 0;
    $monitor("a=%0b b=%0b cin=%0b cout=%0b sum=%0b", a, b, cin, cout, sum);
    for (i = 0; i < 8; i = i + 1) begin
        {a, b, cin} = i;
        #10;
    end
end
endmodule

仿真日志

ncsim> run
a=0 b=0 cin=0 cout=0 sum=0
a=0 b=0 cin=1 cout=0 sum=1
a=0 b=1 cin=0 cout=0 sum=1
a=0 b=1 cin=1 cout=1 sum=0
a=1 b=0 cin=0 cout=0 sum=1
a=1 b=0 cin=1 cout=1 sum=0
a=1 b=1 cin=0 cout=1 sum=0
a=1 b=1 cin=1 cout=1 sum=1
ncsim: *W,RNQUIE: Simulation is complete.

示例 #4:2x1 多路选择器

简单 2x1 多路选择器用三元运算符决定哪个输入赋给输出 c。sel 为 1 时输出 a,为 0 时输出 b。

module mux_2x1 (input a, b, sel, output reg c);
always @ (a or b or sel) begin
    c = sel ? a : b;
end
endmodule

测试平台

module tb;
reg a, b, sel;
wire c;
integer i;
mux_2x1 u0 ( .a(a), .b(b), .sel(sel), .c(c));
initial begin
    a <= 0; b <= 0; sel <= 0;
    $monitor("a=%0b b=%0b sel=%0b c=%0b", a, b, sel, c);
    for (i = 0; i < 3; i = i + 1) begin
        {a, b, sel} = i;
        #10;
    end
end
endmodule

仿真日志

ncsim> run
a=0 b=0 sel=0 c=0
a=0 b=0 sel=1 c=0
a=0 b=1 sel=0 c=1
ncsim: *W,RNQUIE: Simulation is complete.

示例 #5:1x4 解多路器

解多路器用 sel 和 f 组合驱动不同输出信号。每个输出信号类型为 reg,在 always 块中根据敏感列表信号变化更新。

module demux_1x4 (
    input f,
    input [1:0] sel,
    output reg a, b, c, d
);
always @ (f or sel) begin
    a = f & ~sel[1] & ~sel[0];
    b = f & sel[1] & ~sel[0];
    c = f & ~sel[1] & sel[0];
    d = f & sel[1] & sel[0];
end
endmodule

测试平台

module tb;
reg f;
reg [1:0] sel;
wire a, b, c, d;
integer i;
demux_1x4 u0 ( .f(f), .sel(sel), .a(a), .b(b), .c(c), .d(d));
initial begin
    f <= 0; sel <= 0;
    $monitor("f=%0b sel=%0b a=%0b b=%0b c=%0b d=%0b", f, sel, a, b, c, d);
    for (i = 0; i < 8; i = i + 1) begin
        {f, sel} = i;
        #10;
    end
end
endmodule

仿真日志

ncsim> run
f=0 sel=0 a=0 b=0 c=0 d=0
f=0 sel=1 a=0 b=0 c=0 d=0
f=0 sel=10 a=0 b=0 c=0 d=0
f=0 sel=11 a=0 b=0 c=0 d=0
f=1 sel=0 a=1 b=0 c=0 d=0
f=1 sel=1 a=0 b=0 c=1 d=0
f=1 sel=10 a=0 b=1 c=0 d=0
f=1 sel=11 a=0 b=0 c=0 d=1
ncsim: *W,RNQUIE: Simulation is complete.

示例 #6:4x16 解码器

module dec_3x8 (
    input en,
    input [3:0] in,
    output reg [15:0] out
);
always @ (en or in) begin
    out = en ? 1 << in: 0;
end
endmodule

测试平台

module tb;
reg en;
reg [3:0] in;
wire [15:0] out;
integer i;
dec_3x8 u0 ( .en(en), .in(in), .out(out));
initial begin
    en <= 0; in <= 0;
    $monitor("en=%0b in=0x%0h out=0x%0h", en, in, out);
    for (i = 0; i < 32; i = i + 1) begin
        {en, in} = i;
        #10;
    end
end
endmodule

仿真日志

ncsim> run
en=0 in=0x0 out=0x0
en=0 in=0x1 out=0x0
...
en=1 in=0xf out=0x8000
ncsim: *W,RNQUIE: Simulation is complete.

Verilog

  1. 树莓派精准监测机柜温度:DS18B20 多点部署实战
  2. 开关控制电路实战:从原理图到面包板的基础电路构建
  3. 集成电路:数字逻辑门基础
  4. 可编程逻辑控制器(PLC):工业系统的现代数字控制
  5. 理解布尔代数:从逻辑基础到数字电路
  6. 精通卡诺图逻辑化简
  7. 科学计数法乘除法精通:简化极值运算
  8. 工业4.0洞察:Bosch.IO高级解决方案架构师Verena Majuntke谈物联网、自动化与未来工厂
  9. 以冈本精密磨床实现完美表面光洁度
  10. 精通VHDL与Verilog:编写整洁组合与时序逻辑
  11. Verilog 门级设计实战:与/或/非门与 2x1 多路选择器
  12. 掌握 Verilog $timeformat:精度控制与显示格式化