【HDLBits 刷题 13】Buliding Larger Circuits

目录

写在前面

Buliding Larger Circuits

count1k

shiftcount

fsm seq

fsmshift

fsm

fancytimer

fsm onehot


写在前面

以下的解题方法不一定为最佳解决方案,有更好的方法欢迎提出,共同学习,共同进步!

Buliding Larger Circuits

count1k

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

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

always @(posedge clk) begin
	if (reset) begin
		q <= 'd0;
	end
	else if (q=='d999) begin
		q <= 'd0;
	end
	else begin
		q <= q + 'd1;
	end
end

endmodule

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
		q <= {q[2:0],data};
	end
	else if (count_ena) begin
		q <= q - 'd1;
	end
	else begin
		q <= q;
	end
end

endmodule

fsm seq

这是一系列五个练习中的第二个组件,该练习从几个较小的电路中构建一个复杂的计数器。

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

module top_module (
    input      clk,
    input      reset,      // Synchronous reset
    input      data,
    output     start_shifting
);

//状态申明
parameter  IDLE    =  'd1;
parameter  A_1     =  'd2;
parameter  B_1     =  'd3;
parameter  C_0     =  'd4;
parameter  D_1     =  'd5;

//现态和次态
reg  [2:0]   state;
reg  [2:0]   next_state;

//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
	if (reset) begin
		state <= IDLE;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	next_state = state;
	case(state)
		IDLE: begin
			if (data) begin
				next_state = A_1;
			end
			else begin
				next_state = IDLE;
			end
		end
		A_1: begin
			if (data) begin
				next_state = B_1;
			end
			else begin
				next_state = IDLE;
			end
		end
		B_1: begin
			if (~data) begin
				next_state = C_0;
			end
			else begin
				next_state = B_1;
			end
		end
		C_0: begin
			if (data) begin
				next_state = D_1;
			end
			else begin
				next_state = IDLE;
			end
		end
		D_1: begin
			next_state = D_1;
		end
		default: begin
			next_state = IDLE;
		end
	endcase
end

//状态机第三段,结果输出,组合逻辑
assign start_shifting = (state==D_1);

endmodule

fsmshift

这是一系列五个练习中的第三个组件,该练习从几个较小的电路中构建一个复杂的计数器。

作为用于控制移位寄存器的FSM的一部分,我们希望能够在检测到正确的位模式时使移位寄存器精确4个时钟周期,考虑前面的处理序列检测,因此 FSM 的这一部分仅处理启用移位寄存器 4 个周期。

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

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

reg  [1:0]  cnt;

always @(posedge clk) begin
	if (reset) begin
		cnt <= 'd0;
	end
	else begin
		cnt <= cnt + 'd1;
	end
end

always @(posedge clk) begin
	if (reset) begin
		shift_ena <= 'd1;
	end
	else if (cnt=='d3) begin
		shift_ena <= 'd0;
	end
	else begin
		shift_ena <= shift_ena;
	end
end

endmodule

fsm

这是一系列五个练习中的第四个组件,该练习从几个较小的电路中构建一个复杂的计数器。

想要创建一个计时器,

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

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

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

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

此时,状态机必须断言 done 以通知用户计时器已超时,并等到输入 ack 为 1,然后重置以查找下一个匹配的开始序列 (1101)。

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

下面是预期输入和输出的示例。“x”状态可能读起来有点混乱。它们表明,密克罗尼西亚联邦不应关心该周期中的特定输入信号。例如,一旦检测到 1101 模式,FSM 将不再查看数据输入,直到完成其他所有操作后恢复搜索。

module top_module (
    input         clk,
    input         reset,      // Synchronous reset
    input         data,
    input         ack,
    input         done_counting, 
    output        shift_ena,
    output        counting,
    output        done
);

//状态申明
parameter  IDLE    =  'd1;
parameter  A_1     =  'd2;
parameter  B_1     =  'd3;
parameter  C_0     =  'd4;
parameter  CNT_1   =  'd5;
parameter  CNT_2   =  'd6;
parameter  CNT_3   =  'd7;
parameter  CNT_4   =  'd8;
parameter  CNT     =  'd9;
parameter  WAIT    =  'd10;

//现态和次态
reg  [3:0]   state;
reg  [3:0]   next_state;

//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
	if (reset) begin
		state <= IDLE;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	next_state = state;
	case(state)
		IDLE: begin
			if (data) begin
				next_state = A_1;
			end
			else begin
				next_state = IDLE;
			end
		end
		A_1: begin
			if (data) begin
				next_state = B_1;
			end
			else begin
				next_state = IDLE;
			end
		end
		B_1: begin
			if (~data) begin
				next_state = C_0;
			end
			else begin
				next_state = B_1;
			end
		end
		C_0: begin
			if (data) begin
				next_state = CNT_1;
			end
			else begin
				next_state = IDLE;
			end
		end
		CNT_1: begin
			next_state = CNT_2;
		end
		CNT_2: begin
			next_state = CNT_3;
		end
		CNT_3: begin
			next_state = CNT_4;
		end
		CNT_4: begin
			next_state = CNT;
		end
		CNT: begin
			if (done_counting) begin
				next_state = WAIT;
			end
			else begin
				next_state = CNT;
			end
		end
		WAIT: begin
			if (ack) begin
				next_state = IDLE;
			end
			else begin
				next_state = WAIT;
			end
		end
		default: begin
			next_state = IDLE;
		end
	endcase
end

//状态机第三段,结果输出,组合逻辑
assign shift_ena = (state==CNT_1) | (state==CNT_2) | (state==CNT_3) | (state==CNT_4);
assign counting = state==CNT;
assign done = state==WAIT;

endmodule

fancytimer

这是一系列五个练习中的第五个组件,该练习从几个较小的电路中构建一个复杂的计数器。

想要创建一个具有一个输入的计时器:

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

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

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

此时,电路必须断言完成以通知用户计时器已超时,并等到输入ack为1,然后重置以查找下一个出现的开始序列(1101)。

电路应复位到开始搜索输入序列1101的状态。

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

module top_module (
    input           clk,
    input           reset,      // Synchronous reset
    input           data,
    input           ack,
    output [3:0]    count,
    output          counting,
    output          done
);

//状态申明
parameter  IDLE      =  'd1;
parameter  A_1       =  'd2;
parameter  B_1       =  'd3;
parameter  C_0       =  'd4;
parameter  SHIFT_1   =  'd5;
parameter  SHIFT_2   =  'd6;
parameter  SHIFT_3   =  'd7;
parameter  SHIFT_4   =  'd8;
parameter  CNT       =  'd9;
parameter  WAIT      =  'd10;

//现态和次态
reg  [3:0]   state;
reg  [3:0]   next_state;
reg  [3:0]   delay;
reg  [15:0]  delay_cnt;
reg  [3:0]   delay_num;
wire         delay_cnt_done;

//当计数到设定的计数值时,将延时计数完成标志信号拉高
assign  delay_cnt_done  =  (delay_cnt == ((delay + 'd1) * 'd1000))?'d1:'d0;

//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
	if (reset) begin
		state <= IDLE;
	end
	else begin
		state <= next_state;
	end
end

//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
	next_state = state;
	case(state)
		IDLE: begin
			if (data) begin
				next_state = A_1;
			end
			else begin
				next_state = IDLE;
			end
		end
		A_1: begin
			if (data) begin
				next_state = B_1;
			end
			else begin
				next_state = IDLE;
			end
		end
		B_1: begin
			if (~data) begin
				next_state = C_0;
			end
			else begin
				next_state = B_1;
			end
		end
		C_0: begin
			if (data) begin
				next_state = SHIFT_1;
			end
			else begin
				next_state = IDLE;
			end
		end
		SHIFT_1: begin
			next_state = SHIFT_2;
			delay[3]   = data;
		end
		SHIFT_2: begin
			next_state = SHIFT_3;
			delay[2]   = data;
		end
		SHIFT_3: begin
			next_state = SHIFT_4;
			delay[1]   = data;
		end
		SHIFT_4: begin
			next_state = CNT;
			delay[0]   = data;
		end
		CNT: begin
			if (delay_cnt_done) begin
				next_state = WAIT;
			end
			else begin
				next_state = CNT;
			end
		end
		WAIT: begin
			if (ack) begin
				next_state = IDLE;
			end
			else begin
				next_state = WAIT;
			end
		end
		default: begin
			next_state = IDLE;
		end
	endcase
end

//delay_cnt
always @(posedge clk) begin
	if (reset) begin
		delay_cnt <= 'd0;
	end
	else if (next_state == WAIT) begin
		delay_cnt <= 'd0;
	end
	else if (next_state == CNT) begin
		delay_cnt <= delay_cnt + 'd1;
	end
	else begin
		delay_cnt <= delay_cnt;
	end
end

//对于延时计数的范围值,确定具体的count值
always @(*) begin
	if (delay_cnt <= 'd1000) begin
		delay_num = 'd0;
	end
	else if (delay_cnt > 'd1000 && delay_cnt <= 'd2000) begin
		delay_num = 'd1;
	end
	else if (delay_cnt > 'd2000 && delay_cnt <= 'd3000) begin
		delay_num = 'd2;
	end
	else if (delay_cnt > 'd3000 && delay_cnt <= 'd4000) begin
		delay_num = 'd3;
	end
	else if (delay_cnt > 'd4000 && delay_cnt <= 'd5000) begin
		delay_num = 'd4;
	end
	else if (delay_cnt > 'd5000 && delay_cnt <= 'd6000) begin
		delay_num = 'd5;
	end
	else if (delay_cnt > 'd6000 && delay_cnt <= 'd7000) begin
		delay_num = 'd6;
	end
	else if (delay_cnt > 'd7000 && delay_cnt <= 'd8000) begin
		delay_num = 'd7;
	end
	else if (delay_cnt > 'd8000 && delay_cnt <= 'd9000) begin
		delay_num = 'd8;
	end
	else if (delay_cnt > 'd9000 && delay_cnt <= 'd10000) begin
		delay_num = 'd9;
	end
	else if (delay_cnt > 'd10000 && delay_cnt <= 'd11000) begin
		delay_num = 'd10;
	end
	else if (delay_cnt > 'd11000 && delay_cnt <= 'd12000) begin
		delay_num = 'd11;
	end
	else if (delay_cnt > 'd12000 && delay_cnt <= 'd13000) begin
		delay_num = 'd12;
	end
	else if (delay_cnt > 'd13000 && delay_cnt <= 'd14000) begin
		delay_num = 'd13;
	end
	else if (delay_cnt > 'd14000 && delay_cnt <= 'd15000) begin
		delay_num = 'd14;
	end
	else if (delay_cnt > 'd15000 && delay_cnt <= 'd16000) begin
		delay_num = 'd15;
	end
	else begin
		delay_num = 'd0;
	end
end

//状态机第三段,结果输出,组合逻辑
assign  count     =  (state == CNT)?(delay - delay_num):'d0;
assign  counting  =  (state == CNT);
assign  done      =  (state == WAIT);

endmodule

fsm onehot

假设使用以下单热编码,则通过检查派生下一状态逻辑方程和输出逻辑方程:(S,S1,S11,S110,B0,B1,B2,B3,计数,等待)= (10'b0000000001,10'b00000000010,10'b00000000100,...,10'b10000000000)

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 = (state[S] && ~d) | (state[S1] && ~d) | (state[S110] && ~d) | (state[Wait] && ack);
assign S1_next = (state[S] && d);
assign Count_next = (state[B3] | (state[Count] && ~done_counting));
assign Wait_next = (state[Count] && done_counting) | (state[Wait] && ~ack);
assign done = state[Wait];
assign counting = state[Count];
assign shift_ena = (state[B0] | state[B1] | state[B2] | state[B3]);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Linest-5

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

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

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

打赏作者

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

抵扣说明:

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

余额充值