• 《牛客刷verilog》Part II Verilog进阶挑战


    前言

    • 之前刷过HDLbits上面的题目,点击链接可以查看详细笔记:verilog练习:hdlbits网站系列完结!
    • 最近又想刷一下牛客上面的题目,可以点击链接与小编一起刷题:牛客刷题
    • 小编不才,文中如有不当之处,可以在评论中互相交流。此处题目推荐看牛客的评论区,再提一嘴,注意积累自己的基本功算法、设计模式、软件等

    Part I Verilog快速入门

    Part II Verilog进阶挑战

    01 序列检测

    VL25 输入序列连续的序列检测

    在这里插入图片描述

    答案1:状态机法

    `timescale 1ns/1ns
    module sequence_detect(
    	input clk,
    	input rst_n,
    	input a,
    	output reg match
    	);
        
        parameter IDLE = 4'b0000;
        parameter S0   = 4'b0001;
        parameter S1   = 4'b0011;
        parameter S2   = 4'b0010;
        parameter S3   = 4'b0110;
        parameter S4   = 4'b0111;
        parameter S5   = 4'b0101;
        parameter S6   = 4'b0100;
        parameter S7   = 4'b1100;
    
        reg [3:0] cur_state, next_state;
        
        always@(posedge clk or negedge rst_n)
            if (!rst_n) begin
                cur_state <= IDLE;
                next_state <= IDLE;
            end else begin
               cur_state <= next_state; 
            end
        
        always@(*)
            case(cur_state)
                IDLE   :    next_state = (a==0)?S0:IDLE;
                S0     :    next_state = (a==1)?S1:S0;
                S1     :    next_state = (a==1)?S2:S0;
                S2     :    next_state = (a==1)?S3:S0;
                S3     :    next_state = (a==0)?S4:IDLE;
                S4     :    next_state = (a==0)?S5:IDLE;
                S5     :    next_state = (a==0)?S6:IDLE;
                S6     :    next_state = (a==1)?S7:IDLE;
                S7     :    next_state = (a==0)?S0:IDLE;
                default:    next_state = IDLE;
            endcase
            
            always@(posedge clk or negedge rst_n)
            if (!rst_n)
                match <= 1'b0;
            else if (cur_state == S7)
                match <= 1'b1;
            else
                match <= 1'b0;
      
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    在这里插入图片描述

    • 再说一个方法,这个方法我会称之为移位寄存器法

    答案2:移位寄存器法

    // `define SIZE 8 
    // `define SEQ 8'b01110001
    `timescale 1ns/1ns
    module sequence_detect(
    	input clk,
    	input rst_n,
    	input a,
    	output reg match
    	);
        
        reg [7:0] reg_8_a;
        always@(posedge clk or negedge rst_n)
            if (!rst_n)
                reg_8_a <= 'b0;
            else 
                reg_8_a <={reg_8_a[6:0],a};
        
            
        always@(posedge clk or negedge rst_n)
            if (!rst_n)begin
                match <= 1'b0;
            end
            else if (reg_8_a == 8'b01110001)
                match <= 1'b1;
            else
                match <= 1'b0;
    
      
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 为了可重用,想引入参数化设计。优化代码如下:
    `define SIZE 8 
    `define SEQ 8'b01110001
    `timescale 1ns/1ns
    module sequence_detect(
    	input clk,
    	input rst_n,
    	input a,
    	output reg match
    	);
        
        reg [`SIZE - 1:0] reg_a;
        always@(posedge clk or negedge rst_n)
            if (!rst_n)
                reg_a <= 'b0;
            else 
                reg_a <={reg_a[`SIZE - 2:0],a};
        
            
        always@(posedge clk or negedge rst_n)
            if (!rst_n)begin
                match <= 1'b0;
            end
            else if (reg_a == `SEQ)
                match <= 1'b1;
            else
                match <= 1'b0;
    
      
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    复盘

    • 题目不难,基本思想就是实现如下的状态转移图。(等熟练了,也可以不画)
      在这里插入图片描述

    • 上述的状态编码,使用了格雷码,并没有使用8421码,也没有使用独热码
      在这里插入图片描述

    • 为了可重用设计,推荐使用移位寄存器法

    VL26 含有无关项的序列检测

    在这里插入图片描述

    答案1:状态机法

    `timescale 1ns/1ns
    module sequence_detect(
    	input clk,
    	input rst_n,
    	input a,
    	output reg match
    	);
        parameter IDLE = 4'b0000;
        parameter S0   = 4'b0001;
        parameter S1   = 4'b0011;
        parameter S2   = 4'b0010;
        parameter S3   = 4'b0110;
        parameter S4   = 4'b0111;
        parameter S5   = 4'b0101;
        parameter S6   = 4'b0100;
        parameter S7   = 4'b1100;
        parameter S8   = 4'b1101;
    
        reg [3:0] cur_state, next_state;
        
        always@(posedge clk or negedge rst_n)
            if (!rst_n) begin
                cur_state <= IDLE;
                next_state <= IDLE;
            end else begin
               cur_state <= next_state; 
            end
        
        always@(*)
            case(cur_state)
                IDLE   :    next_state = (a==0)?S0:IDLE;
                S0     :    next_state = (a==1)?S1:S0;
                S1     :    next_state = (a==1)?S2:S0;
                S2     :    next_state = S3;
                S3     :    next_state = S4;
                S4     :    next_state = S5;
                S5     :    next_state = (a==1)?S6:IDLE;
                S6     :    next_state = (a==1)?S7:IDLE;
                S7     :    next_state = (a==0)?S8:IDLE;
                S8     :    next_state = (a==0)?S0:IDLE;
                default:    next_state = IDLE;
            endcase
            
         always@(posedge clk or negedge rst_n)
            if (!rst_n)
                match <= 1'b0;
            else if (cur_state == S8)
                match <= 1'b1;
            else
                match <= 1'b0;
      
      
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    在这里插入图片描述

    答案2:移位寄存器法

    `define SIZE 9
    `define SEQ 9'011XXX110
    `timescale 1ns/1ns
    module sequence_detect(
    	input clk,
    	input rst_n,
    	input a,
    	output reg match
    	);
        
        reg [`SIZE - 1:0] reg_a;
        always@(posedge clk or negedge rst_n)
            if (!rst_n)
                reg_a <= 'b0;
            else 
                reg_a <={reg_a[`SIZE - 2:0],a};
        
            
        always@(posedge clk or negedge rst_n)
            if (!rst_n)begin
                match <= 1'b0;
            end
        else if (reg_a[8:6] == 3'b011 && reg_a[2:0] == 3'b110)
                match <= 1'b1;
            else
                match <= 1'b0;
    
      
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    复盘

    • 和上题一样

    VL27 不重叠序列检测

    在这里插入图片描述

    答案

    `define SIZE 6
    `define SEQ 6'b011100
    
    `timescale 1ns/1ns
    module sequence_detect(
    	input clk,
    	input rst_n,
    	input data,
    	output reg match,
    	output reg not_match
    	);
        
            
        reg [`SIZE - 1:0] reg_a;
        always@(posedge clk or negedge rst_n)
            if (!rst_n)
                reg_a <= 'b0;
            else 
                reg_a <={reg_a[`SIZE - 2:0],data};
        
    
        
        reg [2:0] cnt;
        always@(posedge clk or negedge rst_n)
            if (!rst_n)begin
                cnt <= 1'b0;
            end
            else if (cnt == 3'd5)
                cnt <= 1'b0;
            else
                cnt <= cnt + 1'b1;
        
        
        always@(posedge clk or negedge rst_n)begin
            if (!rst_n)begin
                match <= 1'b0;
                not_match <= 1'b0;
            end
            else if (cnt == 3'd5)begin
                if ({reg_a[`SIZE - 2:0],data} == `SEQ)begin
                        match <= 1'b1;
                end
                else begin
                        not_match <= 1'b1;
                end
            end
            else begin
                match <= 1'b0;
                not_match <= 1'b0;
            end
        end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    在这里插入图片描述

    复盘

    • 注意,此题是要求最后一个数,输入最后1bit立马输出标志位,不是下一个时钟周期输出!
    • 前面两题是两个时钟周期才输出。
      在这里插入图片描述

    VL28 输入序列不连续的序列检测

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    module sequence_detect(
    	input clk,
    	input rst_n,
    	input data,
    	input data_valid,
    	output reg match
    	);
        
        reg [3:0] reg_data;
        always@(posedge clk or negedge rst_n) 
            if(!rst_n)
                reg_data <= 'd0;
            else if(data_valid)
                reg_data <= {reg_data[2:0],data};
            else 
                reg_data <= data;
        
        always@(posedge clk or negedge rst_n)
            if (!rst_n)
                match <= 'b0;
            else if({reg_data[2:0],data} == 'b0110)
                match <= 'b1;
            else 
                match <= 'b0;
        
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    复盘

    • 如果你习惯这种写法,就不用费尽心思去写状态机了。

    02 时序逻辑

    VL29 信号发生器

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    module signal_generator(
    	input clk,
    	input rst_n,
    	input [1:0] wave_choise,
    	output reg [4:0]wave
    	);
    
        reg [4:0] cnt;
        reg flag;
        
      	// 方波模式下,计数器控制
        always@(posedge clk or negedge rst_n) begin
            if(~rst_n)
                cnt <= 0;
            else
                cnt <= wave_choise!=0 ? 0:
                       cnt        ==19? 0:
                       cnt + 1;
        end
        
      	// 三角波模式下,标志位控制
        always@(posedge clk or negedge rst_n) begin
            if(~rst_n)
                flag <= 0;
            else
                flag <= wave_choise!=2 ? 0:
                        wave       ==1 ? 1:
                        wave       ==19? 0:
                        flag;
        end
        
      
      	// 更新wave信号
        always@(posedge clk or negedge rst_n) begin
            if(~rst_n) 
                wave <= 0;
            else 
                case(wave_choise)
                    0      : wave <= cnt == 9? 20    : 
                                     cnt ==19? 0     :
                                     wave;
                    1      : wave <= wave==20? 0     : wave+1;
                    2      : wave <= flag==0 ? wave-1: wave+1;
                    default: wave <= 0;
                endcase
        end
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在这里插入图片描述

    复盘

    • 没看明白题目
    • 看题解

    VL30 数据串转并电路

    在这里插入图片描述

    答案1

    `timescale 1ns/1ns
    
    module s_to_p(
    	input 				clk 		,   
    	input 				rst_n		,
    	input				valid_a		,
    	input	 			data_a		,
     
     	output	reg 		ready_a		,
     	output	reg			valid_b		,
    	output  reg [5:0] 	data_b
    );
    
        always@(posedge clk or negedge rst_n)
            if(!rst_n)begin
                ready_a <= 1'b0;
            end
            else begin
                ready_a <= 1'b1;
            end  
        
        reg [5:0] data_b_reg;  
        reg [2:0] cnt;    
        always@(posedge clk or negedge rst_n)
            if(!rst_n)begin
                data_b_reg <= 'd0;
                data_b <= 'd0;
                valid_b <= 1'b0;
                cnt <= 1'b0;
            end
            else if (valid_a)begin
                data_b_reg <= {data_a, data_b_reg[5:1]};
                if(cnt == 3'd5)begin
                    data_b <= {data_a, data_b_reg[5:1]};
                    valid_b <= 1'b1;
                    cnt <= 'd0;
                end
                else begin
                    valid_b <= 1'b0;
                    data_b <= data_b;
                    cnt <= cnt + 1'b1;
                end
            end
            else begin
                data_b_reg <= data_b_reg; 
            end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    答案2

    `timescale 1ns/1ns
    
    module s_to_p(
    	input 				clk 		,   
    	input 				rst_n		,
    	input				valid_a		,
    	input	 			data_a		,
     
     	output	reg 		ready_a		,
     	output	reg			valid_b		,
    	output  reg [5:0] 	data_b
    );
    
        always@(posedge clk or negedge rst_n)
            if(!rst_n)begin
                 ready_a <= 1'b0;
            end
            else begin
                 ready_a <= 1'b1;
            end  
       
        reg [5:0] data_b_reg;
        always@(posedge clk or negedge rst_n)
            if(!rst_n)begin
                data_b_reg <= 'd0;
            end
            else if (valid_a)begin
                data_b_reg <= {data_a, data_b_reg[5:1]};
            end
            else begin
                data_b_reg <= data_b_reg; 
            end  
        
        reg [2:0] cnt; 
        always@(posedge clk or negedge rst_n)
            if(!rst_n)begin
                cnt <= 'd0;
            end
            else if (valid_a)begin
                if (cnt == 'd5)
                    cnt <= 'd0;
                else
                    cnt <= cnt + 1'b1;
            end
        
        always@(posedge clk or negedge rst_n)
            if(!rst_n)begin
                valid_b <= 1'b0;
            end
            else if(cnt == 3'd5)begin
                valid_b <= 1'b1;
            end
            else begin
                valid_b <= 1'b0;
            end      
        
        always@(posedge clk or negedge rst_n)
            if(!rst_n)begin
                data_b <= 'd0;
            end
            else if(cnt == 3'd5)begin
                data_b <= {data_a, data_b_reg[5:1]};
            end else begin
                data_b <= data_b; 
            end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    在这里插入图片描述

    复盘

    • 仔细点就行。

    VL31 数据累加输出

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module valid_ready(
    	input 				clk 		,   
    	input 				rst_n		,
    	input		[7:0]	data_in		,
    	input				valid_a		,
    	input	 			ready_b		,
     
     	output		 		ready_a		,
     	output	reg			valid_b		,
    	output  reg [9:0] 	data_out
    );
        
        
        
        reg [1:0] cnt;
        always@(posedge clk or negedge rst_n)
            if(!rst_n)
                cnt <= 'b0;
            else if(ready_a && valid_a)begin 
                if(cnt == 2'd3)
                    cnt <= 'd0;
                else 
                    cnt <= cnt + 1'b1;
            end
            else begin
               cnt <= cnt; 
            end
        
        always@(posedge clk or negedge rst_n)
            if(!rst_n)begin
                valid_b <= 'b0;
            end
            else if(cnt==2'd3 && valid_a && ready_a)begin 
                valid_b <= 1'b1;
            end  
            else if(valid_b && ready_b)begin
                valid_b <= 1'b0;
            end
            else begin
                valid_b <= valid_b ;
            end
        
        always@(posedge clk or negedge rst_n)
            if(!rst_n)begin
                data_out <= 'b0;
            end
            else if(ready_a && valid_a)begin 
                if(cnt == 2'd0 )begin 
                data_out <= data_in;
                end 
                else begin
                    data_out <= data_out + data_in ;
                end
            end
        
        assign ready_a = ~valid_b | ready_b;
        
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    在这里插入图片描述

    复盘

    • 注意观察各个信号间的关系

    VL32 非整数倍数据位宽转换24to128

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module width_24to128(
    	input 				clk 		,   
    	input 				rst_n		,
    	input				valid_in	,
    	input	[23:0]		data_in		,
     
     	output	reg			valid_out	,
    	output  reg [127:0]	data_out
    );
        
        reg [3:0] cnt; 
        always@(posedge clk or negedge rst_n)
            if (!rst_n)
                cnt <= 'b0;
            else if (valid_in) begin
                if(cnt == 'd15)
                    cnt <= 4'd0;
                else
                    cnt <= cnt + 1'b1;
            end
            else 
                cnt <= cnt;
        
         always@(posedge clk or negedge rst_n)
            if (!rst_n) begin
                valid_out <= 1'b0;
            end
            else if (valid_in && (cnt == 'd5 || cnt == 'd10 || cnt == 'd15)) begin
                valid_out <= 1'b1;
            end else begin
                valid_out <= 1'b0;
            end 
        
        reg [127:0] data_out_reg;
        always@(posedge clk or negedge rst_n)
            if (!rst_n) begin
                data_out<= 'd0;
                data_out_reg <= 'd0;
            end
            else if (valid_in) begin
               if (cnt == 'd5) begin
                    data_out <= {data_out_reg,data_in[23:16]};
                    data_out_reg <= data_in[15:0];
                end if (cnt == 'd10)begin
                    data_out <= {data_out_reg,data_in[23:8]};
                    data_out_reg <= data_in[7:0];
                end if (cnt == 'd15)begin
                    data_out <= {data_out_reg,data_in};
                    data_out_reg <= 'd0;
                end else begin
                data_out_reg <= {data_out_reg,data_in};
                end 
            end
            else begin
                data_out_reg <= data_out_reg;
            end
                
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    在这里插入图片描述

    复盘

    • 注意理解5、10、15处的逻辑位置
    • 我们通常使用计数器来判断输出条件
      在这里插入图片描述

    VL33 非整数倍数据位宽转换8to12

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module width_8to12(
    	input 				   clk 		,   
    	input 			      rst_n		,
    	input				      valid_in	,
    	input	[7:0]			   data_in	,
     
     	output  reg			   valid_out,
    	output  reg [11:0]   data_out
    );
        
        reg [2:0] cnt; 
        always@(posedge clk or negedge rst_n)
            if (!rst_n)
                cnt <= 'd0;
            else if (valid_in) begin
                if(cnt == 'd2)
                    cnt <= 'd0;
                else
                    cnt <= cnt + 1'b1;
            end
            else 
                cnt <= cnt;
        
         always@(posedge clk or negedge rst_n)
            if (!rst_n) begin
                valid_out <= 1'b0;
            end
        else if (valid_in && (cnt == 'd1 || cnt == 'd2)) begin
                valid_out <= 1'b1;
            end else begin
                valid_out <= 1'b0;
            end 
        
        reg [11:0] data_out_reg;
        always@(posedge clk or negedge rst_n)
            if (!rst_n) begin
                data_out<= 'd0;
                data_out_reg <= 'd0;
            end
            else if (valid_in) begin
                if (cnt == 'd1) begin
                    data_out <= {data_out_reg,data_in[7:4]};
                    data_out_reg <= data_in[3:0];
                end if (cnt == 'd2)begin
                    data_out <= {data_out_reg,data_in};
                    data_out_reg <= 'd0;
                end else begin
                    data_out_reg <= {data_out_reg,data_in};
                end 
            end
            else begin
                data_out_reg <= data_out_reg;
            end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    在这里插入图片描述

    复盘

    • 和上题思路一致

    VL34 整数倍数据位宽转换8to16

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module width_8to16(
    	input 				   clk 		,   
    	input 				   rst_n		,
    	input				      valid_in	,
    	input	   [7:0]		   data_in	,
     
     	output	reg			valid_out,
    	output   reg [15:0]	data_out
    );
        
        reg  cnt; 
        always@(posedge clk or negedge rst_n)
            if (!rst_n)
                cnt <= 'd0;
            else if (valid_in) begin
                if(cnt == 'd1)
                    cnt <= 'd0;
                else
                    cnt <= cnt + 1'b1;
            end
            else 
                cnt <= cnt;
        
         always@(posedge clk or negedge rst_n)
            if (!rst_n) begin
                valid_out <= 1'b0;
            end
            else if (valid_in && cnt == 'd1) begin
                valid_out <= 1'b1;
            end else begin
                valid_out <= 1'b0;
            end 
        
        reg [15:0] data_out_reg;
        always@(posedge clk or negedge rst_n)
            if (!rst_n) begin
                data_out<= 'd0;
                data_out_reg <= 'd0;
            end
            else if (valid_in) begin
                if (cnt == 'd1) begin
                    data_out <= {data_out_reg,data_in};
                    data_out_reg <= data_in;
                end else begin
                    data_out_reg <= {data_out_reg,data_in};
                end 
            end
            else begin
                data_out_reg <= data_out_reg;
            end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    在这里插入图片描述

    复盘

    • 和上题思路一致

    VL35 状态机-非重叠的序列检测

    在这里插入图片描述

    答案1:寄存器写法

    `define SEQR 5'b10111
    
    `timescale 1ns/1ns
    
    module sequence_test1(
    	input wire clk  ,
    	input wire rst  ,
    	input wire data ,
    	output reg flag
    );
    //*************code***********//
        reg [4:0] data_reg;
        always@(posedge clk or negedge rst)
            if(!rst)
                data_reg <= 'd0;
            else 
                data_reg <= {data_reg,data};
        
        reg flag_bit = 1'b1;
        always@(posedge clk or negedge rst)
            if(!rst)
                flag <= 1'b0;
            else if(flag_bit && {data_reg,data} == `SEQR)begin
                flag <= 1'b1;
                flag_bit <= 1'b0;
            end
            else
                flag <= 1'b0;
    //*************code***********//
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    答案2:状态机法

    `define SEQR 5'b10111
    
    `timescale 1ns/1ns
    
    module sequence_test1(
    	input wire clk  ,
    	input wire rst  ,
    	input wire data ,
    	output reg flag
    );
    //*************code***********//
        parameter IDLE = 4'b0000;
        parameter S0   = 4'b0001;
        parameter S1   = 4'b0011;
        parameter S2   = 4'b0010;
        parameter S3   = 4'b0110;
        parameter S4   = 4'b0111;
        parameter S5   = 4'b0101;
        parameter S6   = 4'b0100;
        parameter S7   = 4'b1100;
    
        reg [3:0] cur_state, next_state;
        
        always@(posedge clk or negedge rst)
            if (!rst) begin
                cur_state <= IDLE;
                next_state <= IDLE;
            end else begin
               cur_state <= next_state; 
            end
        
        always@(*)
            case(cur_state)
                IDLE   :    next_state = (data==1)?S0:IDLE;
                S0     :    next_state = (data==0)?S1:IDLE;
                S1     :    next_state = (data==1)?S2:IDLE;
                S2     :    next_state = (data==1)?S3:S1;
                S3     :    next_state = (data==1)?S4:S1;
                S4     :    next_state = S5;
                default:    next_state = IDLE;
            endcase
            
        always@(*)
            if (cur_state == S4)
                flag <= 1'b1;
            else
                flag <= 1'b0;
      
    //*************code***********//
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    复盘

    • 这和1、2、3、4题一致

    VL36 状态机-重叠序列检测

    在这里插入图片描述

    答案1:寄存器法

    `timescale 1ns/1ns
    `define SEQR 4'b1011
    module sequence_test2(
    	input wire clk  ,
    	input wire rst  ,
    	input wire data ,
    	output reg flag
    );
    //*************code***********//
        reg [3:0] data_reg;
        always@(posedge clk or negedge rst)
            if(!rst)
                data_reg <= 'd0;
            else 
                data_reg <= {data_reg,data};
        
        reg cnt = 1'b1;
        always@(posedge clk or negedge rst)
            if(!rst)
                flag <= 1'b0;
            else if(data_reg == `SEQR)begin
                flag <= 1'b1;
            end
            else
                flag <= 1'b0;
    
    //*************code***********//
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    方法2:状态机法

    `timescale 1ns/1ns
    `define SEQR 4'b1011
    module sequence_test2(
    	input wire clk  ,
    	input wire rst  ,
    	input wire data ,
    	output reg flag
    );
    //*************code***********//
        parameter IDLE = 4'b0000;
        parameter S0   = 4'b0001;
        parameter S1   = 4'b0011;
        parameter S2   = 4'b0010;
        parameter S3   = 4'b0110;
        parameter S4   = 4'b0111;
        parameter S5   = 4'b0101;
        parameter S6   = 4'b0100;
        parameter S7   = 4'b1100;
    
        reg [3:0] cur_state, next_state;
        
        always@(posedge clk or negedge rst)
            if (!rst) begin
                cur_state <= IDLE;
                next_state <= IDLE;
            end else begin
               cur_state <= next_state; 
            end
        
        always@(*)
            case(cur_state)
                IDLE   :    next_state = (data==1)?S0:IDLE;
                S0     :    next_state = (data==0)?S1:IDLE;
                S1     :    next_state = (data==1)?S2:IDLE;
                S2     :    next_state = (data==1)?S3:S0;
                S3     :    next_state = (data==1)?S0:S1;
                default:    next_state = IDLE;
            endcase
            
        always@(posedge clk or negedge rst)
            if (!rst)
                 flag <= 1'b0;
            else if (cur_state == S3)
                flag <= 1'b1;
            else
                flag <= 1'b0;
    
    //*************code***********//
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在这里插入图片描述

    VL37 时钟分频(偶数)

    在这里插入图片描述

    答案1:计数器法

    `timescale 1ns/1ns
    
    module even_div
        (
        input     wire rst ,
        input     wire clk_in,
        output    wire clk_out2,
        output    wire clk_out4,
        output    wire clk_out8
        );
    //*************code***********//
    /*-------------------------------------------------------------
                                二分频
    -----------------------------------------------------------*/
        reg clk_out2_reg;
        always@(posedge clk_in or negedge rst)
            if(!rst)
                clk_out2_reg <= 1'b0;
            else
                clk_out2_reg <= ~clk_out2_reg;
        
        assign clk_out2 = clk_out2_reg;
    /*-------------------------------------------------------------
                                四分频
    -----------------------------------------------------------*/   
        reg [1:0] cnt_4;
        always@(posedge clk_in or negedge rst)
            if(!rst)
                cnt_4 <= 'd0;
    //         else if(cnt_4 == 'd3)
    //             cnt_4 <= 1'b0;
            else
                cnt_4 <= cnt_4 + 1'b1;
        
        reg clk_out4_reg;
        always@(posedge clk_in or negedge rst)
            if(!rst)
                clk_out4_reg <= 1'b0;
            else if(cnt_4 < 2'd2)
                clk_out4_reg <= 1'b1;
            else
                clk_out4_reg <= 1'b0;
        
        assign clk_out4 = clk_out4_reg;
    /*-------------------------------------------------------------
                                八分频
    -----------------------------------------------------------*/  
        reg [2:0] cnt_8;
        always@(posedge clk_in or negedge rst)
            if(!rst)
                cnt_8 <= 'b0;
    //         else if(cnt_8 == 'd7)
    //             cnt_8 <= 1'b0;
            else
                cnt_8 <= cnt_8 + 1'b1;
        
        reg clk_out8_reg;
        always@(posedge clk_in or negedge rst)
            if(!rst)
                clk_out8_reg <= 1'b0;
        else if(cnt_8 < 3'd4)
                clk_out8_reg <= 1'b1;
            else
                clk_out8_reg <= 1'b0;
        
        assign clk_out8 = clk_out8_reg;
        
    //*************code***********//
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    答案2:寄存器级联法

    `timescale 1ns/1ns
    
    module even_div
        (
        input     wire rst ,
        input     wire clk_in,
        output    wire clk_out2,
        output    wire clk_out4,
        output    wire clk_out8
        );
    //*************code***********//
        reg clk_out2_reg, clk_out4_reg, clk_out8_reg;
        
        always@(posedge clk_in or negedge rst) begin
            if(~rst)
                clk_out2_reg <= 0;
            else
                clk_out2_reg <= ~clk_out2_reg;
        end
        
        always@(posedge clk_out2 or negedge rst) begin
            if(~rst)
                clk_out4_reg <= 0;
            else
                clk_out4_reg <= ~clk_out4_reg;
        end
        
        always@(posedge clk_out4 or negedge rst) begin
            if(~rst)
                clk_out8_reg <= 0;
            else
                clk_out8_reg <= ~clk_out8_reg;
        end
        
        assign clk_out2 = clk_out2_reg;
        assign clk_out4 = clk_out4_reg;
        assign clk_out8 = clk_out8_reg;
    //*************code***********//
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    答案3:取巧思路

    `timescale 1ns/1ns
    
    module even_div
        (
        input     wire rst ,
        input     wire clk_in,
        output    wire clk_out2,
        output    wire clk_out4,
        output    wire clk_out8
        );
    //*************code***********//
    reg [2:0] cnt8;
    always @ (posedge clk_in or negedge rst) begin
        if(~rst) begin
            cnt8 <= 3'b0;
        end 
        else begin
            cnt8 <= cnt8 - 3'd1;
        end 
    end 
    
    assign clk_out2 = cnt8[0];
    assign clk_out4 = cnt8[1];
    assign clk_out8 = cnt8[2];
    
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    复盘

    VL38 自动贩售机1

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    module seller1(
    	input wire clk  ,
    	input wire rst  ,
    	input wire d1 ,
    	input wire d2 ,
    	input wire d3 ,
    	
    	output reg out1,
    	output reg [1:0]out2
    );
    //*************code***********//
        parameter IDLE = 4'b0000;
        parameter S0   = 4'b0001;
        parameter S1   = 4'b0011;
        parameter S2   = 4'b0010;
        parameter S3   = 4'b0110;
        parameter S4   = 4'b0111;
        parameter S5   = 4'b0101;
    //     parameter S6   = 4'b0100;
    //     parameter S7   = 4'b1100;
    
        reg [3:0] cur_state, next_state;
        
        always@(posedge clk or negedge rst)
            if (!rst) begin
                cur_state <= IDLE;
            end else begin
               cur_state <= next_state; 
            end
        
        always@(*)
            case(cur_state)
                IDLE   :
                    begin
                        if(d1)
                            next_state = S0;
                        else if(d2)
                            next_state = S1;
                        else if(d3)
                            next_state = S3;
                        else
                            next_state = next_state;
                    end
                S0     : 
                    begin
                        if(d1)
                            next_state = S1;
                        else if(d2)
                            next_state = S2;
                        else if(d3)
                            next_state = S4;
                        else
                            next_state = next_state;
                    end
                S1     :    
                    begin
                        if(d1)
                            next_state = S2;
                        else if(d2)
                            next_state = S3;
                        else if(d3)
                            next_state = S5;
                        else
                            next_state = next_state;
                    end
                default:    next_state = IDLE;
            endcase
            
        always@(posedge clk or negedge rst)
            if (!rst)begin
                out1 <= 'd0;
                out2 <= 'd0;
            end
            else begin
                case(next_state)
                    S2:begin out1 <= 1'b1;out2 <= 2'b00;end
                    S3:begin out1 <= 1'b1;out2 <= 2'b01;end
                    S4:begin out1 <= 1'b1;out2 <= 2'b10;end
                    S5:begin out1 <= 1'b1;out2 <= 2'b11;end
                    default:begin out1 <= 1'b0;out2 <= 2'b00;end
                endcase
            end
    
    //*************code***********//
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    复盘

    本题可以抽象为三输入二输出,存在状态0 0.5 1 1.5 2 2.5 3 七个状态,

    这样输出信号的特性应该为: out1饮料为一位,out2找零为2位(0 1 2 3个0.5元)

    因此先做状态转移图:

    • 注意,0.5/1/2是不会同时给信号的;在钱数大于2.5时就不能再继续投币了,在下一拍就要回到IDLE。

    在这里插入图片描述

    VL39 自动贩售机2

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module seller2(
    	input wire clk  ,
    	input wire rst  ,
    	input wire d1 ,
    	input wire d2 ,
    	input wire sel ,
    	
    	output reg out1,
    	output reg out2,
    	output reg out3
    );
    //*************code***********//
        parameter IDLE = 4'b0000;
        parameter S0   = 4'b0001;
        parameter S1   = 4'b0011;
        parameter S2   = 4'b0010;
        parameter S3   = 4'b0110;
        parameter S4   = 4'b0111;
        parameter S5   = 4'b0101;
    //     parameter S6   = 4'b0100;
    //     parameter S7   = 4'b1100;
    
        reg [3:0] cur_state, next_state;
        
        always@(posedge clk or negedge rst)
            if (!rst) begin
                cur_state <= IDLE;
            end else begin
               cur_state <= next_state; 
            end
        
        always@(*)
            case(cur_state)
                IDLE   :
                    begin
                        if(d1)
                            next_state = S0;
                        else if(d2)
                            next_state = S1;
                        else
                            next_state = next_state;
                    end
                S0     : 
                    begin
                        if(d1)
                            next_state = S1;
                        else if(d2)
                            next_state = S2;
                        else
                            next_state = next_state;
                    end
                S1     :    
                    begin
                        if(d1)
                            next_state = S2;
                        else if(d2)
                            next_state = S3;
                        else
                            next_state = next_state;
                    end
               S2     :    
                    begin
                        if(sel == 0)begin
                            next_state = IDLE;
                        end else begin
                            if(d1)
                                next_state = S3;
                            else if(d2)
                                next_state = S4;
                            else
                                next_state = next_state;
                        end
                    end
                S3     :    
                    begin
                        if(sel == 0)begin
                            next_state = IDLE;
                        end else begin
                            if(d1)
                                next_state = S4;
                            else if(d2)
                                next_state = S5;
                            else
                                next_state = next_state;
                        end
                    end           
                default:    next_state = IDLE;
            endcase
            
        always@(posedge clk or negedge rst)
            if (!rst)begin
                out1 <= 'd0;
                out2 <= 'd0;
                out3 <= 'd0;
            end
            else begin
                case(next_state)
                    S2:
                        begin 
                            if(sel == 0) begin 
                                out1 <= 1'b1;
                                out2 <= 1'b0;
                                out3 <= 1'b0;
                            end else begin
                                out1 <= 1'b0;
                                out2 <= 1'b0;
                                out3 <= 1'b0;
                            end
                        end
                    S3:
                       begin 
                            if(sel == 0) begin 
                                out1 <= 1'b1;
                                out2 <= 1'b0;
                                out3 <= 1'b1;
                            end else begin
                                out1 <= 1'b0;
                                out2 <= 1'b0;
                                out3 <= 1'b0;
                            end
                        end
    
                    S4:
                        begin
                            out1 <= 1'b0;
                            out2 <= 1'b1;
                            out3 <= 1'b0;
                        end
                    S5:
                        begin
                            out1 <= 1'b0;
                            out2 <= 1'b1;
                            out3 <= 1'b1;
                        end
                    default:
                        begin
                            out1 <= 1'b0;
                            out2 <= 1'b0;
                            out3 <= 1'b0;
                        end
                endcase
            end
    
    //*************code***********//
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147

    在这里插入图片描述

    复盘

    • 经典的三段式,状态转移图如下:
    • 第一段,时序逻辑寄存下一个状态
    • 第二段,组合逻辑计算下一个状态
    • 第三段,输出当前状态需要输出的条件

    在这里插入图片描述

    • 如果觉得代码不好看,可以继续更改格式

    VL40 占空比50%的奇数分频

    在这里插入图片描述

    答案

    `define CNT 3'd7
    
    `timescale 1ns/1ns
    
    module odo_div_or (
        input    wire  rst ,
        input    wire  clk_in,
        output   wire  clk_out7
    );
    
    //*************code***********//
    reg [2:0] count_p;	//上升沿计数
    reg [2:0] count_n;	//下降沿计数
    reg clk_p;			//上升沿分频
    reg clk_n;			//下降沿分频
    
    //上升沿计数
    always @ ( posedge clk_in or negedge rst )
    begin 
    	if( !rst ) 
    		count_p <= 3'b0;
    	else if( count_p == `CNT - 1 ) 
    		count_p <= 3'b0;
    	else  
    		count_p <= count_p + 1'b1;
    end
    
    //上升沿分频
    always  @ ( posedge clk_in or negedge rst )
    begin 
    	if( !rst ) begin 
    		clk_p <= 1'b0;
    	end 
    	else begin 
    		if( count_p == `CNT / 2 || count_p == `CNT - 1 ) begin 
    			clk_p <= ~clk_p;
    		end
    	end
    end
    
    //下降沿计数
    always @ ( negedge clk_in or negedge rst )
    begin 
    	if( !rst ) 
    		count_n <= 3'b0;
        else if( count_n == `CNT - 1)
    		count_n <= 3'b0;
    	else  
    		count_n <= count_n + 1'b1;
    end
    
    //下降沿分频
    always  @ ( negedge clk_in or negedge rst )
    begin 
    	if( !rst ) begin 
    		clk_n <= 1'b0;
    	end 
    	else begin 
            if( count_n == `CNT / 2 || count_n == `CNT - 1 ) begin 
    			clk_n <= ~clk_n;
    		end
    	end
    end 
    
    assign clk_out7 = clk_p | clk_n;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    复盘

    `define CNT 3'd7
    
    `timescale 1ns/1ns
    
    module odo_div_or (
        input    wire  rst ,
        input    wire  clk_in,
        output   wire  clk_out7
    );
    
    //*************code***********//
    reg [2:0] count;	//计数
    reg clk_p;			//上升沿分频
    reg clk_n;			//下降沿分频
    
    //沿计数
    always @ ( posedge clk_in or negedge rst )
    begin 
    	if( !rst ) 
    		count <= 3'b0;
    	else if( count == `CNT - 1 ) 
    		count <= 3'b0;
    	else  
    		count <= count + 1'b1;
    end
    
    //上升沿分频
    always  @ ( posedge clk_in or negedge rst )
    begin 
    	if( !rst ) begin 
    		clk_p <= 1'b0;
    	end 
    	else begin 
    		if( count == `CNT / 2 || count == `CNT - 1 ) begin 
    			clk_p <= ~clk_p;
    		end
    	end
    end
    
    //下降沿分频
    always  @ ( negedge clk_in or negedge rst )
    begin 
    	if( !rst ) begin 
    		clk_n <= 1'b0;
    	end 
    	else begin 
            if( count == `CNT / 2 || count == `CNT - 1 ) begin 
    			clk_n <= ~clk_n;
    		end
    	end
    end 
    
    assign clk_out7 = clk_p | clk_n;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    VL41 任意小数分频

    在这里插入图片描述

    答案

    复盘

    VL42 无占空比要去的奇数分频

    在这里插入图片描述

    答案

    复盘

    VL43 根据状态转移写状态机-三段式

    在这里插入图片描述

    答案

    复盘

    VL44 根据状态转移写状态机-二段式

    在这里插入图片描述

    03 跨时钟域传输

    VL45 异步FIFO

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    /***************************************RAM*****************************************/
    module dual_port_RAM #(parameter DEPTH = 16,
    					   parameter WIDTH = 8)(
    	 input wclk
    	,input wenc
    	,input [$clog2(DEPTH)-1:0] waddr  //深度对2取对数,得到地址的位宽。
    	,input [WIDTH-1:0] wdata      	//数据写入
    	,input rclk
    	,input renc
    	,input [$clog2(DEPTH)-1:0] raddr  //深度对2取对数,得到地址的位宽。
    	,output reg [WIDTH-1:0] rdata 		//数据输出
    );
    
    reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
    
    always @(posedge wclk) begin
    	if(wenc)
    		RAM_MEM[waddr] <= wdata;
    end 
    
    always @(posedge rclk) begin
    	if(renc)
    		rdata <= RAM_MEM[raddr];
    end 
    
    endmodule  
    
    /***************************************AFIFO*****************************************/
    module asyn_fifo#(
    	parameter	WIDTH = 8,
    	parameter 	DEPTH = 16
    )(
    	input 					wclk	, 
    	input 					rclk	,   
    	input 					wrstn	,
    	input					rrstn	,
    	input 					winc	,
    	input 			 		rinc	,
    	input 		[WIDTH-1:0]	wdata	,
    
    	output wire				wfull	,
    	output wire				rempty	,
    	output wire [WIDTH-1:0]	rdata
    );
     
        localparam ADDR_WIDTH = $clog2(DEPTH) - 1 + 1;
        //通过深度换算出需要多少位宽,因为fifo在最高位需要一个标志位产生满信号,上述再+1
        
        
        //第二步:给RAM申明缺少的端口信号
        /// 
        reg [ADDR_WIDTH:0] waddr,raddr;//写地址,读地址
        wire wenc,renc;//写使能信号,读使能信号
        
        
        //第三步:写地址操作,什么时候写
        /// 
        always@(posedge wclk or negedge wrstn) begin
            if(!wrstn) begin
                waddr <= 'd0;
            end
            else begin
                if(wenc) begin
                    waddr <= waddr + 1'b1;
                end 
                else begin
                    waddr <= waddr;
                end         
            end
        end
        
        assign wenc  = winc && ~wfull;//写使能信号
        
        
        //第四步:读地址操作,什么时候读
        /// 
        always@(posedge rclk or negedge rrstn) begin
            if(!rrstn) begin
                raddr <= 'd0;
            end
            else begin
                if(renc) begin
                    raddr <= raddr + 1'b1;
                end 
                else begin
                    raddr <= raddr;
                end         
            end
        end
        
        assign renc  = rinc && ~rempty;//读使能信号
        
        
        //第五步:产生空满信号---->异步 涉及到 跨时钟域同步
        //空信号是在读时钟域产生,所以需要将写时钟域的写地址同步到读时钟域
        //满信号是在写时钟域产生,所以需要将读时钟域的读地址同步到写时钟域
        //---->推荐将跨时钟域的地址转换为格雷码再同步
        ///
            ///
            //5.1 生成格雷码地址
            ///  
            reg [ADDR_WIDTH:0] waddr_gray,raddr_gray;//写地址格雷码,读地址格雷码
    
            always@(posedge wclk or negedge wrstn) begin
                if(!wrstn) begin
                    waddr_gray <= 'd0;
                end
                else begin
                    waddr_gray <= waddr ^ (waddr >> 1);
                end
            end
            always@(posedge rclk or negedge rrstn) begin
                if(!rrstn) begin
                    raddr_gray<= 'd0;
                end
                else begin
                    raddr_gray <= raddr ^ (raddr >> 1);
                end
            end
            ///
            //5.2 将格雷码地址同步到相应的时钟域
            ///      
            reg [ADDR_WIDTH:0] addr_w2r_reg,addr_w2r;
            always@(posedge rclk or negedge rrstn) begin
                if(!rrstn) begin
                    addr_w2r_reg <= 'd0;
                    addr_w2r <= 'd0;
                end
                else begin
                    addr_w2r_reg <= waddr_gray;
                    addr_w2r <= addr_w2r_reg;
                end
            end
    
            reg [ADDR_WIDTH:0] addr_r2w_reg,addr_r2w;
            always@(posedge wclk or negedge wrstn) begin
                if(!wrstn) begin
                    addr_r2w_reg <= 'd0;
                    addr_r2w <= 'd0;
                end
                else begin
                    addr_r2w_reg <= raddr_gray;
                    addr_r2w <= addr_r2w_reg;
                end
            end
            ///
            //5.3 产生空满信号
            ///    
            assign wfull  = (waddr_gray == {~addr_r2w[ADDR_WIDTH:ADDR_WIDTH-1],addr_r2w[ADDR_WIDTH-2:0]});
            assign rempty = (raddr_gray == addr_w2r);
        
        //第一步:例化双口RAM
        ///
        dual_port_RAM 
        #(
            .DEPTH(DEPTH)
           ,.WIDTH(WIDTH)
         )
        dual_port_RAM_inst
        (
             .wclk  (wclk                         )
            ,.wenc  (wenc                         )    
            ,.waddr (waddr[ADDR_WIDTH - 1 : 0]    )       //深度对2取对数,得到地址的位宽。
            ,.wdata (wdata                        )       //数据写入
            ,.rclk  (rclk                         )    
            ,.renc  (renc                         )    
            ,.raddr (raddr[ADDR_WIDTH - 1 : 0]    )       //深度对2取对数,得到地址的位宽。
            ,.rdata (rdata                        )	      //数据输出
        );
        
        
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174

    在这里插入图片描述

    复盘

    VL46 同步FIFO

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    /**********************************RAM************************************/
    module dual_port_RAM #(parameter DEPTH = 16,
    					   parameter WIDTH = 8)(
    	 input wclk
    	,input wenc
    	,input [$clog2(DEPTH)-1:0] waddr  //深度对2取对数,得到地址的位宽。
    	,input [WIDTH-1:0] wdata      	//数据写入
    	,input rclk
    	,input renc
    	,input [$clog2(DEPTH)-1:0] raddr  //深度对2取对数,得到地址的位宽。
    	,output reg [WIDTH-1:0] rdata 		//数据输出
    );
    
    reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
    
    always @(posedge wclk) begin
    	if(wenc)
    		RAM_MEM[waddr] <= wdata;
    end 
    
    always @(posedge rclk) begin
    	if(renc)
    		rdata <= RAM_MEM[raddr];
    end 
    
    endmodule  
    
    /**********************************SFIFO************************************/
    module sfifo#(
    	parameter	WIDTH = 8,
    	parameter 	DEPTH = 16
    )(
    	input 					clk		, 
    	input 					rst_n	,
    	input 					winc	,
    	input 			 		rinc	,
    	input 		[WIDTH-1:0]	wdata	,
    
    	output reg				wfull	,
    	output reg				rempty	,
    	output wire [WIDTH-1:0]	rdata
    );
        
        localparam ADDR_WIDTH = $clog2(DEPTH) - 1 + 1;
        //通过深度换算出需要多少位宽,因为fifo在最高位需要一个标志位产生满信号,上述再+1
        
        
        //第二步:给RAM申明缺少的端口信号
        /// 
        reg [ADDR_WIDTH:0] waddr,raddr;//写地址,读地址
        wire wenc,renc;//写使能信号,读使能信号
        
        
        
        
        //第三步:写地址操作,什么时候写
        /// 
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                waddr <= 'd0;
            end
            else begin
                if(wenc) begin
                    waddr <= waddr + 1'b1;
                end 
                else begin
                    waddr <= waddr;
                end         
            end
        end
        
        assign wenc  = winc && ~wfull;//写使能信号
        
        
        //第四步:读地址操作,什么时候读
        /// 
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                raddr <= 'd0;
            end
            else begin
                if(renc) begin
                    raddr <= raddr + 1'b1;
                end 
                else begin
                    raddr <= raddr;
                end         
            end
        end
        
        assign renc  = rinc && ~rempty;//读使能信号
        
        
        //第五步:产生空满信号
        ///
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                wfull <= 'd0;
                rempty <= 'd0;
            end
            else begin
                wfull <= ((waddr[ADDR_WIDTH] != raddr[ADDR_WIDTH]) && (waddr[ADDR_WIDTH-1:0] == raddr[ADDR_WIDTH-1:0]));
                rempty <= raddr == waddr;
            end
        end
    
        
        
        //第一步:例化双口RAM
        ///
        dual_port_RAM 
        #(
            .DEPTH(DEPTH)
           ,.WIDTH(WIDTH)
         )
        dual_port_RAM_inst
        (
             .wclk  (clk     )
            ,.wenc  (wenc     )    
            ,.waddr (waddr   )       //深度对2取对数,得到地址的位宽。
            ,.wdata (wdata   )       //数据写入
            ,.rclk  (clk    )    
            ,.renc  (renc    )    
            ,.raddr (raddr   )       //深度对2取对数,得到地址的位宽。
            ,.rdata (rdata   )	    //数据输出
        );
        
        
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130

    复盘

    VL47 格雷码计数器

    在这里插入图片描述

    答案

    • 什么逆天计数器,两个时钟周期
    `timescale 1ns/1ns
    module gray_counter(
       input   clk,
       input   rst_n,
       output  reg [3:0] gray_out
    );
        
        reg [4:0] bin_cnt = 'd0;
        always @ (posedge clk or negedge rst_n) 
        begin
            if( ~rst_n ) begin
                bin_cnt <= 'd0;
            end 
            else begin
                bin_cnt <= bin_cnt + 'd1;
            end 
        end 
    
        wire [3:0] bin;
        assign bin = bin_cnt[4:1];
        always @ (*) 
        begin
            gray_out = bin ^ (bin>>1);
    //         gray_out[3] = bin[3];
    //         gray_out[2] = bin[3] ^ bin[2];
    //         gray_out[1] = bin[2] ^ bin[1];
    //         gray_out[0] = bin[1] ^ bin[0];
    
        end 
        
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    进行修改

    `timescale 1ns/1ns
    module gray_counter(
       input   clk,
       input   rst_n,
       output  reg [3:0] gray_out
    );
        
        reg [4:0] bin_cnt = 'd0;
        always @ (posedge clk or rst_n) 
        begin
            if( ~rst_n ) begin
                bin_cnt <= 'd0;
                gray_out <= 'd0;
            end 
            else begin
                bin_cnt <= bin_cnt + 'd1;
                gray_out <= bin_cnt[4:1] ^ (bin_cnt[4:1]>>1);
            end 
        end  
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    既然是两个时钟周期出结果,我们可以先讲时钟进行二分频,在该时钟下完成计数器累加

    `timescale 1ns/1ns
    module gray_counter(
       input   clk,
       input   rst_n,
       output  reg [3:0] gray_out
    );
        reg clk2;
        always @ (posedge clk or negedge rst_n) 
        if(!rst_n)
            clk2 <= 'b0;
        else 
            clk2 <= ~clk2;
        
            
        reg [3:0] bin_cnt = 'd0;
        always @ (posedge clk2 or negedge rst_n) 
        begin
            if( !rst_n ) begin
                bin_cnt <= 'd0;
            end 
            else begin
                bin_cnt <= bin_cnt + 'd1;
            end 
        end  
        
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                gray_out <= 0;
            end
            else begin
                gray_out = (bin_cnt >> 1) ^ bin_cnt;
            end
        end
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    复盘

    在这里插入图片描述

    在这里插入图片描述

    VL48 多bit MUX同步器

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module mux(
    	input 				clk_a	, 
    	input 				clk_b	,   
    	input 				arstn	,
    	input				brstn   ,
    	input		[3:0]	data_in	,
    	input               data_en ,
    
    	output reg  [3:0] 	dataout
    );
        
        reg data_en_b,data_en_b_reg;
        reg [3:0] data_in_b,data_in_b_reg;
        
        always@(posedge clk_b or negedge brstn) begin
            if(!brstn)begin
                {data_en_b,data_en_b_reg} <= 'd0;
                {data_in_b,data_in_b_reg} <= 'd0;
            end 
            else begin
                {data_en_b,data_en_b_reg} <= {data_en_b_reg,data_en};
                {data_in_b,data_in_b_reg} <= {data_in_b_reg,data_in};
            end
        end
        
        always@(posedge clk_b or negedge brstn) begin
            if(!brstn)begin
                dataout <= 'd0;
            end 
            else if (data_en_b)begin
                dataout <= data_in_b;
            end 
            else begin
                dataout <= dataout;
            end
        end    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在这里插入图片描述

    复盘

    • 注意对比异步FIFO的格雷码跨时钟域同步

    VL49 脉冲同步电路

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module pulse_detect(
    	input 				clk_fast	, 
    	input 				clk_slow	,   
    	input 				rst_n		,
    	input				data_in		,
    
    	output  		 	dataout
    );
        reg data_in_fast;
        always @ (posedge clk_fast or negedge rst_n) 
        begin
            if(~rst_n) begin
                data_in_fast <= 1'b0;
            end
            else begin
                if(data_in == 1'b1)
                    data_in_fast <= ~data_in_fast;
                else 
                    data_in_fast <= data_in_fast;
            end 
        end 
    
        reg data_in_slow_t1;
        reg data_in_slow_t2;
        reg data_in_slow_t3;
        always @ (posedge clk_slow or negedge rst_n) 
        begin
            if(~rst_n) begin
                data_in_slow_t1 <= 1'b0;
                data_in_slow_t2 <= 1'b0;
                data_in_slow_t3 <= 1'b0;
            end
            else begin
                data_in_slow_t1 <= data_in_fast;
                data_in_slow_t2 <= data_in_slow_t1;
                data_in_slow_t3 <= data_in_slow_t2;
            end 
        end
    
        assign dataout = data_in_slow_t2 ^ data_in_slow_t3;
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    复盘

    04 计数器

    VL50 简易秒表

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module count_module(
    	input clk,
    	input rst_n,
    
        output reg [5:0]second,
        output reg [5:0]minute
    	);
        
    	
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                second <= 'd0;
            end
            else if (minute == 'd60)begin
                second <= 'd0;
            end
            else if (second == 'd60)begin
                second <= 'd1;
            end 
            else begin
                second <= second + 'd1;
            end
        end
        
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                minute <= 'd0;
            end
    //         else if (minute == 'd60)begin
    //             minute <= minute;
    //         end 
            else if(second == 'd60)begin
                minute <= minute + 'd1;
            end
            else begin
                minute <= minute;
            end 
        end	
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    复盘

    • 就是简单的计数器
    • 注意思考,被注释掉的三行代码,

    VL51 可置位计数器

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module count_module(
    	input clk,
    	input rst_n,
    	input set,
    	input [3:0] set_num,
    	output reg [3:0]number,
    	output reg zero
    	);
        
        reg [3:0] cnt;
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                cnt <= 'd0;
            end
            else if(set) begin
               cnt <= set_num; 
            end
            else begin
                cnt <= cnt + 1'b1;
            end
        end
        
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                zero <= 'd0;
            end   
            else if(cnt == 'd0)begin
                zero <= 1'b1;
            end else begin
                zero <= 1'b0;
            end
        end
    
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                number <= 'd0;
            end   
            else begin
                number <= cnt;
            end
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在这里插入图片描述

    复盘

    • 计数器的基础上,增加了设置计数器数值的功能

    VL52 加减计数器

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module count_module(
    	input clk,
    	input rst_n,
    	input mode,
    	output reg [3:0]number,
    	output reg zero
    	);
        
        reg [3:0] cnt;
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                cnt <= 'd0;
            end
            else if(mode) begin
                if(cnt == 'd9) begin
                    cnt <= 'd0;
                end 
                else begin
                    cnt <= cnt + 1'b1;
                end
            end
            else begin
                if(cnt == 'd0) begin
                    cnt <= 'd9;
                end 
                else begin
                    cnt <= cnt - 1'b1;
                end
            end
        end
        
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                zero <= 'd0;
            end   
            else if(cnt == 'd0)begin
                zero <= 1'b1;
            end else begin
                zero <= 1'b0;
            end
        end
    
        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                number <= 'd0;
            end   
            else begin
                number <= cnt;
            end
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    在这里插入图片描述

    复盘

    • 就是在计数器的逻辑上增加了一些基本条件

    05 存储器

    VL53 单端口RAM

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module RAM_1port(
        input clk,
        input rst,
        input enb,
        input [6:0]addr,
        input [3:0]w_data,
        output wire [3:0]r_data
    );
    //*************code***********//
        reg[3:0] mem [127:0];
        
        reg[3:0] data;
        integer i;
        always@(posedge clk or negedge rst) begin
            if(!rst)begin
                for(i = 0; i < 128; i = i + 1)begin
                    mem[i] = 'd0;
                end
            end
            else if(enb)
                mem[addr] <= w_data;
        end
        
        reg [3:0] r_data_reg;
        always@(*) begin
            r_data_reg = 'd0;
            if(~enb)
                r_data_reg = mem[addr];
        end
        
    //     always@(negedge clk or negedge rst) begin
    //         if(!rst)begin
    //             r_data_reg <= 'd0;
    //         end
    //         else if(~enb)
    //             r_data_reg <= mem[addr];
    //     end
        
        assign r_data = r_data_reg;
    //*************code***********//
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    复盘

    • enb=1的时候是写,addr就是写地址,enb=0的时候读,addr就是读地址。
    • 深度是128bit, 宽度是4bit. 使用reg [3:0] ram_reg[127:0]表示。这个初始化不能用 ram_reg <= 'd0; 需要用一个for循环来实现初始化。
    • 注意思考被注释的逻辑与上述组合逻辑的区别

    VL54 RAM的简单实现

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    module ram_mod(
    	input clk,
    	input rst_n,
    	
    	input write_en,
    	input [7:0]write_addr,
    	input [3:0]write_data,
    	
    	input read_en,
    	input [7:0]read_addr,
    	output reg [3:0]read_data
    );
        
        reg [3:0] RAM [255:0];
         
        integer i; // 不可综合
    //     reg [8:0] i;
        always@(posedge clk or negedge rst_n) begin
            if(~rst_n)
                for(i=0;i<256;i=i+1)
                    RAM[i] <= 0;
            else if(write_en) 
                RAM[write_addr] <= write_data;
            else
                RAM[write_addr] <= RAM[write_addr];
        end
        always@(posedge clk or negedge rst_n) begin
            if(~rst_n)
                read_data <= 0;
            else if(read_en) 
                read_data <= RAM[read_addr];
            else
                read_data <= read_data;
        end	
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    复盘

    • 最基本的双口RAM

    06 综合

    VL55 Johnson Counter

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module JC_counter(
       input                clk ,
       input                rst_n,
     
       output reg [3:0]     Q  
    );
        always@(posedge clk or negedge rst_n)
            if(!rst_n)
                Q <= 'd0;
            else
                Q <= {~Q[0],Q[3:1]};
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    复盘

    • 实现思路:将最后一位取反挪到最高位

    VL56 流水线乘法器

    在这里插入图片描述

    答案

    `timescale 1ns/1ns
    
    module multi_pipe#(
    	parameter size = 4
    )(
    	input 						clk 		,   
    	input 						rst_n		,
    	input	[size-1:0]			mul_a		,
    	input	[size-1:0]			mul_b		,
     
     	output	reg	[size*2-1:0]	mul_out		
    );
    
    
        reg [7:0]	addr01;
        reg [7:0]	addr23;
    
        wire [7:0]	temp0 ;
        wire [7:0]	temp1 ;
        wire [7:0]	temp2 ;
        wire [7:0]	temp3 ;
    
        assign temp0 = mul_b[0]? {4'b0, mul_a} : 'd0;
        assign temp1 = mul_b[1]? {3'b0, mul_a, 1'b0} : 'd0;
        assign temp2 = mul_b[2]? {2'b0, mul_a, 2'b0} : 'd0;
        assign temp3 = mul_b[3]? {1'b0, mul_a, 3'b0} : 'd0;
    
        always @(posedge clk or negedge rst_n) begin 
            if(~rst_n) begin
                addr01  <= 'd0;
                addr23  <= 'd0;
                mul_out <= 'd0;
            end 
            else begin
                addr01 <= temp0 + temp1;
                addr23 <= temp2 + temp3;
    
                mul_out <= addr01 + addr23;
            end
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    复盘

    VL57 交通灯

    在这里插入图片描述

    答案

    复盘

    VL58 游戏机计费程序

    在这里插入图片描述

    答案

    复盘

    Part III Verilog企业真题

    后记

    推荐相关文章

  • 相关阅读:
    自己定义 Advisor 实现自定义注解修饰的方法增强
    java技术:knife4j实现后端swagger文档
    一款集成ST-link下载及虚拟串口的STM32F103C8T6最小系统板设计
    探索智能应用的基石:多模态大模型赋能文档图像处理
    Linux 软链接与硬链接
    python装饰器
    scala 转换、过滤、分组、排序
    LeetCode 第113 双周赛补题
    java高级:动态代理
    Mysql的优化(二) Linux中搭建主从
  • 原文地址:https://blog.csdn.net/haojie_duan/article/details/125438272