HDLBits学习------Problem 151~157

参考链接:HDLBits导学


Problem 151 Counter with period 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 begin
            if(q < 10'd999)
				q <= q + 1'b1;
			else
				q <= 10'd0;
        end
	end

endmodule

Problem 152 4-bit shift register and down counter

        问题:构建一个四位移位寄存器,它也可用作递减计数器。当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)
			q <= {q[2:0],data};
		else if(count_ena)
			q <= q - 1'b1;
		else
			q <= q;
	end

endmodule

Problem 153 FSM: Sequence 1101 recognizer

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

        解决:

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output start_shifting);
	
    //状态说明
    //没有检测到1 检测到一个1 检测到两个1 检测到110 完成状态
	parameter S0=0,S1=1,S2=2,S3=3,Done=4;
	reg[2:0] state,next_state;
	
	always @(*) begin
		case(state)
			S0: next_state = data ? S1 : S0;
			S1: next_state = data ? S2 : S0;
			S2: next_state = data ? S2 : S3;
			S3: next_state = data ? Done : S0;
			Done: next_state = Done;
		endcase
	end
	
	always @(posedge clk) begin
		if(reset)
			state <= S0;
		else
			state <= next_state;
	end
	
	assign start_shifting = (state==Done);

endmodule

Problem 154 FSM:Enable shift register

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

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

        解决:

module top_module (
    input clk,
    input reset,      // Synchronous reset
    output shift_ena);
	
	parameter S0=0,S1=1;
	reg state,next_state;
	reg[1:0] cnt;

	always @(*) begin
		case(state)
			S0: next_state = reset ? S1 : S0;
			S1: next_state = (cnt==2'd3) ? S0 : S1;
		endcase
	end
	
	always @(posedge clk) begin
		state <= next_state;
	end
	
	always @(posedge clk) begin
        if(state == S1)
            cnt <= cnt + 1'b1;
        else
            cnt <= 2'd0;
	end
	
	assign shift_ena = (state == S1);

endmodule

        因为这个状态机最后会复位到初始状态,所以就没加入复位值,而且输入信号本就是复位值,感觉再用来复位状态机就怪怪的(其实就是写不出来)


Problem 155 FSM:The complete FSM

        问题:复杂计数器需要如下这些功能特性:

  1. 在数据流中检测到特定序列后启动计数器,该序列为: 1101
  2. 将 4bits 数据输入移位寄存器,作为计数器的初值
  3. 等待计数器结束计数
  4. 告知上层应用计数完成,并等待用户通过 ack 信号确认

在本题练习中,只需要实现控制状态机,不需要实现数据通路,比如计数器本身以及数据比较器等。

数据流从模块的 data 信号输入,当检测到 1101 序列后,状态机需要置高输出信号 shft_ena 并保持 4 个周期(用于将接下来 4bit 数据输入移位寄存器)。

之后,状态机置高 counting 信号,表示其正在等待计数器完成计数,当计数器完成计数输出 done_counting 信号后,counting 信号置低。

再此后,状态机置高 done 信号通知上层应用计数器计数完成,等待 ack 信号置高后,状态机清除 done 信号,返回空闲状态等待捕获下一个 1101 序列。

本题给出了一个期望输入输出的例子。图中的斜线代表当前信号为 'X', 表示状态机不关心该信号当前的值。比如图例中,一旦 FSM 检测到 1101 序列后,在此次计数器事件完成前,对于当前的数据流不再关心

        提示:官方给的状态转换图

        解决:

module top_module (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output shift_ena,
    output counting,
    input done_counting,
    output done,
    input ack );
	
    //状态说明
    //序列检测1 序列检测2 序列检测3 序列检测4
    //输出shift_ena 等待计数 完成状态
	parameter S0=0,S1=1,S2=2,S3=3,Out_shift_ena=4,Wait_count=5,Done=6;
	reg[2:0] state,next_state;
	reg[1:0] cnt;
	
	always @(*) begin
		case(state)
			S0: next_state = data ? S1 : S0;
			S1: next_state = data ? S2 : S0;
			S2: next_state = data ? S2 : S3;
			S3: next_state = data ? Out_shift_ena : S0;
			Out_shift_ena: next_state = (cnt==2'd3) ? Wait_count : Out_shift_ena;
			Wait_count: next_state = done_counting ? Done : Wait_count;
			Done: next_state = ack ? S0 : Done;
		endcase
	end
	
	always @(posedge clk) begin
		if(reset)
			state <= S0;
		else
			state <= next_state;
	end
	
	always @(posedge clk) begin
		if(reset)
			cnt <= 2'd0;
		else begin
			if(state == Out_shift_ena)
				cnt <= cnt + 1'b1;
			else
				cnt <= 2'd0;
		end
	end
	
	assign shift_ena = (state==Out_shift_ena);
	assign counting = (state == Wait_count);
	assign done = (state == Done);

endmodule

        在这个题挣扎了一会,发现居然在这个题序列检测出现了问题???,相想想之前不是通过了吗,为什么在这里会出现了问题,然后发现确实在S3那个状态写错了

开始的写法(Problem 153) 这样写不是通过了????

S3: next_state = data ? Out_shift_ena : S1;

但是这样写是错的,在检测到110后如果检测到0的话应该回到S0(一个1都没有的)状态

        这个题也可以参考官方给的状态转换图来写,我没有看,想试着自己去写状态,然后我一般都是一个状态一个状态的往下写,最后再来对所有状态进行编码。


Problem 156 The complete timer

        问题:在数据流中检测到序列 1101 后,电路需要将接下来的 4bit 数据移入移位寄存器。4bit 数据决定了计数器的计数周期,称为 delay[3:0]。首先到达的比特作为数据的高位。

之后,状态机置高 counting 信号,表示其正在等待计数器完成计数。在 FSM 中增加计数器状态,计数周期为 (delay[3:0] + 1 )* 1000 个时钟周期。比如 delay = 0 时,计数值为 1000 个周期。delay = 5 代表 6000 个周期。同时输出 count 当前剩余的计数周期,输出当前剩余计数周期的千位(比如,还剩1000个周期输出 1,还剩 999 个周期时输出 0)。当计数停止后,count 的输出可以为任意数。

当计数完成后,电路置高 done 信号通知上层应用计数器计数完成,等待 ack 信号置高后,状态机清除 done 信号,返回空闲状态等待捕获下一个 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 );

wire shift_ena;
wire [9:0] cnt;

wire done_counting = (count==0 && cnt==10'd999) ? 1'b1 : 1'b0;
wire count_ena = (cnt==10'd999) ? 1'b1 : 1'b0;

fsm fsm_inst(
	.clk(clk),
	.reset(reset),
	.data(data),
	.shift_ena(shift_ena),
	.counting(counting),
	.done_counting(done_counting),
	.done(done),
	.ack(ack)
);

getdata getdata_inst(
	.clk(clk),
	.shift_ena(shift_ena),
	.count_ena(count_ena),
	.data(data),
	.q(count)
);

cnt_1k cnt_1k_inst(
	.clk(clk),
    .reset(reset || !counting),
	.q(cnt)
);


endmodule

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

endmodule

module getdata (
    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)
			q <= q - 1'b1;
		else
			q <= q;
	end

endmodule

module fsm (
    input clk,
    input reset,      // Synchronous reset
    input data,
    output shift_ena,
    output counting,
    input done_counting,
    output done,
    input ack );
	
    //状态说明
    //序列检测1 序列检测2 序列检测3 序列检测4
    //输出shift_ena 等待计数 完成状态
	parameter S0=0,S1=1,S2=2,S3=3,Out_shift_ena=4,Wait_count=5,Done=6;
	reg[2:0] state,next_state;
	reg[1:0] cnt;
	
	always @(*) begin
		case(state)
			S0: next_state = data ? S1 : S0;
			S1: next_state = data ? S2 : S0;
			S2: next_state = data ? S2 : S3;
			S3: next_state = data ? Out_shift_ena : S0;
			Out_shift_ena: next_state = (cnt==2'd3) ? Wait_count : Out_shift_ena;
			Wait_count: next_state = done_counting ? Done : Wait_count;
			Done: next_state = ack ? S0 : Done;
		endcase
	end
	
	always @(posedge clk) begin
		if(reset)
			state <= S0;
		else
			state <= next_state;
	end
	
	always @(posedge clk) begin
		if(reset)
			cnt <= 2'd0;
		else begin
			if(state == Out_shift_ena)
				cnt <= cnt + 1'b1;
			else
				cnt <= 2'd0;
		end
	end
	
	assign shift_ena = (state==Out_shift_ena);
	assign counting = (state == Wait_count);
	assign done = (state == Done);

endmodule

        牛呀牛呀,成功得有点突然,看着参考时序图改了好几遍,然后发现是计数器复位写错了,应该用或的写成了与,,, 一改就好了(激动.jpg)

        写完这个题发现模块构建电路是真的好,要是单独拿出这个题来让我写,估计就是写这几个模块时间的好几倍了,总体来写在时序上就会难写很多感觉

        所以这个题认真理解一下前几个模块的用途,然后添加一些中间变量把他们联系起来就比较好解决了。

        主要就是计数器复位,应该等状态机进入计数中的时候,才开始计数,否则就一直处于复位状态。然后就是完成计数状态,应该在延时值为0且计数值到999的时候再拉高完成信号,而不是延时值到0就好了!


Problem 157 FSM:One-hot logic equations

        问题:本题给出了一个具有 3 输入,3 输出以及 10 个状态的 FSM 的状态转移图。

仅需要实现状态转移和输出逻辑的组合逻辑,tb 会检测是否按照要求使用了独热码。

图中的状态依次进行了独热码编码, (S, S1, S11, S110, B0, B1, B2, B3, Count, Wait) = (10'b0000000001, 10 'b0000000010, 10'b0000000100, ... , 10'b1000000000)

本题仅要求产生以下状态的状态转移信号:

  • B3_next ,B2状态的次态
  • S_next
  • S1_next
  • Count_next
  • done
  • counting
  • 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) || (state[S1]&~d) || (state[S110]&~d) || (state[Wait]&ack); 
	assign S1_next = (state[S]&d);
	assign Count_next = (state[Count]&~done_counting) || state[B3];
	assign Wait_next = (state[Wait]&~ack) || (state[Count]&done_counting);
	assign done = state[Wait];
	assign counting = state[Count];
	assign shift_ena = |state[B3:B0];

endmodule

        有状态转换图写起来就是好写~~~

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值