§ TOP-схема
Тактировать на 25 мгц, но в целом, можно на любой близкой частоте.Эта версия отличается от предыдущей тем, что здесь учтена проверка бита четности, а также истечение таймаута для предотвращения зависания в статусе чтения, улучшена установка done на негативном фронте.
wire [ 7:0] ps_data; wire ps_done; ps2 Keyb ( .clock (clock_25), .ps_clock (PS2_CLK), .ps_data (PS2_DAT), .done (ps_done), .data (ps_data) ); // Пример имплементации reg [7:0] new_data; always @(posedge clock_25) if (ps_done) new_data <= ps_data;
§ Код ps2.v
module ps2 ( input clock, input ps_clock, input ps_data, output reg done, output reg [7:0] data ); reg kbusy = 1'b0; reg kdone = 1'b0; reg [1:0] klatch = 2'b00; reg [3:0] kcount = 1'b0; reg [9:0] kin = 1'b0; reg [19:0] kout = 1'b0; initial begin data = 8'h00; done = 1'b0; end // Для повышения точности always @(negedge clock) done <= kdone; // Основная логика работы контроллера always @(posedge clock) begin kdone <= 1'b0; // Процесс приема сигнала if (kbusy) begin // Позитивный фронт if (klatch == 2'b01) begin // Завершающий такт if (kcount == 4'hA) begin data <= kin[8:1]; kbusy <= 1'b0; kdone <= ^kin[9:1]; // =1 Если четность совпадает end kcount <= kcount + 1'b1; kin <= {ps_data, kin[9:1]}; end // Считать "зависший процесс" kout <= ps_clock ? kout + 1 : 1'b0; // И если прошло более 20 мс, то перевести в состояние ожидания if (kout > 25000*20) kbusy <= 1'b0; end else begin // Обнаружен негативный фронт \__ if (klatch == 2'b10) begin kbusy <= 1'b1; // Активировать прием данных kcount <= 1'b0; kout <= 1'b0; end end klatch <= {klatch[0], ps_clock}; end endmodule