SummerCart64/fw/rtl/cpu/cpu_i2c.sv

156 lines
4.3 KiB
Systemverilog
Raw Normal View History

2021-08-05 19:50:29 +02:00
module cpu_i2c (
2021-08-20 19:51:55 +02:00
if_system.sys sys,
2021-08-15 21:49:02 +02:00
if_cpu_bus bus,
2021-08-05 19:50:29 +02:00
2021-08-20 19:51:55 +02:00
output i2c_scl,
2021-08-15 21:49:02 +02:00
inout i2c_sda
2021-08-05 19:50:29 +02:00
);
2021-08-12 21:07:47 +02:00
reg [1:0] state;
reg mack;
reg [8:0] trx_data;
always_comb begin
2021-08-15 21:49:02 +02:00
bus.rdata = 32'd0;
if (bus.ack) begin
case (bus.address[2])
0: bus.rdata = {27'd0, |state, ~trx_data[0], mack, 2'b00};
1: bus.rdata = {23'd0, trx_data[0], trx_data[8:1]};
default: bus.rdata = 32'd0;
endcase
end
2021-08-12 21:07:47 +02:00
end
2021-08-20 19:51:55 +02:00
always_ff @(posedge sys.clk) begin
2021-08-15 21:49:02 +02:00
bus.ack <= 1'b0;
if (bus.request) begin
bus.ack <= 1'b1;
end
2021-08-20 19:51:55 +02:00
if (sys.reset) begin
2021-08-12 21:07:47 +02:00
mack <= 1'b0;
2021-08-15 21:49:02 +02:00
end else if (bus.request && bus.wmask[0] && !bus.address[2]) begin
mack <= bus.wdata[2];
2021-08-12 21:07:47 +02:00
end
end
reg [5:0] clock_div;
reg [3:0] clock_phase_gen;
wire clock_tick = &clock_div;
wire [3:0] clock_phase = {4{clock_tick}} & clock_phase_gen;
2021-08-20 19:51:55 +02:00
always_ff @(posedge sys.clk) begin
if (sys.reset) begin
2021-08-12 21:07:47 +02:00
clock_div <= 6'd0;
end else begin
clock_div <= clock_div + 1'd1;
end
2021-08-20 19:51:55 +02:00
if (sys.reset || state == 2'd0) begin
2021-08-12 21:07:47 +02:00
clock_phase_gen <= 4'b0001;
end else if (clock_tick) begin
clock_phase_gen <= {clock_phase_gen[2:0], clock_phase_gen[3]};
end
end
reg [3:0] bit_counter;
reg sda_i_ff1, sda_i_ff2;
reg scl_o;
reg sda_o;
2021-08-15 21:49:02 +02:00
assign i2c_scl = scl_o ? 1'bZ : 1'b0;
assign i2c_sda = sda_o ? 1'bZ : 1'b0;
2021-08-12 21:07:47 +02:00
2021-08-20 19:51:55 +02:00
always_ff @(posedge sys.clk) begin
2021-08-15 21:49:02 +02:00
{sda_i_ff2, sda_i_ff1} <= {sda_i_ff1, i2c_sda};
2021-08-12 21:07:47 +02:00
2021-08-20 19:51:55 +02:00
if (sys.reset) begin
2021-08-12 21:07:47 +02:00
state <= 2'd0;
scl_o <= 1'b1;
sda_o <= 1'b1;
end else begin
case (state)
2'd0: begin
bit_counter <= 4'd0;
2021-08-15 21:49:02 +02:00
if (bus.request && bus.wmask[0]) begin
case (bus.address[2])
2021-08-12 21:07:47 +02:00
0: begin
2021-08-15 21:49:02 +02:00
if (bus.wdata[1]) state <= 2'd2;
if (bus.wdata[0]) state <= 2'd1;
2021-08-12 21:07:47 +02:00
end
1: begin
state <= 2'd3;
2021-08-15 21:49:02 +02:00
trx_data <= {bus.wdata[7:0], ~mack};
2021-08-12 21:07:47 +02:00
end
endcase
end
end
2'd1: begin
if (clock_phase[0]) begin
scl_o <= 1'b1;
sda_o <= 1'b1;
end
if (clock_phase[1]) begin
sda_o <= 1'b0;
end
if (clock_phase[3]) begin
state <= 2'd0;
scl_o <= 1'b0;
end
end
2'd2: begin
if (clock_phase[0]) begin
scl_o <= 1'b0;
sda_o <= 1'b0;
end
if (clock_phase[1]) begin
scl_o <= 1'b1;
end
if (clock_phase[3]) begin
state <= 2'd0;
sda_o <= 1'b1;
end
end
2'd3: begin
if (clock_phase[0]) begin
bit_counter <= bit_counter + 1'd1;
scl_o <= 1'b0;
sda_o <= trx_data[8];
end
if (clock_phase[1]) begin
scl_o <= 1'b1;
end
if (clock_phase[3]) begin
trx_data <= {trx_data[7:0], sda_i_ff2};
scl_o <= 1'b0;
end
if (bit_counter == 4'b1010) begin
state <= 2'd0;
end
end
default: begin
state <= 2'd0;
scl_o <= 1'b1;
sda_o <= 1'b1;
end
endcase
end
end
2021-08-05 19:50:29 +02:00
endmodule