Если поможет, такая реализация:
CODE
`timescale 1ns / 1ps
module iButton(
// --------------- Сигналы сброса и синхронизации. --------------- //
input LRESETn, // Асинхронный сброс (формируется после того, как уровни напряжения питания моста будут в допуске).
input wFtakt, // Тактовая частота 33 МГц.
// --------------- Внутренние сигналы. --------------- //
input [7:0] D_CPU_iBut, // Данные для выдачи по интерфейсу 1-Wire.
input [1:0] CMD_In, // Код операции.
input [3:0] Add_In, // Адрес регистра данных/команд со стороны адресного простанства процессора (Add_In = 4'b0101).
input WE, // Сигнал записи в регистр данных/команд (запускает автомат состояний).
input OE, // Сигнал подтверждения ("1") операции записи.
input CS, // Сигнал выбора кристалла ("0").
output [7:0] D_iBut_CPU, // Данные, принятые по интерфейсу 1-Wire.
output [1:0] CMD_Out, // Команда, записанная в приемный регистр команд.
output iBut_Busy, // Линия занята (сигнал логической "1" - наличие обмена данными).
output iBut_Pres, // Устройство присутствует на шине (сигнал логической "1" - устройство на шине).
// --------------- Интерфейс 1-Wire. --------------- //
input iButIn,
output iButOut
);
// --------------- Регистр команд. --------------- //
reg [1:0] RgCom;
always @(posedge WE or negedge LRESETn)
begin
if (~LRESETn)
RgCom <= 2'd0;
else if ((Add_In == 4'b1000) && OE && ~CS)
RgCom <= CMD_In;
end
assign CMD_Out = RgCom;
wire w_Res_iBut = (RgCom == 2'b00); // Инициирована диаграмма сброса с последующим определением устройства на шине.
wire w_Wr_iBut = (RgCom == 2'b01); // Инициирована диаграмма записи данных в устройство.
// --------------- Регистр наличия (уровень логической "1") устройства i-Button на шине. --------------- //
reg Rg_iB_PRS; // Регистр наличия устройства i-Button на шине.
reg Ena_Rg_iB_PRS; // Установка в "1" регистра наличия устройства i-Button на шине.
reg Clr_Rg_iB_PRS; // Сброс в "0" регистра наличия устройства i-Button на шине.
always @(posedge wFtakt or posedge Clr_Rg_iB_PRS)
begin
if (Clr_Rg_iB_PRS)
Rg_iB_PRS <= 1'b0;
else if (Ena_Rg_iB_PRS)
Rg_iB_PRS <= 1'b1;
end
assign iBut_Pres = Rg_iB_PRS;
// --------------- Регистр занятости (уровень логической "1") устройства i-Button на шине. --------------- //
reg Rg_iB_BSY; // Регистр занятости устройства i-Button на шине.
reg Clr_Rg_iB_BSY; // Сброс в "0" регистра занятости устройства i-Button на шине.
always @(posedge WE or posedge Clr_Rg_iB_BSY)
begin
if (Clr_Rg_iB_BSY)
Rg_iB_BSY <= 1'b0;
else if ((Add_In == 4'b1000) && OE && ~CS)
Rg_iB_BSY <= 1'b1;
end
assign iBut_Busy = Rg_iB_BSY;
// --------------- Строб запуска автомата состояний. --------------- //
/*
Импульс формируется из строба занятости устройства путем привязки к
основной тактовой частоте и задержки на соответствующее кол-во тактов.
Этот же импульс, записывает принятые данные в сдвиговый регистр выдачи данных.
*/
reg Rg_iB_BSY_Z1; // Задержка строба занятости на один такт.
reg Rg_iB_BSY_Z2; // Задержка строба занятости на два такта.
always @(posedge wFtakt or negedge LRESETn)
begin
if (~LRESETn)
begin
Rg_iB_BSY_Z1 <= 1'b0;
Rg_iB_BSY_Z2 <= 1'b0;
end
else
begin
Rg_iB_BSY_Z1 <= Rg_iB_BSY;
Rg_iB_BSY_Z2 <= Rg_iB_BSY_Z1;
end
end
wire Rg_Start_SM = Rg_iB_BSY_Z1 && ~Rg_iB_BSY_Z2;
// --------------- Приемный регистр команд/данных шины iButton. --------------- //
reg [7:0] Rec_Rg_CD;
always @(posedge WE or negedge LRESETn)
begin
if (~LRESETn)
Rec_Rg_CD <= 8'd0;
else if ((Add_In == 4'b1000) && OE && ~CS)
Rec_Rg_CD <= D_CPU_iBut;
end
// --------------- Сдвиговый регистр выдачи команд/данных шины iButton. --------------- //
/*
Данные выдаются на линию в следующей последовательности: D[0], D[1], D[2]...D[6], D[7].
*/
reg [7:0] Rg_CD; // Сдвиговый регистр выдачи команд/данных шины iButton.
reg Ena_Rg_CD; // Разрешение сдвига данных регистра 'Rg_CD'.
always @(posedge wFtakt or negedge LRESETn)
begin
if (~LRESETn)
Rg_CD <= 8'd0;
else if (Rg_Start_SM)
Rg_CD <= Rec_Rg_CD;
else if (Ena_Rg_CD)
begin
Rg_CD[6:0] <= Rg_CD[7:1];
Rg_CD[0] <= Rg_CD[1];
end
end
// --------------- Мультиплексор управления выдачей на линию данных iButton либо "1", либо "0", либо разряда данных. --------------- //
reg [1:0] Upr_MUX;
reg Rg_iB_Out; // Регистр выдачи данных.
always @ (posedge wFtakt)
begin
case (Upr_MUX)
2'd0 : Rg_iB_Out <= 1'b1;
2'd1 : Rg_iB_Out <= 1'b0;
2'd2 : Rg_iB_Out <= Rg_CD[0];
default : Rg_iB_Out <= 1'b1;
endcase
end
assign iButOut = Rg_iB_Out;
// --------------- Cчетчик длительности импульса сброса в режиме инициализации. --------------- //
/*
Разрядность счетчика 2^14 = 16384.
Тактовая частота счетчика 32 МГц, следовательно период 31,25 нсек.
*/
reg [13:0] CntRes; // Cчетчик длительности импульса сброса в режиме инициализации.
reg EnaCntRes; // Разрешение счета счетчика 'CntRes'.
reg ClrCntRes; // Сигнал сброса счетчика 'CntRes'.
always @(posedge wFtakt or negedge ClrCntRes)
begin
if (~ClrCntRes)
CntRes <= 14'd0;
else if (EnaCntRes)
CntRes <= CntRes + 1'b1;
end
wire w_512us = (CntRes == 14'h3FFF); // Значение счетчика 'CntRes' равно 16384 (512 мкс).
wire w_100us = (CntRes == 14'h0C80); // Значение счетчика 'CntRes' равно 3200 (100 мкс).
// --------------- Привязка цепей 'w_512us' и 'w_100us' к тактовой частоте. --------------- //
reg Rg_w_512us;
reg Rg_w_100us;
always @(posedge wFtakt or negedge LRESETn)
begin
if (~LRESETn)
begin
Rg_w_512us <= 1'b0;
Rg_w_100us <= 1'b0;
end
else
begin
Rg_w_512us <= w_512us;
Rg_w_100us <= w_100us;
end
end
// --------------- Cчетчик формирования диаграммы записи/чтения данных. --------------- //
/*
Разрядность счетчика 2^11 = 2048.
Рабочие интервалы (счетчик 11-ти разрядный):
48 * 31,25 нсек = 1,5 мксек.
480 * 31,25 нсек = 15 мксек.
2000 * 31,25 нсек = 62,5 мксек.
2048 * 31,25 нсек = 64 мксек.
*/
reg [10:0] CntData; // Cчетчик формирования диаграммы записи/чтения данных.
reg EnaCntData; // Разрешение счета счетчика 'CntData'.
reg ClrCntData; // Сигнал сброса счетчика 'CntData'.
always @(posedge wFtakt or negedge ClrCntData)
begin
if (~ClrCntData)
CntData <= 11'd0;
else if (EnaCntData)
CntData <= CntData + 1'b1;
end
wire w_1_5us = (CntData == 11'h2F); // Значение счетчика 'CntData' равно 48 (1,5 мкс).
wire w_15us = (CntData == 11'h1DF); // Значение счетчика 'CntData' равно 480 (15 мкс).
wire w_62_5us = (CntData == 11'h7CF); // Значение счетчика 'CntData' равно 2000 (62,5 мкс).
wire w_64us = (CntData == 11'h7FF); // Значение счетчика 'CntData' равно 2048 (64 мкс).
// --------------- Привязка цепей 'w_1_5us', 'w_15us', 'w_62_5us', 'w_64us' к тактовой частоте. --------------- //
reg Rg_w_1_5us;
reg Rg_w_15us;
reg Rg_w_62_5us;
reg Rg_w_64us;
always @(posedge wFtakt or negedge LRESETn)
begin
if (~LRESETn)
begin
Rg_w_1_5us <= 1'b0;
Rg_w_15us <= 1'b0;
Rg_w_62_5us <= 1'b0;
Rg_w_64us <= 1'b0;
end
else
begin
Rg_w_1_5us <= w_1_5us;
Rg_w_15us <= w_15us;
Rg_w_62_5us <= w_62_5us;
Rg_w_64us <= w_64us;
end
end
// --------------- Cчетчик числа принятых/переданных бит в режиме записи/чтения команд/данных. --------------- //
reg [2:0] CntDatR; // Cчетчик числа принятых/переданных бит в режиме записи/чтения команд/данных.
reg ClrCntDatR; // Сигнал сброса счетчика 'CntDatR'.
always @(posedge wFtakt or negedge ClrCntDatR)
begin
if (~ClrCntDatR)
CntDatR <= 3'd0;
else if (Ena_Rg_CD)
CntDatR <= CntDatR + 1'b1;
end
// --------------- Привязка входной линии данных к тактовой частоте. --------------- //
reg Rg_iB_In;
always @(posedge wFtakt or negedge LRESETn)
begin
if (~LRESETn)
Rg_iB_In <= 1'b0;
else
Rg_iB_In <= iButIn;
end
// --------------- Приемный регистр данных с шины i-Button. --------------- //
/*
Данные принимаются в следующей последовательности: D[0], D[1], D[2], D[3]...D[6], D[7].
*/
reg [7:0] RgRdShift; // Приемный регистр данных с шины i-Button.
reg EnaRdShift; // Сигнал разрешения записи в сдвиговый регистр в цикле чтения данных.
always @(posedge wFtakt or negedge LRESETn)
begin
if (~LRESETn)
RgRdShift <= 8'd0;
else if (EnaRdShift)
begin
RgRdShift[6:0] <= RgRdShift[7:1];
RgRdShift[7] <= Rg_iB_In;
end
end
assign D_iBut_CPU = RgRdShift;
// --------------- Объявление автомата состояний. --------------- //
reg [9:0] State;
parameter [9:0]
Idle = 10'b0000000001,
Wait_Zero = 10'b0000000010,
Wait_One = 10'b0000000100,
Wait_One2 = 10'b0000001000,
CS_Low = 10'b0000010000,
CS_TransD = 10'b0000100000,
CS_RecD = 10'b0001000000,
Wait_Exch = 10'b0010000000,
End_Trans = 10'b0100000000,
Back_Off = 10'b1000000000;
// --------------- Автомат состояний Миля с синхронными выходами. --------------- //
always @ (posedge wFtakt or negedge LRESETn)
begin
if (!LRESETn)
begin
State <= Idle;
Ena_Rg_iB_PRS <= 1'b0; // Установка в "1" регистра наличия устройства i-Button на шине.
Clr_Rg_iB_PRS <= 1'b0; // Сброс в "0" регистра наличия устройства i-Button на шине.
Clr_Rg_iB_BSY <= 1'b0; // Сброс в "0" регистра занятости устройства i-Button на шине.
EnaCntRes <= 1'b0; // Разрешение счета счетчика 'CntRes'.
ClrCntRes <= 1'b0; // Сигнал сброса счетчика 'CntRes'.
Upr_MUX <= 2'd0; // Мультиплексор управления выдачей на линию данных.
Ena_Rg_CD <= 1'b0; // Разрешение сдвига данных регистра 'Rg_CD'.
EnaCntData <= 1'b0; // Разрешение счета счетчика 'CntData'.
ClrCntData <= 1'b0; // Сигнал сброса счетчика 'CntData'.
ClrCntDatR <= 1'b0; // Сигнал сброса счетчика 'CntDatR'.
EnaRdShift <= 1'b0; // Сигнал разрешения записи в сдвиговый регистр в цикле чтения данных.
end
else
begin
case (State)
Idle: // Ожидание импульса запуска автомата состояний.
begin
if (Rg_Start_SM)
begin
Upr_MUX <= 2'd1; // На линию данных выдаем логический "0".
if (w_Res_iBut) // Команда сброса с последующей инициализацией устройства на шине.
begin
State <= Wait_Zero;
EnaCntRes <= 1'b1;
ClrCntRes <= 1'b1;
end
else
begin
State <= CS_Low;
EnaCntData <= 1'b1;
ClrCntData <= 1'b1;
ClrCntDatR <= 1'b1;
end
end
else
begin
State <= Idle;
end
end
Wait_Zero:
begin
if (Rg_w_512us)
begin
State <= Wait_One;
Upr_MUX <= 2'd0; // На линию данных выдаем логическую "1".
end
else
State <= Wait_Zero;
end
Wait_One:
begin
if (Rg_w_100us)
begin
if (Rg_iB_In) // На шине нет устройств.
begin
State <= End_Trans;
Clr_Rg_iB_PRS <= 1'b1;
end
else
begin
State <= Wait_One2; // На шине есть устройства.
Ena_Rg_iB_PRS <= 1'b1;
end
end
else
State <= Wait_One;
end
Wait_One2:
begin
Ena_Rg_iB_PRS <= 1'b0;
if (Rg_w_512us)
State <= End_Trans;
else
State <= Wait_One2;
end
CS_Low:
begin
Ena_Rg_CD <= 1'b0;
if (Rg_w_1_5us)
begin
if (w_Wr_iBut) // Команда записи данных.
begin
State <= CS_TransD;
Upr_MUX <= 2'd2;
end
else
begin
State <= CS_RecD;
Upr_MUX <= 2'd0;
end
end
else
State <= CS_Low;
end
CS_TransD:
begin
if (Rg_w_62_5us)
begin
State <= Wait_Exch;
Upr_MUX <= 2'd0;
end
else
State <= CS_TransD;
end
CS_RecD:
begin
if (Rg_w_15us)
begin
State <= Wait_Exch;
EnaRdShift <= 1'b1;
end
else
State <= CS_RecD;
end
Wait_Exch:
begin
EnaRdShift <= 1'b0;
if (Rg_w_64us)
begin
if (CntDatR == 3'd7)
State <= End_Trans;
else
begin
State <= CS_Low;
Upr_MUX <= 2'd1;
Ena_Rg_CD <= 1'b1;
end
end
else
State <= Wait_Exch;
end
End_Trans:
begin
State <= Back_Off;
Clr_Rg_iB_PRS <= 1'b0;
EnaCntRes <= 1'b0;
ClrCntRes <= 1'b0;
Clr_Rg_iB_BSY <= 1'b1;
Upr_MUX <= 2'd0;
EnaCntData <= 1'b0;
ClrCntData <= 1'b0;
ClrCntDatR <= 1'b0;
end
Back_Off:
begin
State <= Idle;
Clr_Rg_iB_BSY <= 1'b0;
end
default:
begin
State <= Idle;
Ena_Rg_iB_PRS <= 1'b0;
Clr_Rg_iB_PRS <= 1'b0;
Clr_Rg_iB_BSY <= 1'b0;
EnaCntRes <= 1'b0;
ClrCntRes <= 1'b0;
Upr_MUX <= 2'd0;
Ena_Rg_CD <= 1'b0;
EnaCntData <= 1'b0;
ClrCntData <= 1'b0;
ClrCntDatR <= 1'b0;
EnaRdShift <= 1'b0;
end
endcase
end
end
endmodule