赞
踩
今天继续更新状态机小节的习题。
题目描述1:
第一道题目比较容易,题目中的in信号包含了一个起始位(0),8个数据位和一个停止位(1),开始in为1,也就是IDLE状态,当in为0时,进入START状态,然后经过8个周期,如果in为1,则进入STOP状态,接着如果in为0,进入第二轮START状态,否则进入IDLE状态。
这里我用了很多个状态,实际上可以用计数器来代替中间的8个状态,这里是8个周期,如果是100个、200个周期,那么需要100个、200个状态,显然不现实。这道题目是三道题目中的基础题,大家不用考虑那么多,直接完成就好了。
Solution1:
module top_module( input clk, input in, input reset, // Synchronous reset output done ); parameter [3:0] START = 4'd0; parameter [3:0] ONE = 4'd1; parameter [3:0] TWO = 4'd2; parameter [3:0] THREE = 4'd3; parameter [3:0] FOUR = 4'd4; parameter [3:0] FIVE = 4'd5; parameter [3:0] SIX = 4'd6; parameter [3:0] SEVEN = 4'd7; parameter [3:0] EIGHT = 4'd8; parameter [3:0] STOP = 4'd9; parameter [3:0] IDLE = 4'd10; parameter [3:0] WAIT = 4'd11; reg [3:0] state,next_state; always @(*)begin case(state) START:begin next_state = ONE; end ONE:begin next_state = TWO; end TWO:begin next_state = THREE; end THREE:begin next_state = FOUR; end FOUR:begin next_state = FIVE; end FIVE:begin next_state = SIX; end SIX:begin next_state = SEVEN; end SEVEN:begin next_state = EIGHT; end EIGHT:begin if(in)begin next_state = STOP; end else begin next_state = WAIT; end end STOP:begin if(in)begin next_state = IDLE; end else begin next_state = START; end end WAIT:begin if(in)begin next_state = IDLE; end else begin next_state = WAIT; end end IDLE:begin if(~in)begin next_state = START; end else begin next_state = IDLE; end end endcase end always @(posedge clk)begin if(reset)begin state <= IDLE; end else begin state <= next_state; end end assign done = (state == STOP); endmodule
题目描述2:
这道题目是上一道题目的扩展,不仅需要输出done信号,还需要输出数据。
Solution2:
/* way 1*/ module top_module( input clk, input in, input reset, // Synchronous reset output [7:0] out_byte, output done ); // parameter [3:0] START = 4'd0; parameter [3:0] ONE = 4'd1; parameter [3:0] TWO = 4'd2; parameter [3:0] THREE = 4'd3; parameter [3:0] FOUR = 4'd4; parameter [3:0] FIVE = 4'd5; parameter [3:0] SIX = 4'd6; parameter [3:0] SEVEN = 4'd7; parameter [3:0] EIGHT = 4'd8; parameter [3:0] STOP = 4'd9; parameter [3:0] IDLE = 4'd10; parameter [3:0] WAIT = 4'd11; reg [3:0] state,next_state; reg [7:0] par_in; always @(*)begin case(state) START:begin next_state = ONE; par_in[0] = in; end ONE:begin next_state = TWO; par_in[1] = in; end TWO:begin next_state = THREE; par_in[2] = in; end THREE:begin next_state = FOUR; par_in[3] = in; end FOUR:begin next_state = FIVE; par_in[4] = in; end FIVE:begin next_state = SIX; par_in[5] = in; end SIX:begin next_state = SEVEN; par_in[6] = in; end SEVEN:begin next_state = EIGHT; par_in[7] = in; end EIGHT:begin if(in)begin next_state = STOP; end else begin next_state = WAIT; end end STOP:begin if(in)begin next_state = IDLE; end else begin next_state = START; end end WAIT:begin if(in)begin next_state = IDLE; end else begin next_state = WAIT; end end IDLE:begin if(~in)begin next_state = START; end else begin next_state = IDLE; end end endcase end always @(posedge clk)begin if(reset)begin state <= IDLE; end else begin state <= next_state; end end assign done = (state == STOP); assign out_byte = (state == STOP) ? par_in : 8'd0; endmodule /* way 2 */ module top_module( input clk, input in, input reset, // Synchronous reset output [7:0] out_byte, output done ); parameter IDLE = 3'd0, START = 3'd1, DATA = 3'd2; parameter STOP = 3'd3, WAIT = 3'd4; reg [3:0] current_state; reg [3:0] next_state; reg [3:0] counter; reg [7:0] par_in; // Use FSM from Fsm_serial always @(*)begin case(current_state) IDLE:begin if(~in)begin next_state = START; end else begin next_state = IDLE; end end START:begin next_state = DATA; end DATA:begin if(counter == 4'd8)begin next_state = in? STOP:WAIT; end else begin next_state = DATA; end end STOP:begin next_state = in? IDLE:START; end WAIT:begin next_state = in? IDLE:WAIT; end default:begin next_state = IDLE; end endcase end always @(posedge clk)begin if(reset)begin current_state <= IDLE; end else begin current_state <= next_state; end end always @(posedge clk)begin if(reset)begin done <= 1'd0; out_byte <= 8'd0; counter <= 4'd0; end else begin case(next_state) IDLE:begin done <= 1'd0; out_byte <= 8'd0; counter <= 4'd0; end START:begin done <= 1'd0; out_byte <= 8'd0; counter <= 4'd0; end DATA:begin done <= 1'd0; out_byte <= 8'd0; par_in[counter] <= in; counter <= counter + 1'd1; end STOP:begin done <= 1'd1; out_byte <= par_in; counter <= 4'd0; end WAIT:begin done <= 1'd0; out_byte <= 8'd0; counter <= 4'd0; end endcase end end // New: Datapath to latch input bits. endmodule
上述第一种解法虽然正确,但是会生成锁存器,并且这里只有1个字节数据还好,用8个状态是可以的,如果换成了10个字节、100个字节,难道要80、800个状态吗?这是不可能的,于是便诞生了方法二博主最想让大家使用的方法。大家可以好好看一下,这里将8个数据状态定义成了一个DATA状态,不用定义S1、S2、S3什么的了,在状态机的第三段,将除了DATA状态的其他状态时的counter都清零,只有到了DATA状态时开始计数,顺便将par_in中的位数用counter代替,这样只需要增加counter和out_byte的位宽,就可以实现任意宽度数据的输出,实用性强。
题目描述3:
较上题添加了奇偶校验位。
module top_module( input clk, input in, input reset, // Synchronous reset output [7:0] out_byte, output done ); // parameter IDLE = 3'd0,START = 3'd1,DATA = 3'd2; parameter STOP = 3'd3,WAIT = 3'd4; reg [2:0] current_state,next_state; reg [3:0] counter; reg [8:0] data_in; reg odd_temp; wire Isdone; // Modify FSM and datapath from Fsm_serialdata always @(*) begin case(current_state) IDLE:begin if(~in)begin next_state = START; end else begin next_state = IDLE; end end START:begin next_state = DATA; end DATA:begin if(counter == 4'd9)begin next_state = in ? STOP : WAIT; end else begin next_state = DATA; end end STOP:begin next_state = in ? IDLE : START; end WAIT:begin next_state = in ? IDLE : WAIT; end default:begin next_state = IDLE; end endcase end always @(posedge clk) begin if(reset)begin current_state <= IDLE; end else begin current_state <= next_state; end end always @(posedge clk) begin if(reset)begin done <= 1'd0; out_byte <= 8'd0; counter <= 4'd0; end else begin case(next_state) IDLE:begin done <= 1'd0; out_byte <= 8'd0; counter <= 4'd0; end START:begin done <= 1'd0; out_byte <= 8'd0; counter <= 4'd0; end DATA:begin done <= 1'd0; out_byte <= 8'd0; counter <= counter + 1'd1; data_in[counter] <= in; end STOP:begin done <= odd_temp ? 1'd1 : 1'd0; out_byte <= odd_temp ? data_in[7:0] : 8'd0; counter <= 4'd0; end WAIT:begin done <= 1'd0; out_byte <= 8'd0; counter <= 4'd0; end endcase end end // New: Add parity checking. assign Isdone = (next_state == START); parity u0(clk,Isdone,in,odd_temp); endmodule
该题答案与上题类似,这里我将奇偶校验位数据也计算在DATA状态内,判断起来相对较容易,大家可以借鉴一下。
注意作者在题目中给了奇偶校验的模块,大家直接调用即可。
好久没更新HDLBits了,寒假在家闲来无事,希望勉励自己把HDLBits刷完吧,加油!有问题的地方欢迎大家与我讨论交流。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。