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集成电路的基本单元,所以选择了这样的实现形式。

卡诺图化简 2-4译码器门级电路图

题目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

思路及电路图

BCD译码器功能表 门级电路图 Vivado综合的门级电路图

题目015

用verilog设计8bit奇偶校验电路。

思路

这道题照抄答案:

  1. 奇校验的含义:原数和校验位中共有奇数个1
  2. 偶校验的含义:原数和校验位中共有偶数个1
  3. 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)

  1. x和y是8bit无符号数
  2. 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,哪个逻辑面积更小?可以用工具跑跑看。(待解决)

  1. 两个减法器的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
  1. 一个减法器、一个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,考虑三种情况:

  1. 都是无符号数
  2. 都是有符号数
  3. 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设计工程师