Verilog에서 유한 상태 시스템을 구현하는 중이고 문제가 발생했습니다. 그러나 문제가 무엇인지는 알지만 해결 방법을 모르겠습니다.FSM 컴퓨터의 상태가 현재 상태를 업데이트하는 시계 문제로 인해 너무 빠르게 변경됩니다.
이 내 현재 코드입니다 :
module moore_SM(clk, rstn, btn, z, rstLED, state);
//Port Assignments
input clk, rstn;
input [2:0] btn;
output z;
output reg rstLED;
output reg [5:0] state;
//Internal Port Assignments
reg [1:0] w, x; //NOTE: This is typically the input in FSM,
//but it is internal because there is a conversion from btn to w.
reg [2:0] y, Y; //Present state and next state respectively
reg [2:0] pstBtn;
reg [31:0] cnt;
//Define some parameters
//Input Type (i.e. A, B or C)
parameter [1:0] A = 2'b00, B = 2'b01, C = 2'b11, DC = 2'b10; //DC => don't care - shouldn't affect FSM
//State (i.e. S1, S2, S3, S4, S5 or S6)
parameter [2:0] S1 = 3'b000, S2 = 3'b001, S3 = 3'b010, S4 = 3'b011, S5 = 3'b100, S6 = 3'b101;
initial begin
state = 0;
end
//Determine which button is active
always @(*)
begin
case(btn)
3'b110: begin w = A; end
3'b101: begin w = B; end
3'b011: begin w = C; end
// default: w = DC;
endcase
end
//Define the next state and output combinational circuits
always @(w,y)
begin
case(y)
S1: begin
state = 6'b000001;
if(w == A) begin Y = S2; end
else begin Y = S1; end
end
S2: begin
state = 6'b000010;
if(w == B) begin Y = S3; end
else begin if(w == A) begin Y = S2; end
else Y = S1; end
end
S3: begin
state = 6'b000100;
if(w == A) begin Y = S2; end
else begin if(w == B) begin Y = S4; end
else Y = S1; end
end
S4: begin
state = 6'b001000;
if(w == A) begin Y = S5; end
else begin Y = S1; end
end
S5: begin
state = 6'b010000;
if(w == A) begin Y = S2; end
else begin if(w == B) begin Y = S3; end
else Y = S6; end
end
S6: begin
state = 6'b100000;
if(w == A) begin Y = S2; end
else begin Y = S1; end
end
//default: Y = 3'b111;
endcase
end
//assign z = (Y == S2);
//Define the sequential block
always @(posedge clk)
begin
y <= Y;
end
endmodule
이 코드는 패턴 ABBAC를 식별 할 예정이다. 나는이 논리가이 목적을 달성한다고 믿는다.
그러나 문제가 발생했습니다. 세 개의 버튼 중 하나를 누르면 첫 번째 항상 차단 - always @(*)
- 변경 사항을 실행하고 평가합니다. 버튼의 상태가 인코딩되어 w.
에 저장됩니다. 동시에 다음 블록 인 always @(w,y)
이 변경을 감지하고 상주 할 상태를 결정합니다. 예상했던대로 입력을 A
으로 보내면 기기가 S1
에서 S2
으로 이동합니다.
입력을 B
으로 보내면 기기는 상태 S1
으로 다시 이동합니다. 내가 몇 가지를 바꾼 후에 나는 그 문제가 무엇인지를 밝혀 냈습니다. 마지막 항상 블록에 주목하십시오 : always @(posedge clk).
이 항상 블록은 현재 상태를 계속 업데이트합니다. y.
버튼을 누르면 두 번째 항상 블록 인 always @(w,y),
이 업데이트 된 y
을 50mHz로 수신한다고 가정합니다. 단추를 눌렀다 놓을 수있는 것보다 훨씬 빠릅니다. 상태가 S2
인 동안 B
버튼을 누르면 상태가 지속적으로 업데이트되어 S3
에서 S4
으로, 그 다음으로는 S1
으로 빠르게 변경됩니다.
그렇다면이 문제를 해결할 수있는 방법이 생길 것 같습니다. 기본적으로 버튼을 누를 때마다 하나의 상태 만 변경하는 방법이 필요합니다.
실험용 보드에서이 코드를 주로 테스트합니다. 나는 테스트 벤치를 작성했지만, 시뮬레이션은 내가 디자인 보드에서 보는 것과 일치하지 않는 것처럼 보인다. 경우 누군가가 테스트 벤치 코드를보고 싶어, 나는 아래에 게시 :
`timescale 1ns/1ns
module moore_SM_TB();
reg clk;
reg [2:0] btn;
wire [5:0] state;
wire z;
wire rstLED;
initial begin
clk = 1;
#0 btn = 3'b111;
#50 btn = 3'b110;
#50 btn = 3'b111;
#50 btn = 3'b101;
#50 btn = 3'b111;
#50 btn = 3'b011;
#50 btn = 3'b111;
end
always begin
#20 clk = ~clk;
end
//MUT
moore_SM MUT (clk, 0, btn, z, rstLED, state);
endmodule
참고 : 나는이 솔루션은 궁극적으로 버튼을 처리하는 방법을 수정 포함 할 것이다 생각합니다. 버튼을 놓으면 변경 사항으로 등록됩니다. 따라서 기본 상태를 주석 처리해야했기 때문에 컴퓨터가 어느 상태에 있는지도 알 수 있습니다.
업데이트 : 코드를 디버깅하려고 시도한 위의 FSM 축소 버전을 작성했습니다. 시퀀스 AB를 감지하려고 시도합니다.
module moore_SM(clk, btn, rstN, state, rstLED);
//Port assignments
input clk;
input rstN;
input [2:0] btn;
output reg rstLED;
output reg [5:0] state;
//Internal Port Assignments
reg [1:0] w;
reg [2:0] y, Y;
reg [2:0] pstBtn;
//Define some parameters
parameter [1:0] A = 2'b00, B = 2'b01, C = 2'b11, DC = 2'b10;
parameter [2:0] S1 = 3'b000, S2 = 3'b001, S3 = 3'b010, S4 = 3'b011, S5 = 3'b100, S6 = 3'b101;
//Initialize some values to prevent Quartus from doing
initial
begin
y = S1;
Y = y;
state = 0;
rstLED = 0;
end
always @(*)
begin
if(btn == pstBtn) begin w = DC; end
else begin
case(btn)
3'b110: w = A;
3'b101: w = B;
3'b011: w = C;
default: w = DC;
endcase
end
end
always @(*)
begin
case(y)
S1: begin
state = 6'b000001;
if(w == A) begin Y = S2; end
else begin Y = S1; end
end
S2: begin
state = 6'b000010;
if(w == B) begin Y = S3; end
if(w == DC) begin Y = S2; end
else begin Y = S1; end
end
S3: begin
state = 6'b000100;
if(w == DC) begin Y = S3; end
else begin Y = S1; end
end
default: begin state = 6'b100000; Y = S1; end
endcase
end
//Update state and check for reset signal
always @(posedge clk, negedge rstN)
begin
pstBtn <= btn;
if(rstN == 0) begin y <= S1; rstLED <= 1; end
else begin y <= Y; rstLED <= 0; end
end
endmodule
마지막 항상 블록의 상태를 "샘플링"하려고합니다. 과거에이 방법을 사용했지만 여기서는 효과가없는 것 같습니다. 단추를 누를 때마다 상태가 변경되지 않습니다. 이것이 타이밍 문제인지 지금 궁금합니다.
상태가 시계의 가장자리에서 바뀌어야합니다. 조합 코드가 아닙니다. – Morgan
코드를 다시 살펴본 후 이것이 무엇을하는지 믿습니다. 조합 블록은 다음 상태 인 'Y'를 정의하고 클록 에지에서 현재 상태 'y'를 업데이트한다. – Mlagma
아니요,이 책에서는 'Y'(명료하게하기 위해 * nextState * 또는 * next_state *라고도 함)가 조합 적으로 변경되고 있음을 보여줍니다. 그러나 * nextState * 값은 다음 클럭 에지에만 등록됩니다. 'always @ (posedge clk) ... y <= Y;' – smci