Line 191... |
Line 191... |
|
|
|
|
// state machine variable
|
// state machine variable
|
reg [17:0] c_state; // synopsys enum_state
|
reg [17:0] c_state; // synopsys enum_state
|
reg [4:0] slave_state;
|
reg [4:0] slave_state;
|
// A counter to indicate a too-long wait has occurred for the next set
|
|
// of clocks for the read, and in fact it's likely the master has simply
|
|
// released SCL and wants to issue a stop.
|
|
reg [3:0] slave_read_timeout_cnt;
|
|
wire slave_read_timeout;
|
|
|
|
|
|
|
|
//
|
//
|
// module body
|
// module body
|
//
|
//
|
|
|
// whenever the slave is not ready it can delay the cycle by pulling SCL low
|
// whenever the slave is not ready it can delay the cycle by pulling SCL low
|
// delay scl_oen
|
// delay scl_oen
|
always @(posedge clk)
|
always @(posedge clk)
|
dscl_oen <= scl_oen;
|
dscl_oen <= scl_oen;
|
|
|
// slave_wait is asserted when master wants to drive SCL high, but the
|
// slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low
|
// slave pulls it low.
|
|
// slave_wait remains asserted until the slave releases SCL
|
// slave_wait remains asserted until the slave releases SCL
|
always @(posedge clk or negedge nReset)
|
always @(posedge clk or negedge nReset)
|
if (!nReset)
|
if (!nReset) slave_wait <= 1'b0;
|
slave_wait <= 1'b0;
|
else slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) | (slave_wait & ~sSCL);
|
else
|
|
slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) |
|
|
(slave_wait & ~sSCL) ;
|
|
|
|
// master drives SCL high, but another master pulls it low
|
// master drives SCL high, but another master pulls it low
|
// master start counting down its low cycle now (clock synchronization)
|
// master start counting down its low cycle now (clock synchronization)
|
wire scl_sync = dSCL & ~sSCL & scl_oen;
|
wire scl_sync = dSCL & ~sSCL & scl_oen;
|
|
|
Line 246... |
Line 234... |
begin
|
begin
|
cnt <= cnt - 16'h1;
|
cnt <= cnt - 16'h1;
|
clk_en <= 1'b0;
|
clk_en <= 1'b0;
|
end
|
end
|
|
|
|
|
// generate bus status controller
|
// generate bus status controller
|
|
|
// capture SDA and SCL
|
// capture SDA and SCL
|
// reduce metastability risk
|
// reduce metastability risk
|
always @(posedge clk or negedge nReset)
|
always @(posedge clk or negedge nReset)
|
Line 640... |
Line 629... |
slave_adr_received <= 1'b0;
|
slave_adr_received <= 1'b0;
|
slave_act <= 1'b0;
|
slave_act <= 1'b0;
|
end
|
end
|
end
|
end
|
|
|
|
|
|
|
parameter [4:0] slave_idle = 5'b0_0000;
|
parameter [4:0] slave_idle = 5'b0_0000;
|
parameter [4:0] slave_wr = 5'b0_0001;
|
parameter [4:0] slave_wr = 5'b0_0001;
|
parameter [4:0] slave_wr_a = 5'b0_0010;
|
parameter [4:0] slave_wr_a = 5'b0_0010;
|
parameter [4:0] slave_rd = 5'b0_0100;
|
parameter [4:0] slave_rd = 5'b0_0100;
|
parameter [4:0] slave_rd_a = 5'b0_1000;
|
parameter [4:0] slave_rd_a = 5'b0_1000;
|
parameter [4:0] slave_wait_next_cmd_1 = 5'b1_0000;
|
parameter [4:0] slave_wait_next_cmd_1 = 5'b1_0000;
|
parameter [4:0] slave_wait_next_cmd_2 = 5'b1_0001;
|
parameter [4:0] slave_wait_next_cmd_2 = 5'b1_0001;
|
|
|
|
|
// Slave timeout counter during read
|
|
always @(posedge clk or negedge nReset)
|
|
if (~nReset)
|
|
slave_read_timeout_cnt <= 0;
|
|
else if (rst)
|
|
slave_read_timeout_cnt <= 0;
|
|
else if (slave_state==slave_wr)
|
|
slave_read_timeout_cnt <= 0;
|
|
else if (slave_state==slave_wr_a && sSCL && cnt==1)
|
|
slave_read_timeout_cnt <= slave_read_timeout_cnt + 1;
|
|
|
|
assign slave_read_timeout = (&slave_read_timeout_cnt) & cnt==1;
|
|
|
|
always @(posedge clk or negedge nReset)
|
always @(posedge clk or negedge nReset)
|
if (!nReset)
|
if (!nReset)
|
begin
|
begin
|
slave_state <= slave_idle;
|
slave_state <= slave_idle;
|
cmd_slave_ack <= 1'b0;
|
cmd_slave_ack <= 1'b0;
|
Line 693... |
Line 670... |
|
|
begin
|
begin
|
|
|
case (slave_cmd) // synopsys full_case parallel_case
|
case (slave_cmd) // synopsys full_case parallel_case
|
`I2C_SLAVE_CMD_WRITE: slave_state <= slave_wr;
|
`I2C_SLAVE_CMD_WRITE: slave_state <= slave_wr;
|
`I2C_SLAVE_CMD_READ: slave_state <= slave_rd;
|
`I2C_SLAVE_CMD_READ:
|
|
begin
|
|
slave_state <= slave_rd;
|
|
// Restore SDA high here in case we're got it low
|
|
sda_oen_slave <= 1'b1;
|
|
end
|
default:
|
default:
|
begin
|
begin
|
slave_state <= slave_idle;
|
slave_state <= slave_idle;
|
sda_oen_slave <= 1'b1; // Moved this here, JB
|
sda_oen_slave <= 1'b1; // Moved this here, JB
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
|
|
slave_wr:
|
slave_wr:
|
begin
|
begin
|
if (~sSCL & ~dSCL) begin //SCL = LOW
|
if (~sSCL & ~dSCL) begin //SCL == LOW
|
slave_state <= slave_wr_a;
|
slave_state <= slave_wr_a;
|
sda_oen_slave <= din;
|
sda_oen_slave <= din;
|
end
|
end
|
end
|
end
|
|
|
Line 716... |
Line 698... |
begin
|
begin
|
if (~sSCL & dSCL) begin //SCL FALLING EDGE
|
if (~sSCL & dSCL) begin //SCL FALLING EDGE
|
cmd_slave_ack <= 1'b1;
|
cmd_slave_ack <= 1'b1;
|
slave_state <= slave_wait_next_cmd_1;
|
slave_state <= slave_wait_next_cmd_1;
|
end
|
end
|
// Timeout! Go back to idle, release SDA
|
|
else if(slave_read_timeout) begin
|
|
slave_state <= slave_idle;
|
|
sda_oen_slave <= 1;
|
|
end
|
|
end
|
end
|
|
|
slave_wait_next_cmd_1:
|
slave_wait_next_cmd_1:
|
slave_state <= slave_wait_next_cmd_2;
|
slave_state <= slave_wait_next_cmd_2;
|
|
|
Line 732... |
Line 709... |
slave_state <= slave_idle;
|
slave_state <= slave_idle;
|
|
|
|
|
slave_rd:
|
slave_rd:
|
begin
|
begin
|
if (sSCL & ~dSCL) begin
|
if (sSCL & ~dSCL) begin // SCL Rising edge
|
slave_state <= slave_rd_a;
|
slave_state <= slave_rd_a;
|
end
|
end
|
end
|
end
|
|
|
slave_rd_a:
|
slave_rd_a:
|
begin
|
begin
|
if (~sSCL & dSCL) begin
|
if (~sSCL & dSCL) begin // SCL falling edge
|
cmd_slave_ack <= 1'b1;
|
cmd_slave_ack <= 1'b1;
|
slave_state <= slave_wait_next_cmd_1;
|
slave_state <= slave_wait_next_cmd_1;
|
end
|
end
|
end
|
end
|
endcase // case (slave_state)
|
endcase // case (slave_state)
|