§ Описание
Эта программа была написана для того, чтобы принимать и передавать данные на клавиатуру. Прием осуществляется подключением
ps_clk
и
ps_dat
к физическому интерфейсу.
Чтобы отослать команду, для начала, надо дождаться статуса
ready=1
и только после этого установить
cmd=1
одновременно установить значение
dat
. Даже если сейчас происходит приём данных от устройства, то в этом случае, сначала закончится прием и только после отошлётся команда на устройство.
Частота
clock
должна быть 25 мгц. Можно и другую, но для этого придется исправлять локальную константу
PERIOD
.
Прием данных с устройства происходит по входящему стробу
hit
, который появляется раз в 1 такт, так что его нельзя пропускать и приоритет должен быть самый максимальный. Входящие данные будут в регистре
kbd
. В случае ошибки, появится
err=1
.
§ Программа
module keyboard
(
input clock,
input reset_n,
input cmd,
input [7:0] dat,
inout ps_clk,
inout ps_dat,
output reg [7:0] kbd,
output reg hit,
output reg err,
output ready
);
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;
reg [ 1:0] stage;
reg [ 7:0] t;
reg [ 9:0] dm;
reg [ 6:0] dx;
reg [ 1:0] rt;
reg [ 3:0] cnt;
reg CMD;
reg [ 9:0] DAT;
reg we_clk, we_dat;
reg PS_CLK, PS_DAT;
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;
end
else begin
hit <= 0;
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 <= ps_dat ^ (^kbd); end
10: begin stage <= IDLE; err <= ~ps_dat; CMD <= 0; 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