HDLbits答案更新系列20(3.3 Building Larger Circuits 3.3.4 FSM: Enable shift register等)

目录

前言

3.3 Building Larger Circuits

3.3.4 FSM: Enable shift register(Exams/review2015 fsmshift)

3.3.5 FSM: The complete FSM(Exams/review2015 fsm)

3.3.6 The complete timer(Exams/review2015 fancytimer)

3.3.7 FSM: One-hot logic equations(Exams/review2015 fsmonehot)

结语

HDLbits网站链接


前言

今天将这一小节剩余的题目全部更新完,第一题尤其精彩,四种方法真的很有技巧性,下面就开始吧。

3.3 Building Larger Circuits

3.3.4 FSM: Enable shift register(Exams/review2015 fsmshift)

HDLbits答案更新系列20(3.3 Building Larger Circuits 3.3.4 FSM: Enable shift register等)_第1张图片

module top_module (
    input clk,
    input reset,      // Synchronous reset
    output shift_ena);
    
    parameter S0 = 3'd0, S1 = 3'd1, S2 = 3'd2, S3 = 3'd3, S4 = 3'd4;
    reg [2:0]	current_state;
    reg [2:0]	next_state;
    
    always@(posedge clk)begin
        if(reset)begin
            current_state <= S0;
        end
        else begin
            current_state <= next_state;
        end
    end
    
    always@(*)begin
        case(current_state)
            S0:begin
                next_state = S1;
            end
            S1:begin
                next_state = S2;
            end
            S2:begin
                next_state = S3;
            end
            S3:begin
                next_state = S4;
            end
            S4:begin
                next_state = S4;
            end
            default:begin
                next_state = S4;
            end
        endcase
    end
    
    assign shift_ena = (current_state == S0 || current_state == S1 || current_state == S2 || current_state == S3);
    
endmodule

/*
//second way
module top_module (
    input clk,
    input reset,      // Synchronous reset
    output reg shift_ena);    
    
    reg [3:0]	counter;
    wire		add_cnt;
    wire		end_cnt;
      
    always@(posedge clk)begin
        if(reset)begin
            counter <= 4'd0;
        end
        else if(add_cnt)begin
            if(end_cnt)begin
                counter <= 4'd0;
            end
            else begin
                counter <= counter + 1'b1;
            end
        end
    end
    
    assign add_cnt = shift_ena;
    assign end_cnt = add_cnt && counter == 4'd3;
    
    always@(posedge clk)begin
        if(reset)begin
            shift_ena <= 1'b1;
        end
        else if(end_cnt)begin
            shift_ena <= 1'b0;
        end
    end
    
endmodule
*/

/*
//third way
module top_module (
    input clk,
    input reset,      // Synchronous reset
    output shift_ena);
    
    reg 		shift_ena_reg1;
    reg 		shift_ena_reg2;
    reg 		shift_ena_reg3;
    reg 		shift_ena_reg4;   
    
    always@(posedge clk)begin
        if(reset)begin
            shift_ena_reg1 <= 1'b1;
        end
        else begin
            shift_ena_reg1 <= 1'b0;
        end
    end
    
    always@(posedge clk)begin
        if(reset)begin
            shift_ena_reg2 <= 1'b1;
            shift_ena_reg3 <= 1'b1;
            shift_ena_reg4 <= 1'b1;
        end
        else begin
            shift_ena_reg2 <= shift_ena_reg1;
            shift_ena_reg3 <= shift_ena_reg2;
            shift_ena_reg4 <= shift_ena_reg3;
        end
    end
    
    assign shift_ena = shift_ena_reg1 | shift_ena_reg2 | shift_ena_reg3 | shift_ena_reg4;

endmodule
*/

/*
//forth way
module top_module (
    input clk,
    input reset,      // Synchronous reset
    output shift_ena);
    
    reg [10:0]	counter;

    always@(posedge clk)begin
        if(reset)begin
            counter <= 11'd0;
        end
        else begin
            counter <= counter + 1'b1;
        end
    end

    assign shift_ena = counter < 11'd4;

endmodule
*/

首先,这道题题目中说,如果复位信号有效,shift_ena信号就变为1,当复位信号撤销以后,shift_ena信号保持4个周期为1后变为0。

这道题目博主给出4中解法,下面一种一种来说。

第一种解法:这种解法是常规解法,就是用状态机定义几个状态,然后当复位信号有效,进入状态S0,复位信号撤销就进入S1,然后进入S2、S3、S4,当进入S4状态,下一个状态就永远保持为S4。然后shift_ena信号在状态S0、S1、S2、S3时有效,这样就完成了题目。

第二种解法:这种解法非常巧妙,博主用了一个计数器,当shift_ena为1时启动计数器,然后当计数到3时将计数器清零,注意,这里非常巧妙的一点是复位信号有效时将shift_ena置为1,当计数器计数结束将shift_ena置为0,这样计数器就不再计数了,大家好好体会一下这种方法,非常巧妙。

第三种解法:这种解法中,博主定义了4个寄存器,在复位有效时将1号寄存器置为1,复位信号撤销以后将1号寄存器清0,然后将这个信号打三拍,这样最终的shift_ena信号只需要将这4个寄存器相或就好了。但是这种解法由于shift_ena是组合逻辑生成的,所以会有毛刺,谨慎使用。

第四种解法:这种解法是暴力解法,不建议使用,只为了得到success可以用。博主定义了一个非常大的计数器,然后一直不停计数,如果计数器的值小于4,shift_ena的就为1,否则就为0。这种解法非常不可靠,只是多一个思路供大家思考。

3.3.5 FSM: The complete FSM(Exams/review2015 fsm)

HDLbits答案更新系列20(3.3 Building Larger Circuits 3.3.4 FSM: Enable shift register等)_第2张图片

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output shift_ena,
    output counting,
    input done_counting,
    output done,
    input ack );
    
    parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, COUNT=8, WAIT=9;
    reg [3:0]	current_state;
    reg [3:0]	next_state;
    
    always@(posedge clk)begin
        if(reset)begin
            current_state <= S;
        end
        else begin
            current_state <= next_state;
        end
    end
    
    always@(*)begin
        case(current_state)
            S:begin
                next_state = data ? S1 : S;
            end
            S1:begin
                next_state = data ? S11 : S;
            end
            S11:begin
                next_state = data ? S11 : S110;
            end
            S110:begin
                next_state = data ? B0 : S;
            end
            B0:begin
                next_state = B1;
            end
            B1:begin
                next_state = B2;
            end
            B2:begin
                next_state = B3;
            end
            B3:begin
                next_state = COUNT;
            end
            COUNT:begin
                next_state = done_counting ? WAIT : COUNT;
            end
            WAIT:begin
                next_state = ack ? S : WAIT;
            end
            default:begin
                next_state = S;
            end
        endcase
    end
    
    assign shift_ena = (current_state == B0 || current_state == B1 || current_state == B2 || current_state == B3);
    assign counting = (current_state == COUNT);
    assign done = (current_state == WAIT);

endmodule

题目中说要创建一个计时器,当检测到序列1101时启动,接着等待4位,然后计数器完成计数,最后等待用户确认计数器。

大家也看出来了,这道题其实就是前面几道题目的组合。

3.3.6 The complete timer(Exams/review2015 fancytimer)

HDLbits答案更新系列20(3.3 Building Larger Circuits 3.3.4 FSM: Enable shift register等)_第3张图片

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output [3:0] count,
    output counting,
    output done,
    input ack );
 
    parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, COUNT_REG=8, WAIT=9;
    reg [3:0]	current_state;
    reg [3:0]	next_state;
    reg [3:0]	par_in;
    
    reg [15:0]	counter;
    always@(posedge clk)begin
        if(reset)begin
            counter <= 16'd0;
        end
        else if(next_state == WAIT)begin
            counter <= 16'd0;
        end
        else if(next_state == COUNT_REG)begin
            counter <= counter + 1'b1;
        end
    end
    
    reg [3:0]	a;
    always@(*)begin
        if(counter <= 1000)begin
            a = 4'd0;
        end
        if(counter > 1000 && counter <= 2000)begin
            a = 4'd1;
        end
        if(counter > 2000 && counter <= 3000)begin
            a = 4'd2;
        end
        if(counter > 3000 && counter <= 4000)begin
            a = 4'd3;
        end
        if(counter > 4000 && counter <= 5000)begin
            a = 4'd4;
        end
        if(counter > 5000 && counter <= 6000)begin
            a = 4'd5;
        end
        if(counter > 6000 && counter <= 7000)begin
            a = 4'd6;
        end
        if(counter > 7000 && counter <= 8000)begin
            a = 4'd7;
        end
        if(counter > 8000 && counter <= 9000)begin
            a = 4'd8;
        end
        if(counter > 9000 && counter <= 10000)begin
            a = 4'd9;
        end
        if(counter > 10000 && counter <= 11000)begin
            a = 4'd10;
        end
        if(counter > 11000 && counter <= 12000)begin
            a = 4'd11;
        end
        if(counter > 12000 && counter <= 13000)begin
            a = 4'd12;
        end
        if(counter > 13000 && counter <= 14000)begin
            a = 4'd13;
        end
        if(counter > 14000 && counter <= 15000)begin
            a = 4'd14;
        end
        if(counter > 15000 && counter <= 16000)begin
            a = 4'd15;
        end
    end 
    
    wire b;
    assign b = (counter == (par_in + 1) * 1000) ? 1'b1 : 1'b0;
    
    
    always@(posedge clk)begin
        if(reset)begin
            current_state <= S;
        end
        else begin
            current_state <= next_state;
        end
    end
    
    always@(*)begin
        case(current_state)
            S:begin
                next_state = data ? S1 : S;
            end
            S1:begin
                next_state = data ? S11 : S;
            end
            S11:begin
                next_state = data ? S11 : S110;
            end
            S110:begin
                next_state = data ? B0 : S;
            end
            B0:begin
                next_state = B1;
                par_in[3] = data;
            end
            B1:begin
                next_state = B2;
                par_in[2] = data;
            end
            B2:begin
                next_state = B3;
                par_in[1] = data;
            end
            B3:begin
                next_state = COUNT_REG;
                par_in[0] = data;
            end
            COUNT_REG:begin
                next_state = b ? WAIT : COUNT_REG;
            end
            WAIT:begin
                next_state = ack ? S : WAIT;
            end
            default:begin
                next_state = S;
            end
        endcase
    end
    
    assign count = (current_state == COUNT_REG) ? (par_in - a) : 4'd0;
    assign counting = (current_state == COUNT_REG);
    assign done = (current_state == WAIT);
    
endmodule

大家注意理解这道题的题意,这里的状态机必须精确计数(delay [3:0] + 1)* 1000个时钟周期。例如,delay = 0表示计数1000个周期,而delay = 5表示计数6000个周期。同时输出当前剩余时间。这应该是等于延迟为1000个循环,然后延迟-1为1000个周期,依此类推,直到它为0,1000次循环。当电路不计数时,count [3:0]输出无关紧要。

这道题目相比上一道加了一个计数器,只要注意counter的加1条件和清零条件实在哪个状态开始的就可以了。

3.3.7 FSM: One-hot logic equations(Exams/review2015 fsmonehot)

HDLbits答案更新系列20(3.3 Building Larger Circuits 3.3.4 FSM: Enable shift register等)_第4张图片

module top_module(
    input d,
    input done_counting,
    input ack,
    input [9:0] state,    // 10-bit one-hot current state
    output B3_next,
    output S_next,
    output S1_next,
    output Count_next,
    output Wait_next,
    output done,
    output counting,
    output shift_ena
); //

    // You may use these parameters to access state bits using e.g., state[B2] instead of state[6].
    parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, Count=8, Wait=9;

    assign B3_next = state[B2];
    assign S_next = ~d & state[S] | ~d & state[S1] | ~d & state[S110] | ack & state[Wait];
    assign S1_next = d & state[S];
    assign Count_next = state[B3] | ~done_counting & state[Count];
    assign Wait_next = done_counting & state[Count] | ~ack & state[Wait];
    assign done = state[Wait];
    assign counting = state[Count];
    assign shift_ena = state[B0] | state[B1] | state[B2] |state[B3];

endmodule

这道题又是作者所表达的one-hot编码的思想和我们平时使用one-hot编码思想的差异,大家不用太过在意,直接完成题目就好了。如果前面的题目做不出来,可以先看这道题目作者给出的状态转移图,基本就没什么问题了。

结语

今天将这个小节内容更新完毕,我觉得剩下的几个小节就没什么特别难的题目了,距离将所有题目答案更新完毕又快了一步~

如果有哪里代码有问题,欢迎随时指出哦,最后祝同学们周末愉快~

HDLbits网站链接

https://hdlbits.01xz.net/wiki/Main_Page

你可能感兴趣的:(HDLbits答案更新系列20(3.3 Building Larger Circuits 3.3.4 FSM: Enable shift register等))