Эта программа была написана для того, чтобы принимать и передавать данные на клавиатуру. Прием осуществляется подключением ps_clk и ps_dat к физическому интерфейсу.
module kb
(
input clock,
input reset_n,
input cmd,
input [7:0] dat,
inout ps_clk,
inout ps_dat,
output ready,
output reg hit,
output reg kdone,
output reg [7:0] kbd,
output reg [7:0] ascii,
output reg err,
output reg [ 1:0] stage,
output reg [ 7:0] t,
output reg [ 9:0] dm,
output reg [ 6:0] dx,
output reg [ 1:0] rt,
output reg [ 3:0] cnt,
output reg CMD,
output reg [ 9:0] DAT,
output reg we_clk,
output reg we_dat,
output reg PS_CLK,
output reg PS_DAT
);
localparam
PERIOD = 124,
CWAIT = 20;
localparam
IDLE = 0,
RECEIVE = 1,
TRANSMIT = 2;
assign ready = (CMD == 0);
assign ps_clk = we_clk ? PS_CLK : 1'bz;
assign ps_dat = we_dat ? PS_DAT : 1'bz;
wire valid = ps_dat ^ (^kbd);
reg released, extended, shift;
always @(negedge clock)
if (reset_n == 0) begin
t <= 0;
dx <= 0;
dm <= 0;
we_clk <= 0;
we_dat <= 0;
cnt <= 0;
err <= 0;
stage <= IDLE;
CMD <= 0;
DAT <= 8'h00;
kdone <= 1'b0;
shift <= 1'b0;
released <= 1'b0;
extended <= 1'b0;
end
else begin
hit <= 1'b0;
kdone <= 1'b0;
if (cmd) begin CMD <= 1; DAT <= { 1'b1, ~^dat, dat}; err <= 0; end
if (dx == PERIOD) begin
rt <= {rt[0], ps_clk};
if (stage) begin dm <= dm + 1; if (&dm) begin stage <= IDLE; CMD <= 0; err <= 1; end end
case (stage)
IDLE: begin
t <= 0;
cnt <= 0;
if (rt == 2'b10) begin
stage <= RECEIVE;
err <= 0;
end
else if (CMD) begin
stage <= TRANSMIT;
err <= 0;
{we_clk, we_dat} <= 2'b11;
{PS_CLK, PS_DAT} <= 2'b11;
end
end
RECEIVE: if (rt == 2'b01) begin
t <= t + 1;
dm <= 0;
case (t)
0: if (ps_dat) begin stage <= IDLE; err <= 1; end
1,2,3,4,5,6,7,8: kbd <= {ps_dat, kbd[7:1]};
9: begin
hit <= valid;
if (kbd == 8'hF0) begin released <= 1'b1; end
else if (kbd == 8'hE0) begin extended <= 1'b1; end
else begin
kdone <= valid && !released;
case ({extended, kbd})
8'h12, 8'h59: begin shift <= ~released; kdone <= 1'b0; end
8'h1C: ascii <= shift ? 8'h41 : 8'h61;
8'h32: ascii <= shift ? 8'h42 : 8'h62;
8'h21: ascii <= shift ? 8'h43 : 8'h63;
8'h23: ascii <= shift ? 8'h44 : 8'h64;
8'h24: ascii <= shift ? 8'h45 : 8'h65;
8'h2B: ascii <= shift ? 8'h46 : 8'h66;
8'h34: ascii <= shift ? 8'h47 : 8'h67;
8'h33: ascii <= shift ? 8'h48 : 8'h68;
8'h43: ascii <= shift ? 8'h49 : 8'h69;
8'h3B: ascii <= shift ? 8'h4A : 8'h6A;
8'h42: ascii <= shift ? 8'h4B : 8'h6B;
8'h4B: ascii <= shift ? 8'h4C : 8'h6C;
8'h3A: ascii <= shift ? 8'h4D : 8'h6D;
8'h31: ascii <= shift ? 8'h4E : 8'h6E;
8'h44: ascii <= shift ? 8'h4F : 8'h6F;
8'h4D: ascii <= shift ? 8'h50 : 8'h70;
8'h15: ascii <= shift ? 8'h51 : 8'h71;
8'h2D: ascii <= shift ? 8'h52 : 8'h72;
8'h1B: ascii <= shift ? 8'h53 : 8'h73;
8'h2C: ascii <= shift ? 8'h54 : 8'h74;
8'h3C: ascii <= shift ? 8'h55 : 8'h75;
8'h2A: ascii <= shift ? 8'h56 : 8'h76;
8'h1D: ascii <= shift ? 8'h57 : 8'h77;
8'h22: ascii <= shift ? 8'h58 : 8'h78;
8'h35: ascii <= shift ? 8'h59 : 8'h79;
8'h1A: ascii <= shift ? 8'h5A : 8'h7A;
8'h45: ascii <= shift ? 8'h29 : 8'h30;
8'h16: ascii <= shift ? 8'h21 : 8'h31;
8'h1E: ascii <= shift ? 8'h40 : 8'h32;
8'h26: ascii <= shift ? 8'h23 : 8'h33;
8'h25: ascii <= shift ? 8'h24 : 8'h34;
8'h2E: ascii <= shift ? 8'h25 : 8'h35;
8'h36: ascii <= shift ? 8'h5E : 8'h36;
8'h3D: ascii <= shift ? 8'h26 : 8'h37;
8'h3E: ascii <= shift ? 8'h2A : 8'h38;
8'h46: ascii <= shift ? 8'h28 : 8'h39;
8'h0E: ascii <= shift ? 8'h7E : 8'h60;
8'h4E: ascii <= shift ? 8'h5F : 8'h2D;
8'h55: ascii <= shift ? 8'h2B : 8'h3D;
8'h5D: ascii <= shift ? 8'h7C : 8'h5C;
8'h54: ascii <= shift ? 8'h7B : 8'h5B;
8'h5B: ascii <= shift ? 8'h7D : 8'h5D;
8'h4C: ascii <= shift ? 8'h3A : 8'h3B;
8'h52: ascii <= shift ? 8'h22 : 8'h27;
8'h41: ascii <= shift ? 8'h3C : 8'h2C;
8'h49: ascii <= shift ? 8'h3E : 8'h2E;
8'h4A: ascii <= shift ? 8'h3F : 8'h2F;
8'h66: ascii <= 8'h08;
8'h0D: ascii <= 8'h09;
8'h5A: ascii <= 8'h0A;
8'h76: ascii <= 8'h1B;
8'h29: ascii <= 8'h20;
9'h17D: ascii <= 8'h01;
9'h17A: ascii <= 8'h02;
9'h175: ascii <= 8'h03;
9'h174: ascii <= 8'h04;
9'h172: ascii <= 8'h05;
9'h16B: ascii <= 8'h06;
9'h171: ascii <= 8'h07;
9'h16C: ascii <= 8'h0B;
9'h170: ascii <= 8'h0C;
9'h169: ascii <= 8'h0D;
default: kdone <= 1'b0;
endcase
released <= 1'b0;
extended <= 1'b0;
end
end
10: begin
CMD <= 0;
stage <= IDLE;
err <= ~ps_dat;
end
endcase
end
TRANSMIT: begin
t <= t + 1;
case (t)
CWAIT: begin PS_CLK <= 0; end
CWAIT+20: begin PS_DAT <= 0; end
CWAIT+28: begin PS_CLK <= 1; end
CWAIT+29: begin we_clk <= 0; dm <= 0; end
CWAIT+30: begin
t <= CWAIT+30;
if (rt == 2'b10) begin
PS_DAT <= DAT[0];
DAT <= DAT[9:1];
cnt <= cnt + 1;
dm <= 0;
end
else if (rt == 2'b01 && cnt == 10) t <= CWAIT+31;
end
CWAIT+31: we_dat <= 0;
CWAIT+33: begin dm <= 0; t <= CWAIT + (rt == 2'b01 ? 34 : 33); end
CWAIT+34: t <= (rt == 2'b10) ? CWAIT+35 : CWAIT+34;
CWAIT+35: begin stage <= RECEIVE; t <= 0; end
endcase
end
endcase
end
dx <= (dx == PERIOD) ? 0 : dx + 1;
end
endmodule
Проставленные стандартные пины.
Модуль принимает на вход данные от контроллера клавиатуры, так как использует тот же протокол передачи. При запуске, мыши отсылается код F4 через PS/2, активируя ее работу, и принимает пакеты по 3 байта, формируя (x,y) координаты. С помощью (xmax,ymax) можно задать правую и нижнюю границу, за которую указатель мыши выйти не может. Если их опустить, то по умолчанию будет принято значение (640,480) в качестве размера окна.