题目要求:
看到题目,很多小伙伴可能不知道高阻态是个啥玩意咧(尤其是我们计院这些不懂硬件的学生),这里普及一下高阻态的概念:
高阻态是数字电路三态门中输出状态的一种,它的输出既不是高电平也不是低电平,相当于浮空状态。如果高阻态再输入下一级电路的话,对下级电路无任何影响,等同于没接入上级电路。如果用万用表测的话,有可能是高电平也有可能是低电平。
在verilog中,高阻态用z表示,比如4位寄存器,如果想使其每一位输出无效(即高阻态),则赋值语句是: v = 4'bzzz
其余的功能就非常好实现了,这里采用行为建模的方式,类似于C语言的算法,便于各位计院大佬理解;且代码简洁,干净利落!
代码如下:
module Unidad_Logica_de_Algoritmo(op0, op1, s, oe, clk, r);
input clk, oe; // OE是使能信号,低电平有效
input[3:0] op0; // 第一个操作数
input[3:0] op1; // 第二个操作数
input[2:0] s; // 选择开关,不同的值(具体见题目描述)进行不同的运算
output[3:0] r; // 输出值
reg[3:0] r; // 因为r在always代码块中被赋值,所以需要定义为寄存器类型
always @(posedge clk) // D触发器上升沿触发
begin
if(oe == 1'b1)
begin
r = 4'bzzzz; // 输出高阻态
end
else
begin
if(s == 3'b000) // PLUS
begin
r <= op0 + op1;
end
else if(s == 3'b001) // MINUS
begin
r <= op0 - op1;
end
else if(s == 3'b100) // AND
begin
r <= op0 & op1;
end
else if(s == 3'b101) // OR
begin
r <= op0 | op1;
end
else if(s == 3'b110) // XOR
begin
r <= op0 ^ op1;
end
end
end
endmodule
波形图模拟仿真如下:
1. 高阻态情况:
2. 异或:
3. 按位或:
4. 按位与:
5. 加法和减法:
2022.08.15更新:
根据逻辑函数表达式推导,我设计了一种结构与行为混合建模的方式。
这里采用带进位的四位全加器,其每一位的运算结果位和进位位通过列真值表
和画卡诺图化简的方式,推导出逻辑递推表达式,然后将它们存入各自的寄存器中,舍
弃掉最后的进位值,只保留四位寄存器中的加减运算结果,并将第一位进位初值设为 0,
表示之前没有进位。
根据第二章的分析,此处应采用带加法/减法切换功能的 4 位全加器实现。首先定义
进位位 𝐶𝑖(0 ≤ 𝑖 ≤ 3) 和最后输出的进位值 𝐶out,再根据 Select 值判断是进行加法运算
还是进行减法运算,最后根据 3.1 小节所述的输入数 op0, op1 和输出运算数 r 来展示运
算结果。Select = 0 时,r 为全加器的求和位,即 r=op0+op1,𝐶out为全加器的高位进位,
𝐶𝑖为全加器低位进位;Select = 1 时,r 为全减器的求差位,即 r=op0-op1,𝐶out为全减器
的高位借位,𝐶𝑖为全减器低位借位。
分析上述定义和功能,对于一位全加器,不难推导出如下表所示的真值表:
根据卡诺图化简,对一位全加/全减运算,可以推导出如下的逻辑表达式:
推广到四位全加/全减器,逻辑表达式修改为:
根据上述推导,得出如下代码(顺便吐槽一句,csdn代码高亮不支持verilog是真恶心):
module Unidad_Logica_de_Algoritmo(
input clk, oe, // OE代表使能位
input[3:0] op0, // 操作数1
input[3:0] op1, // 操作数2
input[2:0] s, // 功能选择
output reg [3:0] r // 运算结果,因需要在D触发器中赋值所以注意标记为寄存器类型
);
wire cin; // 运算前的初始进位
reg cfinal; // 运算后的最高位进位
reg[3:1] c; // 第1~3位运算的进位
assign cin = 0;
always @(posedge clk) // 上升沿触发
begin
if(oe)
begin
r = 4'bzzzz; // 输出高阻态
end
else
begin
case(s)
3'b100: r = op0 & op1;
3'b101: r = op0 | op1;
3'b110: r = op0 ^ op1;
default:
begin
if(s[2] == 0 && s[1] == 0)
begin // s[0]为0时进行4位全加,为1时进行4位全减
// bit 0
r[0] = ((op0[0]^s[0]) ^ op1[0] ^ cin) ^ s[0];
c[1] = ((op0[0]^s[0]) & op1[0]) | ((op0[0]^s[0]) | op1[0])&cin;
// bit 1
r[1] = ((op0[1]^s[0]) ^ op1[1] ^ c[1]) ^ s[0];
c[2] = ((op0[1]^s[0]) & op1[1]) | ((op0[1]^s[0]) | op1[1])&c[1];
// bit 2
r[2] = ((op0[2]^s[0]) ^ op1[2] ^ c[2]) ^ s[0];
c[3] = ((op0[2]^s[0]) & op1[2]) | ((op0[2]^s[0]) | op1[2])&c[2];
// bit 3
r[3] = ((op0[3]^s[0]) ^ op1[3] ^ c[3]) ^ s[0];
cfinal = ((op0[3]^s[0]) & op1[3]) | ((op0[3]^s[0]) | op1[2])&c[3];
end
else // 处理s不为题目中要求值的异常情况 (i.e. 111, 010, 011, etc.),使 r[3:0] 输出无效
begin
r = 4'bzzzz;
end
end
endcase
end
end
endmodule
综合出的电路如下:
仿真波形图如下:
由题意可知,第一个 80ns 周期内,s=3’b000,应进行算术加法运算,1011+0011=1110,
在 40ns 上升沿出现时结果从 zzzz 跳变到 1110,符合预期;
第二个 80ns 周期内,s=3’b001,应进行算术减法运算,1011-0011=1100,在 120ns 时
结果跳变到 1000,符合预期;
第三个 80ns 周期内,s=3’b100,应进行逻辑与运算,1011&0011=0011,在 200ns 时
结果跳变到 0011,符合预期;
第四个 80ns 周期内,s=3’b101,应进行逻辑或运算,1011|0011=1011,在 280ns 时
结果跳变到 1011,符合预期;
第五个 80ns 周期内,s=3’b110,应进行逻辑异或运算,1011^0011=1000,在 360ns
时结果跳变到 1000,符合预期;
第六个 80ns 周期内,s=3’b000,应进行算术减法运算,但在这个周期的开始时期,
OE 电平突然被拉高,输出应该无效,观察波形图发现在 440ns 时结果跳变到 zzzz,符
合预期。