📄 ps2_keyboard.v
字号:
`resetall`timescale 1ns/100ps`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, //复位==1 ps2_clk, ps2_data, rx_extended, //扩展键(AIT CTRL windows ) rx_released, //按键释放=1 rx_shift_key_on, //shift键按下=1 rx_scan_code, //扫描码 rx_ascii, //ascii码 rx_data_ready, // rx_read_o读数据就绪标志==1 rx_read, // rx_read_ack_i读信号==1 tx_data, //写数据bus tx_write, //写信号==1 tx_write_ack_o, //写应答信号 tx_error_no_keyboard_ack//写错误键盘应答 );// Parameters// The timer value can be up to (2^bits) inclusive.parameter TIMER_60USEC_VALUE_PP = 2950; // Number of sys_clks for 60usec.(clk/TIMER_60USEC_VALUE_PP≈16949hz)parameter TIMER_60USEC_BITS_PP = 12; // Number of bits needed for timerparameter TIMER_5USEC_VALUE_PP = 186; // Number of sys_clks for debounce(clk/TIMER_5USEC_VALUE_PP≈268817)parameter TIMER_5USEC_BITS_PP = 8; // Number of bits needed for timerparameter 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 declarationsinput clk;input reset;inout ps2_clk;inout ps2_data;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;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 declarationswire 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_extendedwire 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_strobereg hold_released; // Holds prior value, cleared at rx_output_strobereg ps2_clk_s; // Synchronous version of this inputreg ps2_data_s; // Synchronous version of this inputreg 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 codeassign ps2_clk = ps2_clk_hi_z? 1'bZ : 1'b0;assign ps2_data = ps2_data_hi_z? 1'bZ : 1'b0;// 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; ps2_data_s <= ps2_data;end// State registeralways @(posedge clk)begin : m1_state_register if (reset) m1_state <= m1_rx_clk_h; else m1_state <= m1_next_state;end// State transition logicalways @(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; //清除60usec计时 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 ://rx底电平处理 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -