Verilog典型题-Lemmings4

Lemmings4,两个问题卡了很久。
这里将总结和最后代码附上。

本次出现了两个问题。
    问题1:
    这个题目里边儿,我的状态转换的逻辑是对的。但是计时器的时序逻辑错了。
    计时器用的是寄存器变量,需要在cnt自增的always块中赋值,如果此时判断的条件是cur_st的话(即(cur_st == FALL_L || cur_st == FALL_R)),
    计时器cnt的值的改变就会比cur_st的改变又慢一个周期——在状态FALL_L或者FALL_R中,判断条件
    对于cnt>20,此时,cnt的值还是上一次的值。特别是对于临界值的判断,比如cnt = 20的时候,在
    cnt>20的时候,拿到的值还是19.所以最终在波形上就会出现“当碎而未碎”的情况。
    因此,使用cnt>20的判断条件,就需要将cnt自增时序逻辑中的条件换为nxt_st。

    当然,使用cur_st作为cnt自增的判断条件,也可以将cnt>20改为cnt>19.就是cnt少计时一个周期。

    问题2:
    计时器的位宽问题。
    按照我设计的逻辑,等到Lemming落地的时候,才会判断下落的周数。
    但是Lemming下降的过程中,落地之前,周期数是无限的,可能超过20个。
    因此,按照逻辑判断的逻辑,最好的办法是当周期数目超过20个,计时器就停止自增。

    或者,采取另一种逻辑:当cnt计时到20个周期,就进入到另一个状态:虽然此时没落地,但是周期超时,Lemming必然“碎”。
    当然到了另一个状态,计时逻辑也要停止。
module top_module(
    input clk,
    input areset,
    input bump_left,
    input bump_right,
    input ground,
    input dig,
    output walk_left,
    output walk_right,
    output aaah,
    output digging
);

    localparam
        LEFT = 3'b000,
        RIGHT = 3'b001,
        FALL_L = 3'b010,
        FALL_R = 3'b011,
        DIG_L = 3'b100,
        DIG_R = 3'b101,
        CEASE_L = 3'b110,
        CEASE_R = 3'b111;
    
    reg [2:0] cur_st, nxt_st;
    reg [4:0] cnt;

    always @(posedge clk or posedge areset) begin
        if (areset) cur_st <= LEFT;
        else cur_st <= nxt_st;
    end

    always @(posedge clk or posedge areset) begin
        if (areset) cnt <= 0;
        else if (cur_st == FALL_L || cur_st == FALL_R) begin
            if (cnt > 20) cnt <= cnt;
            else cnt <= cnt+1'b1;
        end 
        else cnt <= 0;
        // $display("当前状态:%d; 当前计时:%d", cur_st, cnt);
    end


  always @(*) begin
    nxt_st = LEFT;
    case (cur_st)
        LEFT: nxt_st = ground?(dig?DIG_L:(bump_left?RIGHT:LEFT)):FALL_L;
        RIGHT: nxt_st = ground?(dig?DIG_R:(bump_right?LEFT:RIGHT)):FALL_R;
        DIG_L: nxt_st = ground?DIG_L:FALL_L;
        DIG_R: nxt_st = ground?DIG_R:FALL_R;
        FALL_L: nxt_st = ground?(cnt>19?CEASE_L:LEFT):FALL_L;
        FALL_R: nxt_st = ground?(cnt>19?CEASE_R:RIGHT):FALL_R;
        CEASE_L: nxt_st = CEASE_L;
        CEASE_R: nxt_st = CEASE_R;
    endcase
  end

    assign walk_left = (cur_st == LEFT);
    assign walk_right = (cur_st == RIGHT);
    assign digging = (cur_st == DIG_L || cur_st == DIG_R);
    assign aaah = (cur_st == FALL_L || cur_st == FALL_R);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值