HDLBits第十五章练习及答案

1、周期为1000的计数器

构建一个从 0 到 999(包括 0 到 999)计数的计数器,周期为 1000 个周期。复位输入是同步的,应将计数器复位为 0。
在这里插入图片描述
代码实现:

module top_module (
    input clk,
    input reset,
    output [9:0] q);
    
    always@(posedge clk) begin
        if(reset)
            q <= 10'd0;
        else if(q == 10'd999)
            q <= 10'd0;
        else
            q <= q + 1'b1;   
        end

endmodule

验证结果:
在这里插入图片描述
在这里插入图片描述

2、四位移位寄存器和递减计数器

构造一个4bit的移位寄存器,同时也可以做递减的计数器使用。其中当shift_ena为1时数据data的高位先进到移位寄存器中;当count_ena为1时,计数器从寄存器中存储的数开始逐时钟递减;shift_ena和count_ena没有重要级先后顺序,因为他们不会同时使能。
在这里插入图片描述
代码实现:

module top_module (
    input clk,
    input shift_ena,
    input count_ena,
    input data,
    output [3:0] q);
    
    always@(posedge clk) begin
        if(shift_ena)
            q <= {q[2:0],data};
        else if(count_ena) begin
            if(q == 4'd0)
                q <= 4'd15;
           else 
                q <= q -1'b1;
           end
    end

endmodule

验证结果:
在这里插入图片描述
在这里插入图片描述

3、FSM 序列1101识别器

构造一个有限状态机检测data中的1101序列,如果检测到该序列,则将输出一直拉高直到同步复位信号为高。
在这里插入图片描述

代码实现:

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output start_shifting);
    
    parameter IDLE = 3'd0, S1 = 3'd1, S2 = 3'd2;
    parameter S3 = 3'd3, OUT = 3'd4;
    reg [2:0] current_state, next_state;

    always @(*) begin
        case(current_state)
            IDLE:    next_state = data ? S1 : IDLE;
            S1:      next_state = data ? S2 : IDLE;
            S2:      next_state = data ? S2 : S3;
            S3:      next_state = data ? OUT : IDLE;
            OUT:     next_state = OUT;
            default: next_state = IDLE;
        endcase
    end

    always @(posedge clk) begin
        if(reset) 
            current_state <= IDLE;
        else 
            current_state <= next_state;
    end

    assign start_shifting = (current_state == OUT);

endmodule

验证结果:
在这里插入图片描述

4、FSM:使能移位寄存器

当有限状态机被复位时,将shift_ena拉高4个周期,之后保持为0直到再次复位。
在这里插入图片描述
注意:复位一直为高的时候输出也一直为高电平。

代码实现:

module top_module (
    input clk,
    input reset,      // Synchronous reset
    output shift_ena);
    
    parameter IDLE = 2'd0, ENA = 2'd1, STOP = 2'd2;
    reg [1:0] current_state, next_state;
    reg [1:0] count;

    always @(*) begin
        case(current_state)
            IDLE: next_state = ENA ;
            ENA:  next_state = (count == 2'd3) ? STOP : ENA;
            STOP: next_state = STOP;
            default: next_state = IDLE;
        endcase
    end

    always @(posedge clk) begin
        if(reset) 
            current_state <= IDLE;
        else 
            current_state <= next_state;
    end
    
    always @(posedge clk) begin
        if(reset) 
            count <= 2'd0;
        else if(count == 2'd3)
            count <= 2'd0;
        else
            count <= count + 1'b1;
    end
    
    assign shift_ena = (current_state == ENA)| (current_state == IDLE);

endmodule

验证结果:
在这里插入图片描述

5、FSM:完整的FSM

我们想要创建一个计时器:
(1)在检测到特定模式(1101)时启动,
(2)再移位4位来确定延迟时间,
(3)等待计数器完成计数,然后
(4)通知用户并等待用户确认计时器。

在这个问题中,只实现控制计时器的有限状态机。这里不包括数据路径(计数器和一些比较器)。

串行数据在数据输入管脚上可用。当接收到模式1101时,状态机必须断言输出shift_ena为4个时钟周期。

之后,状态机断言其计数输出以指示它正在等待计数器,并等待直到输入done_counting为高。

在这一点上,状态机必须断言完成以通知用户定时器已超时,并等待直到输入ack为 1,然后才被重置以寻找下一次出现的启动序列 (1101)。

状态机应重置为开始搜索输入序列 1101 的状态。

这是预期输入和输出的示例。‘x’ 状态读起来可能有点混乱。它们表明 FSM 不应关心该周期中的特定输入信号。例如,一旦检测到 1101 模式,FSM 将不再查看数据输入,直到在其他所有操作完成后恢复搜索。
在这里插入图片描述
提示:
在这里插入图片描述
代码实现:

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 = 4'd0, S1 = 4'd1, S11 = 4'd2, S110 = 4'd3, B0 = 4'd4, B1 = 4'd5;
    parameter B2 = 4'd6, B3 = 4'd7, Count = 4'd8, Wait = 4'd9;
    reg [3:0] current_state, next_state;

    always @(*) begin
        case(current_state)
            S:    next_state = data ? S1 : S;
            S1:   next_state = data ? S11 : S;
            S11:  next_state = data ? S11 : S110;
            S110: next_state = data ? B0 : S;
            B0:   next_state = B1;
            B1:   next_state = B2;
            B2:   next_state = B3;
            B3:   next_state = Count;
            Count: next_state = done_counting ? Wait : Count;
            Wait : next_state = ack ? S : Wait;
            default: next_state = S;
        endcase
    end

    always @(posedge clk) begin
        if(reset) 
            current_state <= S;
        else 
            current_state <= next_state;
    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

验证结果:
在这里插入图片描述

6、完整的计时器

我们想用一个输入创建一个计时器:

(1)当检测到特定的输入模式 (1101) 时启动,
(2)再移动 4 位以确定延迟的持续时间,
(2)等待计数器完成计数,并且
(4)通知用户并等待用户确认定时器。
串行数据在数据输入引脚上可用。当接收到模式 1101 时,电路必须移入接下来的 4 位,最高有效位在前。这 4 位决定了定时器延迟的持续时间。我将其称为delay[3:0]。

之后,状态机断言其计数输出以指示它正在计数。状态机必须精确计数(delay[3:0] + 1) * 1000 个时钟周期。例如,delay=0 表示计数 1000 个周期,delay=5 表示计数 6000 个周期。同时输出当前剩余时间。这应该等于延迟1000 个周期,然后延迟 1为 1000 个周期,依此类推,直到 1000 个周期为 0。当电路不计数时, count[3:0] 输出无关紧要(任何值都方便您实现)。

此时,电路必须断言done以通知用户定时器已超时,并等待直到输入ack为 1,然后才被重置以寻找下一次出现的启动序列 (1101)。

电路应重置为开始搜索输入序列 1101 的状态。

这是预期输入和输出的示例。‘x’ 状态读起来可能有点混乱。它们表明 FSM 不应关心该周期中的特定输入信号。例如,一旦 1101 和 delay[3:0] 被读取,电路将不再查看数据输入,直到它在其他所有事情完成后恢复搜索。在本例中,电路计数 2000 个时钟周期,因为延迟 [3:0] 值为 4’b0001。最后几个周期以 delay[3:0] = 4’b1110 开始另一个计数,这将计数 15000 个周期。
在这里插入图片描述
提示:本题是前面几道状态机的组合,需要设置计数器。

代码实现:

    parameter S = 4'd0, S1 = 4'd1, S11 = 4'd2, S110 = 4'd3, B0 = 4'd4, B1 = 4'd5;
    parameter B2 = 4'd6, B3 = 4'd7, Count = 4'd8, Wait = 4'd9;
    
    reg [3:0] current_state, next_state;
    reg [15:0] num;
    reg [3:0] delay;
    reg [3:0] already_count;

    wire count_state;
    
    assign count_state = (num == (delay + 1'b1) * 10'd1000) ? 1'b1 : 1'b0;
    
    always @(posedge clk) begin
        if(reset) begin
            num <= 16'd0;
        end
        else if(next_state == Wait) begin
            num <= 16'd0;
        end
        else if(next_state == Count) begin
            num <= num + 16'd1;
        end
    end
    
    always @(*) begin
        if(num <= 16'd1000)
            already_count = 4'd0;
        else if(num >= 16'd1000 && num <= 16'd2000)   
            already_count = 4'd1;        
        else if(num >= 16'd2000 && num <= 16'd3000)   
            already_count = 4'd2;
        else if(num >= 16'd3000 && num <= 16'd4000)   
            already_count = 4'd3;   
        else if(num >= 16'd4000 && num <= 16'd5000)   
            already_count = 4'd4; 
        else if(num >= 16'd5000 && num <= 16'd6000)   
            already_count = 4'd5;  
        else if(num >= 16'd6000 && num <= 16'd7000)   
            already_count = 4'd6;  
        else if(num >= 16'd7000 && num <= 16'd8000)   
            already_count = 4'd7;      
        else if(num >= 16'd8000 && num <= 16'd9000)   
            already_count = 4'd8;
        else if(num >= 16'd9000 && num <= 16'd10000)   
            already_count = 4'd9;   
        else if(num >= 16'd10000 && num <= 16'd11000)   
            already_count = 4'd10; 
        else if(num >= 16'd11000 && num <= 16'd12000)   
            already_count = 4'd11;  
        else if(num >= 16'd12000 && num <= 16'd13000)   
            already_count = 4'd12;  
        else if(num >= 16'd13000 && num <= 16'd14000)   
            already_count = 4'd13;    
        else if(num >= 16'd14000 && num <= 16'd15000)   
            already_count = 4'd14;  
        else  
            already_count = 4'd15;  
    end
    
    always @(*) begin
        case(current_state)
            S:    next_state = data ? S1 : S;
            S1:   next_state = data ? S11 : S;
            S11:  next_state = data ? S11 : S110;
            S110: next_state = data ? B0 : S;
            B0:begin   
                  next_state = B1;
                  delay[3] = data;
            end
            B1:begin   
                  next_state = B2;
                  delay[2] = data;
            end
            B2:begin   
                  next_state = B3;
                  delay[1] = data;
            end
            B3:begin   
                  next_state = Count;
                  delay[0] = data;
            end
            Count: next_state = count_state ? Wait : Count;
            Wait : next_state = ack ? S : Wait;
            default: next_state = S;
        endcase
    end

    always @(posedge clk) begin
        if(reset) 
            current_state <= S;
        else 
            current_state <= next_state;
    end
    
    assign counting = (current_state == Count);
    assign count = (current_state == Count) ? (delay - already_count) : 4'd0;
    assign done = (current_state == Wait);
    
endmodule

验证结果:
在这里插入图片描述

7、FSM:One hot 逻辑方程

给定以下具有 3 个输入、3 个输出和 10 个状态的状态机:
在这里插入图片描述
假设使用以下独热编码,通过检查导出下一状态逻辑方程和输出逻辑方程: (S, S1, S11, S110, B0, B1, B2, B3, Count, Wait) = (10’b0000000001, 10 'b0000000010, 10’b0000000100, … , 10’b1000000000)

通过检查假设单热编码来导出状态转换和输出逻辑方程。仅为此状态机实现状态转换逻辑和输出逻辑(组合逻辑部分)。

编写生成以下等式的代码:

  • B3_next – next-state logic for state B1
  • S_next
  • S1_next
  • Count_next
  • Wait_next
  • done – output logic
  • counting
  • shift_ena

用one-hot编码的状态写出状态转移代码。

代码实现:

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=4'd0, S1=4'd1, S11=4'd2, S110=4'd3, B0=4'd4, B1=4'd5, B2=4'd6, B3=4'd7, Count=4'd8, Wait=4'd9;
  
    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

验证结果:
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值