参考链接: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
问题:复杂计数器需要如下这些功能特性:
- 在数据流中检测到特定序列后启动计数器,该序列为: 1101
- 将 4bits 数据输入移位寄存器,作为计数器的初值
- 等待计数器结束计数
- 告知上层应用计数完成,并等待用户通过 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
有状态转换图写起来就是好写~~~