微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > 状态机在疑惑

状态机在疑惑

时间:10-02 整理:3721RD 点击:
大家帮我理解理解!谢谢了!
我的理解:
比如说状态机:

1:
always @(CS or in)
case(CS)
S0: if(in)NS=S1;
elseNS=S0;

组合逻辑跟时序没有关系,它不断的对输入信号(in)进行判断,只要输入信号发生变化就改变NS,反之NS=CS保持原状态

always@(posedge clk)

case(NS)
S0ut<=2'b00;

如果这样说的没错,可不可以理解为在第一个上升沿对当前输入进行判断,决定下一状态,同时输出上一状态NS,也就是说在输出的同时进行判断!算是同步吧!

不知道我理解的对不对,愿大家指导!
2:
我想要问的是:

如果我改变状态的条件不是有输入决定的,而是由逻辑的运算结果决定的,可不可以去代替输入(IN)进行判断?
比如:
always@(posedge clk)
begin
count<=count+1;
if(count==10)
in<=1;
count<=0;
else
in<=0;

end

3:
我想解决的:

就是我想把一个大模块,分成小模块,想用状态机解决,可是试了好多次,结果不正确,有时候就是不同步,当然加上RESET也不行!
所以我 对FPGA的工作流程产生的不小的疑问!希望大家能解决我的疑惑!

1。
always@(posedge clk)
case(NS)
S0 out<=2'b00;
这是次态寄存器输出,他和现态组合逻辑输出效果是一样的,但是比现态寄存器输出要早一拍,具体怎么输出要有具体的时序要求决定。
还有你这里说的同步是什么意思?
2。完全没有问题。
3。你可以把一个大模块分成小模块,每一个小模块用状态机,大模块用状态机,大模块的状态机在适当的时候产生信号激活小模块状态机,这就是所谓major FSM和minor FSM。可以给一个例子,说明你要做什么,你怎么做了但行不通。

比交通灯简单点,这是代码
当然这个代码不对,我写在一个模块里没错误,想写成状态机就不行了,主要就是不能在不同的模块里该同一变量赋值
用tir,要做个三态驱动吗,怎么做呢?
我所指的同步是在改变状态的同时有输出
还请大虾指点

module traffic1(CLK,LAMP,nrst,num);
output[7:0] num;
output[2:0] LAMP;
input CLK,nrst;
reg[7:0] num,numa;
reg[2:0] LAMP,CS,NS;
reg temp;
parameter[2:0] IDLE=3'b000, S1=3'b001, S2=3'b010,S3=3'b011;
parameter[7:0] red=8'd15,yellow=8'd10,bule=8'd5;
always @(posedge CLK )
if(!nrst)
CS<=IDLE;
else
CS<=NS;
always @(CS or temp )//三灯循环点亮,在变换状态的同时
begin
NS=3'bx;
case(CS)
IDLE: begin
if(temp) NS=IDLE;
if(!temp) NS=S1;
end

S1:begin
if(temp) NS=IDLE;
if(!temp) NS=S2;
end
S2:begin
if(temp) NS=IDLE;
if(!temp) NS=S3;
end
S3:begin
if(temp) NS=IDLE;
if(!temp) NS=S1;
end

default:NS=IDLE;
endcase

end
always @(posedge CLK )//三灯循环点亮,在变换状态的同时
//改变倒计时,时间
if(!nrst)
begin
LAMP<=3'b000;
end
else
begin
case(NS)
IDLE: begin
LAMP<=3'b000;
numa<=8'd0;
end

S1:begin
LAMP<=3'b001;
numa<=red;
end

S2:begin
LAMP<=3'b010;
numa<=yellow;
end

S3:begin
LAMP<=3'b100;
numa<=bule;
end
endcase
end

always @(posedge CLK ) //倒计时模块
if(!nrst)
num<=8'd0;
else
begin //想在倒计时到0时重新给倒计时赋值
num<=numa;//,因为不能在两个模块给同一变量赋值,
//这里没办法了我用一个中间变量(numa)传递
if(num>0)//最小情况为1
begin
if(num[3:0]==0)
begin
num[3:0]<=9;
num[7:4]<=num[7:4]-1;
end
else
num[3:0]<=num[3:0]-1;

if(num==1) temp<=0;//因为是非阻塞,全结束之前还是旧值,结束后才变为0,
//所以等与1时结束后就为0 ,这样理解行吗?
end

else
temp<=0; //到0时要改变状态

end
endmodule

谢谢关心我的人

1.
if(temp) NS=IDLE;
if(!temp) NS=S1;
这个地方我不知道会不会综合出latch,也许综合器能认出来是组合逻辑,但最好改为:
if(temp)
NS=IDLE;
else
NS=S1;
2.
在不同的模块对一个信号多次赋值是不行的,相当于一个信号点有多个信号源输入,这需要仲裁。
3.建议将次态逻辑和输出逻辑放在一起,采用现态组合逻辑输出,这样的效果和次态寄存器输出一样,但是少用一些寄存器资源。
我修改如下,加了一个计数器来计时,状态转移模块在状态转移时产生信号将计数器清零重新开始计数:
reg [7:0] count;
reg clr_count;
always @( CS)//三灯循环点亮,在变换状态的同时
begin
clr_count = 1'b1
case( CS, coun t)
IDLE:
NS = S1;
LAMP = 3'b000;
S1:
LAMP = 3'b001;
if ( count == red )
begin
clr_count = 1'b0;
NS = S2;
end
else
NS = S1;
S2:
LAMP = 3'b010;
if ( count == yellow )
begin
clr_count = 1'b0;
NS = S3;
end
else
NS = S2;
S3:
LAMP = 3'b100;
if ( count== blue )
begin
clr_count = 1'b0;
NS = S1;
end
else
NS = S3;
default:
LAMP = 3'b000;
NS = IDLE;
endcase
end
always @(posedge clk)
begin
if (clr_count==1'b0 or nrst==1'b0 )
count = 0;
else
count <= count + 1;
end

终于都分成模块了,虽然程序很小,但是就是想掌握这样的方法



//LAMP:灯的状态
//num: 倒计时
//numa: 倒计时赋值的中间变量
module traffic0(CLK,LAMP,nrst,num);
output[7:0] num;
output[2:0] LAMP;
input CLK,nrst;
reg[7:0] num,numa;
reg[3:0] CS,NS;
reg[2:0] LAMP;
reg temp;//倒计时赋值标志
parameter IDLE=4'b001, S1=4'b0010, S2=4'b0100,S3=4'b1000; //one_hot
parameter red=8'd15,yellow=8'd10,bule=8'd5; //红,黄,蓝各亮的时间
always @(posedge CLK )
if(!nrst)
CS<=IDLE;
else
CS<=NS;
always @(CS or temp )
begin
NS=4'bx;
case(CS)
IDLE:
if(temp)
NS=IDLE;
else
NS=S1;
S1:
if(temp)
NS=S1;
else
NS=S2;
S2:
if(temp)
NS=S2;
else
NS=S3;

S3:
if(temp)
NS=S3;
else
NS=S1;

default:NS=IDLE;
endcase
end
//
always @(NS or nrst)//倒计时模块 赋值模块

if(!nrst)
begin
numa=8'd0;
end
else
begin
case(NS)
IDLE:
numa=8'd0;
S1:
numa=red;
S2:
numa=yellow;
S3:
numa=bule;
endcase
end

always @(posedge CLK)//灯的状态模块

if(!nrst)
LAMP<=3'b000;
else
begin
case(NS)
IDLE:
LAMP<=3'b000;
S1:
LAMP<=3'b001;

S2:
LAMP<=3'b010;

S3:
LAMP<=3'b100;
endcase
end
//~

always @(posedge CLK ) //倒计时模块
if(!nrst)
begin
num<=0;
temp<=0;
end
else
begin

if(!temp)
begin
num<=numa;
temp<=1;
end

else
begin
if(num>0)

begin
if(num[3:0]==0)
begin
num[3:0]<=9;
num[7:4]<=num[7:4]-4'b0001;
end
else
num[3:0]<=num[3:0]-4'b0001;

if(num==1)
temp<=0;
else
temp<=1;
end

else
temp<=0;
end

end


endmodule

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top