HDLBits(十 三)学习笔记——Building Lager Circuits (1000计数器 —— FSM:One-hot logic equations独热码)

1、Counter with period 1000

上行1000的计数器
生成一个从 0 到 999(含 0)计数的计数器,周期为 1000 个周期。复位输入是同步的,应将计数器复位至0。
在这里插入图片描述
低电平有效,高电平复位。

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

endmodule

2、4-bit shift register and down counter(移位寄存器)

构造一个四位移位寄存器,同时也能做下行计数器(10,9,8…)
shift_ena为 1 时,数据data的高位先移动到移位寄存器。(暂存)
当前移位寄存器中的数字在count_ena为 1 时逐时钟的进行递减。
shift_ena和count_ena没有重要级先后顺序,因为他们不会同时使能。
在这里插入图片描述
由于递减,因此我们需要找到最大值,q为4位,8421,因此可表示的最大数为15

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

endmodule

3、fsmseq 序列1101识别器

构建一个有限状态机,用于在输入位流中搜索序列1101
找到1101序列后,应将start_shifting设置为 1,直到重置。
在这里插入图片描述
由于检测序列1101,因此共设置五个状态:空闲状态和四位数值接收的四个状态。
在这里插入图片描述

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output start_shifting
);
    parameter IDLE = 5'b00001;
    parameter S1   = 5'b00010;
    parameter S2   = 5'b00100;
    parameter S3   = 5'b01000;
    parameter S4   = 5'b10000;
    
    reg [4:0] state,next_state;
    
    //第一段,状态寄存器
    always @ (posedge clk)
        if(reset)
            state <= IDLE;
        else
            state <= next_state;
    //第二段,组合逻辑描述状态转移
    always @ (*)begin
        case(state)
           IDLE : next_state = data ? S1 : IDLE;
           S1   : next_state = data ? S2 : IDLE;
           S2   : next_state = data ? S2 : S3;
           S3   : next_state = data ? S4 : IDLE;
           S4   : next_state = S4;
           default: next_state = IDLE;
        endcase
    end
    //第三段,组合逻辑描述输出
   
    always@(*)
        start_shifting = (state == S4);
      
endmodule

4、fsmshift 状态机启用移位寄存器

作为用于控制移位寄存器的FSM的一部分,我们希望能够在检测到正确的位模式时使能移位寄存器正好4个时钟周期。
我们在上一题fsmseq中已经完成了序列检测的处理,因此 FSM 的这一部分仅处理 4 个周期的移位寄存器启用。
当有限状态机被复位时,将shift_ena拉高4个周期,之后保持为0直到再次复位。
根据图可看出,复位是高的时候,输出也一直是高电平。
在这里插入图片描述
因此可以设置三个状态,空闲状态,使能拉高状态以及保持为0的状态。其中使能拉高状态下我们设计计数器来完成,拉高四个周期因此设计模4计数器。
在这里插入图片描述

module top_module (
    input clk,
    input reset,      // Synchronous reset
    output shift_ena
);
    parameter IDLE = 3'b001;
    parameter ENA  = 3'b010;
    parameter STOP = 3'b100;
    
    reg [3:0] state,next_state;
    reg [2:0] counter;
    
    //第一段,状态寄存器
        always @(posedge clk) begin
        if(reset) begin
            state <= IDLE;
        end
        else begin
            state <= next_state;
        end
    end
    //第二段,状态转移
    always@(*)
        case(state)
            IDLE: next_state = ENA;
            ENA : next_state = (counter == 3'd3 ) ? STOP : ENA;
            STOP: next_state = STOP;
            default: next_state = IDLE;
        endcase
    //第三段,描述输出
    always@(*)
        shift_ena = (state == ENA | state == IDLE);
    
    //设计一个模4计数器
        always @(posedge clk) begin
            if(reset) 
                counter <= 3'd0;
            else if(next_state == ENA)  //因为采用的是时序逻辑,因此用次态
                counter <= counter + 1'b1;
            else
                counter <=  3'd0;
                        
        end
endmodule

5、fsm (将移位寄存器和序列识别器进行结合)

在这里插入图片描述
题目理解
空闲状态IDLE:主要是对复位初始状态,高电平复位,低电平开始进行序列的检测。
序列检测包括三个状态,S1,S11,S110。状态转移的条件是输入data ( 只要检测错误就要重新检测)
shift_ena抬高四个周期的状态:在序列接收成功后进入此状态,该状态包括ENA0-ENA3四个状态
计数状态:当输入done_counting为高电平的时候跳转到等待通知状态。否则一直计数
等待通知状态:当等待通知输入ack为1的时候,重置以查找下一个出现的启动序列,否则的话一直处于等待通知状态。
至此我们即可完成第一二段状态机。
同时以下三个信号是输出,在第三段状态机中描述。
output shift_ena,
output counting,
output done,
在这里插入图片描述

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output shift_ena,
    output counting,
    input done_counting,
    output done,
    input ack
);
    //十个状态,这里就不采用独热码了
    parameter IDLE  = 4'd0;
    parameter S1    = 4'd1;
    parameter S11   = 4'd2;
    parameter S110  = 4'd3;
    parameter ENA0  = 4'd4;
    parameter ENA1  = 4'd5;
    parameter ENA2  = 4'd6;
    parameter ENA3  = 4'd7;
    parameter COUNT = 4'd8;
    parameter WAIT  = 4'd9;
    
    reg [3:0] state,next_state;
    
    //第一段,状态寄存器
    always@(posedge clk)
        if(reset)
            state <= IDLE;
        else 
            state <= next_state;
    //第二段,状态转移
    always@(*)
        case(state)
            IDLE  :next_state = data ? S1 : IDLE;
            S1    :next_state = data ? S11 : IDLE;
            S11   :next_state = data ? S11 : S110;
            S110  :next_state = data ? ENA0 : IDLE;
            ENA0  :next_state = ENA1;
            ENA1  :next_state = ENA2;
            ENA2  :next_state = ENA3;
            ENA3  :next_state = COUNT;
            COUNT :next_state = done_counting ? WAIT : COUNT;
            WAIT  :next_state = ack? IDLE : WAIT;
            default: next_state = IDLE;
        endcase
    //第三段,描述输出
    always @ (posedge clk )begin
        if(reset)begin
                 shift_ena <=  1'b0;
                 counting <=  1'b0;
                 done <=  1'b0;            
        end
        else
            case(next_state)
            IDLE,S1,S11,S110:begin
                 shift_ena <=  1'b0;
                 counting <= 1'b0;
                 done <=  1'b0;
            end
            ENA0,ENA1,ENA2,ENA3:begin
                 shift_ena <=  1'b1;
                 counting <=  1'b0;
                 done <=  1'b0;
            end
            COUNT:begin
                 shift_ena <=  1'b0;
                 counting <=  1'b1;
                 done <=  1'b0;
            end
            WAIT:begin
                 shift_ena <= 1'b0;
                 counting <=  1'b0;
                 done <= 1'b1;
            end
            default:begin
                 shift_ena <= 1'b0;
                 counting <= 1'b0;
                 done <= 1'b0;
            end
        endcase
    end    
endmodule

6、fancytimer完整的计数器

该题目是前面四个题目的结合。
有四个状态是移位拉高四个周期的状态,上题中我们这里没有其他的操作,只是拉高四位,二本题目需要进行四位的移位,首先是最高有效位。同时这 4 位决定了计时器延迟的持续时间(计数器的计数周期)。我将其称为delay延迟[3:0]。 ——可表示的最大数是15

增加计数器状态,来给予精确的计数,计数周期为(delay[3:0] + 1 )* 1000 个时钟周期,比如 delay = 0 时,计数值为 1000 个周期。delay = 5 代表 6000 个周期。输出count表示当前剩余的计数周期(计数的千位数),这就应该等于1000个周期的延迟,比如说还剩1000周期,那么输出1,还剩999个周期,输出0,还剩15000个周期,输出15,当计数停止后,count可输出任意数。

当计数完成后,done 信号置为高电平,通知上层应用计数器计数完成。
后等待 ack 信号,当该信号置高后,状态机清除 done 信号,返回空闲状态等待重新捕获下一个 1101 序列,否则一直处于等待状态,等ack高电平的到来。
在这里插入图片描述
上图中斜线表示当前信号为X,也就是状态机不关心的值(省略),如图存在序列1101,同时在延迟了四个周期后,开始计数,同时counting置为了1。可看出电路计数周期是2000,因此delay为1,所以 delay[3:0] 数值为 4’b0001 。在后续的第二个计数周期中,count能看出是e,计数周期是15000.

module top_module (
    input 				clk,
    input 				reset,      
    input 				data,
    input 				ack,	
	
    output		[3:0] 	count,
    output 				counting,
    output 				done
);
 
	parameter	        S      = 4'd0;
	parameter			S1     = 4'd1;
	parameter			S11    = 4'd2;
	parameter			S110   = 4'd3;
	parameter			DELAY  = 4'd4;
	parameter			COUNT  = 4'd5;
	parameter			WAIT   = 4'd6;
			
    reg	[3:0]	        cur_state	;			
    reg	[3:0]		    next_state	;   			
			
	reg	[1:0]			cnt_delay	;				//用来接收序列流的计数器
	reg	[15:0]			cnt			;
	reg	[3:0]			delay		;			
//第一段同步时序描述状态转移						
always @(posedge clk)begin
	if(reset)
		cur_state <= S;
	else
		cur_state <= next_state;
end	
//第二段采用组合逻辑,并根据状态转移条件来描述状态转移规律   
always@(*)begin
	case(cur_state)
		S    :  next_state = data ? S1 :S; 
		S1   :  next_state = data ? S11 :S; 
		S11  :  next_state = data ? S11 :S110; 	
		S110 :  next_state = data ? DELAY :S; 
		DELAY:
			if(cnt_delay == 2'd3)
				next_state = COUNT;
			else
				next_state = DELAY;			
		COUNT: 
			if(cnt == 16'd0)
				next_state = WAIT;
			else
				next_state = COUNT;			
		WAIT : 
			if(ack)
				next_state = S;
			else
				next_state = WAIT;			
		default:	next_state = S;
	endcase
end
//第三段,组合逻辑描述描述输出
    always@(*)begin
        count = cnt/1000; //用来输出千位
        counting = (cur_state == COUNT);
        done = (cur_state == WAIT);
    end
//延时计数器,计数4个时钟,来接收delay数据
always @(posedge clk)begin
	if(reset)
		cnt_delay <= 2'd0;
	else if(cur_state == DELAY)begin
		cnt_delay <= cnt_delay + 1'b1;
	end
	else
		cnt_delay <= cnt_delay;
end
//根据接收到的delay数据进行计数周期的运算
always @(posedge clk)begin
	if(reset)
		cnt <= 16'd0;
	else if(cur_state == DELAY)
		cnt <= (delay+1'b1) * 1000-1'd1;	
	else if(cur_state == COUNT)
		cnt <= cnt - 1'd1;
	else 
		cnt <= cnt;
end
//接收delay 的四位数据以计算计数周期,根据每一位的delay计算出十进制数,然后套用计数周期计算公式
//delay为0001,则在上面代入公式计算出cnt=1999
always@(*)begin
	if(cur_state == DELAY)
		case(cnt_delay)
			2'd0:	delay[3] =	data;
			2'd1:   delay[2] =	data;
			2'd2:   delay[1] =	data;
			2'd3:   delay[0] =	data;
			default:;
		endcase
	else
		delay = 4'b0000;
end 
 
endmodule

7、fsmonehot 独热码

该题给出了如果的状态转移图,然后采用独热码的方式来编写组合逻辑部分(状态转移以及输出。)
在这里插入图片描述

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
); //
 
    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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Fighting_FPGA

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

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

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

打赏作者

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

抵扣说明:

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

余额充值