⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ps2_keyboard_interface.v

📁 周立功公司的SOPC源代码
💻 V
📖 第 1 页 / 共 2 页
字号:
				m1_next_state <= m1_tx_done_recovery;
	    end

	    m1_tx_error_no_keyboard_ack :
	    begin
	        tx_error_no_keyboard_ack_r <= 1'b1;
	        if (ps2_clk_in_r && ps2_data_in_r) 
				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
//**************************************************************************************


//**************************************************************************************
//产生数据输出状态标志rx_data_ready_r = 1 时有数据输出,rx_data_ready_r = 0 时无数据输出
//读取数据时(rx_read = 1)清 rx_data_ready_r为0.
//状态机M2
always @(posedge clock)
begin  
    if (reset) 
		m2_state <= m2_rx_data_ready_ack;
    else 
		m2_state <= m2_next_state;
end

//M2状态转换逻辑
always @(m2_state or rx_output_strobe or rx_read)
begin 
    case (m2_state)
        m2_rx_data_ready_ack:
        begin
            rx_data_ready_r <= 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_r <= 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
//**************************************************************************************


//位移位计数器
always @(posedge clock)
begin
    if (reset || rx_shifting_done || (m1_state == m1_tx_wait_keyboard_ack))
		bit_count <= 4'd0;  
    else if (timer_400usec_done && (m1_state == m1_rx_clk_h) && (ps2_clk_in_r)) 
		bit_count <= 4'd0; 
	else if ( (m1_state == m1_rx_falling_edge_marker) ||(m1_state == m1_tx_rising_edge_marker))
    	bit_count <= bit_count + 4'd1;
end

//指示一帧数据读完或写完
assign rx_shifting_done = (bit_count == `TOTAL_BITS);
assign tx_shifting_done = (bit_count == `TOTAL_BITS-1);

//这个信号用来使能加载要发送到PS/2键盘的数据到移位害存器
//同时也指示指令开始传输
assign tx_write_ack = (  (tx_write && (m1_state == m1_rx_clk_h))
                         ||(tx_write && (m1_state == m1_rx_clk_l))
                         );


//奇验证位.
assign tx_parity_bit = ~^tx_data;

//串行数据移位寄存器
always @(posedge clock)
begin
    if (reset) 
		q <= 0;
    else if (tx_write_ack) 
		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_in_r,q[`TOTAL_BITS-1:1]};
end

//400us定时器计数器
always @(posedge clock)
begin
    if (~enable_timer_400usec) 
		timer_400usec_count <= 0;
    else if (~timer_400usec_done) 
		timer_400usec_count <= timer_400usec_count + 1;
end

assign timer_400usec_done = (timer_400usec_count == (TIMER_400USEC_VALUE - 1));

//5us定时器计数器
always @(posedge clock)
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 - 1);




//输出扩展码标志及断码标志
assign extended = (q[8:1] == `EXTEND_CODE) && rx_shifting_done;
assign released = (q[8:1] == `RELEASE_CODE) && rx_shifting_done;


//复位或输出有效键码(非0xF0或0xE0)时清零扩展、断码标志位
//输出键码为扩展、断码时置相应标志位
always @(posedge clock)
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

//**************************************************************************************
//shift按键检测
//
//左shift键
always @(posedge clock)
begin
    if (reset) 
		left_shift_key <= 0;
    else if ((q[8:1] == `LEFT_SHIFT) && rx_shifting_done && ~hold_released)  //shift键通码
    	left_shift_key <= 1;
    else if ((q[8:1] == `LEFT_SHIFT) && rx_shifting_done && hold_released)   //shift键断码
    	left_shift_key <= 0;
end

//右shift键
always @(posedge clock)
begin
    if (reset) 
		right_shift_key <= 0;
    else if ((q[8:1] == `RIGHT_SHIFT) && rx_shifting_done && ~hold_released)  //shift键通码
    	right_shift_key <= 1;
    else if ((q[8:1] == `RIGHT_SHIFT) && rx_shifting_done && hold_released)   //shift键断码
    	right_shift_key <= 0;
end

//输出shift状态标志
//输出1:shift键有按住
//输出0:shift键无按住
assign rx_shift_key_on = left_shift_key || right_shift_key;
//**************************************************************************************


//输出特殊扫描码标志位,及扫描码值和ASCII码
//通过rx_extended_r、rx_released_r的值可判断是断码还是通码,还是扩展码
always @(posedge clock)
begin
    if (reset)
    begin
    	rx_extended_r <= 1'b0;
    	rx_released_r <= 1'b0;
    	rx_scan_code_r <= 8'd0;
    	rx_ascii_r <= 8'd0;
    end
    else if (rx_output_strobe)
    begin
    	rx_extended_r <= hold_extended;    //载入之前保存的状态值
    	rx_released_r <= hold_released;    //载入之前保存的状态值
    	rx_scan_code_r <= q[8:1];
    	rx_ascii_r <= {1'b0,ascii};
    end
end

//收到键盘发送过来的键码,且不是0xE0(扩展码前都有0xE0)和0xF0(断码前都有0xF0)
assign rx_output_event  = (rx_shifting_done
                          && ~extended 
                          && ~released
                          );

//收到键盘发送过来的键码,且不是0xE0(扩展码前都有0xE0)和0xF0(断码前都有0xF0)
//而且不是shift的键值
assign rx_output_strobe = (rx_shifting_done
                          && ~extended 
                          && ~released
                          && ( (TRAP_SHIFT_KEYS == 0) 
                               || ( (q[8:1] != `RIGHT_SHIFT)
                                    &&(q[8:1] != `LEFT_SHIFT)
                                  )
                             )
                          );
//这部分将键盘的扫描码转找成ASCII码,这里只列了一部分,如果还要
//增加更多的键码,可以找到相关的扫描键码增加到下面CASE语句中。
assign shift_key_plus_code = {rx_shift_key_on,q[8:1]};

//表中9'hXXX最高位为1表示有SHIFT键按下
always @(shift_key_plus_code)
begin
    casez (shift_key_plus_code)
	    9'h?66 : ascii <= 7'h08;  // 删除键 "backspace"key
	    9'h?0d : ascii <= 7'h09;  // Tab键
	    9'h?5a : ascii <= 7'h0d;  // 回车键 "enter"key
	    9'h?76 : ascii <= 7'h1b;  // Escape "esc"key
	    9'h?29 : ascii <= 7'h20;  // 空格键"Space"key
	    9'h116 : ascii <= 7'h21;  // !
	    9'h152 : ascii <= 7'h22;  // "
	    9'h126 : ascii <= 7'h23;  // #
	    9'h125 : ascii <= 7'h24;  // $
	    9'h12e : ascii <= 7'h25;  // %
	    9'h13d : ascii <= 7'h26;  // &
	    9'h052 : ascii <= 7'h27;  // '
	    9'h146 : ascii <= 7'h28;  // (
	    9'h145 : ascii <= 7'h29;  // )
	    9'h13e : ascii <= 7'h2a;  // *
	    9'h155 : ascii <= 7'h2b;  // +
	    9'h041 : ascii <= 7'h2c;  // ,
	    9'h04e : ascii <= 7'h2d;  // -
	    9'h049 : ascii <= 7'h2e;  // .
	    9'h04a : ascii <= 7'h2f;  // /
	    9'h045 : ascii <= 7'h30;  // 0
	    9'h016 : ascii <= 7'h31;  // 1
	    9'h01e : ascii <= 7'h32;  // 2
	    9'h026 : ascii <= 7'h33;  // 3
	    9'h025 : ascii <= 7'h34;  // 4
	    9'h02e : ascii <= 7'h35;  // 5
	    9'h036 : ascii <= 7'h36;  // 6
	    9'h03d : ascii <= 7'h37;  // 7
	    9'h03e : ascii <= 7'h38;  // 8
	    9'h046 : ascii <= 7'h39;  // 9
	    9'h14c : ascii <= 7'h3a;  // :
	    9'h04c : ascii <= 7'h3b;  // ;
	    9'h141 : ascii <= 7'h3c;  // <
	    9'h055 : ascii <= 7'h3d;  // =
	    9'h149 : ascii <= 7'h3e;  // >
	    9'h14a : ascii <= 7'h3f;  // ?
	    9'h11e : ascii <= 7'h40;  // @
	    9'h11c : ascii <= 7'h41;  // A
	    9'h132 : ascii <= 7'h42;  // B
	    9'h121 : ascii <= 7'h43;  // C
	    9'h123 : ascii <= 7'h44;  // D
	    9'h124 : ascii <= 7'h45;  // E
	    9'h12b : ascii <= 7'h46;  // F
	    9'h134 : ascii <= 7'h47;  // G
	    9'h133 : ascii <= 7'h48;  // H
	    9'h143 : ascii <= 7'h49;  // I
	    9'h13b : ascii <= 7'h4a;  // J
	    9'h142 : ascii <= 7'h4b;  // K
	    9'h14b : ascii <= 7'h4c;  // L
	    9'h13a : ascii <= 7'h4d;  // M
	    9'h131 : ascii <= 7'h4e;  // N
	    9'h144 : ascii <= 7'h4f;  // O
	    9'h14d : ascii <= 7'h50;  // P
	    9'h115 : ascii <= 7'h51;  // Q
	    9'h12d : ascii <= 7'h52;  // R
	    9'h11b : ascii <= 7'h53;  // S
	    9'h12c : ascii <= 7'h54;  // T
	    9'h13c : ascii <= 7'h55;  // U
	    9'h12a : ascii <= 7'h56;  // V
	    9'h11d : ascii <= 7'h57;  // W
	    9'h122 : ascii <= 7'h58;  // X
	    9'h135 : ascii <= 7'h59;  // Y
	    9'h11a : ascii <= 7'h5a;  // Z
	    9'h054 : ascii <= 7'h5b;  // [
	    9'h05d : ascii <= 7'h5c;  // '\'
	    9'h05b : ascii <= 7'h5d;  // ]
	    9'h136 : ascii <= 7'h5e;  // ^
	    9'h14e : ascii <= 7'h5f;  // _    
	    9'h00e : ascii <= 7'h60;  // `
	    9'h01c : ascii <= 7'h61;  // a
	    9'h032 : ascii <= 7'h62;  // b
	    9'h021 : ascii <= 7'h63;  // c
	    9'h023 : ascii <= 7'h64;  // d
	    9'h024 : ascii <= 7'h65;  // e
	    9'h02b : ascii <= 7'h66;  // f
	    9'h034 : ascii <= 7'h67;  // g
	    9'h033 : ascii <= 7'h68;  // h
	    9'h043 : ascii <= 7'h69;  // i
	    9'h03b : ascii <= 7'h6a;  // j
	    9'h042 : ascii <= 7'h6b;  // k
	    9'h04b : ascii <= 7'h6c;  // l
	    9'h03a : ascii <= 7'h6d;  // m
	    9'h031 : ascii <= 7'h6e;  // n
	    9'h044 : ascii <= 7'h6f;  // o
	    9'h04d : ascii <= 7'h70;  // p
	    9'h015 : ascii <= 7'h71;  // q
	    9'h02d : ascii <= 7'h72;  // r
	    9'h01b : ascii <= 7'h73;  // s
	    9'h02c : ascii <= 7'h74;  // t
	    9'h03c : ascii <= 7'h75;  // u
	    9'h02a : ascii <= 7'h76;  // v
	    9'h01d : ascii <= 7'h77;  // w
	    9'h022 : ascii <= 7'h78;  // x
	    9'h035 : ascii <= 7'h79;  // y
	    9'h01a : ascii <= 7'h7a;  // z
	    9'h154 : ascii <= 7'h7b;  // {
	    9'h15d : ascii <= 7'h7c;  // |
	    9'h15b : ascii <= 7'h7d;  // }
	    9'h10e : ascii <= 7'h7e;  // ~
	    9'h?71 : ascii <= 7'h7f;  //  Delete键或小键盘的DEL键
	    default : ascii <= 7'h2e; // '.' 代表其它没列出的字符
    endcase
end

endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -