HDLbits 刷题记录

今天开始重新刷一遍题目,强迫自己看英文,然后再把知识点记录下来!
2022.11.16 学习打卡第一天开始!

1、wire:线网类型,声明input和output信号时,缺省默认是wire

assign a = 3'b101;  // a = 101
assign b = a;  // b = 1
这种情况下隐式的创建一个单bit的wire类型,默认是1bit的变量b

2、连续性赋值assign:声明连线关系,将等号右边的信号值驱动到左边,assign只是声明连接关系,没有声明变量类型,因而没有先后顺序。后面是组合逻辑。

3、逻辑运算符:&& || !,输出是1bit
位运算符:& | ~,每一位运算,输入是Nbit,输出也是Nbit

4、循环

//第一种
integer i;
    always@(*)begin
        for(i = 0; i <= 7; i = i + 1)begin
            out[i] = in[7-i];
        end
    end
//第二种
generate
        genvar i;
        for(i = 0; i <= 7; i = i + 1)begin:conv  
        //这个地方必须给block命名conv,否则会报错
            assign out[i] = in[7-i];
        end
endgenerate

5、拼接运算符{ }:中间的变量必须声明位宽,不然不知道结果是几位数。

assign a = {5{a,b,c}, {5{a}}};  //5a放到一起也要有括号,容易忘记

6、模块例化方法:按照变量顺序,按照名称例化

7、加法器:32位加法器由两个16位加法器串联组成
16位加法器:
1位全加器:{cout,sum} = a + b + cin
(1)纹波/行波进位加法器 ripple carry adder / RCA:Nbit的加法器由N个1bit的全加器组成。速度较慢,第二部分需要等第一部分计算完,得到它的进位再进行第二部分的计算。
在这里插入图片描述

//第一种方法,更简单!!!
module top_module( 
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );
    
    generate
        genvar i;
        for(i = 0; i <= 99; i = i + 1)begin:adder
        	if(i == 0)begin
            	assign {cout[0], sum[0]} = a[0] + b[0] + cin;
            end
            else begin
            	assign {cout[i], sum[i]} = a[i] + b[i] + cout[i-1];
            end         
        end
    endgenerate
endmodule

//第二种方法,先写全加器,再例化100个全加器
module fulladder(
	input a,
	input b,
	input cin,
	output s,
	output c);
	assign {c,s} = a+b+cin;
endmodule

module top_mod(
	input [99:0] a,
	input [99:0] b,
	input cin,
	output cout,
	output [99:0] sum);
	wire [100:0] cin_tmp;
	assign cin_tmp[0] = cin;
	generate
		genvar i;
		for(i=0;i<=99;i=i+1)begin:adder
			fulladder add1( a[i],
							b[i],
							cin_tmp[i],
							sum[i],
							cin_tmp[i+1]);
		end
	endgenerate
	assign cout = cin_tmp[100];
endmodule

改进方法一:假设第一部分的进位为0或者1,去计算第二部分的结果。根据第一部分的进位去选择结果。
在这里插入图片描述
(2)4位BCD,1位十进制的加法器

module bcd_fadd (
    input [3:0] a,
    input [3:0] b,
    input     cin,
    output   cout,
    output [3:0] sum );
    assign {cout,sum} = a+b+cin;
endmodule

现有400bit的数a和b,例化100个实现100位的加法器

module top_module( 
    input [399:0] a, b,
    input cin,
    output cout,
    output [399:0] sum );
    
    wire [99:0] cout_tmp;
    generate 
        genvar i;
        for(i=0;i<=99;i=i+1)begin:adder
            if(i==0)
                bcd_fadd add1(a[3:0],b[3:0],cin,cout_tmp[0],sum[3:0]);
            else
                bcd_fadd add2(
                a[3+4*(i):4*(i)],
                b[3+4*(i):4*(i)],
                cout_tmp[i-1],
                cout_tmp[i],
                sum[3+4*(i):4*(i)]
                );
        end
    endgenerate
    assign cout = cout_tmp[99];
endmodule

8、加法器-减法器 adder-subtractor
加法器变减法器:就是求b的补码,求补码把b取反加一。
n+n=n+1;n*n=2n
(1)把32{sub}和b进行异或,就能实现取反,同时把sub放到cin。
当sub为0时,是加法器;当sub为1时,b的32位分别取反,同时加一,是减法器。
(2)还可以sub控制二选一的选择器,为0不变,为1取反即可,进位为1。
在这里插入图片描述
9、避免产生latch:case语句、ifelse语句要完整
case语句中很多都是无效状态,全部写出来比较麻烦——可以在case语句之前将输出值都赋初始值。使得在所有可能的情况下,输出都有值。

10、统计输入的向量中1的个数:把输入向量的每一个数相加即可,for循环。
[2:0] in,计算1的个数也是每一位直接相加

11、判断补码相加是否溢出:(不太理解
[7:0] a,b,s;
如果两个数都为负数,那个相加一定为负数,但是最终s的最高位不是1,那就证明溢出了,两个数都是正数同理。

12、卡诺图化简
最小项SOP/sum of product:积之和,最常用的,与或形式。
最大项POS/prodcut of sum:和之积,或与形式
(1)d可以当作是1或者0,下面化简就是cout = a | ~b&c;
在这里插入图片描述

(2)cout = a ^ b ^ c ^ d;
在这里插入图片描述
(3)最大项和最小项
在这里插入图片描述

//sop:sum of product   pos:product of sum
    assign out_sop = c & d | ~a & ~b & c;
    assign out_pos = ~((~c | ~d) & (a | b | ~c));

(4)用尽可能少的二选一选择器实现下面电路
在这里插入图片描述

//先固定ab变量,化简得到cd选项
	assign mux_in[0] = c | d;
    assign mux_in[1] = 1'b0;
    assign mux_in[2] = ~d;
    assign mux_in[3] = c & d;
    
//再把上述表达式变成二选一选择器   
	assign mux_in[0] = c ? 1'b1 : d;
    assign mux_in[1] = 1'b0;
    assign mux_in[2] = d ? 1'b0 : 1'b1;
    assign mux_in[3] = c ? d : 1'b0;

13、触发器
带同步/异步、低电平/高电平复位、保持端的D触发器

14、计数器
(1)已知一个4位二进制计数器,去实现从1-12的计数器
在这里插入图片描述

module count4(
	input clk,
	input enable,
	input load,
	input [3:0] d,
	output reg [3:0] Q
);
module top_module (
    input clk,
    input reset,
    input enable,
    output [3:0] Q,
    output c_enable,
    output c_load,
    output [3:0] c_d
); //
    assign c_enable = enable;
    assign c_load = reset | ((Q == 4'd12) && (enable == 1'b1));
    assign c_d = c_load ? 4'd1 : 4'd0;    
    count4 the_counter (clk, c_enable, c_load, c_d , Q);
endmodule

(2)已知一个模10 BCD的计数器,去实现1000的计数器,对1000hz的clk进行分频,输出1hz的信号,实现1000分频

module bcdcount (
	input clk,
	input reset,
	input enable,
	output reg [3:0] Q
);
module top_module (
    input clk,
    input reset,
    output OneHertz,
    output [2:0] c_enable
); //
    wire[3:0]	one, ten, hundred;
    
    assign c_enable = {one == 4'd9 && ten == 4'd9, one == 4'd9, 1'b1};
    assign OneHertz = (one == 4'd9 && ten == 4'd9 && hundred == 4'd9);
 
    bcdcount counter0 (clk, reset, c_enable[0], one);
    bcdcount counter1 (clk, reset, c_enable[1], ten);
    bcdcount counter2 (clk, reset, c_enable[2], hundred);
 
endmodule

(3)4位二进制数表示一位十进制数,实现4位十进制数的计数器,当个、十、百位为9时,ena输出一个脉冲。
在这里插入图片描述

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);
    
    one_decade one	(.clk(clk), .reset(reset), .enable(1'b1), .q(q[3:0]));
    one_decade two  (.clk(clk), .reset(reset), .enable(ena[1]),.q(q[7:4]));
    one_decade three(.clk(clk), .reset(reset),.enable(ena[2]),.q(q[11:8]));
    one_decade four (.clk(clk),.reset(reset),.enable(ena[3]),.q(q[15:12]));
    
    assign ena[1] = (q[3:0]  == 4'd9) ? 1'b1:1'b0;
    assign ena[2] = (q[7:4]  == 4'd9) && (q[3:0] == 4'd9) ? 1'b1:1'b0;
    assign ena[3] = (q[11:8] == 4'd9) && (q[7:4] == 4'd9) && (q[3:0] == 		   4'd9)? 1'b1:1'b0;
endmodule

module one_decade (
    input clk,
    input reset,        // Synchronous active-high reset
    input enable,
    output [3:0] q);
    
    always @(posedge clk) begin
        if(reset) q <= 0;
        else if(enable) begin
            if(q == 4'd9)	q <= 0;
        	else q <= q + 1;
        end
    end
endmodule

(4)时钟计数(难)
reset:恢复到12:00:00,pm=0。
关键是清零和加一的条件。
在这里插入图片描述
分成两个子模块来写,秒钟和分针都是59计数器的。小时是12计数器。

module mm_ss_bcd(
    input clk,
    input reset,        // Synchronous active-high reset
    input enable,
    output [7:0] q);
    
    always @(posedge clk) begin
        if(reset) q <= 8'h0;
        else if(enable)begin
            if	(q[7:0] == 8'h59) q[7:0] <= 4'h0;
            else if(q[3:0] == 4'h9 ) begin
                 q[3:0] <= 4'h0;
                 q[7:4] <= q[7:4] + 4'h1;
            end
            else q[3:0] <= q[3:0] + 4'h1;
        end
    end
endmodule

module hh_bcd(
    input clk,
    input reset,        // Synchronous active-high reset
    input enable,
    output [7:0] q);
    
    always @(posedge clk) begin
        if(reset) q <= 8'h12;
        else if (enable) begin
            if		(q[7:0] == 8'h12) q[7:0] <= 8'h01;
            else if	(q[7:0] == 8'h9 ) q[7:0] <= 8'h10; //十进制数计数0-9
            else q[7:0] <= q[7:0] + 4'h1;
        end
    end
endmodule

module top_module(
    input  clk,
    input  reset,
    input  ena,
    output pm,
    output [7:0] hh,
    output [7:0] mm,
    output [7:0] ss); 
    
    wire mm_enable,hh_enable;
    
    mm_ss_bcd mm_ss_bcdss(.clk(clk), .reset(reset), .enable(ena), .q(ss));
    mm_ss_bcd mm_ss_bcdmm(.clk(clk), .reset(reset), .enable(mm_enable), .q(mm));
    hh_bcd    hh_bcd_1	 (.clk(clk), .reset(reset), .enable(hh_enable), .q(hh));
    
    assign mm_enable = (ss == 8'h59) ? 1'b1:1'b0;
    assign hh_enable = (mm == 8'h59) &&  (ss == 8'h59) ? 1'b1:1'b0;
    
    always @(posedge clk) begin
        if(reset) pm <= 0;
        if((hh == 8'h11) && (mm == 8'h59) &&  (ss == 8'h59))
            pm <= ~pm;
    end
    
endmodule

15、线性反馈移位寄存器LFSR
组成:由寄存器和异或门组成
(1)五位LFSR
在这里插入图片描述

always@(posedge clk)begin
        if(reset)begin
            q <= 5'd1;
        end
        else begin
            q[4] <= q[0];
            q[3] <= q[4];
            q[2] <= q[3] ^ q[0];
            q[1] <= q[2];
            q[0] <= q[1];
        end
    end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值