Verilog数字系统设计教程[第4版]夏宇闻——第16章EEPROM代码
`timescale 1ns/1ns
`define timeslice 100
module EEPROM(scl,sda);
input scl;
inout sda;
reg out_flag;
reg[7:0] memory[2047:0];
reg[10:0] address;
reg[7:0] memory_buf;
reg[7:0] sda_buf;
reg[7:0] shift;
reg[7:0] addr_byte;
reg[7:0] ctrl_byte;
reg[1:0] State;
integer i;
parameter r7=8'b10101111, w7=8'b10101110,
r6=8'b10101101, w6=8'b10101100,
r5=8'b10101011, w5=8'b10101010,
r4=8'b10101001, w4=8'b10101000,
r3=8'b10100111, w3=8'b10100110,
r2=8'b10100101, w2=8'b10100100,
r1=8'b10100011, w1=8'b10100010,
r0=8'b10100001, w0=8'b10100000;
assign sda = (out_flag == 1) ? sda_buf[7] : 1'bz;
initial
begin
addr_byte =0;
ctrl_byte =0;
out_flag =0;
sda_buf =0;
State =2'b00;
memory_buf =0;
address =0;
shift =0;
for(i=0;i<=2047;i=i+1)
memory[i]=0;
end
always@(negedge sda)
if(scl == 1)
begin
State = State + 1;
if(State == 2'b11)
disable write_to_eeprm;
end
always@(posedge sda)
if(scl == 1)
stop_W_R;
else
begin
casex(State)
2'b10:
begin
read_in;
if(ctrl_byte==w7||ctrl_byte==w6||ctrl_byte==w5||ctrl_byte==w4||ctrl_byte==w3||ctrl_byte==w2||ctrl_byte==w1||ctrl_byte==w0)
begin
State = 2'b10;
write_to_eeprm;
end
else
State = 2'b00;
end
2'b11:
read_from_eeprm;
default:
State=2'b00;
endcase
end
task stop_W_R;
begin
State = 2'b00;
addr_byte = 0;
ctrl_byte = 0;
out_flag = 0;
sda_buf = 0;
end
endtask
task read_in;
begin
shift_in(ctrl_byte);
shift_in(addr_byte);
end
endtask
task write_to_eeprm;
begin
shift_in(memory_buf);
address = {ctrl_byte[3:1],addr_byte};
memory[address] = memory_buf;
$display("eeprm------memory[%0h]=%0h",address,memory[address]);
State = 2'b00;
end
endtask
task read_from_eeprm;
begin
shift_in(ctrl_byte);
if(ctrl_byte==r7||ctrl_byte==r6||ctrl_byte==r5||ctrl_byte==r4||ctrl_byte==r3||ctrl_byte==r2||ctrl_byte==r1||ctrl_byte==r0)
begin
address = {ctrl_byte[3:1],addr_byte};
sda_buf = memory[address];
shift_out;
State = 2'b00;
end
end
endtask
task shift_in;
output[7:0] shift;
begin
@(posedge scl) shift[7]=sda;
@(posedge scl) shift[6]=sda;
@(posedge scl) shift[5]=sda;
@(posedge scl) shift[4]=sda;
@(posedge scl) shift[3]=sda;
@(posedge scl) shift[2]=sda;
@(posedge scl) shift[1]=sda;
@(posedge scl) shift[0]=sda;
@(negedge scl)
begin
#`timeslice;
out_flag = 1;
sda_buf = 0;
end
@(negedge scl)
#`timeslice out_flag = 0;
end
endtask
task shift_out;
begin
out_flag = 1;
for(i=6;i>=0;i=i-1)
begin
@(negedge scl);
#`timeslice;
sda_buf = sda_buf<<1;
end
@(negedge scl) #`timeslice sda_buf[7] = 1;
@(negedge scl) #`timeslice out_flag = 0;
end
endtask
endmodule
`timescale 1ns/1ns
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;
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[5] <= 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/1ns
`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 = 50;
assign DATA = (W_R)? 8'bz : data_to_eeprom;
always #(`timeslice/2)
CLK=~CLK;
initial
begin
RESET = 1;
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
`include"./Signal.v"
`include"./EEPROM.v"
`include"./EEPROM_WR.v"
`timescale 1ns/1ns
`define timeslice 200
module Top;
wire RESET;
wire CLK;
wire RD,WR;
wire ACK;
wire[10:0] ADDR;
wire[7:0] DATA;
wire SCL;
wire SDA;
parameter test_numbers = 123;
initial #(`timeslice*180*test_numbers)$stop;
Signal #(test_numbers) signal(.RESET(RESET),.CLK(CLK),.RD(RD),.WR(WR),.ADDR(ADDR),.ACK(ACK),.DATA(DATA));
EEPROM_WR eeprom_wr(.RESET(RESET),.SDA(SDA),.SCL(SCL),.ACK(ACK),.CLK(CLK),.WR(WR),.RD(RD),.ADDR(ADDR),.DATA(DATA));
EEPROM eeprom(.sda(SDA),.scl(SCL));
endmodule