hdlbits之Exams/ece241 2013 q4的FSM问题
工作和学习中的事情太多,想干的事情更多,所以总感觉时间不够用。再加上自己比较懒,好久没有兴致闲下来写东西了。
之前做过hdlbits的一些题目,挺简单。但是今天被这道题给坑惨了,花费了几个小时才做出来。不是说这道题有多难,一是自己犯了一个脑袋驴踢的及其低级错误,二是题目也有出的不清楚的地方。原题目如下
自己犯下的极其低级和愚蠢的错误为在S0,S1,S2,S3四个状态,判断输入s的值是忘了加数据类型和位宽。这个愚蠢而又低级的错误导致无法进入正确的状态。
1 S0 : begin 2 case(s) 3 000 : next_state = S0; 4 001 : next_state = S1; 5 011 : next_state = S2; 6 111 : next_state = S3; 7 default: next_state = S0; 8 endcase 9 end
正确的应该如下所示:
1 S0 : begin 2 case(s) 3 3'b000 : next_state = S0; 4 3'b001 : next_state = S1; 5 3'b011 : next_state = S2; 6 3'b111 : next_state = S3; 7 default: next_state = S0; 8 endcase 9 end
第二个原题目中没有交代清楚的问题:题目中之说了如果之前水位低于当前水位,为正常水流(即dfr不用打开),如果之前水位大于当前水位,则需要打开dfr。没有说当之前水位与当前水位相同时怎么处理dfr。导致自己这个地方一直出错,最后观察作者的测试波形,才发现作者的愿意是这种情况dfr保持之前的值。这个地方挺坑爹的。
最后代码如下:
1 module top_module ( 2 input clk, 3 input reset, 4 input [3:1] s, 5 output fr3, 6 output fr2, 7 output fr1, 8 output dfr 9 ); 10 11 parameter [1:0] S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11; 12 reg [1:0] current_state, next_state, last_state; 13 14 always @(posedge clk) begin 15 if(reset) begin 16 current_state <= S0; 17 last_state <= S0; 18 end 19 else begin 20 current_state <= next_state; 21 last_state <= current_state; 22 end 23 end 24 25 always @(*) begin 26 case(current_state) 27 S0 : begin 28 case(s) 29 3'b000 : next_state = S0; 30 3'b001 : next_state = S1; 31 3'b011 : next_state = S2; 32 3'b111 : next_state = S3; 33 default: next_state = S0; 34 endcase 35 end 36 S1 : begin 37 case(s) 38 3'b000 : next_state = S0; 39 3'b001 : next_state = S1; 40 3'b011 : next_state = S2; 41 3'b111 : next_state = S3; 42 default: next_state = S0; 43 endcase 44 end 45 S2 : begin 46 case(s) 47 3'b000 : next_state = S0; 48 3'b001 : next_state = S1; 49 3'b011 : next_state = S2; 50 3'b111 : next_state = S3; 51 default: next_state = S0; 52 endcase 53 end 54 S3 : begin 55 case(s) 56 3'b000 : next_state = S0; 57 3'b001 : next_state = S1; 58 3'b011 : next_state = S2; 59 3'b111 : next_state = S3; 60 default: next_state = S0; 61 endcase 62 end 63 default: next_state = S0; 64 endcase 65 end 66 67 always @(*) begin 68 case(current_state) 69 S0 : {fr3,fr2,fr1} = 3'b111; 70 S1 : {fr3,fr2,fr1} = 3'b011; 71 S2 : {fr3,fr2,fr1} = 3'b001; 72 S3 : {fr3,fr2,fr1} = 3'b000; 73 default: {fr3,fr2,fr1} = 3'b111; 74 endcase 75 end 76 //assign fr3 = (current_state == S0); 77 //assign fr2 = (current_state == S0) || (current_state == S1); 78 //assign fr1 = (current_state == S0) || (current_state == S1) || (current_state == S2); 79 80 always @(*) begin 81 if(current_state == S0) 82 dfr = 1'b1; 83 else if(last_state > current_state) 84 dfr = 1'b1; 85 else if(last_state < current_state) 86 dfr = 1'b0; 87 else 88 dfr = dfr; //will generate latch 89 end 90 91 endmodule
原作者的非常简洁。主要区别在于自己的写法是以水位的状态为状态机的各种状态。这个状态机相对简单,但是dfr的情况无法在状态机中体现(即没有考虑水位从高到底的情况下dfr的值)。原作者通过细分状态的方式,简化了dfr的verilog代码逻辑。非常漂亮。原作者代码如下:
1 module top_module ( 2 input clk, 3 input reset, 4 input [3:1] s, 5 output reg fr3, 6 output reg fr2, 7 output reg fr1, 8 output reg dfr 9 ); 10 11 12 // Give state names and assignments. I'm lazy, so I like to use decimal numbers. 13 // It doesn't really matter what assignment is used, as long as they're unique. 14 // We have 6 states here. 15 parameter A2=0, B1=1, B2=2, C1=3, C2=4, D1=5; 16 reg [2:0] state, next; // Make sure these are big enough to hold the state encodings. 17 18 19 20 // Edge-triggered always block (DFFs) for state flip-flops. Synchronous reset. 21 always @(posedge clk) begin 22 if (reset) state <= A2; 23 else state <= next; 24 end 25 26 27 28 // Combinational always block for state transition logic. Given the current state and inputs, 29 // what should be next state be? 30 // Combinational always block: Use blocking assignments. 31 always@(*) begin 32 case (state) 33 A2: next = s[1] ? B1 : A2; 34 B1: next = s[2] ? C1 : (s[1] ? B1 : A2); 35 B2: next = s[2] ? C1 : (s[1] ? B2 : A2); 36 C1: next = s[3] ? D1 : (s[2] ? C1 : B2); 37 C2: next = s[3] ? D1 : (s[2] ? C2 : B2); 38 D1: next = s[3] ? D1 : C2; 39 default: next = 'x; 40 endcase 41 end 42 43 44 45 // Combinational output logic. In this problem, a procedural block (combinational always block) 46 // is more convenient. Be careful not to create a latch. 47 always@(*) begin 48 case (state) 49 A2: {fr3, fr2, fr1, dfr} = 4'b1111; 50 B1: {fr3, fr2, fr1, dfr} = 4'b0110; 51 B2: {fr3, fr2, fr1, dfr} = 4'b0111; 52 C1: {fr3, fr2, fr1, dfr} = 4'b0010; 53 C2: {fr3, fr2, fr1, dfr} = 4'b0011; 54 D1: {fr3, fr2, fr1, dfr} = 4'b0000; 55 default: {fr3, fr2, fr1, dfr} = 'x; 56 endcase 57 end 58 59 endmodule
状态图的s1s2s3排列方式不好,如果改为S3S2S1会更符合习惯。