赞
踩
上行1000的计数器
生成一个从 0 到 999(含 0)计数的计数器,周期为 1000 个周期。复位输入是同步的,应将计数器复位至0。
低电平有效,高电平复位。
module top_module (
input clk,
input reset,
output [9:0] q
);
always @ (posedge clk)
if(reset)
q <= 10'b0;
else if(q == 10'd999)
q <= 10'b0;
else
q <= q + 1'b1;
endmodule
构造一个四位移位寄存器,同时也能做下行计数器(10,9,8…)
当shift_ena为 1 时,数据data的高位先移动到移位寄存器。(暂存)
当前移位寄存器中的数字在count_ena为 1 时逐时钟的进行递减。
shift_ena和count_ena没有重要级先后顺序,因为他们不会同时使能。
由于递减,因此我们需要找到最大值,q为4位,8421,因此可表示的最大数为15
module top_module ( input clk, input shift_ena, input count_ena, input data, output [3:0] q ); reg [3:0] q_temp; always @ (posedge clk)begin if(shift_ena == 1'b1) q_temp <= {q[2:0],data}; else if(count_ena == 1'b1)begin if(q_temp <= 4'd0)begin q_temp <= 4'd15; end else q_temp <= q_temp - 1'b1; end else q_temp <= q_temp; end assign q = q_temp; endmodule
构建一个有限状态机,用于在输入位流中搜索序列1101。
找到1101序列后,应将start_shifting设置为 1,直到重置。
由于检测序列1101,因此共设置五个状态:空闲状态和四位数值接收的四个状态。
module top_module ( input clk, input reset, // Synchronous reset input data, output start_shifting ); parameter IDLE = 5'b00001; parameter S1 = 5'b00010; parameter S2 = 5'b00100; parameter S3 = 5'b01000; parameter S4 = 5'b10000; reg [4:0] state,next_state; //第一段,状态寄存器 always @ (posedge clk) if(reset) state <= IDLE; else state <= next_state; //第二段,组合逻辑描述状态转移 always @ (*)begin case(state) IDLE : next_state = data ? S1 : IDLE; S1 : next_state = data ? S2 : IDLE; S2 : next_state = data ? S2 : S3; S3 : next_state = data ? S4 : IDLE; S4 : next_state = S4; default: next_state = IDLE; endcase end //第三段,组合逻辑描述输出 always@(*) start_shifting = (state == S4); endmodule
作为用于控制移位寄存器的FSM的一部分,我们希望能够在检测到正确的位模式时使能移位寄存器正好4个时钟周期。
我们在上一题fsmseq中已经完成了序列检测的处理,因此 FSM 的这一部分仅处理 4 个周期的移位寄存器启用。
当有限状态机被复位时,将shift_ena拉高4个周期,之后保持为0直到再次复位。
根据图可看出,复位是高的时候,输出也一直是高电平。
因此可以设置三个状态,空闲状态,使能拉高状态以及保持为0的状态。其中使能拉高状态下我们设计计数器来完成,拉高四个周期因此设计模4计数器。
module top_module ( input clk, input reset, // Synchronous reset output shift_ena ); parameter IDLE = 3'b001; parameter ENA = 3'b010; parameter STOP = 3'b100; reg [3:0] state,next_state; reg [2:0] counter; //第一段,状态寄存器 always @(posedge clk) begin if(reset) begin state <= IDLE; end else begin state <= next_state; end end //第二段,状态转移 always@(*) case(state) IDLE: next_state = ENA; ENA : next_state = (counter == 3'd3 ) ? STOP : ENA; STOP: next_state = STOP; default: next_state = IDLE; endcase //第三段,描述输出 always@(*) shift_ena = (state == ENA | state == IDLE); //设计一个模4计数器 always @(posedge clk) begin if(reset) counter <= 3'd0; else if(next_state == ENA) //因为采用的是时序逻辑,因此用次态 counter <= counter + 1'b1; else counter <= 3'd0; end endmodule
题目理解:
空闲状态IDLE:主要是对复位初始状态,高电平复位,低电平开始进行序列的检测。
序列检测包括三个状态,S1,S11,S110。状态转移的条件是输入data ( 只要检测错误就要重新检测)
shift_ena抬高四个周期的状态:在序列接收成功后进入此状态,该状态包括ENA0-ENA3四个状态
计数状态:当输入done_counting为高电平的时候跳转到等待通知状态。否则一直计数
等待通知状态:当等待通知输入ack为1的时候,重置以查找下一个出现的启动序列,否则的话一直处于等待通知状态。
至此我们即可完成第一二段状态机。
同时以下三个信号是输出,在第三段状态机中描述。
output shift_ena,
output counting,
output done,
module top_module ( input clk, input reset, // Synchronous reset input data, output shift_ena, output counting, input done_counting, output done, input ack ); //十个状态,这里就不采用独热码了 parameter IDLE = 4'd0; parameter S1 = 4'd1; parameter S11 = 4'd2; parameter S110 = 4'd3; parameter ENA0 = 4'd4; parameter ENA1 = 4'd5; parameter ENA2 = 4'd6; parameter ENA3 = 4'd7; parameter COUNT = 4'd8; parameter WAIT = 4'd9; reg [3:0] state,next_state; //第一段,状态寄存器 always@(posedge clk) if(reset) state <= IDLE; else state <= next_state; //第二段,状态转移 always@(*) case(state) IDLE :next_state = data ? S1 : IDLE; S1 :next_state = data ? S11 : IDLE; S11 :next_state = data ? S11 : S110; S110 :next_state = data ? ENA0 : IDLE; ENA0 :next_state = ENA1; ENA1 :next_state = ENA2; ENA2 :next_state = ENA3; ENA3 :next_state = COUNT; COUNT :next_state = done_counting ? WAIT : COUNT; WAIT :next_state = ack? IDLE : WAIT; default: next_state = IDLE; endcase //第三段,描述输出 always @ (posedge clk )begin if(reset)begin shift_ena <= 1'b0; counting <= 1'b0; done <= 1'b0; end else case(next_state) IDLE,S1,S11,S110:begin shift_ena <= 1'b0; counting <= 1'b0; done <= 1'b0; end ENA0,ENA1,ENA2,ENA3:begin shift_ena <= 1'b1; counting <= 1'b0; done <= 1'b0; end COUNT:begin shift_ena <= 1'b0; counting <= 1'b1; done <= 1'b0; end WAIT:begin shift_ena <= 1'b0; counting <= 1'b0; done <= 1'b1; end default:begin shift_ena <= 1'b0; counting <= 1'b0; done <= 1'b0; end endcase end endmodule
该题目是前面四个题目的结合。
有四个状态是移位拉高四个周期的状态,上题中我们这里没有其他的操作,只是拉高四位,二本题目需要进行四位的移位,首先是最高有效位。同时这 4 位决定了计时器延迟的持续时间(计数器的计数周期)。我将其称为delay延迟[3:0]。 ——可表示的最大数是15
增加计数器状态,来给予精确的计数,计数周期为(delay[3:0] + 1 )* 1000 个时钟周期,比如 delay = 0 时,计数值为 1000 个周期。delay = 5 代表 6000 个周期。输出count表示当前剩余的计数周期(计数的千位数),这就应该等于1000个周期的延迟,比如说还剩1000周期,那么输出1,还剩999个周期,输出0,还剩15000个周期,输出15,当计数停止后,count可输出任意数。
当计数完成后,done 信号置为高电平,通知上层应用计数器计数完成。
后等待 ack 信号,当该信号置高后,状态机清除 done 信号,返回空闲状态等待重新捕获下一个 1101 序列,否则一直处于等待状态,等ack高电平的到来。
上图中斜线表示当前信号为X,也就是状态机不关心的值(省略),如图存在序列1101,同时在延迟了四个周期后,开始计数,同时counting置为了1。可看出电路计数周期是2000,因此delay为1,所以 delay[3:0] 数值为 4’b0001 。在后续的第二个计数周期中,count能看出是e,计数周期是15000.
module top_module ( input clk, input reset, input data, input ack, output [3:0] count, output counting, output done ); parameter S = 4'd0; parameter S1 = 4'd1; parameter S11 = 4'd2; parameter S110 = 4'd3; parameter DELAY = 4'd4; parameter COUNT = 4'd5; parameter WAIT = 4'd6; reg [3:0] cur_state ; reg [3:0] next_state ; reg [1:0] cnt_delay ; //用来接收序列流的计数器 reg [15:0] cnt ; reg [3:0] delay ; //第一段同步时序描述状态转移 always @(posedge clk)begin if(reset) cur_state <= S; else cur_state <= next_state; end //第二段采用组合逻辑,并根据状态转移条件来描述状态转移规律 always@(*)begin case(cur_state) S : next_state = data ? S1 :S; S1 : next_state = data ? S11 :S; S11 : next_state = data ? S11 :S110; S110 : next_state = data ? DELAY :S; DELAY: if(cnt_delay == 2'd3) next_state = COUNT; else next_state = DELAY; COUNT: if(cnt == 16'd0) next_state = WAIT; else next_state = COUNT; WAIT : if(ack) next_state = S; else next_state = WAIT; default: next_state = S; endcase end //第三段,组合逻辑描述描述输出 always@(*)begin count = cnt/1000; //用来输出千位 counting = (cur_state == COUNT); done = (cur_state == WAIT); end //延时计数器,计数4个时钟,来接收delay数据 always @(posedge clk)begin if(reset) cnt_delay <= 2'd0; else if(cur_state == DELAY)begin cnt_delay <= cnt_delay + 1'b1; end else cnt_delay <= cnt_delay; end //根据接收到的delay数据进行计数周期的运算 always @(posedge clk)begin if(reset) cnt <= 16'd0; else if(cur_state == DELAY) cnt <= (delay+1'b1) * 1000-1'd1; else if(cur_state == COUNT) cnt <= cnt - 1'd1; else cnt <= cnt; end //接收delay 的四位数据以计算计数周期,根据每一位的delay计算出十进制数,然后套用计数周期计算公式 //delay为0001,则在上面代入公式计算出cnt=1999 always@(*)begin if(cur_state == DELAY) case(cnt_delay) 2'd0: delay[3] = data; 2'd1: delay[2] = data; 2'd2: delay[1] = data; 2'd3: delay[0] = data; default:; endcase else delay = 4'b0000; end endmodule
该题给出了如果的状态转移图,然后采用独热码的方式来编写组合逻辑部分(状态转移以及输出。)
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 ); // 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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。