资讯详情

高等数字集成电路分析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形式,时分秒分为两位数字  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

仿真:

标签: 集成电路646u2

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台