赞
踩
今天继续更新状态机小节的习题。
同步帧检测涉及对数据的连续位流进行解码,以寻找指示帧(数据包)开始和结束的位模式。 6个连续的1(即01111110)是表示帧边界的“标志”。 为了避免数据流意外包含“标志”,发送方必须在接收方必须检测并丢弃的每5个连续的1秒后插入一个零。 如果连续7个或更多1,我们还需要发出错误信号。
可以通过状态机来识别下面三种序列:
0111110:表示5个1后面的0bit需被忽略;
01111110:表示一帧的开始或结束;
01111111…:错误
当状态机被复位时,它应当表现为之前的输入为0;
下面是三种波形示例:
官方提供的状态机设计提示:
Solution:
//----------------way1---------------------- module top_module( input clk, input reset, // Synchronous reset input in, output disc, output flag, output err); parameter NONE = 4'd0,ONE = 4'd1,TWO = 4'd2; parameter THREE = 4'd3,FOUR = 4'd4,FIVE = 4'd5; parameter SIX = 4'd6,ERROR = 4'd7; parameter DISC = 4'd8,FLAG = 4'd9; reg [3:0] current_state,next_state; always @(*) begin case(current_state) NONE:begin next_state = in ? ONE : NONE; end ONE:begin next_state = in ? TWO : NONE; end TWO:begin next_state = in ? THREE : NONE; end THREE:begin next_state = in ? FOUR : NONE; end FOUR:begin next_state = in ? FIVE : NONE; end FIVE:begin next_state = in ? SIX : DISC; end SIX:begin next_state = in ? ERROR : FLAG; end DISC:begin next_state = in ? ONE : NONE; end FLAG:begin next_state = in ? ONE : NONE; end ERROR:begin next_state = in ? ERROR : NONE; end endcase end always @(posedge clk) begin if(reset)begin current_state <= NONE; end else begin current_state <= next_state; end end always @(posedge clk) begin if(reset)begin disc <= 1'd0; flag <= 1'd0; err <= 1'd0; end else begin case(next_state) DISC:begin disc <= 1'd1; flag <= 1'd0; err <= 1'd0; end FLAG:begin disc <= 1'd0; flag <= 1'd1; err <= 1'd0; end ERROR:begin disc <= 1'd0; flag <= 1'd0; err <= 1'd1; end default:begin disc <= 1'd0; flag <= 1'd0; err <= 1'd0; end endcase end end endmodule //----------------way2---------------------- module top_module( input clk, input reset, // Synchronous reset input in, output disc, output flag, output err); parameter NONE = 3'd0,DATA = 3'd1; parameter DISC = 3'd2,FLAG = 3'd3,ERROR = 3'd4; reg [2:0] current_state,next_state; reg [2:0] counter; always @(*) begin case(current_state) NONE:begin next_state = in ? DATA : NONE; end DATA:begin case(counter) 3'd5: next_state = in ? DATA : DISC; 3'd6: next_state = in ? ERROR : FLAG; default:next_state = in ? DATA : NONE; endcase end DISC:begin next_state = in ? DATA : NONE; end FLAG:begin next_state = in ? DATA : NONE; end ERROR:begin next_state = in ? ERROR : NONE; end endcase end always @(posedge clk) begin if(reset)begin current_state <= NONE; end else begin current_state <= next_state; end end always @(posedge clk) begin if(reset)begin disc <= 1'd0; flag <= 1'd0; err <= 1'd0; counter <= 3'd0; end else begin case(next_state) DATA:begin disc <= 1'd0; flag <= 1'd0; err <= 1'd0; counter <= counter + 1'd1; end DISC:begin disc <= 1'd1; flag <= 1'd0; err <= 1'd0; counter <= 3'd0; end FLAG:begin disc <= 1'd0; flag <= 1'd1; err <= 1'd0; counter <= 3'd0; end ERROR:begin disc <= 1'd0; flag <= 1'd0; err <= 1'd1; counter <= 3'd0; end default:begin disc <= 1'd0; flag <= 1'd0; err <= 1'd0; counter <= 3'd0; end endcase end end endmodule
其中way1与题目提示的思路相同,其中第三段状态机一开始忘记加reset的那种情况,果然还是长时间没接触verilog手生了,以后继续练习;
way2使用counter去掉中间状态,靠输入和counter的值来决定状态转移,是一种米利状态机的思想;状态转移图如下(手绘有点丑,见谅):
检测输入的X中”101“是否出现,出现的话输出Z为1,否则为0。复位为异步低电平复位;只允许出现3种状态;允许交叠检测:即输入若为10101时,Z应该在时刻3和时刻5各输出一次1;
代码中主要妙在两处:一是如何用3种状态表示,需在第三种状态中将输出与输入关联起来;二是如何进行交叠检测,状态的转移有妙处;
Solution:
module top_module ( input clk, input aresetn, // Asynchronous active-low reset input x, output z ); parameter S0 = 2'd0,S1 = 2'd1,S2 = 2'd2; reg [1:0] current_state,next_state; always @(*) begin case(current_state) S0: next_state = x ? S1 : S0; S1: next_state = x ? S1 : S2; S2: next_state = x ? S1 : S0; endcase end always @(posedge clk or negedge aresetn) begin if(~aresetn)begin current_state <= S0; end else begin current_state <= next_state; end end always @(*) begin z = (current_state == S2) ? x : 1'b0; end endmodule
作者这里假设我们这边输入的都是负数,不用管符号位的问题;即补码全部都是取反加1求得。
以上图为例,输入的左边为低位数据,右边为高位数据;即输入为00110100,则取反加1后得输出为11001100;
取反操作好进行,主要麻烦在加一的操作上,不知道进位到哪一位为止,此时我们用状态机来解决;若最前面的输入都是0的话,取反均为1,低位加1的时候一直进位,则输出都是0,直到输入有个1为止(取反加1不进位),这一阶段我们用一个状态S0来表示;后面阶段就将输入取反进行输出即可,因为进位链在S0状态已结束;
因为是摩尔型状态机,输出的结果与输入无关,仅与状态有关。所以我们这里用到3个状态,代码如下所示:
Solution:
module top_module ( input clk, input areset, input x, output z ); parameter S0 = 2'd0, S1 = 2'd1, S2 = 2'd2; reg [1:0] current_state, next_state; always @(*) begin case(current_state) S0: next_state = x ? S1 : S0; S1: next_state = x ? S2 : S1; S2: next_state = x ? S2 : S1; endcase end always @(posedge clk or posedge areset) begin if(areset)begin current_state <= S0; end else begin current_state <= next_state; end end assign z = (current_state == S1); endmodule
题意与上题相同,此时用米利型状态机实现。下面是官方提供的状态转移提示:
module top_module ( input clk, input areset, input x, output z ); parameter S0 = 1'b0, S1 = 1'b1; reg current_state,next_state; always @(*) begin case(current_state) S0: next_state = x ? S1 : S0; S1: next_state = S1; endcase end always @(posedge clk or posedge areset) begin if(areset)begin current_state <= S0; end else begin current_state <= next_state; end end assign z = ((current_state == S0) && x) || ((current_state == S1) && ~x); endmodule
今天先更新这几题吧,大家如果对转补码的题目还有什么疑问欢迎评论交流,代码有不足之处还望指正。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。