写状态机的流程(实例)
一、实验目标
设计两个可综合的电路模块:第一个模块(M1)能把4位的并行数据转化为符合以下协议的串行数据流,数据流用scl和sda两条线传输,sclk为输入的时钟信号,data[3:0]为输入数据,ack为M1请求M0发送数据信号。第二个模块(M2)能够把串行数据流内的信息接收到,并转换为相应的16条信号线的高电平,即若数据为1,则第一条线路为高电平,数据为n,则第N条线路为高电平。M0为测试用信号模块。该模块接收M1发出的ack信号,并产生新的测试数据data[3:0],如图1所示。
图1 可综合模块结构及波形
通信协议:scl为不断输出的时钟信号,如果scl为高电平时,sda由高变低时刻,串行数据流开始;如果scl为高电平时,sda由低变高时刻,串行数据结束。sda信号的串行数据位必须在scl为低电平时变化,若变为高则为1,否则为零。
二、RTL级数据流
根据图1的可综合结构图,我们可以得到各模块之间的数据传输流程。
模块M1发送ack(高电平)信号 → 模块M0在检测到ack上升沿后,开始发送数据 → 模块M1在检测到ack为高电平之后开始数据。同时M1启动状态机将并行数据转化为串行数据,M2按照协议接收串行数据,进行处理并按照数据值在相应位输出高电平。图2,为M1和M2模块的RTL视图。
图2 M1和M2模块的RTL视图
三、时序
本题的时序可以分成三个部分进行理解,产生开始阶段、产生结束信号阶段、数据传输阶段。只要按照时序图,在scl相应的状态时,控制sda变化即可。
if(scl && ack) //generate start signal
begin
sdabuf <= 0;
state <= bit1;
end
else
begin
state <= start;
end
bit1:
if(!scl) //change data in low of scl
begin
sdabuf <= databuf[3];
state <= bit2;
end
else
state <= bit1;
bit2:
if(!scl) //change data in low of scl
begin
sdabuf <= databuf[2];
state <= bit3;
end
else
state <= bit2;
bit3:
if(!scl) //change data in low of scl
begin
sdabuf <= databuf[1];
state <= bit4;
end
else
state <= bit3;
bit4:
if(!scl) //change data in low of scl
begin
sdabuf <= databuf[0];
state <= bit5;
end
else
state <= bit4;
bit5:
if(!scl)
begin
sdabuf <= 0;//pull down the bus
state <= stop;
end
else
state <= bit5;
stop:
if(scl)
begin
sdabuf <= 1;//pull on the bus
state <= IDLE;
end
else
state <= stop;
IDLE:
begin
link_sda <= 0;//drop out from bus
ack <= 0;
state <= ready;
end
这个题目只有一个开关变量相对比较简单。
四、状态转换图
本想画张图,但感觉花1个小时画张并不实用的图,不如简单一些,用几个变量表达一下。
1.对于M1模块
parameter ready = 8'b0000_0000,//等待ack=1
start = 8'b0000_0001,//开始信号
bit1 = 8'b0000_0010,//第三位数
bit2 = 8'b0000_0100,//第二位数
bit3 = 8'b0000_1000,//第一位数
bit4 = 8'b0001_0000,//第0位数
bit5 = 8'b0010_0000,//为结束信号做准备
stop = 8'b0100_0000,//结束信号
IDLE = 8'b1000_0000;//
2.对于M2模块
开始信号和结束信号分别拥有单独的always进行检测,当满足条件时置位相应的标志位,然后开始传输数据。
always @ (negedge sda)
if(scl)
StartFlag <= 1;
else if(EndFlag)
StartFlag <= 0;
always @ (posedge sda)
if(scl)
begin
EndFlag <= 1;
pdatabuf <= pdata;//得到数据,放入寄存器中.只有在接收完毕之后,patabuf才能得到数据
end
else
EndFlag <= 0;
always @ (posedge scl)
begin
if(StartFlag)
begin
case(mstate)
sbit0:
begin
mstate <= sbit1;
pdata[3] <= sda;
//$display("This is sdabit0");
end
sbit1:
begin
mstate <= sbit2;
pdata[2] <= sda;
//$display("This is sdabit1");
end
sbit2:
begin
mstate <= sbit3;
pdata[1] <= sda;
//$display("This is sdabit2");
end
sbit3:
begin
mstate <= sbit4;
pdata[0] <= sda;
//$display("This is sdabit3");
end
sbit4:
begin
mstate <= sbit0;
//$display("Stop");
end
default:
mstate <= sbit0;
endcase
end//if
else
mstate <= sbit0;//这句话可以确保每次进入case时,首先进入sbit0
end//always
虽然,看明白了这个状态机,但自己写时依然感觉力不从心。只能是多总结,多思考,多练习。
文章评论(0条评论)
登录后参与讨论