刷VHDLbits题目记录

目录

1.Exams/review2015 count1k

2.Exams/review2015 shiftcount

3.Exams/review2015 fsmseq

4.Exams/review2015 fsmshift

 5.Exams/review2015 fsm

6.Exams/review2015 fsmonehot

7.Exams/review2015 fancytimer


1.Exams/review2015 count1k

建立一个从 0 到 999 的计数器,包括 0 到 999,周期为 1000 个周期。复位输入是同步的,应将计数器复位为 0。

module top_module (
    input clk,
    input reset,
    output [9:0] q);

    always@(posedge clk) begin
        if(reset) q <= 0;           //复位后q赋值为零
        else if(q<999) q <= q+1;    //如果q<999 那么+1
        else q <= 0;                //如果q==999,清零
    end

endmodule

编写verilog代码时重要的点就是时序,如上代码所示,q会在reset给进之后的下一拍才会置为0

2.Exams/review2015 shiftcount

构建一个四位移位寄存器,该寄存器也用作递减计数器。当shift_ena为 1时,数据首先移入最高有效位。当count_ena为 1时,当前在移位寄存器中的数字递减。由于整个系统不会同时使用shift_ena和count_ena,因此您的电路无关紧要如果两个控制输入都为 1(这主要意味着哪种情况获得更高优先级并不重要)

module top_module (
    input clk,
    input shift_ena,
    input count_ena,
    input data,
    output [3:0] q);

    always @(posedge clk) begin
        if(shift_ena) begin             //shift_ena 和 count_ena 的优先级无关
            q <= {q[2:0],data};         //移位操作将数据写入
        end
        else if(count_ena) begin
            q <= q -1;                  
        end
        else begin
            q<=q;
        end
    end
endmodule

如果说要考虑优先级,只需要将两个if条件的前后顺序就行调换就行,但是那样就不能同时输入shift_ena 和count_ena因为同一时刻只能处理一个,如果有需求同时输入,就要修改设计代码;


3.Exams/review2015 fsmseq

构建一个有限状态机,在输入比特流中搜索序列 1101。找到序列后,应将start_shifting设置为 1,直到重置。陷入最终状态旨在模拟在尚未实现的更大 FSM 中进入其他状态。我们将在接下来的几个练习中扩展这个 FSM。

module top_module(                                  //mothod 1 use the state_machine
    input clk,
    input reset,      // Synchronous reset
    input data,
    output start_shifting);

    parameter S0=0,S1=1,S2=2,S3=3,PICK=4;
    reg [2:0] cur_st;
    reg [2:0] nxt_st;

    always@(posedge clk) begin              //state change 1
        if(reset) cur_st <= S0;
        else cur_st <= nxt_st;
    end

    always @(*) begin                       //caculte the nxt_st 
        case(cur_st) 
            S0:nxt_st = data ? S1:S0;
            S1:nxt_st = data ? S2:S0;
            S2:nxt_st = data ? S2:S3;
            S3:nxt_st = data ? PICK:S0;
            PICK:nxt_st = data ? S2:S0;
            default : nxt_st = S0;
        endcase
    end 

    //start_shifting
    always@(posedge clk) begin                 //the output start_shifting
        if(reset) start_shifting <= 0;
        else if(nxt_st == PICK) start_shifting <= 1;    //use nxt_st,because use sequential logic 
        else start_shifting <= start_shifting;
    end

endmodule


module top_module (                                 //mothod 2 use the shifting_register
    input clk,
    input reset,      // Synchronous reset
    input data,
    output start_shifting);
    
    reg [3:0] data_seq;                             //4_bits register to match 1101
    always@(posedge clk)begin
        if(reset) data_seq <= 0;
        else data_seq <= {data_seq[2:0],data};      //shifting the input data 
    end
    
    always@(*)begin                                         //use the comb logic so the reset need to flap
        if(reset_r) start_shifting=0;                       //you can try use the sequential logic instead 
        else if(data_seq == 'b1101) start_shifting = 1;
         else start_shifting = start_shifting;
    end

    reg reset_r;
    always@(posedge clk)begin
		reset_r <= reset;    
    end
endmodule
  1. 使用状态机编写代码时,注意该时刻的状态是由之前所有输入的决定的,再该时刻使用组合逻辑根据输入进行下一状态的计算,然后在下一个上升沿到来时修改cur_st 的值;
  2. 个人认为状态机你可以使用nxt_st 或者cur_st 来进行最后输出的计算,关键在于这两个st之间差了一拍而已,如果有需要可用nxt_st,但是目前我见过的状态机都是使用的cur_st;
  3. 使用移位寄存器时注意的点就是由于使用组合逻辑对输出进行计算,所以reset信号要打一拍使用,不然start_shifting信号就与reset信号同拍了;

4.Exams/review2015 fsmshift

作为用于控制移位寄存器的 FSM 的一部分,我们希望能够在检测到正确的位模式时启用移位寄存器恰好 4 个时钟周期。我们在Exams/review2015_fsmseq中处理序列检测,因此 FSM 的这一部分仅处理启用 4 个周期的移位寄存器。

每当 FSM 复位时,将shift_ena置位4 个周期,然后永远为 0(直到复位)。

module top_module (                             //state machine
    input clk,
    input reset,      // Synchronous reset
    output shift_ena);

	parameter S0=0,S1=1,S2=2,S3=3,S4=4;
    reg [2:0] cur_st;
    reg [2:0] nxt_st;
    always @(posedge clk)begin
        if(reset) cur_st <= S0;
        else cur_st <= nxt_st;
    end
    
    always @(*) begin
        case(cur_st)
            S0:nxt_st = reset?S0:S1;
            S1:nxt_st = reset?S0:S2;
            S2:nxt_st = reset?S0:S3;
            S3:nxt_st = reset?S0:S4;
            S4:nxt_st = reset?S0:S4;
        endcase
    end
    assign shift_ena = (cur_st == S0 | cur_st == S1 | cur_st == S2 | cur_st == S3);
    
endmodule

module top_module (         //method 2 reg cnt 
    input clk,
    input reset,
    output shift_ena
);

    reg [2:0] cnt;
    always @(posedge clk) begin
        if(reset) cnt <= 0;
        else if(cnt==4) cnt <= cnt;
        else cnt <= cnt + 1;
    end

    assign shift_ena = (cnt <= 3);
endmodule 
  1.  使用状态机时,中间使用4个状态进行控制4拍的动作,如果reset期间进入,之间跳到S0,组合逻辑根据cur_st输出shift_ena;
  2. method 2 的方法可以通过仿真,但是我好奇的一个点是当第一次reset没来时,cnt的值为多少,此时输出的shift_ena真的是对的?

5.Exams/review2015 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 S0=0,S1=1,S2=2,S3=3,B0=4,B1=5,B2=6,B3=7,COUNT=8,WAIT=9; 
    //S state use to match 
    reg [3:0] cur_st;
    reg [3:0] nxt_st;
    
    always @(posedge clk) begin
        if(reset) cur_st <= S0;
        else cur_st <= nxt_st;
    end
    
    always @(*) begin
        case(cur_st)
            S0: nxt_st = data?S1:S0;
            S1: nxt_st = data?S2:S0;
            S2: nxt_st = data?S2:S3;
            S3: nxt_st = data?B0:S0;
            B0: nxt_st = B1;
            B1:nxt_st = B2;
            B2:nxt_st = B3;
            B3:nxt_st = COUNT;                          
            COUNT:nxt_st = done_counting?WAIT:COUNT;     //output the count
            WAIT:nxt_st = ack?S0:WAIT;                     //output the done_counting     
            default : nxt_st = S0;
        endcase
    end
    
    assign shift_ena = (cur_st == B0 | cur_st == B1 | cur_st == B2 | cur_st == B3); 
    assign counting = cur_st == COUNT;
    assign done = cur_st == WAIT;
            
endmodule
  1. 中间使用B状态进行shift_ena 拉高4拍的控制;
  2. 后续的状态跳转就是输入的done_counting 和 ack 来进行;输出根据状态输出;使用的是cur_st 所以组合逻辑即可;

6.Exams/review2015 fsmonehot

给定以下具有 3 个输入、3 个输出和 10 个状态的状态机:

 

假设使用以下 one-hot 编码, 通过检查导出下一状态逻辑方程和输出逻辑方程: (S, S1, S11, S110, B0, B1, B2, B3, Count, Wait) = (10'b0000000001, 10 'b0000000010, 10'b0000000100, ... , 10'b1000000000)

假设 one-hot 编码,通过检查导出状态转换和输出逻辑方程。仅实现此状态机的状态转换逻辑和输出逻辑(组合逻辑部分)。(测试台将使用非一个热输入进行测试,以确保您不会尝试做更复杂的事情)。

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

  • B3_next -- 状态 B1 的下一个状态逻辑
  • S_next
  • S1_next
  • Count_next
  • 等待下一个
  • 完成——输出逻辑
  • 数数
  • shift_ena
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 = ...;
    // assign S_next = ...;
    // etc.

    assign B3_next = state[B2];
    assign S_next = (state[S]&d==0) | (state[S1]&d==0) | (state[S110] && d==0) | (state[Wait] && ack==1)|(reset==1);
    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. 根据状态转移图判断哪种情况会进入该状态即可;
  2. 根据状态转移图中红色字体,编写相应输出即可;

7.Exams/review2015 fancytimer

我们想创建一个带有一个输入的计时器:

  1. 当检测到特定输入模式 (1101) 时启动,
  2. 再移 4 位以确定延迟的持续时间,
  3. 等待计数器完成计数,并且
  4. 通知用户并等待用户确认计时器。

串行数据在数据输入引脚上可用。当接收到模式 1101 时,电路必须移入接下来的 4 位,首先是最高有效位。这 4 位决定了定时器延迟的持续时间。我将其称为delay[3:0]。

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

此时,电路必须断言done以通知用户计时器已超时,并等待输入ack为 1,然后再复位以查找下一次出现的启动序列 (1101)。

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

这是预期输入和输出的示例。'x' 状态读起来可能有点混乱。它们表明 FSM 不应该关心该周期中的特定输入信号。例如,一旦读取了 1101 和 delay[3:0],电路就不再查看数据输入,直到在其他所有操作完成后恢复搜索。在本例中,电路计数 2000 个时钟周期,因为 delay[3:0] 值为 4'b0001。最后几个周期以 delay[3:0] = 4'b1110 开始另一个计数,它将计数 15000 个周期。

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output [3:0] count,
    output counting,
    output done,
    input ack );
    
    parameter S0=0,S1=1,S2=2,S3=3,S4=4,S5=5,S6=6,S7=7,COUNT=8,WAIT=9;
    reg [3:0] cur_st;
    reg [3:0] nxt_st;
    reg [3:0] delay;            //the delay
    reg [13:0] dly_cnt;         //(delay + 1) * 1000
    wire cnt_done;

    
    always @(posedge clk)begin
        if(reset) cur_st <= S0;
    	else cur_st <= nxt_st;
    end
    
    always@(*) begin
        case(cur_st)
            S0:nxt_st=data?S1:S0;
            S1:nxt_st=data?S2:S0;
            S2:nxt_st=data?S2:S3;
            S3:nxt_st=data?S4:S0;
            S4:nxt_st=S5;
            S5:nxt_st=S6;
            S6:nxt_st=S7;
            S7: nxt_st=COUNT;
            COUNT: nxt_st = cnt_done?WAIT:COUNT; 
            WAIT:nxt_st=ack?S0:WAIT;
            default : nxt_st=S0;
        endcase
    end
    
    wire con_dly;
    assign con_dly = (cur_st == S5 | cur_st == S6| cur_st == S7 | cur_st == S4);
    always@(posedge clk)begin
        if(con_dly==1)begin
            delay <= {delay[2:0],data};             //shift the data into delay 
        end
    end
    
    always@(posedge clk)begin
        if(reset) dly_cnt <= 0;
        else if(cur_st == COUNT) dly_cnt <= dly_cnt+1;
        else dly_cnt <= 0;
    end
    assign cnt_done = (dly_cnt == (delay + 1) * 1000 - 1);  //the dly_cnt do not cnt to the max 
    assign count = delay - dly_cnt / 1000;
    assign counting = cur_st == COUNT;
    assign done = cur_st == WAIT;
        
    

endmodule
  1. 状态转移以上面题目一样,这里就是在后续的S4,5,6,7状态时进行要delay的收集,注意所使用到的状态以及data;比如输入的数据为:11010011;cur_st跳变为S4的同时data会进入第一个0;
  2. 注意由于dly_cnt 使用的是时序逻辑,所以最后的dly_cnt并不会计数到最大值,只能计数到-1值;并且由于使用的是cur_st==COUNT 的条件,当cur_st跳变的COUNT时,dly_cnt 并不会马上进行跳变,而是要等下一拍;

注:以上题目来自:Exams/review2015 fancytimer - HDLBits 答案有些参考网络上其他答案,如有打扰请联系删除;

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汶.z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值