您的位置:首页 > 其它

FSM设计之二-----并行数据流转特殊串行数据流

2010-11-28 17:45 656 查看
夏宇闻《Verilog 数字系统设计教程》P216

设计两个可综合电路模块:M1模块能把4位的并行数据转换为符合以下协议的串行数据流,数据流用scl和sda两条线传输,sclk为输入的时钟信号,data[3:0]为输入数据,ack为M1的请求M0发新数据信号。第二个模块M2能把串行数据流内的信息接收到,并转换为相应16条信号线的高电平,即若数据为1,则第一条线路为高电平,数据为n,则第n条数据线为高电平。M0为 测试用的信号发生模块,该模块接收M1发出的ack信号,并产生新的测试数据data[3:0]。

通信协议:scl为不断输出的时钟信号,如果scl为高电平时,sda由高变低时刻,串行数据流开始;如果scl为高电平时,sda由低变高时刻,串行数据流结束。sda信号的串行数据位必须在scl为低电平时变化,若变为高则为1,否则为0。

M1模块的代码如下

`timescale 1ns/1ns
module ptosda
(
input sclk,
input rst_n,
input [3:0] data,
output reg ack,
output reg scl,
output sda
);

reg link_sda;
reg sdabuf;
reg [3:0] databuf;
reg [7:0] state;

parameter ready = 8'b0000_0001,
start = 8'b0000_0010,
bit1  = 8'b0000_0100,
bit2  = 8'b0000_1000,
bit3  = 8'b0001_0000,
bit4  = 8'b0010_0000,
bit5  = 8'b0100_0000,
stop  = 8'b1000_0000,
idle  = 8'b0000_0000;

assign sda = link_sda?sdabuf:1'bz;

always @ (posedge sclk,negedge rst_n)
begin
if(!rst_n)    scl <= 1'b1;
else            scl <= ~scl;
end

always @ (posedge ack)
begin
databuf <= data;
end

always @ (negedge sclk or negedge rst_n)
begin
if(!rst_n)
begin
link_sda<=1'b0;
state <= ready;
sdabuf<=1'b1;
ack<=1'b0;
end
else
begin
case(state)
ready:
if(ack)
begin
link_sda<=1'b1;
state <= start;
end
else
begin
link_sda<=1'b0;
state<=ready;
ack<=1'b1;
end
start:
if(scl && ack)
begin
sdabuf<=1'b0;
state<=bit1;
end
else        state<= start;
bit1:
if(!scl)
begin
sdabuf<=databuf[3];
state<=bit2;
ack<=1'b0;
end
else        state<=bit1;
bit2:
if(!scl)
begin
sdabuf<=databuf[2];
state<=bit3;
end
else        state<=bit2;
bit3:
if(!scl)
begin
sdabuf<=databuf[1];
state<=bit4;
end
else        state<=bit3;
bit4:
if(!scl)
begin
sdabuf<=databuf[0];
state<=bit5;
end
else        state<=bit4;
bit5:
if(!scl)
begin
sdabuf<=1'b0;
state<=stop;
end
else        state<=bit5;
stop:
if(scl)
begin
sdabuf<=1'b1;
state<=idle;
end
else        state<=stop;
idle:
begin
link_sda<=1'b0;
state<=ready;
end
default:
begin
link_sda<=1'b0;
sdabuf<=1'b1;
state<=ready;
end
endcase
end
end

endmodule


M2模块的代码如下

`timescale 1ns/1ns
module out16hi
(
input scl,
input sda,
output reg [15:0] outhigh,
output reg [3:0] pdata,
output reg [3:0] pdatabuf,
output reg start_flag,
output reg end_flag,
output reg [5:0] mstate
);

//reg [5:0] mstate;/* synthesis preserve*/
//reg [3:0] pdatabuf;
//reg start_flag,end_flag;

always @ (negedge sda)
begin
if(scl)
start_flag<=1'b1;
else if(end_flag)
start_flag<=1'b0;
end

always @ (posedge sda)
begin
if(scl)
begin
end_flag<=1'b1;
pdatabuf<=pdata;
end
else
end_flag<=1'b0;
end

parameter ready = 6'b00_0000,
bit0  = 6'b00_0001,
bit1  = 6'b00_0010,
bit2  = 6'b00_0011,
bit3  = 6'b00_0100,
bit4  = 6'b00_0101;

always @ (pdatabuf)
begin
case(pdatabuf)
4'b0001 : outhigh = 16'b0000_0000_0000_0001;
4'b0010 : outhigh = 16'b0000_0000_0000_0010;
4'b0011 : outhigh = 16'b0000_0000_0000_0100;
4'b0100 : outhigh = 16'b0000_0000_0000_1000;
4'b0101 : outhigh = 16'b0000_0000_0001_0000;
4'b0110 : outhigh = 16'b0000_0000_0010_0000;
4'b0111 : outhigh = 16'b0000_0000_0100_0000;
4'b1000 : outhigh = 16'b0000_0000_1000_0000;
4'b1001 : outhigh = 16'b0000_0001_0000_0000;
4'b1010 : outhigh = 16'b0000_0010_0000_0000;
4'b1011 : outhigh = 16'b0000_0100_0000_0000;
4'b1100 : outhigh = 16'b0000_1000_0000_0000;
4'b1101 : outhigh = 16'b0001_0000_0000_0000;
4'b1110 : outhigh = 16'b0010_0000_0000_0000;
4'b1111 : outhigh = 16'b0100_0000_0000_0000;
4'b0000 : outhigh = 16'b1000_0000_0000_0000;
endcase
end

always @ (posedge scl)
begin
if(start_flag)
case(mstate)
bit0:
begin
mstate <= bit1;
pdata[3] <= sda;
$display("I am is sda bit0");
end
bit1:
begin
mstate <= bit2;
pdata[2] <= sda;
$display("I am is sda bit1");
end
bit2:
begin
mstate <= bit3;
pdata[1] <= sda;
$display("I am is sda bit2");
end
bit3:
begin
mstate <= bit4;
pdata[0] <= sda;
$display("I am is sda bit3");
end
bit4:
begin
mstate <= bit0;
$display("I am is sda stop");
end
default:
mstate <= bit0;
endcase
else
mstate <= bit0;
end

endmodule


信号测试模块:

 data
)]顶层模块:

 `timescale 1ns/1ns
module top;
wire [3:0] data;
wire sclk,scl,sda;
wire rst_n;
wire [15:0] outhigh;
wire [3:0] pdata;
wire [3:0] pdatabuf;
wire start_flag,end_flag;
wire [5:0] mstate;

sigdata M0
(
.rst_n(rst_n),
.sclk(sclk),
.data(data),
.ask_for_data(ack)
);

ptosda M1
(
.rst_n(rst_n),
.sclk(sclk),
.ack(ack),
.scl(scl),
.sda(sda),
.data(data)
);

out16hi M2
(
.scl(scl),
.sda(sda),
.outhigh(outhigh),
.pdata(pdata),
.pdatabuf(pdatabuf),
.start_flag(start_flag),
.end_flag(end_flag),
.mstate(mstate)
);

endmodule


仿真结果:



在模块M2的状态机中,如果if(start_flag)没有加上else mstate<=bit0;就会发生状态跳转不正常的现象,只有第一次状态转移正确。

always @ (posedge scl)
begin
if(start_flag)
case(mstate)
bit0:
begin
mstate <= bit1;
pdata[3] <= sda;
$display("I am is sda bit0");
end
bit1:
begin
mstate <= bit2;
pdata[2] <= sda;
$display("I am is sda bit1");
end
bit2:
begin
mstate <= bit3;
pdata[1] <= sda;
$display("I am is sda bit2");
end
bit3:
begin
mstate <= bit4;
pdata[0] <= sda;
$display("I am is sda bit3");
end
bit4:
begin
mstate <= bit0;
$display("I am is sda stop");
end
default:
mstate <= bit0;
endcase
end


就会出现下面的结果:



FSM的设计,用状态变量来记住曾经发生过的事情,这些曾经发生过的事情对于电路下一步时钟操作有非常重要的作用。

在本例程中,无论M1和M2模块的设计都必须用状态变量记住目前所处的状态,才能正确地控制输入和输出。可综合模块的设计必须在电路总体结构明确的情况下,

用状态机写出控制的节拍和步骤后才能进行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: