目录
前言
3.3 Building Larger Circuits
3.3.4 FSM: Enable shift register(Exams/review2015 fsmshift)
3.3.5 FSM: The complete FSM(Exams/review2015 fsm)
3.3.6 The complete timer(Exams/review2015 fancytimer)
3.3.7 FSM: One-hot logic equations(Exams/review2015 fsmonehot)
结语
HDLbits网站链接
今天将这一小节剩余的题目全部更新完,第一题尤其精彩,四种方法真的很有技巧性,下面就开始吧。
module top_module (
input clk,
input reset, // Synchronous reset
output shift_ena);
parameter S0 = 3'd0, S1 = 3'd1, S2 = 3'd2, S3 = 3'd3, S4 = 3'd4;
reg [2:0] current_state;
reg [2:0] next_state;
always@(posedge clk)begin
if(reset)begin
current_state <= S0;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
S0:begin
next_state = S1;
end
S1:begin
next_state = S2;
end
S2:begin
next_state = S3;
end
S3:begin
next_state = S4;
end
S4:begin
next_state = S4;
end
default:begin
next_state = S4;
end
endcase
end
assign shift_ena = (current_state == S0 || current_state == S1 || current_state == S2 || current_state == S3);
endmodule
/*
//second way
module top_module (
input clk,
input reset, // Synchronous reset
output reg shift_ena);
reg [3:0] counter;
wire add_cnt;
wire end_cnt;
always@(posedge clk)begin
if(reset)begin
counter <= 4'd0;
end
else if(add_cnt)begin
if(end_cnt)begin
counter <= 4'd0;
end
else begin
counter <= counter + 1'b1;
end
end
end
assign add_cnt = shift_ena;
assign end_cnt = add_cnt && counter == 4'd3;
always@(posedge clk)begin
if(reset)begin
shift_ena <= 1'b1;
end
else if(end_cnt)begin
shift_ena <= 1'b0;
end
end
endmodule
*/
/*
//third way
module top_module (
input clk,
input reset, // Synchronous reset
output shift_ena);
reg shift_ena_reg1;
reg shift_ena_reg2;
reg shift_ena_reg3;
reg shift_ena_reg4;
always@(posedge clk)begin
if(reset)begin
shift_ena_reg1 <= 1'b1;
end
else begin
shift_ena_reg1 <= 1'b0;
end
end
always@(posedge clk)begin
if(reset)begin
shift_ena_reg2 <= 1'b1;
shift_ena_reg3 <= 1'b1;
shift_ena_reg4 <= 1'b1;
end
else begin
shift_ena_reg2 <= shift_ena_reg1;
shift_ena_reg3 <= shift_ena_reg2;
shift_ena_reg4 <= shift_ena_reg3;
end
end
assign shift_ena = shift_ena_reg1 | shift_ena_reg2 | shift_ena_reg3 | shift_ena_reg4;
endmodule
*/
/*
//forth way
module top_module (
input clk,
input reset, // Synchronous reset
output shift_ena);
reg [10:0] counter;
always@(posedge clk)begin
if(reset)begin
counter <= 11'd0;
end
else begin
counter <= counter + 1'b1;
end
end
assign shift_ena = counter < 11'd4;
endmodule
*/
首先,这道题题目中说,如果复位信号有效,shift_ena信号就变为1,当复位信号撤销以后,shift_ena信号保持4个周期为1后变为0。
这道题目博主给出4中解法,下面一种一种来说。
第一种解法:这种解法是常规解法,就是用状态机定义几个状态,然后当复位信号有效,进入状态S0,复位信号撤销就进入S1,然后进入S2、S3、S4,当进入S4状态,下一个状态就永远保持为S4。然后shift_ena信号在状态S0、S1、S2、S3时有效,这样就完成了题目。
第二种解法:这种解法非常巧妙,博主用了一个计数器,当shift_ena为1时启动计数器,然后当计数到3时将计数器清零,注意,这里非常巧妙的一点是复位信号有效时将shift_ena置为1,当计数器计数结束将shift_ena置为0,这样计数器就不再计数了,大家好好体会一下这种方法,非常巧妙。
第三种解法:这种解法中,博主定义了4个寄存器,在复位有效时将1号寄存器置为1,复位信号撤销以后将1号寄存器清0,然后将这个信号打三拍,这样最终的shift_ena信号只需要将这4个寄存器相或就好了。但是这种解法由于shift_ena是组合逻辑生成的,所以会有毛刺,谨慎使用。
第四种解法:这种解法是暴力解法,不建议使用,只为了得到success可以用。博主定义了一个非常大的计数器,然后一直不停计数,如果计数器的值小于4,shift_ena的就为1,否则就为0。这种解法非常不可靠,只是多一个思路供大家思考。
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output shift_ena,
output counting,
input done_counting,
output done,
input ack );
parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, COUNT=8, WAIT=9;
reg [3:0] current_state;
reg [3:0] next_state;
always@(posedge clk)begin
if(reset)begin
current_state <= S;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
S:begin
next_state = data ? S1 : S;
end
S1:begin
next_state = data ? S11 : S;
end
S11:begin
next_state = data ? S11 : S110;
end
S110:begin
next_state = data ? B0 : S;
end
B0:begin
next_state = B1;
end
B1:begin
next_state = B2;
end
B2:begin
next_state = B3;
end
B3:begin
next_state = COUNT;
end
COUNT:begin
next_state = done_counting ? WAIT : COUNT;
end
WAIT:begin
next_state = ack ? S : WAIT;
end
default:begin
next_state = S;
end
endcase
end
assign shift_ena = (current_state == B0 || current_state == B1 || current_state == B2 || current_state == B3);
assign counting = (current_state == COUNT);
assign done = (current_state == WAIT);
endmodule
题目中说要创建一个计时器,当检测到序列1101时启动,接着等待4位,然后计数器完成计数,最后等待用户确认计数器。
大家也看出来了,这道题其实就是前面几道题目的组合。
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output [3:0] count,
output counting,
output done,
input ack );
parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, COUNT_REG=8, WAIT=9;
reg [3:0] current_state;
reg [3:0] next_state;
reg [3:0] par_in;
reg [15:0] counter;
always@(posedge clk)begin
if(reset)begin
counter <= 16'd0;
end
else if(next_state == WAIT)begin
counter <= 16'd0;
end
else if(next_state == COUNT_REG)begin
counter <= counter + 1'b1;
end
end
reg [3:0] a;
always@(*)begin
if(counter <= 1000)begin
a = 4'd0;
end
if(counter > 1000 && counter <= 2000)begin
a = 4'd1;
end
if(counter > 2000 && counter <= 3000)begin
a = 4'd2;
end
if(counter > 3000 && counter <= 4000)begin
a = 4'd3;
end
if(counter > 4000 && counter <= 5000)begin
a = 4'd4;
end
if(counter > 5000 && counter <= 6000)begin
a = 4'd5;
end
if(counter > 6000 && counter <= 7000)begin
a = 4'd6;
end
if(counter > 7000 && counter <= 8000)begin
a = 4'd7;
end
if(counter > 8000 && counter <= 9000)begin
a = 4'd8;
end
if(counter > 9000 && counter <= 10000)begin
a = 4'd9;
end
if(counter > 10000 && counter <= 11000)begin
a = 4'd10;
end
if(counter > 11000 && counter <= 12000)begin
a = 4'd11;
end
if(counter > 12000 && counter <= 13000)begin
a = 4'd12;
end
if(counter > 13000 && counter <= 14000)begin
a = 4'd13;
end
if(counter > 14000 && counter <= 15000)begin
a = 4'd14;
end
if(counter > 15000 && counter <= 16000)begin
a = 4'd15;
end
end
wire b;
assign b = (counter == (par_in + 1) * 1000) ? 1'b1 : 1'b0;
always@(posedge clk)begin
if(reset)begin
current_state <= S;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
S:begin
next_state = data ? S1 : S;
end
S1:begin
next_state = data ? S11 : S;
end
S11:begin
next_state = data ? S11 : S110;
end
S110:begin
next_state = data ? B0 : S;
end
B0:begin
next_state = B1;
par_in[3] = data;
end
B1:begin
next_state = B2;
par_in[2] = data;
end
B2:begin
next_state = B3;
par_in[1] = data;
end
B3:begin
next_state = COUNT_REG;
par_in[0] = data;
end
COUNT_REG:begin
next_state = b ? WAIT : COUNT_REG;
end
WAIT:begin
next_state = ack ? S : WAIT;
end
default:begin
next_state = S;
end
endcase
end
assign count = (current_state == COUNT_REG) ? (par_in - a) : 4'd0;
assign counting = (current_state == COUNT_REG);
assign done = (current_state == WAIT);
endmodule
大家注意理解这道题的题意,这里的状态机必须精确计数(delay [3:0] + 1)* 1000个时钟周期。例如,delay = 0表示计数1000个周期,而delay = 5表示计数6000个周期。同时输出当前剩余时间。这应该是等于延迟为1000个循环,然后延迟-1为1000个周期,依此类推,直到它为0,1000次循环。当电路不计数时,count [3:0]输出无关紧要。
这道题目相比上一道加了一个计数器,只要注意counter的加1条件和清零条件实在哪个状态开始的就可以了。
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 = 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
这道题又是作者所表达的one-hot编码的思想和我们平时使用one-hot编码思想的差异,大家不用太过在意,直接完成题目就好了。如果前面的题目做不出来,可以先看这道题目作者给出的状态转移图,基本就没什么问题了。
今天将这个小节内容更新完毕,我觉得剩下的几个小节就没什么特别难的题目了,距离将所有题目答案更新完毕又快了一步~
如果有哪里代码有问题,欢迎随时指出哦,最后祝同学们周末愉快~
https://hdlbits.01xz.net/wiki/Main_Page