📄 ps2keyboard.v
字号:
// Copyright 2006, 2007 Dennis van Weeren//// This file is part of Minimig//// Minimig is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 3 of the License, or// (at your option) any later version.//// Minimig 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 General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program. If not, see <http://www.gnu.org/licenses/>.//////// This is the Minimig PS/2 keyboard handler//// 19-11-2006 -started coding// 20-11-2006 -more coding// 21-11-2006 -finished PS/2 state machine, added keymap// 29-11-2006 -keymap is now blockram, saves almost 80 slices!// 04-12-2006 -added keyack signal// 05-12-2006 -more work; cleaning up, optimizing// -added on-screen-display control// 01-01-2007 -added extra key for on-screen-display control// 11-02-2007 -reset is now ctrl-alt-alt (as in Amiga OS4) instead of ctrl-lgui-rgui // this is the ps2 keyboard module itself// every time a new key is decoded, keystrobe is asserted.// keydat is only valid when keystrobe is asserted// after keystrobe, keyboard controller waits for keyack or timeout// kbdrst is asserted when the control, left gui and right gui keys are hold down together// leda and ledb control the numlock and scrolllock leds//JB:// 2008-03-01 - added support for prtscr and ctrlbrk keys// - verilog 2001 style module declarationmodule ps2keyboard( input clk, //bus clock input reset, //reset (system reset in) inout ps2kdat, //keyboard PS/2 data inout ps2kclk, //keyboard PS/2 clk input leda, //keyboard led a in input ledb, //keyboard led b in output kbdrst, //keyboard reset out output [7:0]keydat, //keyboard data out output reg keystrobe, //keyboard data out strobe input keyack, //keyboard data out acknowledge output [5:0]osdctrl //on-screen-display controll);//local signalsreg pclkout; //ps2 clk outwire pdatout; //ps2 data outwire pclkneg; //negative edge of ps2 clock strobereg pdatb,pclkb,pclkc; //input synchronization reg [11:0]preceive; //ps2 receive registerreg [11:0]psend; //ps2 send registerreg [19:0]ptimer; //ps2 timerreg [2:0]kstate; //keyboard controller current statereg [2:0]knext; //keyboard controller next statereg capslock; //capslock statusreg prreset; //ps2 receive resetwire prbusy; //ps2 receive busyreg ptreset; //ps2 reset timerwire pto1; //ps2 timer timeout 1 wire pto2; //ps2 timer timeout 2reg psled1; //ps2 send led code 1reg psled2; //ps2 send led code 2wire psready; //ps2 send readywire valid; //valid amiga key code at keymap output//bidirectional open collector IO buffersassign ps2kclk=(pclkout)?1'bz:1'b0;assign ps2kdat=(pdatout)?1'bz:1'b0;//input synchronization of external signalsalways @(posedge clk)begin pdatb<=ps2kdat; pclkb<=ps2kclk; pclkc<=pclkb;end //detect ps2 clock negative edgeassign pclkneg=pclkc&(~pclkb);//PS2 input shifterwire prready;always @(posedge clk) if(prreset||prready) preceive[11:0]<=12'b111111111111; else if(pclkneg) preceive[11:0]<={1'b0,pdatb,preceive[10:1]};assign prready=~preceive[0];assign prbusy=~preceive[11];//PS2 timeralways @(posedge clk) if(ptreset) ptimer[19:0]<=0; else if(!pto2) ptimer[19:0]<=ptimer[19:0]+1;assign pto1=ptimer[15];//4.6ms @ 7.09Mhzassign pto2=ptimer[19];//74ms @ 7.09Mhz//PS2 send shifteralways @(posedge clk) if(psled1) psend[11:0]<=12'b111111011010;//$ED else if(psled2) psend[11:0]<={2'b11,~(capslock^leda^ledb),5'b00000,capslock,leda,ledb,1'b0};//led status else if(!psready && pclkneg) psend[11:0]<={1'b0,psend[11:1]};assign psready=(psend[11:0]==12'b000000000001)?1:0;assign pdatout=psend[0];//keyboard state machinealways @(posedge clk) if(reset)//master reset kstate<=0; else kstate<=knext;always @(kstate or pto1 or pto2 or psready or prready or prbusy or keystrobe or keyack)begin case(kstate) 0://reset timer begin prreset=1; ptreset=1; pclkout=0; psled1=0; psled2=0; knext=1; end 1://"request-to-send" for led1 code begin prreset=1; ptreset=0; pclkout=0; psled1=1; psled2=0; if(pto1) knext=2; else knext=1; end 2://wait for led1 code to be sent and acknowledge received begin prreset=~psready; ptreset=1; pclkout=1; psled1=0; psled2=0; if(prready) knext=3; else knext=2; end 3://"request-to-send" for led2 code begin prreset=1; ptreset=0; pclkout=0; psled1=0; psled2=1; if(pto1) knext=4; else knext=3; end 4://wait for led2 code to be sent begin prreset=~psready; ptreset=1; pclkout=1; psled1=0; psled2=0; if(prready) knext=5; else knext=4; end 5://wait for valid amiga key code begin prreset=0; ptreset=keystrobe; pclkout=1; psled1=0; psled2=0; if(keystrobe)//valid amiga key decoded knext=6; else if(!prbusy && pto2)//timeout, update leds knext=0; else//stay here knext=5; end 6://hold of ps2 keyboard and wait for keyack or timeout begin prreset=0; ptreset=keyack; pclkout=0; psled1=0; psled2=0; if(keyack || pto2)//keyack or timeout knext=5; else//stay here knext=6; end default://we should never come here begin prreset=0;//ps2 receiver reset ptreset=0;//ps2 timer reset pclkout=1;//ps2 clock override psled1=0;//ps2 send led code 1 psled2=0;//ps2 send led code 2 knext=0;//go to reset state end endcaseend//instantiate keymap to convert ps2 scan codes to amiga raw key codeswire ctrl,aleft,aright,caps;ps2keyboardmap km1( .clk(clk), .reset(reset), .enable(prready), .ps2key(preceive[8:1]), .valid(valid), .akey(keydat[7:0]), .ctrl(ctrl), .aleft(aleft), .aright(aright), .caps(caps), .osdctrl(osdctrl));//Duplicate key filter and caps lock handling.//A ps/2 keyboard has a future called "typematic".//This means that the last key downstroke event//is repeated (at approx 2Hz default).//An Amiga keyboard does not do this so this filter removes//all duplicate downstroke events://When a duplicate downstroke event is detected, keystrobe is not asserted.//When the event is unique (no duplicate), keystrobe is asserted when valid is asserted.////Capslock on amiga is "remembered" by keyboard. A ps/2 keyboard doesn't do this//therefore, amiga-like caps lock behaviour is simulated herewire keyequal;reg [7:0]keydat2;assign keyequal=(keydat2[6:0]==keydat[6:0])?1:0;//detect if latched key equals new key//latch last key downstroke eventalways @(posedge clk) if(reset) keydat2[7:0]<=0; else if(valid && !keydat[7])//latch downstroke event for last key pressed keydat2[7:0]<=keydat[7:0]; else if (valid && keydat[7] && keyequal)//upstroke event for latched key received keydat2[7:0]<=keydat[7:0];//toggle capslock status on capslock downstroke event always @(posedge clk) if(reset) capslock<=0; else if(valid && !keydat[7] && caps && !(keyequal && (keydat[7]==keydat2[7]))) capslock<=~capslock;//generate keystrobe to indicate valid keycode //assign keystrobe=(keyequal && (keydat[7]==keydatlatch[7]))?0:keyok;always @(capslock or caps or keyequal or keydat or keydat2 or valid) if(capslock && caps)//filter out capslock downstroke && capslock upstroke events if capslock is set keystrobe=0; else if(keyequal && (keydat[7]==keydat2[7]))//filter out duplicate events keystrobe=0; else if(valid)//valid amiga keycode, assert strobe keystrobe=1; else keystrobe=0;//Keyboard reset detector. //Reset is accomplished by holding down the//ctrl, left alt en right alt keys all at the same timereg [2:0]kbdrststatus;always @(posedge clk)begin //latch status of control key if(reset) kbdrststatus[2]<=1; else if (valid && ctrl) kbdrststatus[2]<=keydat[7]; //latch status of left alt key
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -