module main(input reset);
wire scl,clk;
wire sda_line;
wire sda_master_enable;
master main_master(.reset(reset),.sda_line(sda_line),.scl(scl),.sda_master_enable(sda_master_enable));
slave main_slave(.sda_line(sda_line),.scl(scl),.sda_master_enable(sda_master_enable));
endmodule
////////////////////////////////////////////////////////////////////////////////////
module master(input reset, inout sda_line, output reg scl,[2:0]state_out,wire sda_master_enable);
wire clk,reset;
reg sda,sda_enable = 1;
reg [2:0]state = 3'b000;
reg [2:0] state_out;
reg sda_master_enable;
reg [6:0]addr_reg = 7'h69; //69 = 1101001
reg [2:0]count = 3'd6;
reg rw_reg = 0; //FOR NOW transmitting data from master;
reg [7:0] data_reg = 8'b10001010;
reg data_out;
reg addr_ack_bit = 1;
reg data_ack_bit;
reg ack_flag = 0;
reg [2:0]data_count = 3'd7;
parameter IDLE_STATE = 3'b000,
START_STATE = 3'b001,
ADDR_STATE = 3'b010,
RW_STATE = 3'b011,
ADDR_ACK_STATE = 3'b100,
DATA_STATE = 3'b101,
DATA_ACK_STATE = 3'b110,
STOP_STATE = 3'b111;
clock_divider master_cd(.i2c_clk(clk));
assign sda_line = (sda_enable) ? sda : 1'bz; // Master drives SDA only when sda_enable = 1
always @(posedge clk) begin
if(reset == 0) begin
case(state)
IDLE_STATE: begin
sda<=1;scl<=1;
state_out <= IDLE_STATE;
state<=START_STATE;
end
START_STATE: begin
sda<=0;
state_out <= START_STATE;
state<=ADDR_STATE;
end
ADDR_STATE: begin
sda_enable = 1;
if(count == 0) begin
sda<=addr_reg[count];
state_out <= ADDR_STATE;
state<=RW_STATE;
count<=3'd6;
end
else begin
sda<=addr_reg[count];
count = count-1; // DATA will work according to sysclk;
// you have to configure scl accordingly to match i2c rule;
end
end
RW_STATE: begin
sda<=rw_reg;
state_out <= RW_STATE;
state<=ADDR_ACK_STATE;
end
ADDR_ACK_STATE: begin
sda_enable = 0;
state_out <= ADDR_ACK_STATE;
end
DATA_STATE: begin
sda_enable = 1;
if(data_count == 0) begin
sda<=data_reg[data_count];
state_out <= DATA_STATE;
state<=DATA_ACK_STATE;
end
else begin
sda<=data_reg[data_count];
data_count = data_count-1; // DATA will work according to sysclk;
// you have to configure scl accordingly to match i2c rule;
end
end
DATA_ACK_STATE: begin
sda_enable = 0;
data_ack_bit = sda_line;
state_out <= DATA_STATE;
state <= (data_ack_bit) ? DATA_STATE : STOP_STATE;
end
STOP_STATE: begin
sda_enable <= 1;
sda<= 1;
scl<=1;
state_out <= STOP_STATE;
end
default: begin sda<=1;scl<=1; end
endcase
end
else if(reset == 1) begin
sda<=1;
scl <= 1;
end
state_out <= state;
end
always @(posedge scl) begin
if(state_out == ADDR_ACK_STATE) begin
sda = sda_line; // Capture it properly
addr_ack_bit = sda;
$display("ACK Bit Read: %b", sda);
if(addr_ack_bit == 1) begin
state <= ADDR_STATE; // Retry address phase if no ACK
end
else if(addr_ack_bit == 0) begin
state <= DATA_STATE; // Proceed to data transmission
end
end
end
always @(clk) begin
if(state == ADDR_STATE || state == RW_STATE || state == ADDR_ACK_STATE || state == DATA_STATE ||state == DATA_ACK_STATE) begin //Starting of scl after completing starting state;
scl <= ~clk;
end
if(state_out == DATA_ACK_STATE) begin
scl <= 1;
end
end
always @(sda_enable) begin
sda_master_enable = sda_enable;
end
endmodule
///////////////////////////////////////////////////////////////
module slave(input scl,sda_master_enable,inout sda_line,output addr_data_out,addr_count_out,flag);
reg sda,sda_enable = 0; // Controls when slave drives SDA
wire clk;
reg flag_reg = 1'bz;
wire flag;
reg [7:0] addr_data = 8'b00000000;
reg [7:0] addr_data_out;
reg [3:0] addr_count = 4'b1010; //here from 9 to 0 10 states // we require 8 bits (7+1) //+1 bit for starting posedge of scl from Hi-im state;
reg [3:0] addr_count_out;
reg addr_flag = 0;
parameter slave_addr = 8'hD2;8'hD1;
assign sda_line = sda_enable ? sda : 1'bz; // To drive the inout net
clock_divider master_cd(.i2c_clk(clk));
always @(negedge clk) begin
if(flag_reg == 1) begin
if(addr_flag == 0) begin
if(addr_count <= 9 && addr_count >= 2) begin
sda = sda_line; //no non-blocking for sda because we want it right now and here, nd not on next clock cycle
addr_data = addr_data | (sda << addr_count-2) ; //same case with addr_data
addr_data_out[7:0] <= addr_data[7:0];
addr_count <= addr_count -1; //Some fucked up shit combining bloacking and non blocking is not advisable but for now its giving me correct result so gud!!
addr_count_out <= addr_count -1;
end
else begin
addr_count <= addr_count -1;
addr_count_out <= addr_count -1; //earlier it was addr_count_out <= addr_count ,,,,which was two step process first addt_count updates in one cycle and then addr_count_out;
end
end
end
end
always @(negedge sda_line) begin
#1;
if(scl == 1)
flag_reg <= 1; //Starting condition detected
end
always @(posedge sda_line) begin
#1;
if(scl == 1)
flag_reg <= 0; //stopping condition detected;
end
always @(negedge sda_master_enable) begin
if(addr_flag == 0) begin
if(sda_master_enable == 0) begin
sda_enable = 1;
if (addr_data == slave_addr) begin
sda = 1'b0;
addr_data <= 8'b00000000;
addr_data_out[7:0] <= 8'b00000000;
addr_count <= 4'b1010;
addr_count_out <= 4'b10;
addr_flag<=1;
end
else begin
sda = 1'b1; //NACK
addr_data <= 8'b00000000;
addr_data_out[7:0] <= 8'b00000000;
addr_count <= 4'b1010;
addr_count_out <= 4'b1010;
addr_flag<=0; //If NACK then resend data from master and re store it in slave
end
end
end
else if(addr_flag == 1) begin
sda_enable = 1;
sda<=1'b0;
end
end
always @(posedge sda_master_enable) begin
if(sda_master_enable == 1) begin
sda_enable = 0;
end
end
assign flag = flag_reg; //Do notconfuse non blocking /blocking sign to assign sign here "=" simply means they are equal so when ever the reg changes the wire changes;
//Above is the good choice to see reg output in testbench waveform since testbench only takes wires:)
endmodule
////////////////////////////////////////////////////////////
module clock_signal (
output reg val
);
initial begin
val = 0;
forever #5 val = ~val; // 10 nanosecond main clock ;Frequency = 100MHz gud!!
// BUT For standard i2c speed we want 100KHz or 10us clock
end
endmodule
/////////////////////////////////////////////////////////////////////////////////
module clock_divider(output i2c_clk);
wire ref_clk;
wire reset;
reg i2c_clk = 1;
reg [10:0] counter = 0;
clock_signal cd_cs(.val(ref_clk));
always @(posedge ref_clk) begin
if(counter == (500)) begin
i2c_clk = ~ i2c_clk;
counter = 0;
end
else begin
counter = counter + 1; // up counter is always efficient than down counter bcus ripple carry is gud!!
end
end
endmodule
/////////////////////////////////////////