赞
踩
i0 | i1 | i2 | o0 | 01 | o2 | o3 | o4 | o5 | o6 | o7 |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
分析上述真值表,可以发现输入是三位的二进制数字,38译码器将其转化为十进制数字。如想要得到5,即o5对应输出端口为1,输入则是101。
打开Quartus,采用Verilog编程(if-else或者case)设计一个3-8译码器,生成RTL原理电路图;
写法一
运用case语句声明所有情况,即每个输入对应的输出,直接生成RTL原理电路图。
module decode38( output reg [7:0] out, //由于后面采用always语句,此处赋值必须为reg input [2:0] in ); always case (in) 0:out=8'b00000001; 1:out=8'b00000010; 2:out=8'b00000100; 3:out=8'b00001000; 4:out=8'b00010000; 5:out=8'b00100000; 6:out=8'b01000000; 7:out=8'b10000000; endcase endmodule
写法二
module decode38(
output reg [7:0] out,
input [2:0] in
);
integer i;
always
for(i=0;i<7;i=i+1)
out[i]=(in==i);
endmodule
可以看出,不一样的语言描述,会画出不一样的原理图。
1)Verilog 综合生成的3-8译码器电路原理图与原始设计电路存在一定差异,尤其是不详细描写其内部结构后,差异尤其明显,但是仿真测试生成的结果都与真值表一致。
2) Verilog代码设计的3-8译码器模块的输出信号之所以定义为reg类型而不用默认wire(导线)类型,是因为后面运用了过程语句always,因此被赋值的只能说reg变量。改成wire型(即把 output reg [7:0] out 改为 output [7:0] out)后,相应地也要将alway语句改为连续赋值语句assign。
先用Verilog的门级描述方式写一个“1位全加器”, 生成RTL电路,与Logisim的“1位全加器”进行对比。
Logisim的“1位全加器”图样如下:
Verilog代码:
1.功能级写法
module fulladder_1 {A,B,Cin,Sum,Cout};
input A,B,Cout;
output Sum,Cout;
assign {Cout,Sum}=A+B+Cin;
endmodule
2行为级写法
module fulladder_1(
input a,b,cin,
output sum,cout
);
assign sum=a^b^cin;
assign cout=(a&b)|(a&cin)|(b&cin);
endmodule
module FA( input x,y,cin, output f,cout ); assign f=x^y^cin; assign cout=(x&y)|(x&cin)|(y&cin); endmodule module CRA( input [3:0]x,y, input cin, output [3:0]f, output cout ); wire [4:0]c; assign c[0]=cin; FA fa0(x[0],y[0],c[0],f[0],c[1]); FA fa1(x[1],y[1],c[1],f[1],c[2]); FA fa2(x[2],y[2],c[2],f[2],c[3]); FA fa3(x[3],y[3],c[3],f[3],c[4]); assign cout=c[4]; endmodule
采用Verilog设计一个8位全加器模块。
```c module FA( input x,y,cin, output f,cout ); assign f=x^y^cin; assign cout=(x&y)|(x&cin)|(y&cin); endmodule module FA_8( input [7:0]x,y, input cin, output [7:0]f, output cout ); wire [8:0]c; assign c[0]=cin; FA fa0(x[0],y[0],c[0],f[0],c[1]); FA fa1(x[1],y[1],c[1],f[1],c[2]); FA fa2(x[2],y[2],c[2],f[2],c[3]); FA fa3(x[3],y[3],c[3],f[3],c[4]); FA fa4(x[4],y[4],c[4],f[4],c[5]); FA fa5(x[5],y[5],c[5],f[5],c[6]); FA fa6(x[6],y[6],c[6],f[6],c[7]); FA fa7(x[7],y[7],c[7],f[7],c[8]); assign cout=c[8]; endmodule
module ALU_16#( parameter n=16 )( input [n-1:0] opA, // 输入操作数A,长度为n input [n-1:0] opB, // 输入操作数B,长度为n input [3:0] S, // 输入选择信号S,长度为4 input wire M, // 输入M,控制加/减操作 input wire Cin, // 输入进位信号Cin output reg[n-1:0] DO, // 输出结果DO,长度为n output wire C, // 输出进位信号C output wire V, // 输出溢出信号V output wire N, // 输出负数信号N output wire Z // 输出零信号Z ); reg [n-1:0] p; // 中间变量p reg [n-1:0] g; // 中间变量g reg [n:0] carry; // 进位寄存器carry always@(opA,opB,S,M,Cin) begin carry[0]=Cin; // 进位寄存器的第一个位等于Cin g={n{S[3]}}&opA&opB | {n{S[2]}}&opA&(~opB) | {n{(~M)}}; // 计算g p=~({n{S[3]}})&opA&opB | {n{S[2]}}&opA&(~opB) | {n{S[1]}}&(~opA)&opB | {n{S[0]}}&(~opA)&(~opB); // 计算p carry[n:1]=g | (p & carry[n-1:0]); // 更新进位寄存器carry DO=p^carry[n-1:0]; // 计算结果DO end assign C=carry[n]; // 连接进位信号C assign V=(opA[n-1]&opB[n-1]&~DO[n-1]) | (~opA[n-1]&~opB[n-1]&DO[n-1]); // 计算溢出信号V assign N=DO[n-1]; // 连接负数信号N assign Z=(!(DO))?1:0; // 计算零信号Z endmodule
Verilog的许多编程思路同C语言相似,语法也相近。要格外注意使用过程语句编程时,输出端口要注意reg赋值。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。