Skip to content
Permalink
Fetching contributors…
Cannot retrieve contributors at this time
229 lines (209 sloc) 6.44 KB
// Secure EEPROM
`ifdef DEBUG
`define DEBUG_DISPLAY(_args) $display("%s", $sformatf _args);
`else
`define DEBUG_DISPLAY(_args)
`endif
module seeprom (
input i_clk,
input logic i_i2c_scl,
input logic i_i2c_sda,
output logic o_i2c_sda
);
initial begin
o_i2c_sda = 1;
i2c_state = I2C_IDLE;
mem_secure = 0;
i2c_scl_state = I2C_SCL_STABLE_HIGH;
i2c_address_valid = 0;
end
/* verilator lint_off UNDRIVEN */
enum {
I2C_IDLE,
I2C_START,
I2C_LOAD_CONTROL,
I2C_ACK_THEN_LOAD_ADDRESS,
I2C_ACK_THEN_READ,
I2C_ACK_THEN_WRITE,
I2C_LOAD_ADDRESS,
I2C_READ,
I2C_WRITE,
I2C_ACK,
I2C_NACK
} i2c_state;
/* verilator lint_on UNDRIVEN */
logic [255:0][7:0] mem_storage;
logic [3:0] mem_secure;
logic [7:0] i2c_control;
logic [3:0] i2c_control_bits;
logic [7:0] i2c_address;
logic [3:0] i2c_address_bits;
logic i2c_address_valid;
logic [7:0] i2c_data;
logic [3:0] i2c_data_bits;
wire i2c_address_secure = mem_secure[i2c_address / 64];
wire i2c_next_address_secure = mem_secure[(i2c_address + 1) / 64];
wire [3:0] i2c_control_prefix = i2c_control[7:4];
wire [3:0] i2c_control_bank = i2c_control[3:0];
wire i2c_control_rw = i2c_control[0];
`define I2C_CONTROL_EEPROM 4'b1010
`define I2C_CONTROL_SECURE 4'b0101
logic i2c_last_scl;
logic i2c_last_sda;
always_ff @(posedge i_clk) begin
i2c_last_scl <= i_i2c_scl;
i2c_last_sda <= i_i2c_sda;
end
/* verilator lint_off UNDRIVEN */
enum {
I2C_SCL_STABLE_HIGH,
I2C_SCL_STABLE_LOW,
I2C_SCL_FALLING,
I2C_SCL_RISING
} i2c_scl_state;
/* verilator lint_on UNDRIVEN */
always_comb begin
if (i2c_last_scl && i_i2c_scl) begin
i2c_scl_state = I2C_SCL_STABLE_HIGH;
end else if (!i2c_last_scl && !i_i2c_scl) begin
i2c_scl_state = I2C_SCL_STABLE_LOW;
end else if (i2c_last_scl && !i_i2c_scl) begin
i2c_scl_state = I2C_SCL_FALLING;
end else if (!i2c_last_scl && i_i2c_scl) begin
i2c_scl_state = I2C_SCL_RISING;
end
end
wire i2c_start;
wire i2c_stop;
always_comb begin
if (i2c_scl_state == I2C_SCL_STABLE_HIGH) begin
i2c_start = i2c_last_sda && !i_i2c_sda;
i2c_stop = !i2c_last_sda && i_i2c_sda;
end else begin
i2c_start = 0;
i2c_stop = 0;
end
end
`define ACK_THEN_TRANSITION(_ack, _next_state) \
begin \
if (i2c_scl_state == I2C_SCL_FALLING) begin \
o_i2c_sda <= _ack; \
end else if (i2c_scl_state == I2C_SCL_RISING) begin \
i2c_state <= _next_state; \
end \
end
always_ff @(posedge i_clk) begin
`DEBUG_DISPLAY(("i2c_state = %s", i2c_state.name));
`DEBUG_DISPLAY(("i2c_scl_state = %s", i2c_scl_state.name));
`DEBUG_DISPLAY(("i2c_address_valid = %b", i2c_address_valid));
`DEBUG_DISPLAY(("mem_secure = %b", mem_secure));
case (i2c_state)
I2C_IDLE: begin
if (i2c_start) begin
i2c_state <= I2C_START;
end
end
I2C_START: begin
if (i2c_scl_state == I2C_SCL_FALLING) begin
i2c_control_bits <= 0;
i2c_state <= I2C_LOAD_CONTROL;
end
end
I2C_LOAD_CONTROL: begin
`DEBUG_DISPLAY(("i2c_control = %b", i2c_control));
`DEBUG_DISPLAY(("i2c_control_bits = %d", i2c_control_bits));
if (i2c_control_bits == 8) begin
case (i2c_control_prefix)
`I2C_CONTROL_EEPROM: begin
if (i2c_control_rw) begin
if (i2c_address_valid) begin
i2c_data_bits <= 0;
i2c_state <= I2C_ACK_THEN_READ;
end else begin
i2c_state <= I2C_NACK;
end
end else begin
i2c_address_bits <= 0;
i2c_state <= I2C_ACK_THEN_LOAD_ADDRESS;
end
end
`I2C_CONTROL_SECURE: begin
mem_secure <= mem_secure | i2c_control_bank;
i2c_state <= I2C_ACK;
end
default: begin
i2c_state <= I2C_NACK;
end
endcase
i2c_control_bits <= 0;
end else if (i2c_scl_state == I2C_SCL_RISING) begin
i2c_control <= {i2c_control[6:0], i_i2c_sda};
i2c_control_bits <= i2c_control_bits + 1;
end
end
I2C_LOAD_ADDRESS: begin
`DEBUG_DISPLAY(("i2c_address = %b", i2c_address));
`DEBUG_DISPLAY(("i2c_address_bits = %d", i2c_address_bits));
if (i2c_address_bits == 8) begin
if (i2c_address_secure) begin
i2c_address_valid <= 0;
i2c_state <= I2C_NACK;
end else begin
i2c_data_bits <= 0;
i2c_address_valid <= 1;
i2c_state <= I2C_ACK_THEN_WRITE;
end
end else if (i2c_scl_state == I2C_SCL_RISING) begin
i2c_address <= {i2c_address[6:0], i_i2c_sda};
i2c_address_bits <= i2c_address_bits + 1;
end
end
I2C_WRITE: begin
`DEBUG_DISPLAY(("i2c_data_ = %b", i2c_data));
`DEBUG_DISPLAY(("i2c_data_bits = %d", i2c_data_bits));
if (i2c_data_bits == 8) begin
i2c_data_bits <= 0;
if (i2c_address_secure == i2c_next_address_secure) begin
`DEBUG_DISPLAY(("WRITE: i2c_address = 0x%x, i2c_data = 0x%x", i2c_address, i2c_data));
mem_storage[i2c_address] <= i2c_data;
i2c_address <= i2c_address + 1;
i2c_state <= I2C_ACK_THEN_WRITE;
end else begin
i2c_state <= I2C_NACK;
end
end else if (i2c_scl_state == I2C_SCL_RISING) begin
i2c_data <= {i2c_data[6:0], i_i2c_sda};
i2c_data_bits <= i2c_data_bits + 1;
end
end
I2C_READ: begin
`DEBUG_DISPLAY(("i2c_data_bits = %d", i2c_data_bits));
if (i2c_data_bits == 8 && i2c_scl_state == I2C_SCL_RISING) begin
i2c_data_bits <= 0;
if (i2c_address_secure == i2c_next_address_secure) begin
`DEBUG_DISPLAY(("READ: i2c_address = 0x%x", i2c_address));
i2c_address <= i2c_address + 1;
i2c_state <= I2C_ACK_THEN_READ;
end else begin
i2c_state <= I2C_NACK;
end
end else if (i2c_scl_state == I2C_SCL_FALLING) begin
`DEBUG_DISPLAY(("READ (bit): i2c_address = 0x%x", i2c_address));
o_i2c_sda <= mem_storage[i2c_address][7 - i2c_data_bits[2:0]];
i2c_data_bits <= i2c_data_bits + 1;
end
end
I2C_ACK: `ACK_THEN_TRANSITION(0, I2C_IDLE)
I2C_ACK_THEN_LOAD_ADDRESS: `ACK_THEN_TRANSITION(0, I2C_LOAD_ADDRESS)
I2C_ACK_THEN_READ: `ACK_THEN_TRANSITION(0, I2C_READ)
I2C_ACK_THEN_WRITE: `ACK_THEN_TRANSITION(0, I2C_WRITE)
I2C_NACK: `ACK_THEN_TRANSITION(1, I2C_IDLE)
endcase
if (i2c_stop) begin
i2c_address_valid <= 0;
i2c_state <= I2C_IDLE;
end else if (i2c_start) begin
i2c_state <= I2C_START;
end
end
endmodule
You can’t perform that action at this time.