📄 i2c_slave_model.v
字号:
`timescale 1ns/10ps
module i2c_slave_model(sda_en,sda_in,sda_out,scl,reset,chip_address,chip_outdata,chip_inputdata,cpu_cs,cpu_we);
input scl;
input sda_in;
output sda_out;
output sda_en;
input reset;
//-----added today----------
output [7:0] chip_address;
output [7:0] chip_outdata;
input [7:0] chip_inputdata;
output cpu_cs;
output cpu_we;
reg cpu_cs;
//--------------define the port address-------------------------
parameter I2C_ADR = 7'b0010_000;
//--------------the test memory space---------------------------
reg [7:0] mem [255:0];
reg [7:0] mem_adr;
//--------------general register declearation------------------
reg ld;
reg [2:0] bit_cnt;
reg data_out;
reg write_enable;
assign sda_out=data_out;
parameter idle = 3'b000;//---------------------0
parameter slave_ack = 3'b001;//---------------------1
parameter get_mem_adr = 3'b010;//---------------------2
parameter gma_ack = 3'b011;//---------------------3
parameter data = 3'b100;//---------------------4
parameter data_ack = 3'b101;//---------------------5
reg [2:0] state;
reg [2:0] start_rw;
reg rw;
reg [7:0] mem_do;
reg sda_o;
wire debug = 1'b1;
//--------------detect the start condition----------------------
reg start;
wire start_reset_n;
assign start_reset_n=reset & (scl | sda_in);
always @(negedge sda_in or negedge start_reset_n)
begin
if(~start_reset_n)
start<= 1'b0;
else
if(scl)
start<= 1'b1;
else
start<= 1'b0;
end
//---------------detect the stop condition-----------------------
reg stop;
wire stop_reset_n;
assign stop_reset_n=reset &(scl | sda_in);
always @(posedge sda_in or negedge stop_reset_n)
begin
if(~stop_reset_n)
stop<=1'b0;
else
begin
if(scl)
stop<=1'b1;
else
stop<=1'b0;
end
end
//--------------shift the receive data bus------------------------
reg [7:0] src;
always @(negedge scl)
begin
if(start==1'b1) begin
src <= 8'b0;
end
else begin
src <= {src[6:0],sda_in};
end
end
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------------------------------------------------
reg [3:0] count;
always @(posedge scl or posedge start)
begin
if(start)
count <= 4'b0000;
else
begin
if (count==4'd9)
count <= count;
else
count <= count + 1'b1;
end
end
//---------------judge if the address is my own--------------------
wire my_adr;
assign my_adr = (src[6:0] == I2C_ADR);
//------------------generate done signal--------------------------
wire acc_done;
assign acc_done = !(|bit_cnt);
//-----------generate the muti_reset signal-----------------------
wire reverse_reset;
assign reverse_reset=~reset;
wire combine;
assign combine = start | stop | reverse_reset;
//-----------the state machine------------------------------------
always @ (negedge scl or posedge combine)
begin
if(combine)
begin
sda_o <= 1'b1;
state <= idle; // reset statemachine
ld <= 1'b1;
bit_cnt<= 3'b111;
cpu_cs <= 1'b1;
end
else
begin
// ld <= 1'b0;
// sda_o <= 1'b1;
case (state)
idle:
begin
bit_cnt <= bit_cnt - 3'b1;
if(acc_done && my_adr && count==4'd8) begin
state <= slave_ack;
sda_o <= 1'b0; // generate i2c_ack
data_out <= 1'b0;
//if(rw)
//mem_do <= mem[mem_adr];
end
end
slave_ack:
begin
bit_cnt <= 3'b111;
if(rw) begin
state <= data;
sda_o <= 1'b0;
cpu_cs<= 1'b0;
data_out <= mem_do[7];//**//**//**//**//**//**
//mem_do <= mem[mem_adr];=========================================
end
else
begin
state <= get_mem_adr;
ld <= 1'b1;
sda_o <= 1'b1;
cpu_cs<=1'b1;
end
end
get_mem_adr: // wait for memory address
begin
bit_cnt <= bit_cnt - 3'b1;
if(acc_done)
begin
state <= gma_ack;
data_out <= 1'b0;
sda_o <= 1'b0; // generate i2c_ack, for valid address
cpu_cs<= 1'b1;
end
end
gma_ack:
begin
bit_cnt <= 3'b111;
ld <= 1'b1;
mem_adr <= src; // store memory address
state <= data;
sda_o <= 1'b1;
cpu_cs<=1'b1;
end
data: // receive or drive data
begin
bit_cnt <= bit_cnt - 3'b1;
if(rw)
begin
sda_o <= 1'b0;
data_out <= mem_do[7];//**//**//**//**//**//**
if(acc_done) begin
mem_adr <= mem_adr + 8'h1;
sda_o<=1'b1;
cpu_cs <=1'b1;
state <= data_ack;
end
else
cpu_cs <= 1'b0;
end
else
begin
if(acc_done)
begin
state <= data_ack;
//write_enable<=1'b1;
sda_o <= 1'b0; // send ack on write, receive ack on read
cpu_cs<=1'b1;
end
end
end
data_ack:
begin
ld <= 1'b1;
bit_cnt <= 3'b111;
if(rw)
begin
if(sda_in) // read operation && master send NACK
begin
state <= idle;
sda_o <= 1'b1;
cpu_cs<= 1'b0;
end
else
begin
state <= data;
sda_o <= 1'b0;
data_out <= mem_do[7];//**//**//**//**//**//**
//data_out<=1'b0;////////////////////////////////////////////
cpu_cs<=1'b0;
end
end
else
begin
cpu_cs<=1'b1;
mem_adr <= mem_adr + 8'h1;
mem[mem_adr] <= src;
state <= data;
sda_o <= 1'b1;
end
end
endcase
end
end
//--------------------------------------------------------------------
always @(negedge scl or posedge combine)
begin
if(combine)
write_enable<=1'b0;
else
begin
if(state==data && acc_done && ~rw)
write_enable <= 1'b1;
else
write_enable <= 1'b0;
end
end
always @(posedge scl or negedge reset)
begin
if(~reset)
mem_do <= 8'b0;
else begin
if(~rw)
mem_do <= chip_inputdata;//------------------------------5:00
else
begin
if(state==data_ack || state==slave_ack)
mem_do <=chip_inputdata;//--------------------------5:00
else
mem_do <= {mem_do[6:0], 1'b1};
end
end
end
assign sda_en=sda_o;
assign chip_address=mem_adr;
assign chip_outdata=src[7:0];
//////////////////////////////////////////////////////////////////////////
always @(posedge scl)
begin
if(count==4'd8)
rw <= src[0];
else
rw <= rw;
end
//////////////////////////////////////////////////////////////////////////
/*
always @(posedge scl)
begin
if(~rw && state==data_ack)
write_enable <= 1'b1;
else
write_enable <= 1'b0;
end
*/
assign cpu_we=write_enable;
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -