高等数字集成电路分析2021-11-23

(自用)高集第四五章作业:后续再详细编辑

跑表:

思路:首先做两个按键消抖,一个表示clear按钮,一个是暂停继续按钮,优先级是clear>start_stop,通过编写代码最后的数通过一个bin2bcd用十进制表示出来。

代码:

module stop_watch
(
	input						clk,			//10MHz
	input						rst_n,		//系统复位
	input						clear,		//任意状态按下时分秒值清零并停止计时
	input						start_stop,	//若当前状态为停止则按下继续进行计时,若当前状态为计时则按下暂停计时
	
	output			[3:0]	hr_h,			//数字显示为XX : XX : XX形式,时分秒各为2位数字
	output			[3:0]	hr_l,			//对每位数字使用4位二进制编码输出表示
	output			[3:0]	min_h,
	output			[3:0]	min_l,	
	output			[3:0]	sec_h,
	output			[3:0]	sec_l
);
	
	parameter			NUMBER 		= 24'd9_999_999;
	parameter			MUNBER_MIN  = 32'd599_999_940;
	parameter			MUNBER_HOUR = 36'd35_999_996_400;	
	
	reg		[23:0]	cnt;
	reg					second;
	reg		[32:0]	cnt_min;
	reg					minutes;
	reg		[35:0]	cnt_hour;
	reg					hour;
	
	reg		[7:0]		clock_sec;
	reg		[7:0]		clock_min;
	reg		[7:0]		clock_hr;
	
	wire		[23:0]	clock_out;
	
	wire					flag_clear;
	wire					flag_ss;
	
	key_fliter fliter_clear(
		.clk(clk),
		.rst_n(rst_n),
		.key(clear),
		
		.flag(flag_clear)
	);

	key_fliter fliter_ss(
		.clk(clk),
		.rst_n(rst_n),
		.key(start_stop),
		
		.flag(flag_ss)
	);
	
	reg					en_start_stop;
	reg					en_clear;	
	
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				begin
					en_start_stop <= 1'b0;
					en_clear <= 1'b0;
				end
			else
				begin
					if(flag_clear)
						en_clear <= !en_clear;
					else
						en_clear <= en_clear;
					if(flag_ss)
						en_start_stop <= !en_start_stop;
					else
						en_start_stop <= en_start_stop;
				end
				
		
		end
		
		

	
	//通过clk产生一秒时钟源
	always @ (posedge clk,negedge rst_n)
		if(!rst_n)
			begin
				second <= 1'b0;
				cnt <= 24'd0;
			end
		else
			if(flag_clear == 1'b1)
				begin
					second <= 1'b0;
					cnt <= 24'd0;
				end
			else
				if(en_start_stop == 1'b1)
					begin
						second <= second;
						cnt <= cnt;
					end
				else		
					begin
						if(cnt == NUMBER - 1)
							begin
								second <= 1'b1;
								cnt <= 24'd0;
							end
						else
							begin
								cnt <= cnt + 1'b1;
								second <= 1'b0;
							end
					end
			
	//产生一分钟时钟源
	always @ (posedge clk,negedge rst_n)
		if(!rst_n)
			begin
				minutes <= 1'b0;
				cnt_min <= 6'd0;
			end
		else
			if(flag_clear == 1'b1)
				begin
					minutes <= 1'b0;
					cnt_min <= 6'd0;
				end
			else
				if(en_start_stop == 1'b1)
					begin
						minutes <= minutes;
						cnt_min <= cnt_min;
					end
				else
					begin
						if(cnt_min == MUNBER_MIN - 1)
							begin
								minutes <= 1'b1;
								cnt_min <= 6'd0;
							end
						else
							begin
								minutes <= 1'b0;
								cnt_min <= cnt_min + 1'b1;						
							end
					end
		
	//产生一小时时钟源
	always @ (posedge clk,negedge rst_n)
		if(!rst_n)
			begin
				hour <= 1'b0;
				cnt_hour <= 6'd0;
			end
		else
			if(flag_clear == 1'b1)
				begin
					hour <= 1'b0;
					cnt_hour <= 6'd0;
				end
			else
				if(en_start_stop == 1'b1)
					begin
						hour <= hour;
						cnt_hour <= cnt_hour;
					end
				else
					begin
						if(cnt_hour == MUNBER_HOUR - 1)
							begin
								hour <= 1'b1;
								cnt_hour <= 6'd0;
							end
						else
							begin
								hour <= 1'b0;
								cnt_hour <= cnt_hour + 1'b1;						
							end
					end
					
					
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				clock_sec <= 8'd0;
			else
				if(flag_clear == 1'b1)
					clock_sec <= 8'd0;
				else
					if(en_start_stop == 1'b1)
						clock_sec <= clock_sec;
					else
						if(second == 1'b1)
							clock_sec <= clock_sec + 1'b1;
						else
							if(clock_sec == 8'd60)
								clock_sec <= 8'd0;
							else
								clock_sec <= clock_sec;
		end
		
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				clock_min <= 8'd0;
			else
				if(flag_clear == 1'b1)
					clock_min <= 8'd0;
				else
					if(en_start_stop == 1'b1)
						clock_min <= clock_min;
					else
						if(minutes == 1'b1)
							clock_min <= clock_min + 1'b1;
						else
							if(clock_min == 8'd60)
								clock_min <= 8'd0;
							else
								clock_min <= clock_min;
		end
		
	always @ (posedge clk,negedge rst_n)
		begin
			if(!rst_n)
				clock_hr <= 8'd0;
			else
				if(flag_clear == 1'b1)
					clock_hr <= 8'd0;
				else
					if(en_start_stop == 1'b1)
						clock_hr <= clock_hr;
					else
						if(hour == 1'b1)
							clock_hr <= clock_hr + 1'b1;
						else
							if(clock_hr == 8'd24)
								clock_hr <= 8'd0;
							else
								clock_hr <= clock_hr;
		end
		
	bin2bcd bin2bcd_inst
(
	.bin({clock_hr,clock_min,clock_sec}),
	
	.bcd({hr_h[3:0],hr_l[3:0],min_h[3:0],min_l[3:0],sec_h[3:0],sec_l[3:0]})
);	
	

	assign clock_out = {hr_h[3:0],hr_l[3:0],min_h[3:0],min_l[3:0],sec_h[3:0],sec_l[3:0]};
	
	
endmodule
       
 module key_fliter(
	input 	 	clk,
	input 	 	rst_n,
	input 	 	key,
	
	output reg	 	flag
);
	reg	[31:0]	cnt;
	reg 			state;
	
	parameter 	 	S0=1'b0;
	parameter 	 	S1=1'b1;
	parameter 	 	CNT_NUM=10;//实际上为50_0000
	
	always @ (posedge clk, negedge rst_n) begin
		if(!rst_n) begin
			flag<=1'b0;
			state<=S0;
			cnt<=32'd0;
		end
		else
			case(state)
				S0	:	if(key==1'b0) begin
							if(cnt<CNT_NUM-1) begin
								flag<=1'b0;
								state<=S0;
								cnt<=cnt+32'd1;
							end
							else  begin
								flag<=1'b1;
								cnt<=32'd0;
								state<=S1;
							end
						end 
						else
							state<=S0;
				S1	:	begin
							flag<=1'b0;
						if(key==1'b1) begin
							if(cnt<CNT_NUM-1) begin
								flag<=1'b0;
								state<=S1;
								cnt<=cnt+32'd1;
							end
							else  begin
								flag<=1'b0;
								cnt<=32'd0;
								state<=S0;
							end
						end 
						else
							state<=S1;							
						end
				default : 	begin
						flag<=1'b0;
				            state<=S0;
						cnt<=32'd0;
						end
			endcase
	end                                 

endmodule
      

endmodule

module bin2bcd
(
	input 	 		[23:0] bin,
	
	output reg	 	[23:0] bcd
);
	
	always @ (*)	
		begin
			bcd[3:0] = bin[7:0] % 10;
			bcd[7:4] = bin[7:0] / 10 % 10;
			bcd[11:8] = bin[15:8] % 10;
			bcd[15:12] = bin[15:8] / 10 % 10;		
			bcd[19:16] = bin[23:16] % 10;
			bcd[23:20] = bin[23:16]/ 10 % 10;		
		end
	
endmodule

仿真:

在这里插入图片描述
第二个start_stop的flag标志,之前已经按了一次,第一次表示暂停,这里表示按了二次,表示继续计数
第三个start_stop的flag标志,表示第二次暂停。
第四个start_stop的flag标志,表示继续计数。
第二次清零,可以看到clock_out等于00_00_00
第三次清零,同上。
在这里插入图片描述
当我们计数到23:59:59时,放大上图可得如下:
在这里插入图片描述
由上图可得23:59:59时,变成了00:00:00。

超前进位加法器:

首先做一个四位的超前进位加法器,然后例化四个四位超前进位加法器,相互连接的部分用addr_carry模块衔接好,最终得到进位cout。

代码:

module ahead_adder4
(
		input 				cin,
		input [3:0]			A,
		input [3:0]			B,
		input [3:0]			G,		//进位产生项 G = A & B
		input [3:0]			P,		//进位传播向 P = A ^ B
		
		output  reg [3:0]	S,
		output  reg 		cout	//最终进位项 C(i+1) = G + C(i)P
);



		reg [3:0]C;	   //中间变量,C[3]有效果
		
		
			always @ (*)
				begin
					C[0] <= G[0] | (cin&P[0]);
					C[1] <= G[1] | (P[1]&G[0]) | (P[1]&P[0]&cin);
					C[2] <= G[2] | (P[2]&G[1]) | (P[2]&P[1]&G[0]) | (P[2]&P[1]&P[0]&cin);
					C[3] <= G[3] | (P[3]&G[2]) | (P[3]&P[2]&G[1]) | (P[3]&P[2]&P[1]&G[0]) | (P[3]&P[2]&P[1]&P[0]&cin);
					S[0] <= A[0] ^ B[0] ^ cin;
					S[1] <= A[1] ^ B[1] ^ C[0];
					S[2] <= A[2] ^ B[2] ^ C[1];
					S[3] <= A[3] ^ B[3] ^ C[2];
					cout <= C[3];
				end
endmodule
module ahead_carry
(		
		input 						cin,
		input 		[15:0]		G,
		input 		[15:0]		P,
		
		output reg 	[3:0]			cout

);
	

		reg 			[3:0]			G2;
		reg 			[3:0]			P2;
		
		always @ (*)
			begin
				G2[0] = G[3] | P[3]&G[2] | P[3]&P[2]&G[1] | P[3]&P[2]&P[1]&G[0];
				G2[1] = G[7] | P[7]&G[6] | P[7]&P[6]&G[5] | P[7]&P[6]&P[5]&G[4];
				G2[2] = G[11] | P[11]&G[10] | P[11]&P[10]&G[9] | P[11]&P[10]&P[9]&G[8];
				G2[3] = G[15] | P[15]&G[14] | P[15]&P[14]&G[13] | P[15]&P[14]&P[13]&G[12];
				P2[0] = P[3]&P[2]&P[1]&P[0];
				P2[1] = P[7]&P[6]&P[5]&P[4];
				P2[2] = P[11]&P[10]&P[9]&P[8];
				P2[3] = P[15]&P[14]&P[13]&P[12];
				cout[0] <= G2[0] | (cin&P2[0]);
				cout[1] <= G2[1] | (P2[1]&G2[0]) | (P2[1]&P2[0]&cin);
				cout[2] <= G2[2] | (P2[2]&G2[1]) | (P2[2]&P2[1]&G2[0]) | (P2[2]&P2[1]&P2[0]&cin);
				cout[3] <= G2[3] | (P2[3]&G2[2]) | (P2[3]&P2[2]&G2[1]) | (P2[3]&P2[2]&P2[1]&G2[0]) | (P2[3]&P2[2]&P2[1]&P2[0]&cin);
			end

endmodule

module cla_16
(
	input			[15:0]	a,
	input			[15:0]	b,
	input						cin,
	
	output		[16:0]	sum,
	output					cout

);

		wire		[15:0]	G;
		wire		[15:0]	P;
		wire		[3:0]		cin_line;
		wire					cin0;
		wire					cin1;
		wire					cin2;
		
		assign G = a & b;
		assign P = a | b;
		
ahead_carry ahead_carry_inst
(		
		.cin(cin),
		.G(G),
		.P(P),
		
		.cout(cin_line)
);

	
		
ahead_adder4 ahead_adder4_u0
(
		.cin(cin),
		.A(a[3:0]),
		.B(b[3:0]),
		.G(G[3:0]),		//进位产生项 G = A & B
		.P(P[3:0]),		//进位传播向 P = A | B
		
		.S(sum[3:0]),
		.cout(cin0)	
);

ahead_adder4 ahead_adder4_u1
(
		.cin(cin0),
		.A(a[7:4]),
		.B(b[7:4]),
		.G(G[7:4]),		
		.P(P[7:4]),		
		
		.S(sum[7:4]),
		.cout(cin1)	
);

ahead_adder4 ahead_adder4_u2
(
		.cin(cin1),
		.A(a[11:8]),
		.B(b[11:8]),
		.G(G[11:8]),		
		.P(P[11:8]),		
		
		.S(sum[11:8]),
		.cout(cin2)	
);

ahead_adder4 ahead_adder4_u3
(
		.cin(cin2),
		.A(a[15:12]),
		.B(b[15:12]),
		.G(G[15:12]),		
		.P(P[15:12]),		
		
		.S(sum[15:12]),
		.cout(cout)	//最终进位项 C(i+1) = G + C(i)P
);

assign sum[16] = (((a[15] == 1'b1) && (b[15] == 1'b1)) || ((a[15] == 1'b0) && (b[15] == 1'b0)) == 1'b1) ? cout : !cout;
	//
	//begin
	//	if(((a[15] == 1'b1) && (b[15] == 1'b1)) || ((a[15] == 1'b0) && (b[15] == 1'b0)))
	//		sum[16] = cout;
	//	else
	//		if(((a[15] == 1'b0) && (b[15] == 1'b1)) || ((a[15] == 1'b1) && (b[15] == 1'b0)))
	//			sum[16] = !cout;
	//end

endmodule

仿真:

在这里插入图片描述
由上面仿真图可得,a和b(十进制表示)相加后得到了sum,实现了加法器。

快速乘法器:

这个作业参考以下作者,做了一点修改,非原创:
链接:https://blog.csdn.net/zhouxuanyuye/article/details/106366316?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163765719416780274192899%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163765719416780274192899&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-2-106366316.pc_v2_rank_blog_default&utm_term=%E4%B9%98%E6%B3%95%E5%99%A8&spm=1018.2226.3001.4450
设计思路:使用基4 Booth编码表生成系数,其系数规则如下:
1.B[2]决定了输出系数的符号位,定义为neg;
2.当输入码字为011和100时,输出绝对值为2,定义为two;
3.当输入码字为000和111时,输出绝对值为0,定义为zero;
4.除了以上码字,输出绝对值为1,定义为one。
将上面的系数生成部分和,根据编码器输出,与被乘数相乘,生成部分和:、
1.如果编码器zero为1,则输出部分和为0;
2.如果编码器one为1,则输出部分和为被乘数;
3.如果编码器two为1,则输出部分和为被乘数左移1位;
4.如果是负数,则生成补码输出。

代码:

module mul_16(
	input [15:0] A,
	input [15:0] B,
	output [31:0] P
);
wire [7:0] neg;
wire [7:0] zero;
wire [7:0] one;
wire [7:0] two;

genvar i;
generate 
	for(i=0; i<8; i++)begin:booth_enc_inst
		if(i==0)
			booth_enc u_booth_enc(
				.code ({B[1:0],1'b0}),
				.neg  (neg[i]    ),
				.zero (zero[i]   ),
				.one  (one[i]	 ),
				.two  (two[i]	 )
			);
		else
			booth_enc u_booth_enc(
				.code (B[i*2+1:i*2-1]),
				.neg  (neg[i]    ),
				.zero (zero[i]   ),
				.one  (one[i]	 ),
				.two  (two[i]	 )
			);
	end
endgenerate

wire [7:0][31:0] prod;

generate 
	for(i=0; i<8; i++)begin:name2
		gen_prod u_gen_prod (
			.A    ( A       ),
			.neg  ( neg[i]  ),
			.zero ( zero[i] ),
			.one  ( one[i]  ),
			.two  ( two[i]  ),
			.prod ( prod[i] )
		);
	end
endgenerate

wallace_tree u_watree(
    .prod(prod),
    .P(P)
);
endmodule


module gen_prod (
	input [15:0] A,
	input neg,
	input zero,
	input one,
	input two,
	output [31:0] prod
);

reg [31:0] prod_pre;

always @ (*) begin
	prod_pre = 32'd0;
	if (zero)
		prod_pre = 32'd0;
	else if (one)
		prod_pre = { { 16{A[15]} }, A};
	else if (two)
		prod_pre = { { 15{A[15]} }, A, 1'b0};
end

module full_adder(
    input a,
    input b,
    input cin,
    output cout,
    output s
);

assign s = a ^ b ^ cin;
assign cout = a & b | (cin & (a ^ b));

endmodule

module csa #(parameter width=16) (
	input [width-1:0] op1,
	input [width-1:0] op2,
	input [width-1:0] op3,
	output [width-1:0] S,
	output [width-1:0] C
);

genvar i;
generate
	for(i=0; i<width; i=i+1) begin: generate_block_identifier // <-- example block name
		full_adder u_full_adder(
			.a      (   op1[i]    ),
			.b      (   op2[i]    ),
			.cin    (   op3[i]    ),
			.cout   (   C[i]	  ),
			.s      (   S[i]      )
		);
	end
endgenerate

endmodule


assign prod = neg ? ( ~prod_pre+1'b1 ) : prod_pre;
		
endmodule

module booth_enc(
	input [2:0] code,
	output neg,
	output zero,
	output one,
	output two
);

assign neg  = code[2];
assign zero = (code==3'b000) || (code==3'b111);
assign two  = (code==3'b100) || (code==3'b011);
assign one  = !zero & !two;

endmodule

module wallace_tree (
	input [7:0][31:0] prod,
    output [31:0] P
);

wire [31:0] s_lev01;
wire [31:0] c_lev01;
wire [31:0] s_lev02;
wire [31:0] c_lev02;
wire [31:0] s_lev11;
wire [31:0] c_lev11;
wire [31:0] s_lev12;
wire [31:0] c_lev12;
wire [31:0] s_lev21;
wire [31:0] c_lev21;
wire [31:0] s_lev31;
wire [31:0] c_lev31;

//level 0
csa #(32) csa_lev01(
	.op1( prod[0]      ),
	.op2( prod[1] << 2 ),
	.op3( prod[2] << 4 ),
	.S	( s_lev01      ),
	.C	( c_lev01      )
);

csa #(32) csa_lev02(
	.op1( prod[3] << 6 ),
	.op2( prod[4] << 8 ),
	.op3( prod[5] << 10 ),
	.S	( s_lev02      ),
	.C	( c_lev02      )
);

//level 1
csa #(32) csa_lev11(
	.op1( s_lev01      ),
	.op2( c_lev01 << 1 ),
	.op3( s_lev02      ),
	.S	( s_lev11      ),
	.C	( c_lev11      )
);

csa #(32) csa_lev12(
	.op1( c_lev02 << 1 ),
	.op2( prod[6] << 12),
	.op3( prod[7] << 14),
	.S	( s_lev12      ),
	.C	( c_lev12      )
);

//level 2
csa #(32) csa_lev21(
	.op1( s_lev11      ),
	.op2( c_lev11 << 1 ),
	.op3( s_lev12      ),
	.S	( s_lev21      ),
	.C	( c_lev21      )
);

//level 3
csa #(32) csa_lev31(
	.op1( s_lev21 ),
	.op2( c_lev21 << 1 ),
	.op3( c_lev12 << 1 ),
	.S	( s_lev31),
	.C	( c_lev31)
);

//adder
rca #(32) u_rca (
    .op1 ( s_lev31  ), 
    .op2 ( c_lev31 << 1  ),
    .cin ( 1'b0   ),
    .sum ( P      ),
    .cout(        )
);

endmodule


module rca #(parameter width=16) (
    input  [width-1:0] op1,
    input  [width-1:0] op2,
    input  cin,
    output [width-1:0] sum,
    output cout
);

wire [width:0] temp;
assign temp[0] = cin;
assign cout = temp[width];

genvar i;
generate 
for( i=0; i<width; i=i+1) begin: generate_block_identifier // <-- example block name
    full_adder u_full_adder(
        .a      (   op1[i]     ),
        .b      (   op2[i]     ),
        .cin    (   temp[i]    ),
        .cout   (   temp[i+1]  ),
        .s      (   sum[i]     )
    );
end
endgenerate

endmodule

仿真:

在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LANIAKEA_ee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值