module i2c_slave(sda, scl); inout sda; input scl; localparam I2C_ADR = 7'h27; reg adr_match; // флажок совпадения адреса устройства reg [2:0] phase; // 01 - проверка адреса устройства, 10 - запись адреса регистра, 00 - запись значения регистра reg [7:0] reg_mem; // значение адреса регистра reg [7:0] val_mem; // значение регистра reg [3:0] bitcnt; // счетчик битов reg start; // устанавливаем start = 1 при обнаружении START последовательности // другие события устанавливают start = 0 always @(negedge sda or negedge scl) if(~sda) start <= scl; else start <= 0; always @(negedge scl or posedge start) if(start) begin // start = 1, сработал триггер posedge start bitcnt <= 4'h8; // инициируем счетчик битов phase = 2'b01; // переходим к проверки адреса устройства end else begin // start = 0, сработал триггер negedge scl if(bitcnt[3]) begin // считали последний бит bitcnt <= 4'h8; // инициируем счетчик битов phase <= phase << 1; // переходим к записи либо адреса либо значения регистра end else bitcnt <= bitcnt - 4'h1; // уменьшаем счетчик битов end always @(posedge scl) begin // проверка адреса устройства // первый бит адреса, если совпадают - поднимаем флажок совпадения // если хотя бы один бит не совпадает - сбрасываем флажок совпадения if(phase[0] & bitcnt == 7) adr_match <= (sda == I2C_ADR[6]); if(phase[0] & bitcnt == 6 & sda != I2C_ADR[5]) adr_match <= 1'b0; if(phase[0] & bitcnt == 5 & sda != I2C_ADR[4]) adr_match <= 1'b0; if(phase[0] & bitcnt == 4 & sda != I2C_ADR[3]) adr_match <= 1'b0; if(phase[0] & bitcnt == 3 & sda != I2C_ADR[2]) adr_match <= 1'b0; if(phase[0] & bitcnt == 2 & sda != I2C_ADR[1]) adr_match <= 1'b0; if(phase[0] & bitcnt == 1 & sda != I2C_ADR[0]) adr_match <= 1'b0; // запись адреса регистра, только если адрес устройства совпадает if(phase[1] & adr_match) reg_mem[bitcnt] <= sda; // запись значения регистра, только если адрес устройства совпадает if(phase == 2'b00 & adr_match) val_mem[bitcnt] <= sda; end // переполнение счетчика, считали последний бит // если адрес устройства совпадает, прижимаем sda // иначе позволяем прижать другому устройству assign sda = (bitcnt[3] & adr_match) ? 1'b0 : 1'bz; endmodule