//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//// ////
|
//// ////
|
//// ps2_keyboard_model.v ////
|
//// ps2_keyboard_model.v ////
|
//// ////
|
//// ////
|
//// This file is part of the "ps2" project ////
|
//// This file is part of the "ps2" project ////
|
//// http://www.opencores.org/cores/ps2/ ////
|
//// http://www.opencores.org/cores/ps2/ ////
|
//// ////
|
//// ////
|
//// Author(s): ////
|
//// Author(s): ////
|
//// - mihad@opencores.org ////
|
//// - mihad@opencores.org ////
|
//// - Miha Dolenc ////
|
//// - Miha Dolenc ////
|
//// ////
|
//// ////
|
//// All additional information is avaliable in the README.txt ////
|
//// All additional information is avaliable in the README.txt ////
|
//// file. ////
|
//// file. ////
|
//// ////
|
//// ////
|
//// ////
|
//// ////
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//// ////
|
//// ////
|
//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org ////
|
//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org ////
|
//// ////
|
//// ////
|
//// This source file may be used and distributed without ////
|
//// This source file may be used and distributed without ////
|
//// restriction provided that this copyright statement is not ////
|
//// restriction provided that this copyright statement is not ////
|
//// removed from the file and that any derivative work contains ////
|
//// removed from the file and that any derivative work contains ////
|
//// the original copyright notice and the associated disclaimer. ////
|
//// the original copyright notice and the associated disclaimer. ////
|
//// ////
|
//// ////
|
//// This source file is free software; you can redistribute it ////
|
//// This source file is free software; you can redistribute it ////
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
//// Public License as published by the Free Software Foundation; ////
|
//// Public License as published by the Free Software Foundation; ////
|
//// either version 2.1 of the License, or (at your option) any ////
|
//// either version 2.1 of the License, or (at your option) any ////
|
//// later version. ////
|
//// later version. ////
|
//// ////
|
//// ////
|
//// This source is distributed in the hope that it will be ////
|
//// This source is distributed in the hope that it will be ////
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
//// details. ////
|
//// details. ////
|
//// ////
|
//// ////
|
//// You should have received a copy of the GNU Lesser General ////
|
//// You should have received a copy of the GNU Lesser General ////
|
//// Public License along with this source; if not, download it ////
|
//// Public License along with this source; if not, download it ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// ////
|
//// ////
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//
|
//
|
// CVS Revision History
|
// CVS Revision History
|
//
|
//
|
// $Log: not supported by cvs2svn $
|
// $Log: not supported by cvs2svn $
|
// Revision 1.2 2002/04/09 13:15:16 mihad
|
// Revision 1.2 2002/04/09 13:15:16 mihad
|
// Wrong acknowledge generation during receiving repaired
|
// Wrong acknowledge generation during receiving repaired
|
//
|
//
|
// Revision 1.1.1.1 2002/02/18 16:16:55 mihad
|
// Revision 1.1.1.1 2002/02/18 16:16:55 mihad
|
// Initial project import - working
|
// Initial project import - working
|
//
|
//
|
//
|
//
|
|
|
`include "timescale.v"
|
`include "timescale.v"
|
|
|
module ps2_keyboard_model
|
module ps2_keyboard_model
|
(
|
(
|
kbd_clk_io,
|
kbd_clk_io,
|
kbd_data_io,
|
kbd_data_io,
|
last_char_received_o,
|
last_char_received_o,
|
char_valid_o
|
char_valid_o
|
);
|
);
|
|
|
parameter [31:0] kbd_clk_period = 50000; // chould be between 33 and 50 us to generate the clock between 30 and 20 kHz
|
parameter [31:0] kbd_clk_period = 50000; // chould be between 33 and 50 us to generate the clock between 30 and 20 kHz
|
|
|
inout kbd_clk_io,
|
inout kbd_clk_io,
|
kbd_data_io ;
|
kbd_data_io ;
|
|
|
output [7:0] last_char_received_o ;
|
output [7:0] last_char_received_o ;
|
reg [7:0] last_char_received_o ;
|
reg [7:0] last_char_received_o ;
|
|
|
output char_valid_o ;
|
output char_valid_o ;
|
reg char_valid_o ;
|
reg char_valid_o ;
|
|
|
reg kbd_clk,
|
reg kbd_clk,
|
kbd_data ;
|
kbd_data ;
|
|
|
assign kbd_clk_io = kbd_clk ? 1'bz : 1'b0 ;
|
assign kbd_clk_io = kbd_clk ? 1'bz : 1'b0 ;
|
assign kbd_data_io = kbd_data ? 1'bz : 1'b0 ;
|
assign kbd_data_io = kbd_data ? 1'bz : 1'b0 ;
|
|
|
reg receiving ;
|
reg receiving ;
|
initial
|
initial
|
begin
|
begin
|
kbd_clk = 1'b1 ;
|
kbd_clk = 1'b1 ;
|
kbd_data = 1'b1 ;
|
kbd_data = 1'b1 ;
|
|
|
last_char_received_o = 0 ;
|
last_char_received_o = 0 ;
|
char_valid_o = 0 ;
|
char_valid_o = 0 ;
|
|
|
receiving = 0 ;
|
receiving = 0 ;
|
end
|
end
|
|
|
always@(kbd_data_io or kbd_clk_io)
|
always@(kbd_data_io or kbd_clk_io)
|
begin
|
begin
|
// check if host is driving keyboard data low and doesn't drive clock
|
// check if host is driving keyboard data low and doesn't drive clock
|
if ( !kbd_data_io && kbd_data && kbd_clk_io)
|
if ( !kbd_data_io && kbd_data && kbd_clk_io)
|
begin
|
begin
|
// wait for half of clock period
|
// wait for half of clock period
|
#(kbd_clk_period/2) ;
|
#(kbd_clk_period/2) ;
|
|
|
// state hasn't changed - host wishes to send data - go receiving
|
// state hasn't changed - host wishes to send data - go receiving
|
if ( !kbd_data_io && kbd_data && kbd_clk_io)
|
if ( !kbd_data_io && kbd_data && kbd_clk_io)
|
kbd_receive_char(last_char_received_o) ;
|
kbd_receive_char(last_char_received_o) ;
|
end
|
end
|
end
|
end
|
|
|
task kbd_send_char ;
|
task kbd_send_char ;
|
input [7:0] char ;
|
input [7:0] char ;
|
output transmited_ok ;
|
output transmited_ok ;
|
output severe_error ;
|
output severe_error ;
|
reg [10:0] tx_reg ;
|
reg [10:0] tx_reg ;
|
integer i ;
|
integer i ;
|
begin:main
|
begin:main
|
severe_error = 1'b0 ;
|
severe_error = 1'b0 ;
|
transmited_ok = 1'b0 ;
|
transmited_ok = 1'b0 ;
|
|
|
wait ( !receiving ) ;
|
wait ( !receiving ) ;
|
|
|
tx_reg = { 1'b1, !(^char), char, 1'b0 } ;
|
tx_reg = { 1'b1, !(^char), char, 1'b0 } ;
|
|
|
fork
|
fork
|
begin:wait_for_idle
|
begin:wait_for_idle
|
wait( (kbd_clk_io === 1'b1) && (kbd_data_io === 1'b1) ) ;
|
wait( (kbd_clk_io === 1'b1) && (kbd_data_io === 1'b1) ) ;
|
// disable timeout ;
|
// disable timeout ;
|
end
|
end
|
/*begin:timeout
|
/*begin:timeout
|
#(256 * kbd_clk_period) ;
|
#(256 * kbd_clk_period) ;
|
$display("Error! Keyboard bus did not go idle in 256 keyboard clock cycles time!") ;
|
$display("Error! Keyboard bus did not go idle in 256 keyboard clock cycles time!") ;
|
severe_error = 1'b1 ;
|
severe_error = 1'b1 ;
|
transmited_ok = 1'b0 ;
|
transmited_ok = 1'b0 ;
|
disable main ;
|
disable main ;
|
end*/
|
end*/
|
join
|
join
|
|
|
#(kbd_clk_period/2) ;
|
#(kbd_clk_period/2) ;
|
if ( !kbd_clk_io )
|
if ( !kbd_clk_io )
|
begin
|
begin
|
transmited_ok = 1'b0 ;
|
transmited_ok = 1'b0 ;
|
kbd_data = 1'b1 ;
|
kbd_data = 1'b1 ;
|
disable main ;
|
disable main ;
|
end
|
end
|
|
|
i = 0 ;
|
i = 0 ;
|
while ( i < 11 )
|
while ( i < 11 )
|
begin
|
begin
|
kbd_data = tx_reg[i] ;
|
kbd_data = tx_reg[i] ;
|
|
|
#(kbd_clk_period/2) ;
|
#(kbd_clk_period/2) ;
|
|
|
if ( !kbd_clk_io )
|
if ( !kbd_clk_io )
|
begin
|
begin
|
transmited_ok = 1'b0 ;
|
transmited_ok = 1'b0 ;
|
kbd_data = 1'b1 ;
|
kbd_data = 1'b1 ;
|
disable main ;
|
disable main ;
|
end
|
end
|
|
|
kbd_clk = 1'b0 ;
|
kbd_clk = 1'b0 ;
|
|
|
i = i + 1 ;
|
i = i + 1 ;
|
|
|
#(kbd_clk_period/2) ;
|
#(kbd_clk_period/2) ;
|
kbd_clk = 1'b1 ;
|
kbd_clk = 1'b1 ;
|
end
|
end
|
|
|
if ( i == 11 )
|
if ( i == 11 )
|
transmited_ok = 1'b1 ;
|
transmited_ok = 1'b1 ;
|
end
|
end
|
endtask // kbd_send_char
|
endtask // kbd_send_char
|
|
|
task kbd_receive_char;
|
task kbd_receive_char;
|
output [7:0] char ;
|
output [7:0] char ;
|
reg parity ;
|
reg parity ;
|
integer i ;
|
integer i ;
|
reg stop_clocking ;
|
reg stop_clocking ;
|
begin:main
|
begin:main
|
i = 0 ;
|
i = 0 ;
|
receiving = 1 ;
|
receiving = 1 ;
|
stop_clocking = 1'b0 ;
|
stop_clocking = 1'b0 ;
|
|
|
#(kbd_clk_period/2) ;
|
#(kbd_clk_period/2) ;
|
|
|
while ( !stop_clocking )
|
while ( !stop_clocking )
|
begin
|
begin
|
|
|
if ( !kbd_clk_io )
|
if ( !kbd_clk_io )
|
begin
|
begin
|
receiving = 0 ;
|
receiving = 0 ;
|
disable main ;
|
disable main ;
|
end
|
end
|
|
|
kbd_clk = 1'b0 ;
|
kbd_clk = 1'b0 ;
|
|
|
#(kbd_clk_period/2) ;
|
#(kbd_clk_period/2) ;
|
|
|
kbd_clk = 1'b1 ;
|
kbd_clk = 1'b1 ;
|
|
|
if ( i > 0 )
|
if ( i > 0 )
|
begin
|
begin
|
if ( i <= 8 )
|
if ( i <= 8 )
|
char[i - 1] = kbd_data_io ;
|
char[i - 1] = kbd_data_io ;
|
else if ( i == 9 )
|
else if ( i == 9 )
|
begin
|
begin
|
parity = kbd_data_io ;
|
parity = kbd_data_io ;
|
if ( parity !== ( !(^char) ) )
|
if ( parity !== ( !(^char) ) )
|
$display("Invalid parity bit received") ;
|
$display("Invalid parity bit received") ;
|
end
|
end
|
end
|
end
|
|
|
i = i + 1 ;
|
i = i + 1 ;
|
#(kbd_clk_period/4) ;
|
#(kbd_clk_period/4) ;
|
if ( i > 9 )
|
if ( i > 9 )
|
begin
|
begin
|
if ( kbd_data_io === 1'b1 )
|
if ( kbd_data_io === 1'b1 )
|
begin
|
begin
|
kbd_data <= 1'b0 ;
|
kbd_data <= 1'b0 ;
|
stop_clocking = 1'b1 ;
|
stop_clocking = 1'b1 ;
|
end
|
end
|
end
|
end
|
|
|
#(kbd_clk_period/4) ;
|
#(kbd_clk_period/4) ;
|
end
|
end
|
|
|
kbd_clk = 1'b0 ;
|
kbd_clk = 1'b0 ;
|
|
|
#(kbd_clk_period/2) ;
|
#(kbd_clk_period/2) ;
|
kbd_clk <= 1'b1 ;
|
kbd_clk <= 1'b1 ;
|
kbd_data <= 1'b1 ;
|
kbd_data <= 1'b1 ;
|
|
|
receiving = 0 ;
|
receiving = 0 ;
|
|
|
if ( i === 10 )
|
if ( i === 10 )
|
begin
|
begin
|
char_valid_o = !char_valid_o ;
|
char_valid_o = !char_valid_o ;
|
end
|
end
|
end
|
end
|
endtask // kbd_receive_char
|
endtask // kbd_receive_char
|
|
|
|
|
time last_clk_low;
|
time last_clk_low;
|
time last_clk_diference;
|
time last_clk_diference;
|
|
|
|
|
|
|
initial
|
initial
|
begin
|
begin
|
last_clk_low =0;
|
last_clk_low =0;
|
last_clk_diference =0;
|
last_clk_diference =0;
|
|
|
end
|
end
|
|
|
always @(negedge kbd_clk_io)
|
always @(negedge kbd_clk_io)
|
|
|
begin:low_time_check
|
begin:low_time_check
|
if (kbd_clk == 1)
|
if (kbd_clk == 1)
|
begin
|
begin
|
last_clk_low =$time;
|
last_clk_low =$time;
|
fork
|
fork
|
begin
|
begin
|
#61000
|
#61000
|
$display(" clock low more then 61us");
|
$display(" clock low more then 61us");
|
$display("Time %t", $time) ;
|
$display("Time %t", $time) ;
|
#30000
|
#30000
|
$display("error clock low more then 90usec");
|
$display("error clock low more then 90usec");
|
$display("Time %t", $time) ;
|
$display("Time %t", $time) ;
|
$stop;
|
$stop;
|
end
|
end
|
begin
|
begin
|
@(posedge kbd_clk_io);
|
@(posedge kbd_clk_io);
|
disable low_time_check;
|
disable low_time_check;
|
end
|
end
|
join
|
join
|
end
|
end
|
end
|
end
|
|
|
|
|
|
|
|
|
always @(posedge kbd_clk_io )
|
always @(posedge kbd_clk_io )
|
begin
|
begin
|
if (last_clk_low >0 )
|
if (last_clk_low >0 )
|
begin
|
begin
|
last_clk_diference = $time - last_clk_low;
|
last_clk_diference = $time - last_clk_low;
|
if (last_clk_diference < 60000)
|
if (last_clk_diference < 60000)
|
begin
|
begin
|
$display("error time< 60u");
|
$display("error time< 60u");
|
#100 $stop;
|
#100 $stop;
|
end
|
end
|
end
|
end
|
end
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
endmodule // ps2_keyboard_model
|
endmodule // ps2_keyboard_model
|
|
|