(自用)高集第四五章作业:后续详细编辑
跑表:
思路:先做两个按钮抖,一个表示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