HDLBits答案(22)_基于有限状态机的计数器
基于有限狀態(tài)機(jī)的計(jì)數(shù)器
HDLBits鏈接
前言
今天更新搭建更大的電路部分的習(xí)題,內(nèi)容主要跟計(jì)數(shù)器和有限狀態(tài)機(jī)有關(guān)。
題庫
Counter with period 1000
構(gòu)造一個(gè)0-999的計(jì)數(shù)器,同步高電平復(fù)位。
Solution:
module top_module (input clk,input reset,output [9:0] q);always @(posedge clk) beginif(reset) beginq <= 10'd0;endelse if(q == 10'd999) beginq <= 10'd0;endelse beginq <= q + 1'b1;endendendmodule4-bit shift register and down counter
構(gòu)造一個(gè)4bit的移位寄存器,同時(shí)也可以做倒數(shù)的計(jì)數(shù)器使用。其中當(dāng)shift_ena為1時(shí)數(shù)據(jù)data的高位先進(jìn)到移位寄存器中;當(dāng)count_ena為1時(shí),計(jì)數(shù)器從寄存器中存儲的數(shù)開始逐時(shí)鐘遞減;shift_ena和count_ena沒有重要級先后順序,因?yàn)樗麄儾粫瑫r(shí)使能。
Solution:
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) beginif(shift_ena) beginq_temp <= {q_temp[2:0],data};endelse if(count_ena) beginif(q_temp == 4'd0) beginq_temp <= 4'd15;endelse beginq_temp <= q_temp - 1'b1;endendendassign q = q_temp;endmodule我以為計(jì)數(shù)器到0時(shí)停止計(jì)數(shù),本來按這個(gè)邏輯寫的,然后在線提交時(shí)出錯(cuò)。作者的意思是0后面下一個(gè)狀態(tài)是15,這個(gè)大家做題時(shí)需注意。
FSM:Sequence 1101 recognizer
構(gòu)造一個(gè)有限狀態(tài)機(jī)檢測data中的1101序列,如果檢測到該序列,則將輸出一直拉高直到同步復(fù)位信號為高。
Solution:
module top_module (input clk,input reset, // Synchronous resetinput data,output start_shifting);parameter IDLE = 3'd0, S1 = 3'd1, S2 = 3'd2;parameter S3 = 3'd3, OUT = 3'd4;reg [2:0] current_state, next_state;always @(*) begincase(current_state)IDLE: next_state = data ? S1 : IDLE;S1: next_state = data ? S2 : IDLE;S2: next_state = data ? S2 : S3;S3: next_state = data ? OUT : IDLE;OUT: next_state = OUT;default: next_state = IDLE;endcaseendalways @(posedge clk) beginif(reset) begincurrent_state <= IDLE;endelse begincurrent_state <= next_state;endendassign start_shifting = current_state == OUT;endmoduleFSM:Enable shift register
當(dāng)有限狀態(tài)機(jī)被復(fù)位時(shí),將shift_ena拉高4個(gè)周期,之后保持為0直到再次復(fù)位。
Solution:
module top_module (input clk,input reset, // Synchronous resetoutput shift_ena);parameter IDLE = 2'd0, ENA = 2'd1, STOP = 2'd2;reg [1:0] current_state, next_state;reg [2:0] counter;always @(*) begincase(current_state)IDLE: next_state = ENA;ENA: next_state = (counter == 3'd3) ? STOP : ENA;STOP: next_state = STOP;default: next_state = IDLE;endcaseendalways @(posedge clk) beginif(reset) begincurrent_state <= IDLE;endelse begincurrent_state <= next_state;endendalways @(posedge clk) beginif(reset) begincounter <= 3'd0;endelse begincase(next_state)IDLE: counter <= 3'd0;ENA: counter <= counter + 1'b1;STOP: counter <= 3'd0;default: counter <= 3'd0;endcaseend endassign shift_ena = current_state == ENA | current_state == IDLE;endmodule需注意的是復(fù)位一直為高的時(shí)候輸出也一直為高電平;
FSM:The complete FSM
官方提供的狀態(tài)轉(zhuǎn)移圖
Solution:
module top_module (input clk,input reset, // Synchronous resetinput data,output shift_ena,output counting,input done_counting,output done,input ack );parameter S = 4'd0, S1 = 4'd1, S11 = 4'd2, S110 = 4'd3;parameter B0 = 4'd4, B1 = 4'd5, B2 = 4'd6, B3 = 4'd7;parameter Count = 4'd8, Wait = 4'd9;reg [3:0] current_state, next_state;always @(*) begincase(current_state)S: next_state = data ? S1 : S;S1: next_state = data ? S11 : S;S11: next_state = data ? S11 : S110;S110: next_state = data ? B0 : S;B0: next_state = B1;B1: next_state = B2;B2: next_state = B3;B3: next_state = Count;Count: next_state = done_counting ? Wait : Count;Wait: next_state = ack ? S : Wait;default: next_state = S;endcaseendalways @(posedge clk) beginif(reset) begincurrent_state <= S;endelse begincurrent_state <= next_state;endendassign 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標(biāo)準(zhǔn)的FSM格式,沒啥說的,畫出狀態(tài)轉(zhuǎn)移表寫就行了。
The complete timer
該道狀態(tài)機(jī)就是前面幾道狀態(tài)機(jī)的組合,大家需注意的是計(jì)數(shù)那邊的部分;之前我將計(jì)數(shù)子的位寬設(shè)置不當(dāng),導(dǎo)致這題卡的挺久,希望大家做題分析時(shí)注意。
Solution:
module top_module (input clk,input reset, // Synchronous resetinput data,output [3:0] count,output counting,output done,input ack );parameter IDLE = 4'd0, S1 = 4'd1, S2 = 4'd2, S3 = 4'd3;parameter C0 = 4'd4, C1 = 4'd5, C2 = 4'd6, C3 = 4'd7;parameter Count_1000 = 4'd8, Done = 4'd9;reg [3:0] current_state, next_state;reg [15:0] num;reg [3:0] delay;reg [3:0] already_count;wire count_state;assign count_state = (num == (delay + 1'b1)*1000) ? 1'b1 : 1'b0;always @(*) beginif(num <= 16'd1000) beginalready_count = 4'd0;endelse if(num > 16'd1000 && num <= 16'd2000) beginalready_count = 4'd1;endelse if(num > 16'd2000 && num <= 16'd3000) beginalready_count = 4'd2;endelse if(num > 16'd3000 && num <= 16'd4000) beginalready_count = 4'd3;endelse if(num > 16'd4000 && num <= 16'd5000) beginalready_count = 4'd4;endelse if(num > 16'd5000 && num <= 16'd6000) beginalready_count = 4'd5;endelse if(num > 16'd6000 && num <= 16'd7000) beginalready_count = 4'd6;endelse if(num > 16'd7000 && num <= 16'd8000) beginalready_count = 4'd7;endelse if(num > 16'd8000 && num <= 16'd9000) beginalready_count = 4'd8;endelse if(num > 16'd9000 && num <= 16'd10000) beginalready_count = 4'd9;endelse if(num > 16'd10000 && num <= 16'd11000) beginalready_count = 4'd10;endelse if(num > 16'd11000 && num <= 16'd12000) beginalready_count = 4'd11;endelse if(num > 16'd12000 && num <= 16'd13000) beginalready_count = 4'd12;endelse if(num > 16'd13000 && num <= 16'd14000) beginalready_count = 4'd13;endelse if(num > 16'd14000 && num <= 16'd15000) beginalready_count = 4'd14;endelse beginalready_count = 4'd15;endendalways @(posedge clk) beginif(reset) beginnum <= 16'd0;endelse if(next_state == Done) beginnum <= 16'd0;endelse if(next_state == Count_1000) beginnum <= num + 16'd1;endendalways @(*) begincase(current_state)IDLE: next_state = data ? S1 : IDLE;S1: next_state = data ? S2 : IDLE;S2: next_state = data ? S2 : S3;S3: next_state = data ? C0 : IDLE;C0:beginnext_state = C1;delay[3] = data;end C1:beginnext_state = C2; delay[2] = data;end C2:beginnext_state = C3; delay[1] = data;end C3:beginnext_state = Count_1000; delay[0] = data;end Count_1000: next_state = count_state ? Done : Count_1000;Done: next_state = ack ? IDLE : Done;default: next_state = IDLE;endcaseendalways @(posedge clk) beginif(reset) begincurrent_state <= IDLE;endelse begincurrent_state <= next_state;endendassign count = (current_state == Count_1000) ? (delay - already_count) : 4'd0;assign counting = (current_state == Count_1000);assign done = current_state == Done;endmoduleFSM:One-hot logic equations
用one-hot編碼的狀態(tài)寫出狀態(tài)轉(zhuǎn)移代碼。
Solution:
module top_module(input d,input done_counting,input ack,input [9:0] state, // 10-bit one-hot current stateoutput 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結(jié)語
該小結(jié)就算更新結(jié)束了,下面剩的也不多了,爭取在開學(xué)前全部刷完。如有不對的還望大家指正。
總結(jié)
以上是生活随笔為你收集整理的HDLBits答案(22)_基于有限状态机的计数器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: HDLBits答案(21)_Verilo
 - 下一篇: HDLBits答案(23)_找BUG