> 文章列表 > 硬件语言Verilog HDL牛客刷题day11 A里部分 和 Z兴部分

硬件语言Verilog HDL牛客刷题day11 A里部分 和 Z兴部分

硬件语言Verilog HDL牛客刷题day11 A里部分 和 Z兴部分

1.VL72 全加器

1.题目:

①    请用题目提供的半加器实现全加器电路①

半加器的参考代码如下,可在答案中添加并例化此代码。

 


2. 解题思路  (可以看代码)

        2.1 先看 半加器  s 是加位 ,  C 是进位。

        2.2  再看全加器  s 是加位 ,  C 是进位。

        2.3 解题办法一 , 直接assign 不使用 半加器。

        2.4 解题办法二,  直接assign 使用 半加器,两个相加得出 加位, assign 得出 进位。


3. 解题代码

`timescale 1ns/1nsmodule add_half(input                A   ,input                B   ,output	wire        S   ,output   wire        C   
);assign S = A ^ B;
assign C = A & B;
endmodule/***************************************************************/
module add_full(input                A   ,input                B   ,input                Ci  , output	wire        S   ,output   wire        Co   
);assign S = A ^ B ^ Ci;
assign Co = (A & B) | (B & Ci);/*
wire c_1;
wire c_2;
wire sum_1;add_half add_half_1(.A   (A),.B   (B),.S   (sum_1),.C   (c_1)  
);
add_half add_half_2(.A   (sum_1),.B   (Ci),.S   (S),.C   (c_2)  
);assign Co = c_1 | c_2;
*/
endmodule


2.VL73 串行进位加法器

1.题目:

②    请用全加器电路①实现串行进位的4位全加器电路

1位全加器参考代码如下

module add_half(input                A   ,input                B   ,output	wire        S   ,output   wire        C   
);assign S = A ^ B;
assign C = A & B;
endmodule/***************************************************************/
module add_full(input                A   ,input                B   ,input                Ci  , output	wire        S   ,output   wire        Co   
);wire c_1;
wire c_2;
wire sum_1;add_half add_half_1(.A   (A),.B   (B),.S   (sum_1),.C   (c_1)  
);
add_half add_half_2(.A   (sum_1),.B   (Ci),.S   (S),.C   (c_2)  
);assign Co = c_1 | c_2;
endmodule


2.解题思路

        2.1 四位得加法器

        2.2 C0 两个四位数据得 进位, S[3:0] 两个数据得加位。

        2.3 按照数据的位置加就行了, (分成四位)。


3.解题代码

`timescale 1ns/1nsmodule add_4(input         [3:0]  A   ,input         [3:0]  B   ,input                Ci  , output	wire [3:0]  S   ,output   wire        Co   
);wire s1[4:0];
wire c1[4:0];add_full U1(.A (A[0]),.B (B[0]),.Ci (Ci),.S (s1[0]),.Co (c1[0])
);add_full U2(.A (A[1]),.B (B[1]),.Ci (c1[0]),.S (s1[1]),.Co (c1[1])
);add_full U3(.A (A[2]),.B (B[2]),.Ci (c1[1]),.S (s1[2]),.Co (c1[2])
);add_full U4(.A (A[3]),.B (B[3]),.Ci (c1[2]),.S (s1[3]),.Co (Co)
);assign S[0] = s1[0];
assign S[1] = s1[1];
assign S[2] = s1[2];
assign S[3] = s1[3];endmodulemodule add_half(input                A   ,input                B   ,output	wire        S   ,output   wire        C   
);assign S = A ^ B;
assign C = A & B;
endmodule/***************************************************************/
module add_full(input                A   ,input                B   ,input                Ci  , output	wire        S   ,output   wire        Co   
);wire c_1;
wire c_2;
wire sum_1;add_half add_half_1(.A   (A),.B   (B),.S   (sum_1),.C   (c_1)  
);
add_half add_half_2(.A   (sum_1),.B   (Ci),.S   (S),.C   (c_2)  
);assign Co = c_1 | c_2;
endmodule

         



3.VL74 异步复位同步释放

1.题目:

请使用异步复位同步释放来将输入数据a存储到寄存器中,并画图说明异步复位同步释放的机制原理

 


 


2.解题思路

        2.1 了解 异步复位。

        2.2 了解 同步释放

        2.3 了解需求。

        2.4 观看时序图, 了解 同步时序的两个节拍。

         链接:(29条消息) 异步复位,同步释放_异步复位同步释放_三岁囍的博客-CSDN博客

        

 异步复位、同步释放是指复位信号产生时不受时钟信号的控制,但是释放的时候受到时钟信号的同步。主要目的是防止复位信号释放时候产生亚稳态。

        异步复位:当复位信号拉低时,直接进入复位状态。

        同步释放:当复位信号释放时,加入两级同步缓存器,电路不会立即释放,而是同步到时钟有效时再进行释放。
 


 3.解题代码

`timescale 1ns/1nsmodule ali16(
input clk,
input rst_n,
input d,
output reg dout);reg rstn_reg, rstn_reg_1;//异步复位,同步释放always @(posedge clk, negedge rst_n) beginif(!rst_n) beginrstn_reg <= 1'b0;rstn_reg_1 <= 1'b0;   endelse beginrstn_reg <= rst_n;rstn_reg_1 <= rstn_reg;  endend//同步释放
//     always @(posedge clk) begin
//             rstn_reg_1 <= rstn_reg;       
//     end  //赋值always @(posedge clk, negedge rstn_reg_1) beginif(!rstn_reg_1) begindout <= 1'b0;endelsedout <= d;end    endmodule


4.VL75 求最小公倍数

1.题目

  设计一个时序电路,输入2个无符号数,位宽可以通过参数DATA_W确定,输出这两个数的最小公倍数和最大公约数。


2.解题思路

        2.1 首先 最大公约数的求法:辗转相除法, 相减法,穷举法。 (建议采用 相减法,辗转相除法在有 被除数为 0 的时候很尴尬)

        2.1 最小公倍数 的求法是 : 两个数相乘,除去最大公约数。

        2.3 注意时序, (我的时序,最大公约的时候开始的时候错误)

         2.4 主要看代码 (不要注意题目测试的对错)

     


 3. 解题代码:

过关的: (相减法)

`timescale 1ns/1nsmodule lcm#(
parameter DATA_W = 8)
(
input [DATA_W-1:0] A,
input [DATA_W-1:0] B,
input 			vld_in,
input			rst_n,
input 			clk,
output	wire	[DATA_W*2-1:0] 	lcm_out,
output	wire 	[DATA_W-1:0]	mcd_out,
output	reg					vld_out
);
reg	[DATA_W*2-1:0]	mcd,a_buf,b_buf;
reg [DATA_W*2-1:0]	mul_buf;
reg					mcd_vld;
reg	[1:0]			cur_st,nxt_st;
parameter IDLE= 2'b00,S0 = 2'b01, S1 = 2'b10, S2 = 2'b11;
//两段式状态机
always @(posedge clk or negedge rst_n)if (!rst_n)cur_st <= IDLE;elsecur_st <= nxt_st;
always @(posedge clk or negedge rst_n)if (!rst_n) beginnxt_st <= IDLE;mcd	  <= 0;mcd_vld <= 0;a_buf <= 0;b_buf <= 0;mul_buf <= 0;vld_out <= 1'b0;endelse begin	case (cur_st)IDLE:if(vld_in) begin	a_buf <= A;b_buf <= B;nxt_st <= S0;mul_buf <= A*B;mcd_vld <= 0;vld_out <= 1'b0;endelse beginnxt_st <= IDLE;mcd_vld <= 0;vld_out <= 1'b0;endS0:if(a_buf!=b_buf)beginif(a_buf>b_buf)begina_buf<=a_buf-b_buf;b_buf<=b_buf;endelse begin b_buf <= b_buf - a_buf;a_buf <= a_buf;vld_out <= 1'b0;endnxt_st <= S0;endelse begin	nxt_st <=S1;vld_out <= 1'b0;endS1:begin	mcd <= b_buf;mcd_vld <= 1'b1;nxt_st	<= IDLE;vld_out <= 1'b1;enddefault:begin	nxt_st<=IDLE;vld_out <= 1'b0;endendcaseendassign mcd_out = mcd;
assign lcm_out = mul_buf/mcd;
endmodule

    辗转相除法: (我感觉这个可以的, 只是开始的最大公约数的时序不对)

`timescale 1ns/1nsmodule lcm#(
parameter DATA_W = 8)
(
input [DATA_W-1:0] A,
input [DATA_W-1:0] B,
input 			vld_in,
input			rst_n,
input 			clk,
output	wire	[DATA_W*2-1:0] 	lcm_out,
output	wire 	[DATA_W-1:0]	mcd_out,
output	reg					vld_out
);reg [DATA_W-1:0] a_r;reg [DATA_W-1:0] b_r;wire [DATA_W-1:0] a_w;wire [DATA_W-1:0] b_w;wire [DATA_W-1:0] res_w;reg flag_r;reg [DATA_W*2-1:0] lcm_out_r;assign vld_out = flag_r && (a_r == b_r);assign res_w = a_r - b_r;assign {a_w, b_w} = res_w > b_r ? {res_w, b_r} : {b_r, res_w};assign mcd_out = vld_out ? a_r : 'd0;assign lcm_out = lcm_out_r/ mcd_out;always @(posedge clk or negedge rst_n) beginif (!rst_n) begina_r <= 'd0;b_r <= 'd0;flag_r <= 'd0;endelse if (vld_in) begin{a_r, b_r} <= A > B ? {A, B} : {B, A};lcm_out_r <= A * B;flag_r <= 'd1;endelse if (vld_out) beginflag_r <= 'd0;endelse if (flag_r) begina_r <= a_w;b_r <= b_w;endend
endmodule

 简单版的 相减法 (没有注意时序)

`timescale 1ns/1nsmodule lcm#(
parameter DATA_W = 8)
(
input [DATA_W-1:0] A,
input [DATA_W-1:0] B,
input 			vld_in,
input			rst_n,
input 			clk,
output	wire	[DATA_W*2-1:0] 	lcm_out,
output	wire 	[DATA_W-1:0]	mcd_out,
output	reg					vld_out
);
//gcd
reg [DATA_W-1:0] tmp_m,tmp_n,reg_b,reg_s,mcd_out_r;
reg [DATA_W*2-1:0] lcm_out_r;
reg flag;
always@(posedge clk or negedge rst_n) beginif(!rst_n) beginreg_b <= 0;reg_s <= 0;vld_out <= 0;lcm_out_r <= 0;mcd_out_r <= 0;flag <= 0;endelse if(vld_in && A>B) beginreg_b <= A;reg_s <= B;flag <= 1;endelse if(vld_in) beginreg_b <= B;reg_s <= A;flag <= 1;endelse if(reg_b % reg_s != 0) beginreg_b <= reg_s;reg_s <= reg_b % reg_s;endelse if(reg_b % reg_s == 0 && flag == 1) beginvld_out <= 1;mcd_out_r <= reg_s;lcm_out_r <= tmp_m * tmp_n / reg_s;flag <= 0;endelse beginvld_out <= 0;mcd_out_r <= 0;lcm_out_r <= 0;end
end
always@(posedge clk or negedge rst_n) beginif(!rst_n) begintmp_m <= 0;tmp_n <= 0;endelse if(vld_in) begintmp_m <= A;tmp_n <= B;end
endassign mcd_out = mcd_out_r;
assign lcm_out = lcm_out_r;
endmodule


5.VL76 任意奇数倍时钟分频 (这个题,有一点细节)

1.题目:

编写一个模块,对输入的时钟信号clk_in,实现任意奇数分频,要求分频之后的时钟信号占空比为50%。模块应包含一个参数,用于指定分频的倍数。

       模块的接口信号图如下:

 


2.解题思路

        2.1 首先是  奇数的时钟分频。

        2.2 开始的时候我们需要计数, 计数的大小为  n 个周期。

        2.3 我们奇数的分频应该是 在其中一个周期 下降沿的时候开始下降。

        2.4 可以这样说  开始的时候 cnt =2 上升延变化, 4 个版周期。外加一个 下降沿的 周期的1 等于5  看图:

        

 


    3.解题代码

`timescale 1ns/1nsmodule clk_divider#(parameter dividor = 5)
( 	input clk_in,input rst_n,output clk_out
);reg [$clog2(dividor):0] cnt1;reg clk1, clk2;always @ (posedge clk_in, negedge rst_n) beginif(!rst_n) begincnt1 <= 0;endelse if(cnt1 == dividor-1) begincnt1 <= 0;endelse begincnt1 <= cnt1 + 1;endendalways @ (posedge clk_in, negedge rst_n)beginif(!rst_n) beginclk1 <= 1'b0;endelse if(cnt1 == (dividor - 1)>>1) begin clk1 <= ~clk1;endelse if (cnt1 == (dividor-1)) beginclk1 <= ~clk1;endelse beginclk1 <= clk1;end        endalways @ (negedge clk_in, negedge rst_n)beginif(!rst_n) beginclk2 <= 1'b0;endelse if(cnt1 == (dividor - 1)>>1) beginclk2 <= ~clk2;endelse if (cnt1 == (dividor-1)) beginclk2 <= ~clk2;endelse beginclk2 <= clk2;endendassign clk_out = clk1 || clk2;  //(4+1  == 5)endmodule


6.VL77 编写乘法器求解算法表达式

1.题目:

编写一个4bit乘法器模块,并例化该乘法器求解c=12*a+5*b,其中输入信号a,b为4bit无符号数,c为输出。注意请不要直接使用*符号实现乘法功能。


2.解题代码

`timescale 1ns/1nsmodule calculation(input clk,input rst_n,input [3:0] a,input [3:0] b,output reg [8:0] c);
reg[8:0]c1;
always@(posedge clk or negedge rst_n)beginif(~rst_n)beginc1<=0;endelsebeginc1 <= 4'd12 * a + 3'd5 * b;endendalways@(posedge clk or negedge rst_n)beginif(~rst_n)beginc<=0;endelsebeginc <=c1;endend
/*reg [8:0] a_tmp;reg [8:0] b_tmp;reg [8:0] c_tmp;always@(posedge clk or negedge rst_n)beginif(!rst_n)begina_tmp <= 0;b_tmp <= 0;c_tmp <= 0;endelse begina_tmp <= (a << 3) + (a << 2);b_tmp <= (b << 2) + b;c_tmp <= a_tmp + b_tmp;endendassign c = c_tmp;
*/endmodule