Verilog99题——12-21题
前言
1-7题是数字电路基础;
8-21题是组合逻辑相关;
这篇把剩下的组合逻辑相关的题目全部写完。
题目012
012.设计1bit全加器,采用verilog描述并画出门级电路图。
verilog描述
module full_adder(
input a,b,cin,
output out,cout
);
assign {cout,out} = a + b + cin;
//assign out = a^b^cin;
//assign cout = a&b|b&cin|a&cin;
endmodule
思路及电路图
题目013
013.设计2-4译码器。采用verilog描述并画出门级电路图。
verilog描述
module decoder2_4(
input [1:0] a,
output reg [3:0] b
);
always @ (*)
case(a)
2'b00:b=4'b1110;
2'b01:b=4'b1101;
2'b10:b=4'b1011;
2'b11:b=4'b0111;
default:b=4'b1111;
endcase
endmodule
门级电路图
电路图在下面,因为反相器、与非门和或非门是cmos集成电路的基本单元,所以选择了这样的实现形式。
题目014
014.设计BCD译码器,输入0~9。采用verilog描述并画出门级电路图。
verilog描述
module BCD_Decoder(
input [3:0] A,
//output reg [9:0] Y_L
output [9:0] Y_L
);
always @ (*)
case(A)
4'd0:Y_L=10'b11_1111_1110;
4'd1:Y_L=10'b11_1111_1101;
4'd2:Y_L=10'b11_1111_1011;
4'd3:Y_L=10'b11_1111_0111;
4'd4:Y_L=10'b11_1110_1111;
4'd5:Y_L=10'b11_1101_1111;
4'd6:Y_L=10'b11_1011_1111;
4'd7:Y_L=10'b11_0111_1111;
4'd8:Y_L=10'b10_1111_1111;
4'd9:Y_L=10'b01_1111_1111;
default:Y_L=10'b11_1111_1111;
endcase
/*
assign Y_L[0] = ~(~A[3] & ~A[2] & ~A[1] & ~A[0]);
assign Y_L[1] = ~(~A[3] & ~A[2] & ~A[1] & A[0]);
assign Y_L[2] = ~(~A[3] & ~A[2] & A[1] & ~A[0]);
assign Y_L[3] = ~(~A[3] & ~A[2] & A[1] & A[0]);
assign Y_L[4] = ~(~A[3] & A[2] & ~A[1] & ~A[0]);
assign Y_L[5] = ~(~A[3] & A[2] & ~A[1] & A[0]);
assign Y_L[6] = ~(~A[3] & A[2] & A[1] & ~A[0]);
assign Y_L[7] = ~(~A[3] & A[2] & A[1] & A[0]);
assign Y_L[8] = ~(A[3] & ~A[2] & ~A[1] & ~A[0]);
assign Y_L[9] = ~(A[3] & ~A[2] & ~A[1] & A[0]);
*/
endmodule
思路及电路图
题目015
用verilog设计8bit奇偶校验电路。
思路
这道题照抄答案:
- 奇校验的含义:原数和校验位中共有奇数个1
- 偶校验的含义:原数和校验位中共有偶数个1
- logic[7:0] data;则data自异或的结果为:若data中有奇数个1,则^data = 1;若data中有偶数个1,则^data = 0。对于这一点,可以这么理解:若有奇数个1,则有奇数个0,所以
^data = (奇数个1逐位异或的结果) ^ (奇数个0逐位异或的结果) = 1 ^ 0 = 1
;若有偶数个1,则有偶数个0,所以^data = (偶数个1逐位异或的结果) ^ (偶数个0逐位异或的结果) = 0 ^ 0 =0
。
verilog描述
module odd_even_check(
input [7:0] din;
output dout_even;
output dout_odd;
);
assign dout_odd = ^din; //奇校验位
assign dout_even = ~dout_odd; //偶校验位
endmodule
题目016
用verilog描述一个多路复用器,输入的通道数目N,每一路的位宽为M。
注意
Verilog不允许在端口定义二维数组。
verilog描述
思路大概就是这样,但是这个仿真没做通,还不确定是否正确。
module test
#(
parameter N = 8,
parameter M = 8
)
(
input [N*M-1:0] i_data,
input [clogb2(N):0] i_sel,
output [M-1:0] o_data
);
assign o_data = i_data[(M*i_sel)+:M];
function integer clogb2 (input integer depth);
begin
for(clogb2=0; depth>0; clogb2=clogb2+1)
depth = depth >> 1;
end
endfunction
endmodule
题目017
第十七题.用Verilog实现 z = abs(x - y)
- x和y是8bit无符号数
- x和y是8bit有符号数(2补码)
verilog描述
无符号数:
module abs(
input [7:0] i_x,
input [7:0] i_y,
output [7:0] o_z
);
assign o_z= (i_x > i_y) ? (i_x - i_y) : (i_y - i_x);
endmodule
有符号数:这里有大神提了问题——两个减法器的mux,和一个减法一个abs,哪个逻辑面积更小?可以用工具跑跑看。(待解决)
- 两个减法器的mux:
module abs(
input signed [7:0] i_x,
input signed [7:0] i_y,
output [8:0] o_z
);
wire signed [8:0] z_r;
assign z_r = (i_x > i_y) ? (i_x - i_y) : (i_y - i_x);
assign o_z = z_r;
endmodule
- 一个减法器、一个abs:若有符号数为负数则有
|A|=~A+1
module abs(
input signed [7:0] i_x,
input signed [7:0] i_y,
output [8:0] o_z
);
wire signed [8:0] dout_r;
assign dout_r = i_x - i_y;
assign o_z = (dout_r[8] == 1'b1)? (~dout_r + 1'b1):dout_r;
endmodule
题目018
018.用Verilog实现取整函数(ceil、floor、round)。以5bit为例,小数部分1位,取整后保留4bit。
wire [4:0] data;
wire [3:0] data_ceil;
wire [3:0] data_floor;
wire [3:0] data_round;
基础知识
floor(x),表示不超过x的整数中最大的一个。朝负无穷方向取整。
ceil(x),表示不小于x的整数中最小的一个。朝正无穷方向取整。
round(x)四舍五入到最近的整数。
思路
data为有符号数(2补码),只有1bit的小数位,精度有限,所以假设data都是小数,例如整数部分是7,则data只能表示大于7.5或小于7.5的小数,不表示整数7。
floor——非负取整即可,负数取整减一;
ceil——正数,取整+1,非正数取整即可;
round——小数位为1,取整+1;小数位为0,取整即可。
verilog描述
module test18(
input [4:0] data ,
output [3:0] data_ceil ,
output [3:0] data_floor,
output [3:0] data_round
);
assign data_ceil = data[4] == 1'b0 ? {1'b0,data[3:1]+1'b1} : data[4:1];
assign data_floor = data[4] == 1'b0 ? data[4:1] : data[4:1]-1'b1;
assign data_round = data[0] == 1'b0 ? data[4:1] : data[4:1]+1'b1;
endmodule
testbench
module tb18( );
reg [4:0] data ;
wire [3:0] data_ceil ;
wire [3:0] data_floor;
wire [3:0] data_round;
reg signed [3:0] data_int = -4'sd8;
reg data_dec = 1'b1;
initial
fork
repeat(15) #20 data_int = data_int + 2'sd1;
repeat(30) #10 data_dec = ~ data_dec;
join
always @ (*) data = {data_int,data_dec};
test18 int_get(
.data ( data ),
.data_ceil ( data_ceil ),
.data_floor ( data_floor),
.data_round ( data_round)
);
endmodule
仿真结果
仿真结果见图,其中有两处溢出,分别在data_floor最左和data_ceil最右。本题限定条件下无法解决(增加位宽即可)。
题目019
第十九题.用verilog实现乘法y = a * b
a和b都是8bit,考虑三种情况:
- 都是无符号数
- 都是有符号数
- a是有符号数,b是无符号数
verilog描述
//1)
module test19(
input [ 7:0] i_a ,
input [ 7:0] i_b ,
output [15:0] o_y
);
assign o_y = i_a * i_b;
endmodule
//2)
module test19(
input signed [ 7:0] i_a ,
input signed [ 7:0] i_b ,
output signed [14:0] o_y
);
assign o_y = i_a * i_b;
endmodule
//3)
module test19(
input signed [ 7:0] i_a ,
input [ 7:0] i_b ,
output signed [15:0] o_y
);
wire signed [8:0] b_r;
assign b_r = {1'b0,i_b};
assign o_y = i_a * b_r;
endmodule
注意
第3小问若直接用$signed()
机制(即assign o_y = i_a * $signed(i_b);
)的话,计算结果并不同,比如:a为127,b为255,y=127*255=32385;使用$signed()
的话,y=127*$signed(255)=127*(-1)=-127
。要注意两者的区别。可以按照如下方法:
module test19(
input signed [ 7:0] i_a ,
input [ 7:0] i_b ,
output signed [15:0] o_y
);
assign o_y = i_a * $signed({1'b0,i_b});
endmodule
题目020
020.输入一个8bit数,统计其中1的个数。
verilog描述
module test_20(
input [7:0] i_data,
output [2:0] o_count
);
assign o_count = ( ( (i_data[0] + i_data[1]) + (i_data[2] + i_data[3]) ) + ( (i_data[4] + i_data[5]) + (i_data[6] + i_data[7]) ) );
endmodule
附加题
本题至少使用多少个1bit全加器
下图使用八个1来说明。
题目021
021.求三个数的最大值:
y = max(a,b,c)
wire [3:0] a,b,c;
verilog描述
module test21(
input signed [3:0] a,b,c,
output reg [3:0] max
);
always @ (*) begin
if (a >= b && a >= c)
max = a;
else if (b >= a && b >= c)
max = b;
else if (c >= b && c >= a)
max = c;
else
max = max;
end
endmodule
即将入行的数字IC设计工程师