URL
https://opencores.org/ocsvn/ps2/ps2/trunk
Subversion Repositories ps2
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 12 to Rev 13
- ↔ Reverse comparison
Rev 12 → Rev 13
/trunk/rtl/verilog/ps2_io_ctrl.v
43,7 → 43,10
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.1.1.1 2002/02/18 16:16:56 mihad |
// Initial project import - working |
// |
// |
|
// synopsys translate_off |
`include "timescale.v" |
53,51 → 56,51
( |
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 |
ps2_ctrl_clk_en_i_, |
ps2_ctrl_data_en_i_, |
ps2_clk_pad_i, |
ps2_clk_pad_oe_o, |
ps2_data_pad_oe_o, |
inhibit_if_i, |
ps2_ctrl_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 ; |
ps2_ctrl_clk_en_i_, |
ps2_ctrl_data_en_i_, |
ps2_clk_pad_i, |
inhibit_if_i ; |
|
output ps2_kbd_clk_pad_oe_o, |
ps2_kbd_data_pad_oe_o, |
ps2_ctrl_kbd_clk_o ; |
output ps2_clk_pad_oe_o, |
ps2_data_pad_oe_o, |
ps2_ctrl_clk_o ; |
|
reg ps2_kbd_clk_pad_oe_o, |
ps2_kbd_data_pad_oe_o ; |
reg ps2_clk_pad_oe_o, |
ps2_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 ; |
ps2_clk_pad_oe_o <= #1 1'b0 ; |
ps2_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_ ; |
ps2_clk_pad_oe_o <= #1 !ps2_ctrl_clk_en_i_ || inhibit_if_i ; |
ps2_data_pad_oe_o <= #1 !ps2_ctrl_data_en_i_ ; |
end |
end |
|
reg inhibit_kbd_if_previous ; |
reg inhibit_if_previous ; |
always@(posedge clk_i or posedge rst_i) |
begin |
if ( rst_i ) |
inhibit_kbd_if_previous <= #1 1'b1 ; |
inhibit_if_previous <= #1 1'b1 ; |
else |
inhibit_kbd_if_previous <= #1 inhibit_kbd_if_i ; |
inhibit_if_previous <= #1 inhibit_if_i ; |
end |
|
assign ps2_ctrl_kbd_clk_o = ps2_kbd_clk_pad_i || ps2_kbd_clk_pad_oe_o && inhibit_kbd_if_previous ; |
assign ps2_ctrl_clk_o = ps2_clk_pad_i || ps2_clk_pad_oe_o && inhibit_if_previous ; |
endmodule // ps2_io_ctrl |
/trunk/rtl/verilog/ps2_defines.v
43,12 → 43,15
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.2 2002/02/18 16:33:08 mihad |
// Changed defines for simulation to work without xilinx primitives |
// |
// Revision 1.1.1.1 2002/02/18 16:16:56 mihad |
// Initial project import - working |
// |
// |
|
//`define PS2_RAMB4 |
`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 |
58,9 → 61,11
`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_VALUE_PP 1500 // 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 PS2_TIMER_5USEC_VALUE_PP 125 // Number of sys_clks for debounce |
`define PS2_TIMER_5USEC_BITS_PP 7 // Number of bits needed for timer |
|
//`define PS2_AUX |
|
//`define SIM |
/trunk/rtl/verilog/ps2_keyboard.v
1,710 → 1,536
//------------------------------------------------------------------------------------- |
// |
// 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 |
|
//------------------------------------------------------------------------------------- |
// |
// 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 RELEASE_CODE 16'hF0 |
|
module ps2_keyboard ( |
clk, |
reset, |
ps2_clk_en_o_, |
ps2_data_en_o_, |
ps2_clk_i, |
ps2_data_i, |
rx_released, |
rx_scan_code, |
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 |
|
// 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_released; |
output [7:0] rx_scan_code; |
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_released; |
reg [7:0] rx_scan_code; |
reg rx_data_ready; |
reg tx_error_no_keyboard_ack; |
|
// Internal signal declarations |
wire timer_60usec_done; |
wire timer_5usec_done; |
wire released; |
|
// 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; |
|
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 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." |
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_released <= 0; |
end |
else |
begin |
if (rx_shifting_done && released) hold_released <= 1; |
end |
end |
|
// Output the special scan code flags, the scan code and the ascii |
always @(posedge clk) |
begin |
if (reset) |
begin |
rx_released <= 0; |
rx_scan_code <= 0; |
end |
else if (rx_output_strobe) |
begin |
rx_released <= hold_released; |
rx_scan_code <= q[8:1]; |
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 |
&& ~released |
); |
|
assign rx_output_strobe = (rx_shifting_done |
&& ~released |
); |
|
endmodule |
|
//`undefine TOTAL_BITS |
//`undefine EXTEND_CODE |
//`undefine RELEASE_CODE |
//`undefine LEFT_SHIFT |
//`undefine RIGHT_SHIFT |
|
/trunk/rtl/verilog/ps2_top.v
43,7 → 43,10
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.1.1.1 2002/02/18 16:16:56 mihad |
// Initial project import - working |
// |
// |
|
`include "ps2_defines.v" |
// synopsys translate_off |
62,9 → 65,9
wb_dat_i, |
wb_dat_o, |
wb_ack_o, |
|
wb_int_o, |
|
wb_int_o, |
|
ps2_kbd_clk_pad_i, |
ps2_kbd_data_pad_i, |
ps2_kbd_clk_pad_o, |
71,6 → 74,17
ps2_kbd_data_pad_o, |
ps2_kbd_clk_pad_oe_o, |
ps2_kbd_data_pad_oe_o |
`ifdef PS2_AUX |
, |
wb_intb_o, |
|
ps2_aux_clk_pad_i, |
ps2_aux_data_pad_i, |
ps2_aux_clk_pad_o, |
ps2_aux_data_pad_o, |
ps2_aux_clk_pad_oe_o, |
ps2_aux_data_pad_oe_o |
`endif |
) ; |
|
input wb_clk_i, |
81,7 → 95,7
|
input [3:0] wb_sel_i ; |
|
input [31:0]wb_adr_i, |
input [31:0]wb_adr_i, |
wb_dat_i ; |
|
output [31:0] wb_dat_o ; |
98,15 → 112,27
ps2_kbd_clk_pad_oe_o, |
ps2_kbd_data_pad_oe_o ; |
|
wire rx_extended, |
rx_released, |
rx_shift_key_on, |
rx_data_ready, |
`ifdef PS2_AUX |
output wb_intb_o ; |
input ps2_aux_clk_pad_i, |
ps2_aux_data_pad_i ; |
|
output ps2_aux_clk_pad_o, |
ps2_aux_data_pad_o, |
ps2_aux_clk_pad_oe_o, |
ps2_aux_data_pad_oe_o ; |
|
assign ps2_aux_clk_pad_o = 1'b0 ; |
assign ps2_aux_data_pad_o = 1'b0 ; |
`endif |
|
wire rx_released, |
rx_kbd_data_ready, |
rx_translated_data_ready, |
rx_read_wb, |
rx_read_tt, |
tx_write, |
tx_write_ack, |
rx_kbd_read_wb, |
rx_kbd_read_tt, |
tx_kbd_write, |
tx_kbd_write_ack, |
tx_error_no_keyboard_ack, |
ps2_ctrl_kbd_data_en_, |
ps2_ctrl_kbd_clk_en_, |
113,28 → 139,74
ps2_ctrl_kbd_clk, |
inhibit_kbd_if ; |
|
wire [7:0] rx_scan_code, |
wire [7:0] rx_scan_code, |
rx_translated_scan_code, |
rx_ascii, |
tx_data ; |
tx_kbd_data ; |
|
assign ps2_kbd_clk_pad_o = 1'b0 ; |
assign ps2_kbd_data_pad_o = 1'b0 ; |
|
ps2_io_ctrl i_ps2_io_ctrl |
ps2_io_ctrl i_ps2_io_ctrl_keyboard |
( |
.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) |
.clk_i (wb_clk_i), |
.rst_i (wb_rst_i), |
.ps2_ctrl_clk_en_i_ (ps2_ctrl_kbd_clk_en_), |
.ps2_ctrl_data_en_i_ (ps2_ctrl_kbd_data_en_), |
.ps2_clk_pad_i (ps2_kbd_clk_pad_i), |
.ps2_clk_pad_oe_o (ps2_kbd_clk_pad_oe_o), |
.ps2_data_pad_oe_o (ps2_kbd_data_pad_oe_o), |
.inhibit_if_i (inhibit_kbd_if), |
.ps2_ctrl_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) |
`ifdef PS2_AUX |
wire rx_aux_data_ready, |
rx_aux_read, |
tx_aux_write, |
tx_aux_write_ack, |
tx_error_no_aux_ack, |
ps2_ctrl_aux_data_en_, |
ps2_ctrl_aux_clk_en_, |
ps2_ctrl_aux_clk, |
inhibit_aux_if ; |
|
wire [7:0] rx_aux_data, |
tx_aux_data ; |
|
ps2_io_ctrl i_ps2_io_ctrl_auxiliary |
( |
.clk_i (wb_clk_i), |
.rst_i (wb_rst_i), |
.ps2_ctrl_clk_en_i_ (ps2_ctrl_aux_clk_en_), |
.ps2_ctrl_data_en_i_ (ps2_ctrl_aux_data_en_), |
.ps2_clk_pad_i (ps2_aux_clk_pad_i), |
.ps2_clk_pad_oe_o (ps2_aux_clk_pad_oe_o), |
.ps2_data_pad_oe_o (ps2_aux_data_pad_oe_o), |
.inhibit_if_i (inhibit_aux_if), |
.ps2_ctrl_clk_o (ps2_ctrl_aux_clk) |
); |
|
ps2_mouse #(`PS2_TIMER_60USEC_VALUE_PP, `PS2_TIMER_60USEC_BITS_PP, `PS2_TIMER_5USEC_VALUE_PP, `PS2_TIMER_5USEC_BITS_PP) |
i_ps2_mouse |
( |
.clk (wb_clk_i), |
.reset (wb_rst_i), |
.ps2_clk_en_o_ (ps2_ctrl_aux_clk_en_), |
.ps2_data_en_o_ (ps2_ctrl_aux_data_en_), |
.ps2_clk_i (ps2_ctrl_aux_clk), |
.ps2_data_i (ps2_aux_data_pad_i), |
.rx_scan_code (rx_aux_data), |
.rx_data_ready (rx_aux_data_ready), |
.rx_read (rx_aux_read), |
.tx_data (tx_aux_data), |
.tx_write (tx_aux_write), |
.tx_write_ack_o (tx_aux_write_ack), |
.tx_error_no_ack (tx_error_no_aux_ack) |
); |
|
`endif |
|
ps2_keyboard #(`PS2_TIMER_60USEC_VALUE_PP, `PS2_TIMER_60USEC_BITS_PP, `PS2_TIMER_5USEC_VALUE_PP, `PS2_TIMER_5USEC_BITS_PP) |
i_ps2_keyboard |
( |
.clk (wb_clk_i), |
143,16 → 215,13
.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), |
.rx_data_ready (rx_kbd_data_ready), |
.rx_read (rx_kbd_read_tt), |
.tx_data (tx_kbd_data), |
.tx_write (tx_kbd_write), |
.tx_write_ack_o (tx_kbd_write_ack), |
.tx_error_no_keyboard_ack (tx_error_no_keyboard_ack), |
.translate (translate) |
); |
169,18 → 238,31
.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), |
.rx_kbd_data_ready_i (rx_translated_data_ready), |
.rx_kbd_read_o (rx_kbd_read_wb), |
.tx_kbd_data_o (tx_kbd_data), |
.tx_kbd_write_o (tx_kbd_write), |
.tx_kbd_write_ack_i (tx_kbd_write_ack), |
.translate_o (translate), |
.ps2_clk_i (ps2_kbd_clk_pad_i), |
.ps2_kbd_clk_i (ps2_kbd_clk_pad_i), |
.inhibit_kbd_if_o (inhibit_kbd_if) |
`ifdef PS2_AUX |
, |
.wb_intb_o (wb_intb_o), |
|
.rx_aux_data_i (rx_aux_data), |
.rx_aux_data_ready_i (rx_aux_data_ready), |
.rx_aux_read_o (rx_aux_read), |
.tx_aux_data_o (tx_aux_data), |
.tx_aux_write_o (tx_aux_write), |
.tx_aux_write_ack_i (tx_aux_write_ack), |
.ps2_aux_clk_i (ps2_aux_clk_pad_i), |
.inhibit_aux_if_o (inhibit_aux_if) |
`endif |
) ; |
|
ps2_translation_table i_ps2_translation_table |
195,12 → 277,11
.we_i (1'b0), |
.re_i (1'b0), |
.data_o (), |
.rx_data_ready_i (rx_data_ready), |
.rx_data_ready_i (rx_kbd_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) |
.rx_read_i (rx_kbd_read_wb), |
.rx_read_o (rx_kbd_read_tt), |
.rx_released_i (rx_released) |
) ; |
|
endmodule // ps2_top |
/trunk/rtl/verilog/ps2_translation_table.v
43,7 → 43,10
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.1.1.1 2002/02/18 16:16:56 mihad |
// Initial project import - working |
// |
// |
|
`include "ps2_defines.v" |
|
67,7 → 70,6
rx_translated_data_ready_o, |
rx_read_i, |
rx_read_o, |
rx_extended_i, |
rx_released_i |
) ; |
|
90,8 → 92,7
output rx_translated_data_ready_o ; |
output rx_read_o ; |
|
input rx_extended_i, |
rx_released_i ; |
input 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 ; |
110,17 → 111,17
|
`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_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 |
133,16 → 134,16
.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 ) |
171,7 → 172,7
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] ; |
179,15 → 180,15
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] ; |
195,31 → 196,31
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] ; |
236,6 → 237,6
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 |
`undef PS2_RAM_SELECTED |
|
endmodule //ps2_translation_table |
/trunk/rtl/verilog/ps2_wb_if.v
43,6 → 43,9
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.4 2002/02/20 16:35:43 mihad |
// Little/big endian changes continued |
// |
// Revision 1.3 2002/02/20 15:20:10 mihad |
// Little/big endian changes incorporated |
// |
70,18 → 73,31
wb_dat_i, |
wb_dat_o, |
wb_ack_o, |
|
|
wb_int_o, |
|
tx_write_ack_i, |
tx_data_o, |
tx_write_o, |
tx_kbd_write_ack_i, |
tx_kbd_data_o, |
tx_kbd_write_o, |
rx_scancode_i, |
rx_data_ready_i, |
rx_read_o, |
rx_kbd_data_ready_i, |
rx_kbd_read_o, |
translate_o, |
ps2_clk_i, |
ps2_kbd_clk_i, |
inhibit_kbd_if_o |
`ifdef PS2_AUX |
, |
wb_intb_o, |
|
rx_aux_data_i, |
rx_aux_data_ready_i, |
rx_aux_read_o, |
tx_aux_data_o, |
tx_aux_write_o, |
tx_aux_write_ack_i, |
ps2_aux_clk_i, |
inhibit_aux_if_o |
`endif |
) ; |
|
input wb_clk_i, |
105,17 → 121,17
output wb_int_o ; |
reg wb_int_o ; |
|
input tx_write_ack_i ; |
input tx_kbd_write_ack_i ; |
|
input [7:0] rx_scancode_i ; |
input rx_data_ready_i ; |
output rx_read_o ; |
input rx_kbd_data_ready_i ; |
output rx_kbd_read_o ; |
|
output tx_write_o ; |
output [7:0] tx_data_o ; |
output tx_kbd_write_o ; |
output [7:0] tx_kbd_data_o ; |
|
output translate_o ; |
input ps2_clk_i ; |
input ps2_kbd_clk_i ; |
|
output inhibit_kbd_if_o ; |
|
122,21 → 138,55
reg [7:0] input_buffer, |
output_buffer ; |
|
assign tx_data_o = output_buffer ; |
reg [7:0] wb_dat_i_sampled ; |
always@(posedge wb_clk_i or posedge wb_rst_i) |
begin |
if ( wb_rst_i ) |
wb_dat_i_sampled <= #1 0 ; |
else if ( wb_cyc_i && wb_stb_i && wb_we_i ) |
wb_dat_i_sampled <= #1 wb_dat_i[31:24] ; |
end |
|
`ifdef PS2_AUX |
output wb_intb_o ; |
reg wb_intb_o ; |
|
input [7:0] rx_aux_data_i ; |
input rx_aux_data_ready_i ; |
output rx_aux_read_o ; |
output [7:0] tx_aux_data_o ; |
output tx_aux_write_o ; |
input tx_aux_write_ack_i ; |
input ps2_aux_clk_i ; |
output inhibit_aux_if_o ; |
reg inhibit_aux_if_o ; |
reg aux_output_buffer_full ; |
reg aux_input_buffer_full ; |
reg interrupt2 ; |
reg enable2 ; |
assign tx_aux_data_o = output_buffer ; |
assign tx_aux_write_o = aux_output_buffer_full ; |
`else |
wire aux_input_buffer_full = 1'b0 ; |
wire aux_output_buffer_full = 1'b0 ; |
wire interrupt2 = 1'b0 ; |
wire enable2 = 1'b1 ; |
`endif |
|
assign tx_kbd_data_o = output_buffer ; |
|
reg input_buffer_full, // receive buffer |
output_buffer_full ; // transmit buffer |
|
assign tx_write_o = output_buffer_full ; |
assign tx_kbd_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 kbd_inhibit = ps2_kbd_clk_i ; |
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} ; |
wire [7:0] status_byte = {perr, timeout, aux_input_buffer_full, kbd_inhibit, a2, system_flag, output_buffer_full || aux_output_buffer_full, input_buffer_full} ; |
|
reg read_input_buffer_reg ; |
wire read_input_buffer = wb_cyc_i && wb_stb_i && wb_sel_i[3] && !wb_ack_o && !read_input_buffer_reg && !wb_we_i && (wb_adr_i[2:0] == 3'h0) ; |
160,16 → 210,26
begin |
if ( wb_rst_i ) |
inhibit_kbd_if_o <= #1 1'b1 ; |
else if ( ps2_clk_i && (rx_data_ready_i || enable1) ) |
else if ( ps2_kbd_clk_i && rx_kbd_data_ready_i && !enable1) |
inhibit_kbd_if_o <= #1 1'b1 ; |
else if ( !rx_data_ready_i && !enable1 ) |
else if ( !rx_kbd_data_ready_i || enable1 ) |
inhibit_kbd_if_o <= #1 1'b0 ; |
|
|
end |
|
wire interrupt2 = 1'b0 ; |
wire enable2 = 1'b1 ; |
`ifdef PS2_AUX |
always@(posedge wb_clk_i or posedge wb_rst_i) |
begin |
if ( wb_rst_i ) |
inhibit_aux_if_o <= #1 1'b1 ; |
else if ( ps2_aux_clk_i && rx_aux_data_ready_i && !enable2 ) |
inhibit_aux_if_o <= #1 1'b1 ; |
else if ( !rx_aux_data_ready_i || enable2 ) |
inhibit_aux_if_o <= #1 1'b0 ; |
|
end |
`endif |
|
assign system_flag = system ; |
|
wire [7:0] command_byte = {1'b0, translate_o, enable2, enable1, 1'b0, system, interrupt2, interrupt1} ; |
200,7 → 260,7
if ( wb_rst_i ) |
current_command <= #1 8'h0 ; |
else if ( send_command_reg ) |
current_command <= #1 wb_dat_i[31:24] ; |
current_command <= #1 wb_dat_i_sampled ; |
end |
|
reg current_command_valid, |
217,8 → 277,8
write_output_buffer_reg_previous <= #1 write_output_buffer_reg ; |
end |
|
wire invalidate_current_command = |
current_command_valid && |
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) ) || |
233,7 → 293,7
current_command_valid <= #1 1'b0 ; |
else if ( send_command_reg ) |
current_command_valid <= #1 1'b1 ; |
|
|
end |
|
reg write_command_byte ; |
241,7 → 301,7
always@( |
current_command or |
command_byte or |
write_output_buffer_reg_previous or |
write_output_buffer_reg_previous or |
current_command_valid or |
output_buffer |
) |
266,7 → 326,7
current_command_returns_value = 1'b1 ; |
current_command_output = 8'h00 ; |
current_command_output_valid = 1'b1 ; |
end |
end |
8'hA4:begin |
current_command_returns_value = 1'b1 ; |
current_command_output = 8'hF1 ; |
278,13 → 338,17
8'hA6:begin |
end |
8'hA7:begin |
end |
end |
8'hA8:begin |
end |
8'hA9:begin |
current_command_returns_value = 1'b1 ; |
current_command_output_valid = 1'b1 ; |
`ifdef PS2_AUX |
current_command_output = 8'h00 ; // interface OK |
`else |
current_command_output = 8'h02 ; // clock line stuck high |
current_command_output_valid = 1'b1 ; |
`endif |
end |
8'hAA:begin |
current_command_returns_value = 1'b1 ; |
297,7 → 361,7
current_command_output_valid = 1'b1 ; |
end |
8'hAD:begin |
end |
end |
8'hAE:begin |
end |
8'hAF:begin |
305,7 → 369,7
current_command_output = 8'h00 ; |
current_command_output_valid = 1'b1 ; |
end |
8'hC0:begin |
8'hC0:begin |
current_command_returns_value = 1'b1 ; |
current_command_output = 8'hFF ; |
current_command_output_valid = 1'b1 ; |
330,6 → 394,11
end |
8'hD3:begin |
current_command_gets_parameter = 1'b1 ; |
`ifdef PS2_AUX |
current_command_returns_value = 1'b1 ; |
current_command_output = output_buffer ; |
current_command_output_valid = write_output_buffer_reg_previous ; |
`endif |
end |
8'hD4:begin |
current_command_gets_parameter = 1'b1 ; |
339,7 → 408,7
current_command_output = 8'hFF ; |
current_command_output_valid = 1'b1 ; |
end |
endcase |
endcase |
end |
|
reg cyc_i_previous ; |
362,7 → 431,7
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) |
391,18 → 460,30
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 |
else if ( output_buffer_full && tx_kbd_write_ack_i || enable1) |
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 |
|
`ifdef PS2_AUX |
always@(posedge wb_clk_i or posedge wb_rst_i) |
begin |
if ( wb_rst_i ) |
aux_output_buffer_full <= #1 1'b0 ; |
else if ( aux_output_buffer_full && tx_aux_write_ack_i || enable2) |
aux_output_buffer_full <= #1 1'b0 ; |
else |
aux_output_buffer_full <= #1 write_output_buffer_reg && current_command_valid && (current_command == 8'hD4) ; |
end |
`endif |
|
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[31:24] ; |
output_buffer <= #1 wb_dat_i_sampled ; |
end |
|
always@(posedge wb_clk_i or posedge wb_rst_i) |
412,6 → 493,9
translate_o <= #1 1'b0 ; |
system <= #1 1'b0 ; |
interrupt1 <= #1 1'b0 ; |
`ifdef PS2_AUX |
interrupt2 <= #1 1'b0 ; |
`endif |
end |
else if ( write_command_byte ) |
begin |
418,6 → 502,9
translate_o <= #1 output_buffer[6] ; |
system <= #1 output_buffer[2] ; |
interrupt1 <= #1 output_buffer[0] ; |
`ifdef PS2_AUX |
interrupt2 <= #1 output_buffer[1] ; |
`endif |
end |
end |
|
431,19 → 518,41
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 ; |
`ifdef PS2_AUX |
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 ; |
enable2 <= #1 1'b1 ; |
else if ( current_command_valid && (current_command == 8'hA8) ) |
enable2 <= #1 1'b0 ; |
else if ( current_command_valid && (current_command == 8'hA7) ) |
enable2 <= #1 1'b1 ; |
else if ( write_command_byte ) |
enable2 <= #1 output_buffer[5] ; |
|
end |
`endif |
|
wire write_input_buffer_from_command = current_command_valid && current_command_returns_value && current_command_output_valid ; |
wire write_input_buffer_from_kbd = !input_buffer_full && rx_kbd_data_ready_i && !enable1 && !current_command_valid ; |
|
`ifdef PS2_AUX |
wire write_input_buffer_from_aux = !input_buffer_full && rx_aux_data_ready_i && !enable2 && !current_command_valid && !write_input_buffer_from_kbd ; |
`endif |
|
wire load_input_buffer_value = |
write_input_buffer_from_command |
|| |
write_input_buffer_from_kbd |
`ifdef PS2_AUX |
|| |
write_input_buffer_from_aux |
`endif |
; |
|
always@(posedge wb_clk_i or posedge wb_rst_i) |
begin |
if ( wb_rst_i ) |
450,10 → 559,22
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) ) |
else if ( load_input_buffer_value ) |
input_buffer_full <= #1 1'b1 ; |
end |
|
`ifdef PS2_AUX |
always@(posedge wb_clk_i or posedge wb_rst_i) |
begin |
if ( wb_rst_i ) |
aux_input_buffer_full <= #1 1'b0 ; |
else if ( read_input_buffer_reg ) |
aux_input_buffer_full <= #1 1'b0 ; |
else if ( write_input_buffer_from_aux || (write_input_buffer_from_command && (current_command == 8'hD3)) ) |
aux_input_buffer_full <= #1 1'b1 ; |
end |
`endif |
|
reg input_buffer_filled_from_command ; |
always@(posedge wb_clk_i or posedge wb_rst_i) |
begin |
461,33 → 582,74
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) |
else if ( write_input_buffer_from_command ) |
input_buffer_filled_from_command <= #1 1'b1 ; |
end |
|
reg rx_data_ready_reg ; |
always@(posedge wb_clk_i or posedge wb_rst_i) |
`ifdef PS2_AUX |
reg [7:0] value_to_load_in_input_buffer ; |
always@ |
( |
write_input_buffer_from_command |
or |
current_command_output |
or |
rx_scancode_i |
or |
write_input_buffer_from_kbd |
or |
rx_aux_data_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 ; |
case ({write_input_buffer_from_command, write_input_buffer_from_kbd}) |
2'b10, |
2'b11 : value_to_load_in_input_buffer = current_command_output ; |
2'b01 : value_to_load_in_input_buffer = rx_scancode_i ; |
2'b00 : value_to_load_in_input_buffer = rx_aux_data_i ; |
endcase |
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) ; |
`else |
wire [7:0] value_to_load_in_input_buffer = write_input_buffer_from_command ? current_command_output : rx_scancode_i ; |
`endif |
|
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 ; |
else if ( load_input_buffer_value ) |
input_buffer <= #1 value_to_load_in_input_buffer ; |
end |
|
assign rx_read_o = enable1 || rx_data_ready_i && !input_buffer_filled_from_command && read_input_buffer_reg ; |
assign rx_kbd_read_o = rx_kbd_data_ready_i && |
( enable1 |
|| |
( read_input_buffer_reg |
&& |
input_buffer_full |
&& |
!input_buffer_filled_from_command |
`ifdef PS2_AUX |
&& |
!aux_input_buffer_full |
`endif |
) |
); |
|
`ifdef PS2_AUX |
assign rx_aux_read_o = rx_aux_data_ready_i && |
( enable2 || |
( read_input_buffer_reg |
&& |
input_buffer_full |
&& |
aux_input_buffer_full |
&& |
!input_buffer_filled_from_command |
) |
); |
`endif |
|
always@(posedge wb_clk_i or posedge wb_rst_i) |
begin |
if ( wb_rst_i ) |
495,7 → 657,27
else if ( read_input_buffer_reg || enable1 || !interrupt1) |
wb_int_o <= #1 1'b0 ; |
else |
wb_int_o <= #1 input_buffer_full ; |
wb_int_o <= #1 input_buffer_full |
`ifdef PS2_AUX |
&& |
!aux_input_buffer_full |
`endif |
; |
end |
|
`ifdef PS2_AUX |
always@(posedge wb_clk_i or posedge wb_rst_i) |
begin |
if ( wb_rst_i ) |
wb_intb_o <= #1 1'b0 ; |
else if ( read_input_buffer_reg || enable2 || !interrupt2) |
wb_intb_o <= #1 1'b0 ; |
else |
wb_intb_o <= #1 input_buffer_full |
&& |
aux_input_buffer_full |
; |
end |
`endif |
|
endmodule // ps2_wb_if |
/trunk/sim/rtl_sim/run/run_ps2_sim.scr
45,6 → 45,9
#// CVS Revision History |
#// |
#// $Log: not supported by cvs2svn $ |
#// Revision 1.2 2002/02/20 15:20:11 mihad |
#// Little/big endian changes incorporated |
#// |
#// Revision 1.1.1.1 2002/02/18 16:16:55 mihad |
#// Initial project import - working |
#// |
60,23 → 63,26
echo '-DEFINE "PS2_NUM_OF_EXTENDED_SCANCODES 38"' >> ./ncvlog.args |
echo '-DEFINE "SIM"' >> ./ncvlog.args |
|
if ( $# > 0 ) then |
if ( $# == 1 ) then |
switch ( $1 ) |
case xilinx: |
echo '-DEFINE "XILINX"' >> ./ncvlog.args |
breaksw |
set current_par = 0 |
set output_waveform = 0 |
set xilinx = 0 |
while ( $current_par < $# ) |
@ current_par = $current_par + 1 |
switch ( $argv[$current_par] ) |
case xilinx: |
echo '-DEFINE "XILINX"' >> ./ncvlog.args |
@ xilinx = 1 |
breaksw |
case wave: |
@ output_waveform = 1 |
breaksw |
default: |
echo 'Unknown option "'$argv[$current_par]'"!' |
exit |
breaksw |
endsw |
end |
|
default: |
echo 'Unknown option "'$1'"!' |
exit |
breaksw |
endsw |
else |
echo "Wrong number of arguments" ; exit |
endif |
endif |
|
echo "-LOGFILE ../log/ncvlog.log" >> ./ncvlog.args |
|
foreach filename ( `cat ../bin/rtl_file_list` ) |
87,14 → 93,10
echo "../../../bench/verilog/"$filename >> ./ncvlog.args |
end |
|
if ( $# > 0 ) then |
switch( $1 ) |
case xilinx: |
foreach filename ( `cat ../bin/xilinx_file_list` ) |
echo "../../../../xilinx_blocks/"$filename >> ./ncvlog.args |
end |
breaksw |
endsw |
if ( $xilinx ) then |
foreach filename ( `cat ../bin/xilinx_file_list` ) |
echo "../../../../xilinx_blocks/"$filename >> ./ncvlog.args |
end |
endif |
|
ncvlog -f ./ncvlog.args |
108,12 → 110,8
echo "-ACCESS +RWC" >> ./ncelab.args |
echo "worklib.ps2_test_bench" >> ./ncelab.args |
|
if ( $# > 0 ) then |
switch ( $1 ) |
case xilinx: |
echo "worklib.glbl" >> ./ncelab.args |
breaksw |
endsw |
if ( $xilinx ) then |
echo "worklib.glbl" >> ./ncelab.args |
endif |
|
ncelab -f ./ncelab.args |
126,9 → 124,14
echo "-LOGFILE ../log/ncsim.log" >> ./ncsim.args |
echo "worklib.ps2_test_bench:rtl" >> ./ncsim.args |
|
echo "database -open waves -shm -into ../out/waves.shm" > ./ncsim.tcl |
echo "probe -create -database waves ps2_test_bench -shm -all -depth all" >> ./ncsim.tcl |
echo "run" >> ./ncsim.tcl |
if ( $output_waveform ) then |
echo "database -open waves -shm -into ../out/waves.shm" > ./ncsim.tcl |
echo "probe -create -database waves ps2_test_bench -shm -all -depth all" >> ./ncsim.tcl |
echo "run" >> ./ncsim.tcl |
else |
echo "run" > ./ncsim.tcl |
endif |
|
echo "quit" >> ./ncsim.tcl |
|
ncsim -f ./ncsim.args |
/trunk/sim/rtl_sim/bin/rtl_file_list
1,4 → 1,5
ps2_keyboard.v |
ps2_mouse.v |
ps2_top.v |
ps2_translation_table.v |
ps2_wb_if.v |