OpenCores
URL https://opencores.org/ocsvn/ps2/ps2/trunk

Subversion Repositories ps2

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /ps2/tags/GATE_LEVEL_SIM_OK/rtl
    from Rev 3 to Rev 51
    Reverse comparison

Rev 3 → Rev 51

/verilog/ps2_io_ctrl.v
0,0 → 1,103
//////////////////////////////////////////////////////////////////////
//// ////
//// ps2_io_ctrl.v ////
//// ////
//// This file is part of the "ps2" project ////
//// http://www.opencores.org/cores/ps2/ ////
//// ////
//// Author(s): ////
//// - mihad@opencores.org ////
//// - Miha Dolenc ////
//// ////
//// All additional information is avaliable in the README.txt ////
//// file. ////
//// ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
//
// CVS Revision History
//
// $Log: not supported by cvs2svn $
//
 
// synopsys translate_off
`include "timescale.v"
// synopsys translate_on
 
module ps2_io_ctrl
(
clk_i,
rst_i,
ps2_ctrl_kbd_clk_en_i_,
ps2_ctrl_kbd_data_en_i_,
ps2_kbd_clk_pad_i,
ps2_kbd_clk_pad_oe_o,
ps2_kbd_data_pad_oe_o,
inhibit_kbd_if_i,
ps2_ctrl_kbd_clk_o
);
 
input clk_i,
rst_i,
ps2_ctrl_kbd_clk_en_i_,
ps2_ctrl_kbd_data_en_i_,
ps2_kbd_clk_pad_i,
inhibit_kbd_if_i ;
 
output ps2_kbd_clk_pad_oe_o,
ps2_kbd_data_pad_oe_o,
ps2_ctrl_kbd_clk_o ;
 
reg ps2_kbd_clk_pad_oe_o,
ps2_kbd_data_pad_oe_o ;
 
always@(posedge clk_i or posedge rst_i)
begin
if ( rst_i )
begin
ps2_kbd_clk_pad_oe_o <= #1 1'b0 ;
ps2_kbd_data_pad_oe_o <= #1 1'b0 ;
end
else
begin
ps2_kbd_clk_pad_oe_o <= #1 !ps2_ctrl_kbd_clk_en_i_ || inhibit_kbd_if_i ;
ps2_kbd_data_pad_oe_o <= #1 !ps2_ctrl_kbd_data_en_i_ ;
end
end
 
reg inhibit_kbd_if_previous ;
always@(posedge clk_i or posedge rst_i)
begin
if ( rst_i )
inhibit_kbd_if_previous <= #1 1'b1 ;
else
inhibit_kbd_if_previous <= #1 inhibit_kbd_if_i ;
end
 
assign ps2_ctrl_kbd_clk_o = ps2_kbd_clk_pad_i || ps2_kbd_clk_pad_oe_o && inhibit_kbd_if_previous ;
endmodule // ps2_io_ctrl
/verilog/ps2_defines.v
0,0 → 1,63
//////////////////////////////////////////////////////////////////////
//// ////
//// ps2_defines.v ////
//// ////
//// This file is part of the "ps2" project ////
//// http://www.opencores.org/cores/ps2/ ////
//// ////
//// Author(s): ////
//// - mihad@opencores.org ////
//// - Miha Dolenc ////
//// ////
//// All additional information is avaliable in the README.txt ////
//// file. ////
//// ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
//
// CVS Revision History
//
// $Log: not supported by cvs2svn $
//
 
`define PS2_RAMB4
`define PS2_TRANSLATION_TABLE_31_0 256'h5b03111e1f2c71665a02101d702a386559290f3e40424464583c3b3d3f4143ff
`define PS2_TRANSLATION_TABLE_63_32 256'h5f0908162432726a5e071522233031695d061314212f39685c040512202d2e67
`define PS2_TRANSLATION_TABLE_95_64 256'h76632b751b1c363a6e620d1a7428736d610c19272635346c600a0b181725336b
`define PS2_TRANSLATION_TABLE_127_96 256'h544649374a514e574501484d4c5053526f7f7e474b7d4f7c7b0e7a7978775655
`define PS2_TRANSLATION_TABLE_159_128 256'h9f9e9d9c9b9a999897969594939291908f8e8d8c8b8a89888786855441828180
`define PS2_TRANSLATION_TABLE_191_160 256'hbfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a0
`define PS2_TRANSLATION_TABLE_223_192 256'hdfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0
`define PS2_TRANSLATION_TABLE_255_224 256'hfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0
 
`define PS2_TIMER_60USEC_VALUE_PP 1920 // Number of sys_clks for 60usec.
`define PS2_TIMER_60USEC_BITS_PP 11 // Number of bits needed for timer
`define PS2_TIMER_5USEC_VALUE_PP 160 // Number of sys_clks for debounce
`define PS2_TIMER_5USEC_BITS_PP 8 // Number of bits needed for timer
 
//`define SIM
verilog/ps2_defines.v Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: verilog/ps2_keyboard.v =================================================================== --- verilog/ps2_keyboard.v (nonexistent) +++ verilog/ps2_keyboard.v (revision 51) @@ -0,0 +1,710 @@ +//------------------------------------------------------------------------------------- +// +// Author: John Clayton +// Date : April 30, 2001 +// Update: 4/30/01 copied this file from lcd_2.v (pared down). +// Update: 5/24/01 changed the first module from "ps2_keyboard_receiver" +// to "ps2_keyboard_interface" +// Update: 5/29/01 Added input synchronizing flip-flops. Changed state +// encoding (m1) for good operation after part config. +// Update: 5/31/01 Added low drive strength and slow transitions to ps2_clk +// and ps2_data in the constraints file. Added the signal +// "tx_shifting_done" as distinguished from "rx_shifting_done." +// Debugged the transmitter portion in the lab. +// Update: 6/01/01 Added horizontal tab to the ascii output. +// Update: 6/01/01 Added parameter TRAP_SHIFT_KEYS. +// Update: 6/05/01 Debugged the "debounce" timer functionality. +// Used 60usec timer as a "watchdog" timeout during +// receive from the keyboard. This means that a keyboard +// can now be "hot plugged" into the interface, without +// messing up the bit_count, since the bit_count is reset +// to zero during periods of inactivity anyway. This was +// difficult to debug. I ended up using the logic analyzer, +// and had to scratch my head quite a bit. +// Update: 6/06/01 Removed extra comments before the input synchronizing +// flip-flops. Used the correct parameter to size the +// 5usec_timer_count. Changed the name of this file from +// ps2.v to ps2_keyboard.v +// Update: 6/06/01 Removed "&& q[7:0]" in output_strobe logic. Removed extra +// commented out "else" condition in the shift register and +// bit counter. +// Update: 6/07/01 Changed default values for 60usec timer parameters so that +// they correspond to 60usec for a 49.152MHz clock. +// +// +// +// +// +// Description +//------------------------------------------------------------------------------------- +// This is a state-machine driven serial-to-parallel and parallel-to-serial +// interface to the ps2 style keyboard interface. The details of the operation +// of the keyboard interface were obtained from the following website: +// +// http://www.beyondlogic.org/keyboard/keybrd.htm +// +// Some aspects of the keyboard interface are not implemented (e.g, parity +// checking for the receive side, and recognition of the various commands +// which the keyboard sends out, such as "power on selt test passed," "Error" +// and "Resend.") However, if the user wishes to recognize these reply +// messages, the scan code output can always be used to extend functionality +// as desired. +// +// Note that the "Extended" (0xE0) and "Released" (0xF0) codes are recognized. +// The rx interface provides separate indicator flags for these two conditions +// with every valid character scan code which it provides. The shift keys are +// also trapped by the interface, in order to provide correct uppercase ASCII +// characters at the ascii output, although the scan codes for the shift keys +// are still provided at the scan code output. So, the left/right ALT keys +// can be differentiated by the presence of the rx_entended signal, while the +// left/right shift keys are differentiable by the different scan codes +// received. +// +// The interface to the ps2 keyboard uses ps2_clk clock rates of +// 30-40 kHz, dependent upon the keyboard itself. The rate at which the state +// machine runs should be at least twice the rate of the ps2_clk, so that the +// states can accurately follow the clock signal itself. Four times +// oversampling is better. Say 200kHz at least. The upper limit for clocking +// the state machine will undoubtedly be determined by delays in the logic +// which decodes the scan codes into ASCII equivalents. The maximum speed +// will be most likely many megahertz, depending upon target technology. +// In order to run the state machine extremely fast, synchronizing flip-flops +// have been added to the ps2_clk and ps2_data inputs of the state machine. +// This avoids poor performance related to slow transitions of the inputs. +// +// Because this is a bi-directional interface, while reading from the keyboard +// the ps2_clk and ps2_data lines are used as inputs. While writing to the +// keyboard, however (which may be done at any time. If writing interrupts a +// read from the keyboard, the keyboard will buffer up its data, and send +// it later) both the ps2_clk and ps2_data lines are occasionally pulled low, +// and pullup resistors are used to bring the lines high again, by setting +// the drivers to high impedance state. +// +// The tx interface, for writing to the keyboard, does not provide any special +// pre-processing. It simply transmits the 8-bit command value to the +// keyboard. +// +// Pullups MUST BE USED on the ps2_clk and ps2_data lines for this design, +// whether they be internal to an FPGA I/O pad, or externally placed. +// If internal pullups are used, they may be fairly weak, causing bounces +// due to crosstalk, etc. There is a "debounce timer" implemented in order +// to eliminate erroneous state transitions which would occur based on bounce. +// +// Parameters are provided in order to configure and appropriately size the +// counter of a 60 microsecond timer used in the transmitter, depending on +// the clock frequency used. The 60 microsecond period is guaranteed to be +// more than one period of the ps2_clk_s signal. +// +// Also, a smaller 5 microsecond timer has been included for "debounce". +// This is used because, with internal pullups on the ps2_clk and ps2_data +// lines, there is some bouncing around which occurs +// +// A parameter TRAP_SHIFT_KEYS allows the user to eliminate shift keypresses +// from producing scan codes (along with their "undefined" ASCII equivalents) +// at the output of the interface. If TRAP_SHIFT_KEYS is non-zero, the shift +// key status will only be reported by rx_shift_key_on. No ascii or scan +// codes will be reported for the shift keys. This is useful for those who +// wish to use the ASCII data stream, and who don't want to have to "filter +// out" the shift key codes. +// +//------------------------------------------------------------------------------------- + + +// synopsys translate_off +`resetall +`include "timescale.v" +// synopsys translate_on +`define TOTAL_BITS 11 +`define EXTEND_CODE 16'hE0 +`define RELEASE_CODE 16'hF0 +`define LEFT_SHIFT 16'h12 +`define RIGHT_SHIFT 16'h59 + + +module ps2_keyboard ( + clk, + reset, + ps2_clk_en_o_, + ps2_data_en_o_, + ps2_clk_i, + ps2_data_i, + rx_extended, + rx_released, + rx_shift_key_on, + rx_scan_code, + rx_ascii, + rx_data_ready, // rx_read_o + rx_read, // rx_read_ack_i + tx_data, + tx_write, + tx_write_ack_o, + tx_error_no_keyboard_ack, + translate + ); + +// Parameters + +// The timer value can be up to (2^bits) inclusive. +parameter TIMER_60USEC_VALUE_PP = 2950; // Number of sys_clks for 60usec. +parameter TIMER_60USEC_BITS_PP = 12; // Number of bits needed for timer +parameter TIMER_5USEC_VALUE_PP = 186; // Number of sys_clks for debounce +parameter TIMER_5USEC_BITS_PP = 8; // Number of bits needed for timer +parameter TRAP_SHIFT_KEYS_PP = 0; // Default: No shift key trap. + +// State encodings, provided as parameters +// for flexibility to the one instantiating the module. +// In general, the default values need not be changed. + +// State "m1_rx_clk_l" has been chosen on purpose. Since the input +// synchronizing flip-flops initially contain zero, it takes one clk +// for them to update to reflect the actual (idle = high) status of +// the I/O lines from the keyboard. Therefore, choosing 0 for m1_rx_clk_l +// allows the state machine to transition to m1_rx_clk_h when the true +// values of the input signals become present at the outputs of the +// synchronizing flip-flops. This initial transition is harmless, and it +// eliminates the need for a "reset" pulse before the interface can operate. + +parameter m1_rx_clk_h = 1; +parameter m1_rx_clk_l = 0; +parameter m1_rx_falling_edge_marker = 13; +parameter m1_rx_rising_edge_marker = 14; +parameter m1_tx_force_clk_l = 3; +parameter m1_tx_first_wait_clk_h = 10; +parameter m1_tx_first_wait_clk_l = 11; +parameter m1_tx_reset_timer = 12; +parameter m1_tx_wait_clk_h = 2; +parameter m1_tx_clk_h = 4; +parameter m1_tx_clk_l = 5; +parameter m1_tx_wait_keyboard_ack = 6; +parameter m1_tx_done_recovery = 7; +parameter m1_tx_error_no_keyboard_ack = 8; +parameter m1_tx_rising_edge_marker = 9; +parameter m2_rx_data_ready = 1; +parameter m2_rx_data_ready_ack = 0; + + +// I/O declarations +input clk; +input reset; +output ps2_clk_en_o_ ; +output ps2_data_en_o_ ; +input ps2_clk_i ; +input ps2_data_i ; +output rx_extended; +output rx_released; +output rx_shift_key_on; +output [7:0] rx_scan_code; +output [7:0] rx_ascii; +output rx_data_ready; +input rx_read; +input [7:0] tx_data; +input tx_write; +output tx_write_ack_o; +output tx_error_no_keyboard_ack; +input translate ; + +reg rx_extended; +reg rx_released; +reg [7:0] rx_scan_code; +reg [7:0] rx_ascii; +reg rx_data_ready; +reg tx_error_no_keyboard_ack; + +// Internal signal declarations +wire timer_60usec_done; +wire timer_5usec_done; +wire extended; +wire released; +wire shift_key_on; + + // NOTE: These two signals used to be one. They + // were split into two signals because of + // shift key trapping. With shift key + // trapping, no event is generated externally, + // but the "hold" data must still be cleared + // anyway regardless, in preparation for the + // next scan codes. +wire rx_output_event; // Used only to clear: hold_released, hold_extended +wire rx_output_strobe; // Used to produce the actual output. + +wire tx_parity_bit; +wire rx_shifting_done; +wire tx_shifting_done; +wire [11:0] shift_key_plus_code; + +reg [`TOTAL_BITS-1:0] q; +reg [3:0] m1_state; +reg [3:0] m1_next_state; +reg m2_state; +reg m2_next_state; +reg [3:0] bit_count; +reg enable_timer_60usec; +reg enable_timer_5usec; +reg [TIMER_60USEC_BITS_PP-1:0] timer_60usec_count; +reg [TIMER_5USEC_BITS_PP-1:0] timer_5usec_count; +reg [7:0] ascii; // "REG" type only because a case statement is used. +reg left_shift_key; +reg right_shift_key; +reg hold_extended; // Holds prior value, cleared at rx_output_strobe +reg hold_released; // Holds prior value, cleared at rx_output_strobe +reg ps2_clk_s; // Synchronous version of this input +reg ps2_data_s; // Synchronous version of this input +reg ps2_clk_hi_z; // Without keyboard, high Z equals 1 due to pullups. +reg ps2_data_hi_z; // Without keyboard, high Z equals 1 due to pullups. + +//-------------------------------------------------------------------------- +// Module code + +assign ps2_clk_en_o_ = ps2_clk_hi_z ; +assign ps2_data_en_o_ = ps2_data_hi_z ; + +// Input "synchronizing" logic -- synchronizes the inputs to the state +// machine clock, thus avoiding errors related to +// spurious state machine transitions. +always @(posedge clk) +begin + ps2_clk_s <= ps2_clk_i; + ps2_data_s <= ps2_data_i; +end + +// State register +always @(posedge clk) +begin : m1_state_register + if (reset) m1_state <= m1_rx_clk_h; + else m1_state <= m1_next_state; +end + +// State transition logic +always @(m1_state + or q + or tx_shifting_done + or tx_write + or ps2_clk_s + or ps2_data_s + or timer_60usec_done + or timer_5usec_done + ) +begin : m1_state_logic + + // Output signals default to this value, unless changed in a state condition. + ps2_clk_hi_z <= 1; + ps2_data_hi_z <= 1; + tx_error_no_keyboard_ack <= 0; + enable_timer_60usec <= 0; + enable_timer_5usec <= 0; + + case (m1_state) + + m1_rx_clk_h : + begin + enable_timer_60usec <= 1; + if (tx_write) m1_next_state <= m1_tx_reset_timer; + else if (~ps2_clk_s) m1_next_state <= m1_rx_falling_edge_marker; + else m1_next_state <= m1_rx_clk_h; + end + + m1_rx_falling_edge_marker : + begin + enable_timer_60usec <= 0; + m1_next_state <= m1_rx_clk_l; + end + + m1_rx_rising_edge_marker : + begin + enable_timer_60usec <= 0; + m1_next_state <= m1_rx_clk_h; + end + + + m1_rx_clk_l : + begin + enable_timer_60usec <= 1; + if (tx_write) m1_next_state <= m1_tx_reset_timer; + else if (ps2_clk_s) m1_next_state <= m1_rx_rising_edge_marker; + else m1_next_state <= m1_rx_clk_l; + end + + m1_tx_reset_timer: + begin + enable_timer_60usec <= 0; + m1_next_state <= m1_tx_force_clk_l; + end + + m1_tx_force_clk_l : + begin + enable_timer_60usec <= 1; + ps2_clk_hi_z <= 0; // Force the ps2_clk line low. + if (timer_60usec_done) m1_next_state <= m1_tx_first_wait_clk_h; + else m1_next_state <= m1_tx_force_clk_l; + end + + m1_tx_first_wait_clk_h : + begin + enable_timer_5usec <= 1; + ps2_data_hi_z <= 0; // Start bit. + if (~ps2_clk_s && timer_5usec_done) + m1_next_state <= m1_tx_clk_l; + else + m1_next_state <= m1_tx_first_wait_clk_h; + end + + // This state must be included because the device might possibly + // delay for up to 10 milliseconds before beginning its clock pulses. + // During that waiting time, we cannot drive the data (q[0]) because it + // is possibly 1, which would cause the keyboard to abort its receive + // and the expected clocks would then never be generated. + m1_tx_first_wait_clk_l : + begin + ps2_data_hi_z <= 0; + if (~ps2_clk_s) m1_next_state <= m1_tx_clk_l; + else m1_next_state <= m1_tx_first_wait_clk_l; + end + + m1_tx_wait_clk_h : + begin + enable_timer_5usec <= 1; + ps2_data_hi_z <= q[0]; + if (ps2_clk_s && timer_5usec_done) + m1_next_state <= m1_tx_rising_edge_marker; + else + m1_next_state <= m1_tx_wait_clk_h; + end + + m1_tx_rising_edge_marker : + begin + ps2_data_hi_z <= q[0]; + m1_next_state <= m1_tx_clk_h; + end + + m1_tx_clk_h : + begin + ps2_data_hi_z <= q[0]; + if (tx_shifting_done) m1_next_state <= m1_tx_wait_keyboard_ack; + else if (~ps2_clk_s) m1_next_state <= m1_tx_clk_l; + else m1_next_state <= m1_tx_clk_h; + end + + m1_tx_clk_l : + begin + ps2_data_hi_z <= q[0]; + if (ps2_clk_s) m1_next_state <= m1_tx_wait_clk_h; + else m1_next_state <= m1_tx_clk_l; + end + + m1_tx_wait_keyboard_ack : + begin + if (~ps2_clk_s && ps2_data_s) + m1_next_state <= m1_tx_error_no_keyboard_ack; + else if (~ps2_clk_s && ~ps2_data_s) + m1_next_state <= m1_tx_done_recovery; + else m1_next_state <= m1_tx_wait_keyboard_ack; + end + + m1_tx_done_recovery : + begin + if (ps2_clk_s && ps2_data_s) m1_next_state <= m1_rx_clk_h; + else m1_next_state <= m1_tx_done_recovery; + end + + m1_tx_error_no_keyboard_ack : + begin + tx_error_no_keyboard_ack <= 1; + if (ps2_clk_s && ps2_data_s) m1_next_state <= m1_rx_clk_h; + else m1_next_state <= m1_tx_error_no_keyboard_ack; + end + + default : m1_next_state <= m1_rx_clk_h; + endcase +end + +// State register +always @(posedge clk) +begin : m2_state_register + if (reset) m2_state <= m2_rx_data_ready_ack; + else m2_state <= m2_next_state; +end + +// State transition logic +always @(m2_state or rx_output_strobe or rx_read) +begin : m2_state_logic + case (m2_state) + m2_rx_data_ready_ack: + begin + rx_data_ready <= 1'b0; + if (rx_output_strobe) m2_next_state <= m2_rx_data_ready; + else m2_next_state <= m2_rx_data_ready_ack; + end + m2_rx_data_ready: + begin + rx_data_ready <= 1'b1; + if (rx_read) m2_next_state <= m2_rx_data_ready_ack; + else m2_next_state <= m2_rx_data_ready; + end + default : m2_next_state <= m2_rx_data_ready_ack; + endcase +end + +// This is the bit counter +always @(posedge clk) +begin + if ( reset + || rx_shifting_done + || (m1_state == m1_tx_wait_keyboard_ack) // After tx is done. + ) bit_count <= 0; // normal reset + else if (timer_60usec_done + && (m1_state == m1_rx_clk_h) + && (ps2_clk_s) + ) bit_count <= 0; // rx watchdog timer reset + else if ( (m1_state == m1_rx_falling_edge_marker) // increment for rx + ||(m1_state == m1_tx_rising_edge_marker) // increment for tx + ) + bit_count <= bit_count + 1; +end +// This signal is high for one clock at the end of the timer count. +assign rx_shifting_done = (bit_count == `TOTAL_BITS); +assign tx_shifting_done = (bit_count == `TOTAL_BITS-1); + +// This is the signal which enables loading of the shift register. +// It also indicates "ack" to the device writing to the transmitter. +assign tx_write_ack_o = ( (tx_write && (m1_state == m1_rx_clk_h)) + ||(tx_write && (m1_state == m1_rx_clk_l)) + ); + +// This is the ODD parity bit for the transmitted word. +assign tx_parity_bit = ~^tx_data; + +// This is the shift register +always @(posedge clk) +begin + if (reset) q <= 0; + else if (tx_write_ack_o) q <= {1'b1,tx_parity_bit,tx_data,1'b0}; + else if ( (m1_state == m1_rx_falling_edge_marker) + ||(m1_state == m1_tx_rising_edge_marker) ) + q <= {ps2_data_s,q[`TOTAL_BITS-1:1]}; +end + +// This is the 60usec timer counter +always @(posedge clk) +begin + if (~enable_timer_60usec) timer_60usec_count <= 0; + else if (~timer_60usec_done) timer_60usec_count <= timer_60usec_count + 1; +end +assign timer_60usec_done = (timer_60usec_count == (TIMER_60USEC_VALUE_PP - 1)); + +// This is the 5usec timer counter +always @(posedge clk) +begin + if (~enable_timer_5usec) timer_5usec_count <= 0; + else if (~timer_5usec_done) timer_5usec_count <= timer_5usec_count + 1; +end +assign timer_5usec_done = (timer_5usec_count == TIMER_5USEC_VALUE_PP - 1); + + +// Create the signals which indicate special scan codes received. +// These are the "unlatched versions." +`ifdef PS2_TRAP_EXTENDED +assign extended = (q[8:1] == `EXTEND_CODE) && rx_shifting_done && translate ; +`else +assign extended = 1'b0 ; +`endif +assign released = (q[8:1] == `RELEASE_CODE) && rx_shifting_done && translate ; + +// Store the special scan code status bits +// Not the final output, but an intermediate storage place, +// until the entire set of output data can be assembled. +always @(posedge clk) +begin + if (reset || rx_output_event) + begin + hold_extended <= 0; + hold_released <= 0; + end + else + begin + if (rx_shifting_done && extended) hold_extended <= 1; + if (rx_shifting_done && released) hold_released <= 1; + end +end + + +// These bits contain the status of the two shift keys +always @(posedge clk) +begin + if (reset) left_shift_key <= 0; + else if ((q[8:1] == `LEFT_SHIFT) && rx_shifting_done && ~hold_released) + left_shift_key <= 1; + else if ((q[8:1] == `LEFT_SHIFT) && rx_shifting_done && hold_released) + left_shift_key <= 0; +end + +always @(posedge clk) +begin + if (reset) right_shift_key <= 0; + else if ((q[8:1] == `RIGHT_SHIFT) && rx_shifting_done && ~hold_released) + right_shift_key <= 1; + else if ((q[8:1] == `RIGHT_SHIFT) && rx_shifting_done && hold_released) + right_shift_key <= 0; +end + +assign rx_shift_key_on = left_shift_key || right_shift_key; + +// Output the special scan code flags, the scan code and the ascii +always @(posedge clk) +begin + if (reset) + begin + rx_extended <= 0; + rx_released <= 0; + rx_scan_code <= 0; + rx_ascii <= 0; + end + else if (rx_output_strobe) + begin + rx_extended <= hold_extended; + rx_released <= hold_released; + rx_scan_code <= q[8:1]; + rx_ascii <= ascii; + end +end + +// Store the final rx output data only when all extend and release codes +// are received and the next (actual key) scan code is also ready. +// (the presence of rx_extended or rx_released refers to the +// the current latest scan code received, not the previously latched flags.) +assign rx_output_event = (rx_shifting_done + && ~extended + && ~released + ); + +assign rx_output_strobe = (rx_shifting_done + && ~extended + && ~released + && ( (TRAP_SHIFT_KEYS_PP == 0) + || ( (q[8:1] != `RIGHT_SHIFT) + &&(q[8:1] != `LEFT_SHIFT) + ) + ) + ); + +// This part translates the scan code into an ASCII value... +// Only the ASCII codes which I considered important have been included. +// if you want more, just add the appropriate case statement lines... +// (You will need to know the keyboard scan codes you wish to assign.) +// The entries are listed in ascending order of ASCII value. +assign shift_key_plus_code = {3'b0,rx_shift_key_on,q[8:1]}; +always @(shift_key_plus_code) +begin + casez (shift_key_plus_code) + 12'h?66 : ascii <= 8'h08; // Backspace ("backspace" key) + 12'h?0d : ascii <= 8'h09; // Horizontal Tab + 12'h?5a : ascii <= 8'h0d; // Carriage return ("enter" key) + 12'h?76 : ascii <= 8'h1b; // Escape ("esc" key) + 12'h?29 : ascii <= 8'h20; // Space + 12'h116 : ascii <= 8'h21; // ! + 12'h152 : ascii <= 8'h22; // " + 12'h126 : ascii <= 8'h23; // # + 12'h125 : ascii <= 8'h24; // $ + 12'h12e : ascii <= 8'h25; // % + 12'h13d : ascii <= 8'h26; // & + 12'h052 : ascii <= 8'h27; // ' + 12'h146 : ascii <= 8'h28; // ( + 12'h145 : ascii <= 8'h29; // ) + 12'h13e : ascii <= 8'h2a; // * + 12'h155 : ascii <= 8'h2b; // + + 12'h041 : ascii <= 8'h2c; // , + 12'h04e : ascii <= 8'h2d; // - + 12'h049 : ascii <= 8'h2e; // . + 12'h04a : ascii <= 8'h2f; // / + 12'h045 : ascii <= 8'h30; // 0 + 12'h016 : ascii <= 8'h31; // 1 + 12'h01e : ascii <= 8'h32; // 2 + 12'h026 : ascii <= 8'h33; // 3 + 12'h025 : ascii <= 8'h34; // 4 + 12'h02e : ascii <= 8'h35; // 5 + 12'h036 : ascii <= 8'h36; // 6 + 12'h03d : ascii <= 8'h37; // 7 + 12'h03e : ascii <= 8'h38; // 8 + 12'h046 : ascii <= 8'h39; // 9 + 12'h14c : ascii <= 8'h3a; // : + 12'h04c : ascii <= 8'h3b; // ; + 12'h141 : ascii <= 8'h3c; // < + 12'h055 : ascii <= 8'h3d; // = + 12'h149 : ascii <= 8'h3e; // > + 12'h14a : ascii <= 8'h3f; // ? + 12'h11e : ascii <= 8'h40; // @ + 12'h11c : ascii <= 8'h41; // A + 12'h132 : ascii <= 8'h42; // B + 12'h121 : ascii <= 8'h43; // C + 12'h123 : ascii <= 8'h44; // D + 12'h124 : ascii <= 8'h45; // E + 12'h12b : ascii <= 8'h46; // F + 12'h134 : ascii <= 8'h47; // G + 12'h133 : ascii <= 8'h48; // H + 12'h143 : ascii <= 8'h49; // I + 12'h13b : ascii <= 8'h4a; // J + 12'h142 : ascii <= 8'h4b; // K + 12'h14b : ascii <= 8'h4c; // L + 12'h13a : ascii <= 8'h4d; // M + 12'h131 : ascii <= 8'h4e; // N + 12'h144 : ascii <= 8'h4f; // O + 12'h14d : ascii <= 8'h50; // P + 12'h115 : ascii <= 8'h51; // Q + 12'h12d : ascii <= 8'h52; // R + 12'h11b : ascii <= 8'h53; // S + 12'h12c : ascii <= 8'h54; // T + 12'h13c : ascii <= 8'h55; // U + 12'h12a : ascii <= 8'h56; // V + 12'h11d : ascii <= 8'h57; // W + 12'h122 : ascii <= 8'h58; // X + 12'h135 : ascii <= 8'h59; // Y + 12'h11a : ascii <= 8'h5a; // Z + 12'h054 : ascii <= 8'h5b; // [ + 12'h05d : ascii <= 8'h5c; // \ + 12'h05b : ascii <= 8'h5d; // ] + 12'h136 : ascii <= 8'h5e; // ^ + 12'h14e : ascii <= 8'h5f; // _ + 12'h00e : ascii <= 8'h60; // ` + 12'h01c : ascii <= 8'h61; // a + 12'h032 : ascii <= 8'h62; // b + 12'h021 : ascii <= 8'h63; // c + 12'h023 : ascii <= 8'h64; // d + 12'h024 : ascii <= 8'h65; // e + 12'h02b : ascii <= 8'h66; // f + 12'h034 : ascii <= 8'h67; // g + 12'h033 : ascii <= 8'h68; // h + 12'h043 : ascii <= 8'h69; // i + 12'h03b : ascii <= 8'h6a; // j + 12'h042 : ascii <= 8'h6b; // k + 12'h04b : ascii <= 8'h6c; // l + 12'h03a : ascii <= 8'h6d; // m + 12'h031 : ascii <= 8'h6e; // n + 12'h044 : ascii <= 8'h6f; // o + 12'h04d : ascii <= 8'h70; // p + 12'h015 : ascii <= 8'h71; // q + 12'h02d : ascii <= 8'h72; // r + 12'h01b : ascii <= 8'h73; // s + 12'h02c : ascii <= 8'h74; // t + 12'h03c : ascii <= 8'h75; // u + 12'h02a : ascii <= 8'h76; // v + 12'h01d : ascii <= 8'h77; // w + 12'h022 : ascii <= 8'h78; // x + 12'h035 : ascii <= 8'h79; // y + 12'h01a : ascii <= 8'h7a; // z + 12'h154 : ascii <= 8'h7b; // { + 12'h15d : ascii <= 8'h7c; // | + 12'h15b : ascii <= 8'h7d; // } + 12'h10e : ascii <= 8'h7e; // ~ + 12'h?71 : ascii <= 8'h7f; // (Delete OR DEL on numeric keypad) + default : ascii <= 8'h2e; // '.' used for unlisted characters. + endcase +end + + +endmodule + +//`undefine TOTAL_BITS +//`undefine EXTEND_CODE +//`undefine RELEASE_CODE +//`undefine LEFT_SHIFT +//`undefine RIGHT_SHIFT +
verilog/ps2_keyboard.v Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: verilog/ps2_top.v =================================================================== --- verilog/ps2_top.v (nonexistent) +++ verilog/ps2_top.v (revision 51) @@ -0,0 +1,206 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// ps2_top.v //// +//// //// +//// This file is part of the "ps2" project //// +//// http://www.opencores.org/cores/ps2/ //// +//// //// +//// Author(s): //// +//// - mihad@opencores.org //// +//// - Miha Dolenc //// +//// //// +//// All additional information is avaliable in the README.txt //// +//// file. //// +//// //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +////////////////////////////////////////////////////////////////////// +// +// CVS Revision History +// +// $Log: not supported by cvs2svn $ +// + +`include "ps2_defines.v" +// synopsys translate_off +`include "timescale.v" +// synopsys translate_on + +module ps2_top +( + wb_clk_i, + wb_rst_i, + wb_cyc_i, + wb_stb_i, + wb_we_i, + wb_sel_i, + wb_adr_i, + wb_dat_i, + wb_dat_o, + wb_ack_o, + + wb_int_o, + + ps2_kbd_clk_pad_i, + ps2_kbd_data_pad_i, + ps2_kbd_clk_pad_o, + ps2_kbd_data_pad_o, + ps2_kbd_clk_pad_oe_o, + ps2_kbd_data_pad_oe_o +) ; + +input wb_clk_i, + wb_rst_i, + wb_cyc_i, + wb_stb_i, + wb_we_i ; + +input [3:0] wb_sel_i ; + +input [31:0]wb_adr_i, + wb_dat_i ; + +output [31:0] wb_dat_o ; + +output wb_ack_o ; + +output wb_int_o ; + +input ps2_kbd_clk_pad_i, + ps2_kbd_data_pad_i ; + +output ps2_kbd_clk_pad_o, + ps2_kbd_data_pad_o, + ps2_kbd_clk_pad_oe_o, + ps2_kbd_data_pad_oe_o ; + +wire rx_extended, + rx_released, + rx_shift_key_on, + rx_data_ready, + rx_translated_data_ready, + rx_read_wb, + rx_read_tt, + tx_write, + tx_write_ack, + tx_error_no_keyboard_ack, + ps2_ctrl_kbd_data_en_, + ps2_ctrl_kbd_clk_en_, + ps2_ctrl_kbd_clk, + inhibit_kbd_if ; + +wire [7:0] rx_scan_code, + rx_translated_scan_code, + rx_ascii, + tx_data ; + +assign ps2_kbd_clk_pad_o = 1'b0 ; +assign ps2_kbd_data_pad_o = 1'b0 ; + +ps2_io_ctrl i_ps2_io_ctrl +( + .clk_i (wb_clk_i), + .rst_i (wb_rst_i), + .ps2_ctrl_kbd_clk_en_i_ (ps2_ctrl_kbd_clk_en_), + .ps2_ctrl_kbd_data_en_i_ (ps2_ctrl_kbd_data_en_), + .ps2_kbd_clk_pad_i (ps2_kbd_clk_pad_i), + .ps2_kbd_clk_pad_oe_o (ps2_kbd_clk_pad_oe_o), + .ps2_kbd_data_pad_oe_o (ps2_kbd_data_pad_oe_o), + .inhibit_kbd_if_i (inhibit_kbd_if), + .ps2_ctrl_kbd_clk_o (ps2_ctrl_kbd_clk) +); + +ps2_keyboard #(`PS2_TIMER_60USEC_VALUE_PP, `PS2_TIMER_60USEC_BITS_PP, `PS2_TIMER_5USEC_VALUE_PP, `PS2_TIMER_5USEC_BITS_PP, 0) +i_ps2_keyboard +( + .clk (wb_clk_i), + .reset (wb_rst_i), + .ps2_clk_en_o_ (ps2_ctrl_kbd_clk_en_), + .ps2_data_en_o_ (ps2_ctrl_kbd_data_en_), + .ps2_clk_i (ps2_ctrl_kbd_clk), + .ps2_data_i (ps2_kbd_data_pad_i), + .rx_extended (rx_extended), + .rx_released (rx_released), + .rx_shift_key_on (rx_shift_key_on), + .rx_scan_code (rx_scan_code), + .rx_ascii (rx_ascii), + .rx_data_ready (rx_data_ready), + .rx_read (rx_read_tt), + .tx_data (tx_data), + .tx_write (tx_write), + .tx_write_ack_o (tx_write_ack), + .tx_error_no_keyboard_ack (tx_error_no_keyboard_ack), + .translate (translate) +); + +ps2_wb_if i_ps2_wb_if +( + .wb_clk_i (wb_clk_i), + .wb_rst_i (wb_rst_i), + .wb_cyc_i (wb_cyc_i), + .wb_stb_i (wb_stb_i), + .wb_we_i (wb_we_i), + .wb_sel_i (wb_sel_i), + .wb_adr_i (wb_adr_i), + .wb_dat_i (wb_dat_i), + .wb_dat_o (wb_dat_o), + .wb_ack_o (wb_ack_o), + + .wb_int_o (wb_int_o), + + .rx_scancode_i (rx_translated_scan_code), + .rx_data_ready_i (rx_translated_data_ready), + .rx_read_o (rx_read_wb), + .tx_data_o (tx_data), + .tx_write_o (tx_write), + .tx_write_ack_i (tx_write_ack), + .translate_o (translate), + .ps2_clk_i (ps2_kbd_clk_pad_i), + .inhibit_kbd_if_o (inhibit_kbd_if) +) ; + +ps2_translation_table i_ps2_translation_table +( + .reset_i (wb_rst_i), + .clock_i (wb_clk_i), + .translate_i (translate), + .code_i (rx_scan_code), + .code_o (rx_translated_scan_code), + .address_i (8'h00), + .data_i (8'h00), + .we_i (1'b0), + .re_i (1'b0), + .data_o (), + .rx_data_ready_i (rx_data_ready), + .rx_translated_data_ready_o (rx_translated_data_ready), + .rx_read_i (rx_read_wb), + .rx_read_o (rx_read_tt), + .rx_released_i (rx_released), + .rx_extended_i (rx_extended) +) ; + +endmodule // ps2_top Index: verilog/timescale.v =================================================================== --- verilog/timescale.v (nonexistent) +++ verilog/timescale.v (revision 51) @@ -0,0 +1 @@ +`timescale 1ns/1ps \ No newline at end of file Index: verilog/ps2_translation_table.v =================================================================== --- verilog/ps2_translation_table.v (nonexistent) +++ verilog/ps2_translation_table.v (revision 51) @@ -0,0 +1,241 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// ps2_translation_table.v //// +//// //// +//// This file is part of the "ps2" project //// +//// http://www.opencores.org/cores/ps2/ //// +//// //// +//// Author(s): //// +//// - mihad@opencores.org //// +//// - Miha Dolenc //// +//// //// +//// All additional information is avaliable in the README.txt //// +//// file. //// +//// //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +////////////////////////////////////////////////////////////////////// +// +// CVS Revision History +// +// $Log: not supported by cvs2svn $ +// + +`include "ps2_defines.v" + +// synopsys translate_off +`include "timescale.v" +// synopsys translate_on + +module ps2_translation_table +( + reset_i, + clock_i, + translate_i, + code_i, + code_o, + address_i, + data_i, + we_i, + re_i, + data_o, + rx_data_ready_i, + rx_translated_data_ready_o, + rx_read_i, + rx_read_o, + rx_extended_i, + rx_released_i +) ; + +input reset_i, + clock_i, + translate_i ; + +input [7:0] code_i ; +output [7:0] code_o ; +input [7:0] address_i ; +input [7:0] data_i ; +input we_i, + re_i ; + +output [7:0] data_o ; + +input rx_data_ready_i, + rx_read_i ; + +output rx_translated_data_ready_o ; +output rx_read_o ; + +input rx_extended_i, + rx_released_i ; + +wire translation_table_write_enable = we_i && (!translate_i || !rx_data_ready_i) ; +wire [7:0] translation_table_address = ((we_i || re_i) && (!rx_data_ready_i || !translate_i)) ? address_i : code_i ; +wire translation_table_enable = we_i || re_i || (translate_i && rx_data_ready_i) ; + +reg rx_translated_data_ready ; +always@(posedge clock_i or posedge reset_i) +begin + if ( reset_i ) + rx_translated_data_ready <= #1 1'b0 ; + else if ( rx_read_i || !translate_i ) + rx_translated_data_ready <= #1 1'b0 ; + else + rx_translated_data_ready <= #1 rx_data_ready_i ; +end + +`ifdef PS2_RAMB4 + `define PS2_RAM_SELECTED + + wire [7:0] ram_out ; + RAMB4_S8 `ifdef SIM + #("ignore", + `PS2_TRANSLATION_TABLE_31_0, + `PS2_TRANSLATION_TABLE_63_32, + `PS2_TRANSLATION_TABLE_95_64, + `PS2_TRANSLATION_TABLE_127_96, + `PS2_TRANSLATION_TABLE_159_128, + `PS2_TRANSLATION_TABLE_191_160, + `PS2_TRANSLATION_TABLE_223_192, + `PS2_TRANSLATION_TABLE_255_224) + `endif + ps2_ram + ( + .DO (ram_out), + .ADDR ({1'b0, translation_table_address}), + .DI (data_i), + .EN (translation_table_enable), + .CLK (clock_i), + .WE (translation_table_write_enable), + .RST (reset_i) + ) ; + +`endif + +`ifdef PS2_RAM_SELECTED +`else + `define PS2_RAM_SELECTED + + reg [7:0] ps2_ram [0:255] ; + reg [7:0] ram_out ; + + always@(posedge clock_i or posedge reset_i) + begin + if ( reset_i ) + ram_out <= #1 8'h0 ; + else if ( translation_table_enable ) + ram_out <= #1 ps2_ram[translation_table_address] ; + end + + always@(posedge clock_i) + begin + if ( translation_table_write_enable ) + ps2_ram[translation_table_address] <= #1 data_i ; + end + + // synopsys translate_off + integer i ; + reg [255:0] temp_init_val ; + initial + begin + temp_init_val = `PS2_TRANSLATION_TABLE_31_0 ; + + for ( i = 0 ; i <= 31 ; i = i + 1 ) + begin + ps2_ram[i] = temp_init_val[7:0] ; + temp_init_val = temp_init_val >> 8 ; + end + + temp_init_val = `PS2_TRANSLATION_TABLE_63_32 ; + + for ( i = 32 ; i <= 63 ; i = i + 1 ) + begin + ps2_ram[i] = temp_init_val[7:0] ; + temp_init_val = temp_init_val >> 8 ; + end + + temp_init_val = `PS2_TRANSLATION_TABLE_95_64 ; + + for ( i = 64 ; i <= 95 ; i = i + 1 ) + begin + ps2_ram[i] = temp_init_val[7:0] ; + temp_init_val = temp_init_val >> 8 ; + end + + temp_init_val = `PS2_TRANSLATION_TABLE_127_96 ; + + for ( i = 96 ; i <= 127 ; i = i + 1 ) + begin + ps2_ram[i] = temp_init_val[7:0] ; + temp_init_val = temp_init_val >> 8 ; + end + + temp_init_val = `PS2_TRANSLATION_TABLE_159_128 ; + + for ( i = 128 ; i <= 159 ; i = i + 1 ) + begin + ps2_ram[i] = temp_init_val[7:0] ; + temp_init_val = temp_init_val >> 8 ; + end + + temp_init_val = `PS2_TRANSLATION_TABLE_191_160 ; + + for ( i = 160 ; i <= 191 ; i = i + 1 ) + begin + ps2_ram[i] = temp_init_val[7:0] ; + temp_init_val = temp_init_val >> 8 ; + end + + temp_init_val = `PS2_TRANSLATION_TABLE_223_192 ; + + for ( i = 192 ; i <= 223 ; i = i + 1 ) + begin + ps2_ram[i] = temp_init_val[7:0] ; + temp_init_val = temp_init_val >> 8 ; + end + + temp_init_val = `PS2_TRANSLATION_TABLE_255_224 ; + + for ( i = 224 ; i <= 255 ; i = i + 1 ) + begin + ps2_ram[i] = temp_init_val[7:0] ; + temp_init_val = temp_init_val >> 8 ; + end + end + + // synopsys translate_on + +`endif + +assign data_o = ram_out ; +assign code_o = translate_i ? {(rx_released_i | ram_out[7]), ram_out[6:0]} : code_i ; +assign rx_translated_data_ready_o = translate_i ? rx_translated_data_ready : rx_data_ready_i ; +assign rx_read_o = rx_read_i ; + +`undef PS2_RAM_SELECTED + +endmodule //ps2_translation_table Index: verilog/ps2_wb_if.v =================================================================== --- verilog/ps2_wb_if.v (nonexistent) +++ verilog/ps2_wb_if.v (revision 51) @@ -0,0 +1,491 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// ps2_wb_if.v //// +//// //// +//// This file is part of the "ps2" project //// +//// http://www.opencores.org/cores/ps2/ //// +//// //// +//// Author(s): //// +//// - mihad@opencores.org //// +//// - Miha Dolenc //// +//// //// +//// All additional information is avaliable in the README.txt //// +//// file. //// +//// //// +//// //// +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +////////////////////////////////////////////////////////////////////// +// +// CVS Revision History +// +// $Log: not supported by cvs2svn $ +// + +// synopsys translate_off +`include "timescale.v" +// synopsys translate_on + +module ps2_wb_if +( + wb_clk_i, + wb_rst_i, + wb_cyc_i, + wb_stb_i, + wb_we_i, + wb_sel_i, + wb_adr_i, + wb_dat_i, + wb_dat_o, + wb_ack_o, + + wb_int_o, + + tx_write_ack_i, + tx_data_o, + tx_write_o, + rx_scancode_i, + rx_data_ready_i, + rx_read_o, + translate_o, + ps2_clk_i, + inhibit_kbd_if_o +) ; + +input wb_clk_i, + wb_rst_i, + wb_cyc_i, + wb_stb_i, + wb_we_i ; + +input [3:0] wb_sel_i ; + +input [31:0] wb_adr_i ; + +input [31:0] wb_dat_i ; + +output [31:0] wb_dat_o ; + +output wb_ack_o ; + +reg wb_ack_o ; + +output wb_int_o ; +reg wb_int_o ; + +input tx_write_ack_i ; + +input [7:0] rx_scancode_i ; +input rx_data_ready_i ; +output rx_read_o ; + +output tx_write_o ; +output [7:0] tx_data_o ; + +output translate_o ; +input ps2_clk_i ; + +output inhibit_kbd_if_o ; + +reg [7:0] input_buffer, + output_buffer ; + +assign tx_data_o = output_buffer ; + +reg input_buffer_full, // receive buffer + output_buffer_full ; // transmit buffer + +assign tx_write_o = output_buffer_full ; + +wire system_flag ; +wire a2 = 1'b0 ; +wire kbd_inhibit = ps2_clk_i ; +wire mouse_output_buffer_full = 1'b0 ; +wire timeout = 1'b0 ; +wire perr = 1'b0 ; + +wire [7:0] status_byte = {perr, timeout, mouse_output_buffer_full, kbd_inhibit, a2, system_flag, output_buffer_full, input_buffer_full} ; + +reg read_input_buffer_reg ; +wire read_input_buffer = wb_cyc_i && wb_stb_i && wb_sel_i[0] && !wb_ack_o && !read_input_buffer_reg && !wb_we_i && (wb_adr_i[2:0] == 3'h0) ; + +reg write_output_buffer_reg ; +wire write_output_buffer = wb_cyc_i && wb_stb_i && wb_sel_i[0] && !wb_ack_o && !write_output_buffer_reg && wb_we_i && (wb_adr_i[2:0] == 3'h0) ; + +reg read_status_register_reg ; +wire read_status_register = wb_cyc_i && wb_stb_i && wb_sel_i[0] && !wb_ack_o && !read_status_register_reg && !wb_we_i && (wb_adr_i[2:0] == 3'h4) ; + +reg send_command_reg ; +wire send_command = wb_cyc_i && wb_stb_i && wb_sel_i[0] && !wb_ack_o && !send_command_reg && wb_we_i && (wb_adr_i[2:0] == 3'h4) ; + +reg translate_o, + enable1, + system, + interrupt1 ; + +reg inhibit_kbd_if_o ; +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + inhibit_kbd_if_o <= #1 1'b1 ; + else if ( ps2_clk_i && (rx_data_ready_i || enable1) ) + inhibit_kbd_if_o <= #1 1'b1 ; + else if ( !rx_data_ready_i && !enable1 ) + inhibit_kbd_if_o <= #1 1'b0 ; + +end + +wire interrupt2 = 1'b0 ; +wire enable2 = 1'b1 ; + +assign system_flag = system ; + +wire [7:0] command_byte = {1'b0, translate_o, enable2, enable1, 1'b0, system, interrupt2, interrupt1} ; + +reg [7:0] current_command ; +reg [7:0] current_command_output ; + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + begin + send_command_reg <= #1 1'b0 ; + read_input_buffer_reg <= #1 1'b0 ; + write_output_buffer_reg <= #1 1'b0 ; + read_status_register_reg <= #1 1'b0 ; + end + else + begin + send_command_reg <= #1 send_command ; + read_input_buffer_reg <= #1 read_input_buffer ; + write_output_buffer_reg <= #1 write_output_buffer ; + read_status_register_reg <= #1 read_status_register ; + end +end + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + current_command <= #1 8'h0 ; + else if ( send_command_reg ) + current_command <= #1 wb_dat_i[7:0] ; +end + +reg current_command_valid, + current_command_returns_value, + current_command_gets_parameter, + current_command_gets_null_terminated_string ; + +reg write_output_buffer_reg_previous ; +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + write_output_buffer_reg_previous <= #1 1'b0 ; + else + write_output_buffer_reg_previous <= #1 write_output_buffer_reg ; +end + +wire invalidate_current_command = + current_command_valid && + (( current_command_returns_value && read_input_buffer_reg && input_buffer_full) || + ( current_command_gets_parameter && write_output_buffer_reg_previous ) || + ( current_command_gets_null_terminated_string && write_output_buffer_reg_previous && (output_buffer == 8'h00) ) || + ( !current_command_returns_value && !current_command_gets_parameter && !current_command_gets_null_terminated_string ) + ) ; + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + current_command_valid <= #1 1'b0 ; + else if ( invalidate_current_command ) + current_command_valid <= #1 1'b0 ; + else if ( send_command_reg ) + current_command_valid <= #1 1'b1 ; + +end + +reg write_command_byte ; +reg current_command_output_valid ; +always@( + current_command or + command_byte or + write_output_buffer_reg_previous or + current_command_valid or + output_buffer +) +begin + current_command_returns_value = 1'b0 ; + current_command_gets_parameter = 1'b0 ; + current_command_gets_null_terminated_string = 1'b0 ; + current_command_output = 8'h00 ; + write_command_byte = 1'b0 ; + current_command_output_valid = 1'b0 ; + case(current_command) + 8'h20:begin + current_command_returns_value = 1'b1 ; + current_command_output = command_byte ; + current_command_output_valid = 1'b1 ; + end + 8'h60:begin + current_command_gets_parameter = 1'b1 ; + write_command_byte = write_output_buffer_reg_previous && current_command_valid ; + end + 8'hA1:begin + current_command_returns_value = 1'b1 ; + current_command_output = 8'h00 ; + current_command_output_valid = 1'b1 ; + end + 8'hA4:begin + current_command_returns_value = 1'b1 ; + current_command_output = 8'hF1 ; + current_command_output_valid = 1'b1 ; + end + 8'hA5:begin + current_command_gets_null_terminated_string = 1'b1 ; + end + 8'hA6:begin + end + 8'hA7:begin + end + 8'hA8:begin + end + 8'hA9:begin + current_command_returns_value = 1'b1 ; + current_command_output = 8'h02 ; // clock line stuck high + current_command_output_valid = 1'b1 ; + end + 8'hAA:begin + current_command_returns_value = 1'b1 ; + current_command_output = 8'h55 ; + current_command_output_valid = 1'b1 ; + end + 8'hAB:begin + current_command_returns_value = 1'b1 ; + current_command_output = 8'h00 ; + current_command_output_valid = 1'b1 ; + end + 8'hAD:begin + end + 8'hAE:begin + end + 8'hAF:begin + current_command_returns_value = 1'b1 ; + current_command_output = 8'h00 ; + current_command_output_valid = 1'b1 ; + end + 8'hC0:begin + current_command_returns_value = 1'b1 ; + current_command_output = 8'hFF ; + current_command_output_valid = 1'b1 ; + end + 8'hC1:begin + end + 8'hC2:begin + end + 8'hD0:begin + current_command_returns_value = 1'b1 ; + current_command_output = 8'h01 ; // only system reset bit is 1 + current_command_output_valid = 1'b1 ; + end + 8'hD1:begin + current_command_gets_parameter = 1'b1 ; + end + 8'hD2:begin + current_command_gets_parameter = 1'b1 ; + current_command_output = output_buffer ; + current_command_output_valid = write_output_buffer_reg_previous ; + end + 8'hD3:begin + current_command_gets_parameter = 1'b1 ; + end + 8'hD4:begin + current_command_gets_parameter = 1'b1 ; + end + 8'hE0:begin + current_command_returns_value = 1'b1 ; + current_command_output = 8'hFF ; + current_command_output_valid = 1'b1 ; + end + endcase +end + +reg cyc_i_previous ; +reg stb_i_previous ; + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + begin + cyc_i_previous <= #1 1'b0 ; + stb_i_previous <= #1 1'b0 ; + end + else if ( wb_ack_o ) + begin + cyc_i_previous <= #1 1'b0 ; + stb_i_previous <= #1 1'b0 ; + end + else + begin + cyc_i_previous <= #1 wb_cyc_i ; + stb_i_previous <= #1 wb_stb_i ; + end + +end + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + wb_ack_o <= #1 1'b0 ; + else if ( wb_ack_o ) + wb_ack_o <= #1 1'b0 ; + else + wb_ack_o <= #1 cyc_i_previous && stb_i_previous ; +end + +reg [31:0] wb_dat_o ; +wire wb_read = read_input_buffer_reg || read_status_register_reg ; + +wire [7:0] output_data = read_status_register_reg ? status_byte : input_buffer ; +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + wb_dat_o <= #1 32'h0 ; + else if ( wb_read ) + wb_dat_o <= #1 {4{output_data}} ; +end + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + output_buffer_full <= #1 1'b0 ; + else if ( output_buffer_full && tx_write_ack_i) + output_buffer_full <= #1 1'b0 ; + else + output_buffer_full <= #1 write_output_buffer_reg && (!current_command_valid || (!current_command_gets_parameter && !current_command_gets_null_terminated_string)) ; +end + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + output_buffer <= #1 8'h00 ; + else if ( write_output_buffer_reg ) + output_buffer <= #1 wb_dat_i[7:0] ; +end + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + begin + translate_o <= #1 1'b0 ; + system <= #1 1'b0 ; + interrupt1 <= #1 1'b0 ; + end + else if ( write_command_byte ) + begin + translate_o <= #1 output_buffer[6] ; + system <= #1 output_buffer[2] ; + interrupt1 <= #1 output_buffer[0] ; + end +end + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + enable1 <= #1 1'b1 ; + else if ( current_command_valid && (current_command == 8'hAE) ) + enable1 <= #1 1'b0 ; + else if ( current_command_valid && (current_command == 8'hAD) ) + enable1 <= #1 1'b1 ; + else if ( write_command_byte ) + enable1 <= #1 output_buffer[4] ; + +end + +wire write_input_buffer_from_command = current_command_valid && current_command_returns_value && current_command_output_valid ; +reg write_input_buffer_from_command_reg ; +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + write_input_buffer_from_command_reg <= #1 1'b0 ; + else + write_input_buffer_from_command_reg <= #1 write_input_buffer_from_command ; +end + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + input_buffer_full <= #1 1'b0 ; + else if ( read_input_buffer_reg ) + input_buffer_full <= #1 1'b0 ; + else if ( (write_input_buffer_from_command && !write_input_buffer_from_command_reg) || (rx_data_ready_i && !enable1) ) + input_buffer_full <= #1 1'b1 ; +end + +reg input_buffer_filled_from_command ; +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + input_buffer_filled_from_command <= #1 1'b0 ; + else if ( read_input_buffer_reg ) + input_buffer_filled_from_command <= #1 1'b0 ; + else if ( write_input_buffer_from_command && !write_input_buffer_from_command_reg) + input_buffer_filled_from_command <= #1 1'b1 ; +end + +reg rx_data_ready_reg ; +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + rx_data_ready_reg <= #1 1'b0 ; + else if ( input_buffer_filled_from_command ) + rx_data_ready_reg <= #1 1'b0 ; + else + rx_data_ready_reg <= #1 rx_data_ready_i ; +end + +wire input_buffer_value_change = (rx_data_ready_i && !rx_data_ready_reg && !enable1) || (write_input_buffer_from_command && !write_input_buffer_from_command_reg) ; + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + input_buffer <= #1 8'h00 ; + else if ( input_buffer_value_change ) + input_buffer <= #1 current_command_valid && current_command_returns_value ? current_command_output : rx_scancode_i ; +end + +assign rx_read_o = enable1 || rx_data_ready_i && !input_buffer_filled_from_command && read_input_buffer_reg ; + +always@(posedge wb_clk_i or posedge wb_rst_i) +begin + if ( wb_rst_i ) + wb_int_o <= #1 1'b0 ; + else if ( read_input_buffer_reg || enable1 || !interrupt1) + wb_int_o <= #1 1'b0 ; + else + wb_int_o <= #1 input_buffer_full ; +end + +endmodule // ps2_wb_if

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.