练习五. 用always块实现较复杂的组合逻辑电路目的: 1.掌握用always实现组合逻辑电路的方法;
2.了解assign与always两种组合逻辑电路实现方法之间的区别。
仅使用assign结构来实现组合逻辑电路,在设计中会发现很多地方会显得冗长且效率低下。而适当地采用always来设计组合逻辑,往往会更具实效。已进行的范例和练习中,我们仅在实现时序逻辑电路时使用always块。从现在开始,我们对它的看法要稍稍改变。
下面是一个简单的指令译码电路的设计示例。该电路通过对指令的判断,对输入数据执行相应的操作,包括加、减、与、或和求反,并且无论是指令作用的数据还是指令本身发生变化,结果都要作出及时的反应。显然,这是一个较为复杂的组合逻辑电路,如果采用assign
语句,表达起来非常复杂。示例中使用了电平敏感的always块,所谓电平敏感的触发条件是指在@后的括号内电平列表中的任何一个电平发生变化,(与时序逻辑不同,它在@后的括号内没有沿敏感关键词,如posedge 或negedge)就能触发always块的动作,并且运用了case结构来进行分支判断,不但设计思想得到直观的体现,而且代码看起来非常整齐、便于理解。
//--------------- alu.v --------------------------
`define plus 3'd0
`define minus 3'd1
`define band 3'd2
`define bor 3'd3
`define unegate 3'd4
module alu(out,opcode,a,b);
output[7:0] out;
reg[7:0] out;
input[2:0] opcode;
input[7:0] a,b; //操作数。
[email=always@(opcode]always@(opcode[/email] or a or b) //电平敏感的always块
begin
case(opcode)
`plus: out = a+b; //加操作。
`minus: out = a-b; //减操作。
`band: out = a&b; //求与。
`bor: out = a|b; //求或。
`unegate: out=~a; //求反。
default: out=8'hx;//未收到指令时,输出任意态。
endcase
end
endmodule
同一组合逻辑电路分别用always块和连续赋值语句assign描述时,代码的形式大相径庭,但是在always中适当运用default(在case结构中)和else(在if…else结构中),通常可以综合为纯组合逻辑,尽管被赋值的变量一定要定义为reg型。不过,如果不使用default或else对缺省项进行说明,则易生成意想不到的锁存器,这一点一定要加以注意。
指令译码器的测试模块源代码:
//------------- alu_Top.v -----------------
`timescale 1ns/1ns
`include "./alu.v"
module alutest;
wire[7:0] out;
reg[7:0] a,b;
reg[2:0] opcode;
parameter times=5;
initial
begin
a={$random}%256; //Give a radom number blongs to [0,255] .
b={$random}%256; //Give a radom number blongs to [0,255].
opcode=3'h0;
repeat(times)
begin
#100 a={$random}%256; //Give a radom number.
b={$random}%256; //Give a radom number.
opcode=opcode+1;
end
#100 $stop;
end
alu alu1(out,opcode,a,b);
endmodule
仿真波形(部分):
[[wysiwyg_imageupload:248:]] 练习:运用always块设计一个八路数据选择器。要求:每路输入数据与输出数据均为4位2进制数,当选择开关(至少3位)或输入数据发生变化时,输出数据也相应地变化。