手撕代码汇总


!!! 务必搞清楚每一个设计的输入和输出信号 !!!<\mark>

1. 计数器

  计数器

2. 分频器

  分频器

3. 状态机

  关于摩尔型状态机与米利型状态机的区别

  3.1 Moore状态机(摩尔)

  摩尔型状态机:输出只取决于当前状态,与输入无直接关系。
在这里插入图片描述

  3.2 Mealy状态机(米利)

  米利型:输出取决于当前状态和输入。
在这里插入图片描述

摩尔型和米利型状态机的对比:
  1)摩尔型更安全
  输出在时钟边沿变化(总是在一个周期后)。在Mealy机器中,输入更改可能会在逻辑完成后立即导致输出更改, 当两台机器互连时出现大问题 - 如果不小心,可能会发生异步反馈。
  2)Mealy机器对输入的反应更快
  在相同的周期内反应 - 不需要等待时钟。 在Moore机器中,可能需要更多逻辑来将状态解码为输出 - 在时钟边沿之后更多的门延迟。
    并非所有时序电路都可以使用Mealy模型实现。 一些时序电路只能作为摩尔机器实现。
    3)对于同一个设计来说,米利型的状态少,减少资源的消耗。但是各个状态间的状态跳转更复杂。

4. 序列检测器

  4.1 状态机描述

    状态机描述_序列检测器

    next_state另一种写法

    这个有电路图

  4.2 移位寄存器

    移位寄存器_序列检测器

    这个带仿真图

两种方法的对比:
   1)跟用状态机实现的区别在于,使用移位寄存器需要存储所有的码字,因此如果序列长度为N,则该方法需要消耗的寄存器就是N个。而使用状态机实现时,每个状态代表部分码字,如果使用十进制编码,则只需要使用log2(N)个寄存器即可编码所有状态,从寄存器资源的角度来看FSM实现起来代价较小。
   2)此外,寄存器版本每来一个码元都要比较所有码字,因此需要消耗N个比较器,而FSM的的状态寄存器每一位在状态转移时都需要不同的译码逻辑,如果状态转移比较简单,组合逻辑可能会比移位寄存器少,状态转移复杂的话就不好说了。
   3)当然,移位寄存器的版本编码更加简洁明了。

5. 序列生成器

   生成序列01011011101111…依次类推
   生成序列01011011101111
思路:有2个0的时候有2个1,有3个0的时候有3个1…

   循环产生序列信号001011
   移位寄存器方法除了可以有一个输入序列的接口,还可以在初始化时将序列填入移位寄存器中。代码如下:
  产生序列信号11010111

module seq_gen(
input                                   clk,
input                                   rst_n,
output                                  seq );

reg [7:0]out_seq;
always@(posedge clk or negedge rst_n)
  if(!rst_n) out_seq <= 8'b11010111;
  else out_seq <= {out_seq[6:0],out_seq[7]};

assign seq = out_seq[7];

6. 伪随机码发生器

  4级伪随机码发生器
  模运算

7. 异步复位,同步释放

  异步复位,同步释放

8. 超前进位加法器

半加器和的输出=A和B的异或;
在这里插入图片描述
图源
在这里插入图片描述

module half_adder(
input  a,
input b, 
output sum,
output c_out
);

assign sum = a^b;
assign cout = a&b;
endmodule

全加器和的输出=A、B、C的异或。
在这里插入图片描述
图源
在这里插入图片描述

module full_adder(
	//输入信号,ain表示被加数,bin表示加数,cin表示低位向高位的进位
	input ain,bin,cin,
	//输出信号,cout表示向高位的进位,sum表示本位的相加和
	output reg cout,sum

);
reg s1,s2,s3;
always @(ain or bin or cin) begin
	sum=(ain^bin)^cin;//本位和输出表达式
	s1=ain&cin;
	s2=bin&cin;
	s3=ain&bin;
	cout=(s1|s2)|s3;//高位进位输出表达式
end
endmodule

两个半加器可以构成一个全加器。
在这里插入图片描述
将多个“一位全加器”级联起来,可以变成“多位全加器”,上一个全加器的“进位输出”连到下一个全加器的“进位输入”。比如8位全加器如下:
图源
在这里插入图片描述
  级联多位全加器高位需要低位的进位位,故位宽增大时,加法的组合逻辑不断增大,延时非常大,超前进位加法器解决了这一问题。
  超前进位加法器 (Carry-Lookahead Adder,CLA)是高速加法器,每一级进位有附加的组合电路产生。高位的运算不需要地位的等待,因此速度很高。
数字电路基础知识(四) 加法器-半加器、全加器与超前进位加法器
在这里插入图片描述
多位超前进位加法器


以全加器代码为例说明门级,数据流级,行为级建模的区别

  • 数据流建模,一般用assign声明描述电路行为(连续赋值语句。因此这里的输出必须设置成wire类型)
  • 行为级建模,一般用initial 或者always (过程连续赋值语句,因为这里有always,输出必须设置成reg类型的)

9. FIR滤波器

10. 自动售卖机

  自动贩售机米利型_B站视频_FPGA探索者
   自动贩售机摩尔型_B站视频


`timescale 1ns/1ns

module sale(
   input                clk   ,
   input                rst_n ,
   input                sel   ,//sel=0,5$dranks,sel=1,10&=$drinks
   input          [1:0] din   ,//din=1,input 5$,din=2,input 10$
 
   output   reg  [1:0] drinks_out,//drinks_out=1,output 5$ drinks,drinks_out=2,output 10$ drinks
   output  reg        change_out   
);
    
    parameter   IDLE  = 2'b01,
                B_5   = 2'b10;
    reg [1:0] curr_state;
    reg [1:0] next_state;
    
    always@(posedge clk or negedge rst_n)begin
        if(~rst_n)
            curr_state <= IDLE;
        else
            curr_state <= next_state;
    end
    
    always@(*)
        if(~rst_n)
            next_state <= IDLE;
        else begin
            case(curr_state) 
                IDLE:
                    begin
                        case({sel,din}) 
                            3'b101:next_state <= B_5;
                            default:next_state <= IDLE;
                        endcase
                    end
                B_5 :
                    begin
                        case({sel,din})
                            3'b100:next_state <= B_5;
                            default:next_state <= IDLE;
                        endcase
                    end
                default:next_state <= IDLE;
            endcase
        end
    
    always@(posedge clk or negedge rst_n)begin
        if(~rst_n)begin
            drinks_out <= 2'd0;
            change_out <= 1'b0;
        end
        else begin
            case(curr_state)
                IDLE:
                    begin
                        case({sel,din})
                            3'b001:begin drinks_out <= 2'd1;change_out <= 1'b0; end
                            3'b010:begin drinks_out <= 2'd1;change_out <= 1'b1; end
                            3'b110:begin drinks_out <= 2'd2;change_out <= 1'b0; end
                            default:begin drinks_out <= 2'd0;change_out <= 1'b0; end
                        endcase
                    end
                B_5:
                    begin
                        case({sel,din})
                            3'b101:begin drinks_out <= 2'd2;change_out <= 1'b0; end
                            3'b110:begin drinks_out <= 2'd2;change_out <= 1'b1; end
                            default:begin drinks_out <= 2'd0;change_out <= 1'b0; end
                        endcase
                    end
                default:
                    begin
                        drinks_out <= 2'd0;
                        change_out <= 1'b0;
                    end
            endcase
        end
    end

endmodule
  • 输入金额累加判断
      设计一个自动贩售机,输入货币有三种,为0.5/1/2元,饮料价格是1.5元,要求进行找零,找零只会支付0.5元。
       ps:投入的货币会自动经过边沿检测并输出一个在时钟上升沿到1,在下降沿到0的脉冲信号,注意rst为低电平复位

11. 红绿灯

12. 格雷码计数器

13. 并串转换

并串转换

14. 串并转换

https://blog.csdn.net/vivid117/article/details/102021707

  1. 利用移位寄存器
module serial_parallel(
    input           clk,
    input           rst_n,en,
    input           data_i,   //一位输入
    output   reg [7:0] data_o	//8位并行输出
    );

always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0)
		data_o <= 8'b0;
	else if (en == 1'b1)
		data_o <= {data_o[6:0], data_i};	//低位先赋值
		//data_o <= {data_i,data_o[7:1],};	//高位先赋值
	else
		data_o <= data_o;
end

endmodule
  1. 利用计数器
module serial_parallel(
    input           clk,
    input           rst_n,
    input           data_i,
    output   reg [7:0] data_o
);

//msb first   most significant bit 表示二进制数据的最高位
reg     [2:0]   cnt; 	//计数器0-7  
always @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        data_o <= 8'b0;
        cnt <= 3'd0;
    end
    else begin
        data_o[7 - cnt] <= data_i;	高位先赋值
        cnt <= cnt + 1'b1;
    end
end

/*
//lsb first	(least significant bit) 表示二进制数据的最低位

reg     [2:0]   cnt;
always @(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        data_o <= 8'b0;
        cnt <= 3'd0;
    end
    else begin
        data_o[cnt] <= data_i;   //低位先赋值
        cnt <= cnt + 1'b1;
    end
end
*/

endmodule

14. 同步FIFO

15. 异步FIFO

改变字体颜色:
浅红色文字:浅红色文字:
深红色文字:深红色文字
浅绿色文字:浅绿色文字

深绿色文字:深绿色文字

改变字体大小:
size为1:size为1

size为2:size为2

size为10:size为10

改变字体背景:

背景色的设置是按照十六进制颜色值:#7FFFD4
背景色的设置是按照十六进制颜色值:#FF83FA
背景色的设置是按照十六进制颜色值:#D1EEEE
背景色的设置是按照十六进制颜色值:#C0FF3E
背景色的设置是按照十六进制颜色值:#54FF9F

改变字体:
我是黑体字
我是宋体字
我是微软雅黑字
我是fantasy字
我是Helvetica字

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值