程序实现一个EEPROM(AT24C02/4/8/16)
代码如下:
`timescale 1ns/1ps
module EEPROM_WR(sda,scl,ACK,RESET,CLK,WR,RD,ADDR,DATA);
output scl;
output ACK;
input RESET;
input CLK;
input WR,RD;
input [10:0] ADDR;
inout sda;
inout [7:0] DATA;
reg ACK;
reg scl;
reg WF,RF;
reg FF;
reg [1:0] head_buf;
reg [1:0] stop_buf;
reg [7:0] sh8out_buf;
reg [8:0] sh8out_state;
reg [9:0] sh8in_state;
reg [2:0] head_state;
reg [2:0] stop_state;
reg [10:0] main_state;
reg [7:0] data_from_rm;
reg link_sda;
reg link_read;
reg link_head;
reg link_write;
reg link_stop;
wire sda1,sda2,sda3,sda4;
//串行数据在开关控制下有秩序的输出或输入
assign sda1=(link_head) ? head_buf[1] :1'b0;
assign sda2=(link_write) ? sh8out_buf[7] : 1'b0;
assign sda3=(link_stop) ?stop_buf[1] :1'b0;
assign sda4=(sda1|sda2|sda3);
assign sda=(link_sda)? sda4:1'bz;
assign DATA=(link_read)?data_from_rm:8'hzz;
//主状态机状态定义
parameter
Idle =11'b00000000001,
Ready =11'b00000000010,
Write_start =11'b00000000100,
Ctrl_write =11'b00000001000,
Addr_write =11'b00000010000,
Data_write =11'b00000100000,
Read_start =11'b00001000000,
Ctrl_read =11'b00010000000,
Data_read =11'b00100000000,
Stop =11'b01000000000,
Ackn =11'b10000000000,
//并行数据串行输出状态
sh8out_bit7=9'b000000001,
sh8out_bit6=9'b000000010,
sh8out_bit5=9'b000000100,
sh8out_bit4=9'b000001000,
sh8out_bit3=9'b000010000,
sh8out_bit2=9'b000100000,
sh8out_bit1=9'b001000000,
sh8out_bit0=9'b010000000,
sh8out_end =9'b100000000;
//串行数据并行输出状态
parameter sh8in_begin =10'b0000000001,
sh8in_bit7 =10'b0000000010,
sh8in_bit6 =10'b0000000100,
sh8in_bit5 =10'b0000001000,
sh8in_bit4 =10'b0000010000,
sh8in_bit3 =10'b0000100000,
sh8in_bit2 =10'b0001000000,
sh8in_bit1 =10'b0010000000,
sh8in_bit0 =10'b0100000000,
sh8in_end =10'b1000000000,
//启动状态
head_begin=3'b001,
head_bit =3'b010,
head_end =3'b100,
//停止状态
stop_begin =3'b001,
stop_bit =3'b010,
stop_end =3'b100;
parameter YES =1,
NO =0;
//产生串行时钟SCL,为输入时钟的2分频
always @(negedge CLK)
if(RESET)
scl<=0;
else
scl<=~scl;
//主状态机程序
always @(posedge CLK)
if(RESET)
begin
link_read<=NO;
link_write<=NO;
link_head<=NO;
link_stop<=NO;
link_sda<=NO;
ACK<=0;
RF<=0;
WF<=0;
FF<=0;
main_state<=Idle;
end
else
begin
casex(main_state)
Idle:
begin
link_read<=NO;
link_write<=NO;
link_head<=NO;
link_stop<=NO;
link_sda<=NO;
if(WR)
begin
WF<=1;
main_state<=Ready;
end
else if(RD)
begin
RF<=1;
main_state<=Ready;
end
else
begin
WF<=0;
RF<=0;
main_state<=Idle;
end
end
Ready:
begin
link_read<=NO;
link_write<=NO;
link_stop<=NO;
link_head<=YES;
link_sda<=YES;
head_buf[1:0]<=2'b10;
stop_buf[1:0]<=2'b01;
head_state<=head_begin;
FF<=0;
ACK<=0;
main_state<=Write_start;
end
Write_start:
if(FF==0)
shift_head;
else
begin
sh8out_buf[7:0]<={1'b1,1'b0,1'b1,1'b0,ADDR[10:8],1'b0};
link_head<=NO;
link_write<=YES;
FF<=0;
sh8out_state<=sh8out_bit6;
main_state<=Ctrl_write;
end
Ctrl_write:
if(FF==0)
shift8_out;
else
begin
sh8out_state<=sh8out_bit7;
sh8out_buf[7:0] <= ADDR[7:0];
FF<=0;
main_state<=Addr_write;
end
Addr_write:
if(FF==0)
shift8_out;
else
begin
FF<=0;
if(WF)
begin
sh8out_state <= sh8out_bit7;
sh8out_buf[7:0] <=DATA;
main_state <=Data_write;
end
if(RF)
begin
head_buf <= 2'b10;
head_state<=head_begin;
main_state<=Read_start;
end
end
Data_write:
if(FF==0)
shift8_out;
else
begin
stop_state<=stop_begin;
main_state<=Stop;
link_write<=NO;
FF<=0;
end
Read_start:
if(FF==0)
shift_head;
else
begin
sh8out_buf<={1'b1,1'b0,1'b1,1'b0,ADDR[10:8],1'b1};
link_head<=NO;
link_sda<=YES;
link_write<=YES;
FF<=0;
sh8out_state<=sh8out_bit6;
main_state<=Ctrl_read;
end
Ctrl_read:
if(FF==0)
shift8_out;
else
begin
link_sda<=NO;
link_write<=NO;
FF<=0;
sh8in_state<=sh8in_begin;
main_state<=Data_read;
end
Data_read:
if(FF==0)
shift8in;
else
begin
link_stop<=YES;
link_sda<=YES;
stop_state<=stop_bit;
FF<=0;
main_state<=Stop;
end
Stop:
if(FF==0)
shift_stop;
else
begin
ACK<=1;
FF<=0;
main_state<=Ackn;
end
Ackn:
begin
ACK<=0;
WF<=0;
RF<=0;
main_state<=Idle;
end
default:
main_state<=Idle;
endcase
end
//串行数据转换为并行数据任务
task shift8in;
begin
casex(sh8in_state)
sh8in_begin:
sh8in_state<=sh8in_bit7;
sh8in_bit7:
if(scl)
begin
data_from_rm[7] <=sda;
sh8in_state<=sh8in_bit6;
end
else
sh8in_state<=sh8in_bit7;
sh8in_bit6:
if(scl)
begin
data_from_rm[6] <=sda;
sh8in_state<=sh8in_bit5;
end
else
sh8in_state<=sh8in_bit6;
sh8in_bit5:
if(scl)
begin
data_from_rm[5] <=sda;
sh8in_state<=sh8in_bit4;
end
else
sh8in_state<=sh8in_bit5;
sh8in_bit4:
if(scl)
begin
data_from_rm[4] <=sda;
sh8in_state<=sh8in_bit3;
end
else
sh8in_state<=sh8in_bit4;
sh8in_bit3:
if(scl)
begin
data_from_rm[3] <=sda;
sh8in_state<=sh8in_bit2;
end
else
sh8in_state<=sh8in_bit3;
sh8in_bit2:
if(scl)
begin
data_from_rm[2] <=sda;
sh8in_state<=sh8in_bit1;
end
else
sh8in_state<=sh8in_bit2;
sh8in_bit1:
if(scl)
begin
data_from_rm[1] <=sda;
sh8in_state<=sh8in_bit0;
end
else
sh8in_state<=sh8in_bit1;
sh8in_bit0:
if(scl)
begin
data_from_rm[0] <=sda;
sh8in_state<=sh8in_end;
end
else
sh8in_state<=sh8in_bit0;
sh8in_end:
if(scl)
begin
link_read<=YES;
FF<=1;
sh8in_state<=sh8in_bit7;
end
else
sh8in_state<=sh8in_end;
default:
begin
link_read<=NO;
sh8in_state<=sh8in_bit7;
end
endcase
end
endtask
//并行数据转换为串行数据任务
task shift8_out;
begin
casex(sh8out_state)
sh8out_bit7:
if(!scl)
begin
link_sda<=YES;
link_write<=YES;
sh8out_state<=sh8out_bit6;
end
else
sh8out_state<=sh8out_bit7;
sh8out_bit6:
if(!scl)
begin
link_sda<=YES;
link_write<=YES;
sh8out_state<=sh8out_bit5;
sh8out_buf<=sh8out_buf<<1;
end
else
sh8out_state<=sh8out_bit6;
sh8out_bit5:
if(!scl)
begin
sh8out_state<=sh8out_bit4;
sh8out_buf<=sh8out_buf<<1;
end
else
sh8out_state<=sh8out_bit5;
sh8out_bit4:
if(!scl)
begin
sh8out_state<=sh8out_bit3;
sh8out_buf<=sh8out_buf<<1;
end
else
sh8out_state<=sh8out_bit4;
sh8out_bit3:
if(!scl)
begin
sh8out_state<=sh8out_bit2;
sh8out_buf<=sh8out_buf<<1;
end
else
sh8out_state<=sh8out_bit3;
sh8out_bit2:
if(!scl)
begin
sh8out_state<=sh8out_bit1;
sh8out_buf<=sh8out_buf<<1;
end
else
sh8out_state<=sh8out_bit2;
sh8out_bit1:
if(!scl)
begin
sh8out_state<=sh8out_bit0;
sh8out_buf<=sh8out_buf<<1;
end
else
sh8out_state<=sh8out_bit1;
sh8out_bit0:
if(!scl)
begin
sh8out_state<=sh8out_end;
sh8out_buf<=sh8out_buf<<1;
end
else
sh8out_state<=sh8out_bit0;
sh8out_end:
if(!scl)
begin
link_sda<=NO;
link_write<=NO;
FF<=1;
end
else
sh8out_state<=sh8out_end;
endcase
end
endtask
//输出启动信号任务
task shift_head;
begin
casex(head_state)
head_begin:
if(!scl)
begin
link_write<=NO;
link_sda<=YES;
link_head<=YES;
head_state<=head_bit;
end
else
head_state<=head_begin;
head_bit:
if(scl)
begin
FF<=1;
head_buf<=head_buf<<1;
head_state<=head_end;
end
else
head_state<=head_bit;
head_end:
if(!scl)
begin
link_head<=NO;
link_write<=YES;
end
else
head_state<=head_end;
endcase
end
endtask
//输出停止信号任务
task shift_stop;
begin
casex(stop_state)
stop_begin:
if(!scl)
begin
link_sda<=YES;
link_write<=NO;
link_stop<=YES;
stop_state<=stop_bit;
end
else
stop_state<=stop_begin;
stop_bit:
if(scl)
begin
stop_buf<=stop_buf<<1;
stop_state<=stop_end;
end
else
stop_state<=stop_bit;
stop_end:
if(!scl)
begin
link_head<=NO;
link_stop<=NO;
link_sda<=NO;
FF<=1;
end
else
stop_state<=stop_end;
endcase
end
endtask
endmodule
仿真文件如下:
`timescale 1ns/1ps
`define timeslice 200
module signal(RESET,CLK,RD,WR,ADDR,ACK,DATA);
output RESET;
output CLK;
output RD,WR;
output [10:0] ADDR;
input ACK;
inout [7:0] DATA;
reg RESET;
reg CLK;
reg RD,WR;
reg W_R;
reg [10:0] ADDR;
reg [7:0] data_to_eeprom;
reg [10:0] addr_mem[0:255];
reg [7:0] data_mem[0:255];
reg [7:0] ROM[1:2047];
integer i,j;
integer OUTFILE;
parameter test_number=5;
assign DATA=(W_R)? 8'bz:data_to_eeprom;
always #(`timeslice/2)
CLK=~CLK;
//读写信号输入
initial
begin
i=0;j=0;
W_R=0;
CLK=0;
RD=0;
WR=0;
#1000;
RESET=0;
repeat(test_number)
begin
#(5*`timeslice);
WR=1;
#(`timeslice);
WR=0;
@(posedge ACK);
end
#(10* `timeslice);
W_R=1;
repeat(test_number)
begin
#(5*`timeslice);
RD=1;
#(`timeslice);
RD=0;
@(posedge ACK);
end
end
//写操作
initial
begin
$display("writing-----writing-----writing-----writing");
#(2*`timeslice);
for(i=0;i<test_number;i=i+1)
begin
ADDR=addr_mem[i];
data_to_eeprom=data_mem[i];
$fdisplay(OUTFILE,"@%0h %0h",ADDR,data_to_eeprom);
@(posedge ACK);
end
end
//读操作
initial
@(posedge W_R)
begin
ADDR=addr_mem[0];
$fclose(OUTFILE);
$readmemh("eeprom.dat",ROM);
$display("Begin READING-----READING-----READING-----READING");
for(j=0;j<=test_number;j=j+1)
begin
ADDR=addr_mem[j];
@(posedge ACK);
if(DATA==ROM[ADDR])
$display("DATA %0h ==ROM[%0h]----READ RIGHT",DATA,ADDR);
else
$display("DATA %0h != ROM[%0h]-----READ WRONG",DATA,ADDR);
end
end
initial
begin
OUTFILE=$fopen("eeprom.dat");
$readmemh("addr.dat",addr_mem);
$readmemh("data.dat",data_mem);
end
endmodule
仿真出不来波形:
请问高手,哪里有问题?谢谢!
|