blob: 5b856b6d0395a4e24d6a9233def6effc1338bc90 [file] [log] [blame]
module i2c_master_bit_ctrl (
clk,
nReset,
ena,
clk_cnt,
cmd,
cmd_ack,
busy,
al,
din,
dout,
scl_i,
scl_o,
scl_oen,
sda_i,
sda_o,
sda_oen
);
input clk;
input nReset;
input ena;
input [15:0] clk_cnt;
input [3:0] cmd;
output reg cmd_ack;
output reg busy;
output reg al;
input din;
output reg dout;
input scl_i;
output wire scl_o;
output reg scl_oen;
input sda_i;
output wire sda_o;
output reg sda_oen;
reg [1:0] cSCL;
reg [1:0] cSDA;
reg [2:0] fSCL;
reg [2:0] fSDA;
reg sSCL;
reg sSDA;
reg dSCL;
reg dSDA;
reg dscl_oen;
reg sda_chk;
reg clk_en;
reg slave_wait;
reg [15:0] cnt;
reg [13:0] filter_cnt;
reg [17:0] c_state;
always @(posedge clk) dscl_oen <= scl_oen;
always @(posedge clk or negedge nReset)
if (!nReset)
slave_wait <= 1'b0;
else
slave_wait <= ((scl_oen & ~dscl_oen) & ~sSCL) | (slave_wait & ~sSCL);
wire scl_sync = (dSCL & ~sSCL) & scl_oen;
always @(posedge clk or negedge nReset)
if (~nReset) begin
cnt <= 16'h0000;
clk_en <= 1'b1;
end
else if ((~|cnt || !ena) || scl_sync) begin
cnt <= clk_cnt;
clk_en <= 1'b1;
end
else if (slave_wait) begin
cnt <= cnt;
clk_en <= 1'b0;
end
else begin
cnt <= cnt - 16'h0001;
clk_en <= 1'b0;
end
always @(posedge clk or negedge nReset)
if (!nReset) begin
cSCL <= 2'b00;
cSDA <= 2'b00;
end
else begin
cSCL <= {cSCL[0], scl_i};
cSDA <= {cSDA[0], sda_i};
end
always @(posedge clk or negedge nReset)
if (!nReset)
filter_cnt <= 14'h0000;
else if (!ena)
filter_cnt <= 14'h0000;
else if (~|filter_cnt)
filter_cnt <= clk_cnt >> 2;
else
filter_cnt <= filter_cnt - 1;
always @(posedge clk or negedge nReset)
if (!nReset) begin
fSCL <= 3'b111;
fSDA <= 3'b111;
end
else if (~|filter_cnt) begin
fSCL <= {fSCL[1:0], cSCL[1]};
fSDA <= {fSDA[1:0], cSDA[1]};
end
always @(posedge clk or negedge nReset)
if (~nReset) begin
sSCL <= 1'b1;
sSDA <= 1'b1;
dSCL <= 1'b1;
dSDA <= 1'b1;
end
else begin
sSCL <= (&fSCL[2:1] | &fSCL[1:0]) | (fSCL[2] & fSCL[0]);
sSDA <= (&fSDA[2:1] | &fSDA[1:0]) | (fSDA[2] & fSDA[0]);
dSCL <= sSCL;
dSDA <= sSDA;
end
reg sta_condition;
reg sto_condition;
always @(posedge clk or negedge nReset)
if (~nReset) begin
sta_condition <= 1'b0;
sto_condition <= 1'b0;
end
else begin
sta_condition <= (~sSDA & dSDA) & sSCL;
sto_condition <= (sSDA & ~dSDA) & sSCL;
end
always @(posedge clk or negedge nReset)
if (!nReset)
busy <= 1'b0;
else
busy <= (sta_condition | busy) & ~sto_condition;
reg cmd_stop;
always @(posedge clk or negedge nReset)
if (~nReset)
cmd_stop <= 1'b0;
else if (clk_en)
cmd_stop <= cmd == 4'b0010;
always @(posedge clk or negedge nReset)
if (~nReset)
al <= 1'b0;
else
al <= ((sda_chk & ~sSDA) & sda_oen) | ((|c_state & sto_condition) & ~cmd_stop);
always @(posedge clk)
if (sSCL & ~dSCL)
dout <= sSDA;
parameter [17:0] idle = 18'b000000000000000000;
parameter [17:0] start_a = 18'b000000000000000001;
parameter [17:0] start_b = 18'b000000000000000010;
parameter [17:0] start_c = 18'b000000000000000100;
parameter [17:0] start_d = 18'b000000000000001000;
parameter [17:0] start_e = 18'b000000000000010000;
parameter [17:0] stop_a = 18'b000000000000100000;
parameter [17:0] stop_b = 18'b000000000001000000;
parameter [17:0] stop_c = 18'b000000000010000000;
parameter [17:0] stop_d = 18'b000000000100000000;
parameter [17:0] rd_a = 18'b000000001000000000;
parameter [17:0] rd_b = 18'b000000010000000000;
parameter [17:0] rd_c = 18'b000000100000000000;
parameter [17:0] rd_d = 18'b000001000000000000;
parameter [17:0] wr_a = 18'b000010000000000000;
parameter [17:0] wr_b = 18'b000100000000000000;
parameter [17:0] wr_c = 18'b001000000000000000;
parameter [17:0] wr_d = 18'b010000000000000000;
always @(posedge clk or negedge nReset)
if (!nReset) begin
c_state <= idle;
cmd_ack <= 1'b0;
scl_oen <= 1'b1;
sda_oen <= 1'b1;
sda_chk <= 1'b0;
end
else if (al) begin
c_state <= idle;
cmd_ack <= 1'b0;
scl_oen <= 1'b1;
sda_oen <= 1'b1;
sda_chk <= 1'b0;
end
else begin
cmd_ack <= 1'b0;
if (clk_en)
case (c_state)
idle: begin
case (cmd)
4'b0001: c_state <= start_a;
4'b0010: c_state <= stop_a;
4'b0100: c_state <= wr_a;
4'b1000: c_state <= rd_a;
default: c_state <= idle;
endcase
scl_oen <= scl_oen;
sda_oen <= sda_oen;
sda_chk <= 1'b0;
end
start_a: begin
c_state <= start_b;
scl_oen <= scl_oen;
sda_oen <= 1'b1;
sda_chk <= 1'b0;
end
start_b: begin
c_state <= start_c;
scl_oen <= 1'b1;
sda_oen <= 1'b1;
sda_chk <= 1'b0;
end
start_c: begin
c_state <= start_d;
scl_oen <= 1'b1;
sda_oen <= 1'b0;
sda_chk <= 1'b0;
end
start_d: begin
c_state <= start_e;
scl_oen <= 1'b1;
sda_oen <= 1'b0;
sda_chk <= 1'b0;
end
start_e: begin
c_state <= idle;
cmd_ack <= 1'b1;
scl_oen <= 1'b0;
sda_oen <= 1'b0;
sda_chk <= 1'b0;
end
stop_a: begin
c_state <= stop_b;
scl_oen <= 1'b0;
sda_oen <= 1'b0;
sda_chk <= 1'b0;
end
stop_b: begin
c_state <= stop_c;
scl_oen <= 1'b1;
sda_oen <= 1'b0;
sda_chk <= 1'b0;
end
stop_c: begin
c_state <= stop_d;
scl_oen <= 1'b1;
sda_oen <= 1'b0;
sda_chk <= 1'b0;
end
stop_d: begin
c_state <= idle;
cmd_ack <= 1'b1;
scl_oen <= 1'b1;
sda_oen <= 1'b1;
sda_chk <= 1'b0;
end
rd_a: begin
c_state <= rd_b;
scl_oen <= 1'b0;
sda_oen <= 1'b1;
sda_chk <= 1'b0;
end
rd_b: begin
c_state <= rd_c;
scl_oen <= 1'b1;
sda_oen <= 1'b1;
sda_chk <= 1'b0;
end
rd_c: begin
c_state <= rd_d;
scl_oen <= 1'b1;
sda_oen <= 1'b1;
sda_chk <= 1'b0;
end
rd_d: begin
c_state <= idle;
cmd_ack <= 1'b1;
scl_oen <= 1'b0;
sda_oen <= 1'b1;
sda_chk <= 1'b0;
end
wr_a: begin
c_state <= wr_b;
scl_oen <= 1'b0;
sda_oen <= din;
sda_chk <= 1'b0;
end
wr_b: begin
c_state <= wr_c;
scl_oen <= 1'b1;
sda_oen <= din;
sda_chk <= 1'b0;
end
wr_c: begin
c_state <= wr_d;
scl_oen <= 1'b1;
sda_oen <= din;
sda_chk <= 1'b1;
end
wr_d: begin
c_state <= idle;
cmd_ack <= 1'b1;
scl_oen <= 1'b0;
sda_oen <= din;
sda_chk <= 1'b0;
end
endcase
end
assign scl_o = 1'b0;
assign sda_o = 1'b0;
endmodule