1
0
mirror of synced 2026-01-11 23:53:00 +00:00
lisper.cpus-pdp8/v/scancode.v
2007-01-02 16:24:48 +00:00

372 lines
7.3 KiB
Verilog

// scancode.v
//
// simple AT style keyboard scancode to ascii convertion
// keeps track of shift, capslock and control keys
// inputs scancodes and outputs ascii
//
`include "scancode_rom.v"
module scancode_convert(clock,
reset_n,
scancode,
ascii,
key_up,
strobe_in,
strobe_out);
input clock;
input reset_n;
input [7:0] scancode;
output reg [7:0] ascii;
output reg key_up;
input strobe_in;
output reg strobe_out;
// one-hot state machine states
parameter [2:0]
C_INIT = 3'd0,
C_IDLE = 3'd1,
C_KEYPRESS = 3'd2,
C_KEYRELEASE = 3'd3,
C_RELEASE = 3'd4,
C_HOLD = 3'd5;
//
reg [2:0] state, nextstate;
reg release_prefix;
reg release_prefix_set, release_prefix_clear;
reg shift;
reg shift_set, shift_clear;
reg ctrl;
reg ctrl_set, ctrl_clear;
reg capslock;
reg capslock_toggle;
reg strobe_out_set, strobe_out_clear;
reg key_up_set, key_up_clear;
reg [2:0] hold_count;
reg [6:0] sc;
wire [7:0] rom_data;
wire raise;
// convert scancodes (plus shift/control) into ascii
scancode_rom scancode_rom(.addr({raise,sc}),
.data(rom_data));
assign raise = shift | capslock | ctrl;
// internal state
always @(posedge clock or negedge reset_n)
if (~reset_n)
begin
shift <= 1'b0;
capslock <= 1'b0;
ctrl <= 1'b0;
release_prefix <= 1'b0;
strobe_out <= 1'b0;
key_up <= 1'b0;
hold_count <= 3'b0;
end
else
begin
if (shift_set)
shift <= 1'b1;
else
if (shift_clear)
shift <= 1'b0;
if (ctrl_set)
ctrl <= 1'b1;
else
if (ctrl_clear)
ctrl <= 1'b0;
if (capslock_toggle)
capslock <= ~capslock;
if (release_prefix_set)
release_prefix <= 1'b1;
else
if (release_prefix_clear)
release_prefix <= 1'b0;
if (strobe_out_set)
strobe_out <= 1'b1;
else
if (strobe_out_clear)
strobe_out <= 1'b0;
if (key_up_set)
key_up <= 1'b1;
else
if (key_up_clear)
key_up <= 1'b0;
//
if (state == C_HOLD)
hold_count <= hold_count + 1;
else
hold_count <= 3'd0;
end
// next state
always @(posedge clock or negedge reset_n)
if (~reset_n)
state <= C_INIT;
else
state <= nextstate;
always @(posedge clock)
if (state == C_IDLE && strobe_in)
sc <= scancode[6:0];
always @(posedge clock)
if (state == C_KEYPRESS || state == C_KEYRELEASE)
ascii <= ctrl ? (rom_data - 8'h40) : rom_data;
always @(state or strobe_in or scancode or release_prefix or shift or ctrl or rom_data or hold_count)
begin
shift_set = 1'b0;
shift_clear = 1'b0;
ctrl_set = 1'b0;
ctrl_clear = 1'b0;
capslock_toggle = 1'b0;
release_prefix_set = 1'b0;
release_prefix_clear = 1'b0;
strobe_out_set = 1'b0;
strobe_out_clear = 1'b0;
key_up_set = 1'b0;
key_up_clear = 1'b0;
case (state) // synthesis full_case
C_INIT:
begin
nextstate = C_IDLE;
end
C_IDLE:
begin
if (strobe_in)
begin
case (scancode)
8'hf0: /* release prefix */
begin
release_prefix_set = 1'b1;
nextstate = C_IDLE;
end
8'h58: /* caps lock */
begin
if (release_prefix)
capslock_toggle = 1'b1;
nextstate = C_RELEASE;
end
8'h12, /* left shift */
8'h59: /* right shift */
begin
if (release_prefix)
shift_clear = 1'b1;
else
shift_set = 1'b1;
nextstate = C_RELEASE;
end
8'h14: /* left ctrl */
begin
if (release_prefix)
ctrl_clear = 1'b1;
else
ctrl_set = 1'b1;
nextstate = C_RELEASE;
end
default:
nextstate = release_prefix ?
C_KEYRELEASE : C_KEYPRESS;
endcase
end
else
nextstate = C_IDLE;
end
C_KEYPRESS:
begin
strobe_out_set = 1'b1;
nextstate = C_RELEASE;
end
C_KEYRELEASE:
begin
`ifdef SEND_KEYUP
strobe_out_set = 1'b1;
`endif
strobe_out_clear = 1'b1;
key_up_set = 1'b1;
nextstate = C_RELEASE;
end
C_RELEASE:
begin
release_prefix_clear = 1'b1;
nextstate = C_HOLD;
end
C_HOLD:
begin
nextstate = C_HOLD;
if (hold_count == 3'd4)
begin
strobe_out_clear = 1'b1;
key_up_clear = 1'b1;
nextstate = C_IDLE;
end
end
endcase
end
endmodule
// ------------------
//`define TEST
`ifdef TEST
`timescale 1ns / 1ns
module test;
reg clk, reset_n;
reg [7:0] testcode;
wire [7:0] kb_ascii;
reg kb_rdy;
wire kb_release;
wire kb_ascii_rdy;
scancode_convert scancode_convert(.clock(clk),
.reset_n(reset_n),
.scancode(testcode),
.ascii(kb_ascii),
.key_up(kb_release),
.strobe_in(kb_rdy),
.strobe_out(kb_ascii_rdy));
initial
begin
$timeformat(-9, 0, "ns", 7);
$dumpfile("scancode.vcd");
$dumpvars(0, test.scancode_convert);
end
initial
begin
clk = 1'b0;
reset_n = 1'b0;
kb_rdy = 1'b0;
#200 begin
reset_n = 1'b1;
end
// press "a"
#10 begin kb_rdy = 1'b1; testcode = 8'h1c; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h1c; end
#80 kb_rdy = 1'b0;
// press "b"
#1000 begin kb_rdy = 1'b1; testcode = 8'h32; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h32; end
#80 kb_rdy = 1'b0;
// enter
#1000 begin kb_rdy = 1'b1; testcode = 8'h5a; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h5a; end
#80 kb_rdy = 1'b0;
// shift "a"
#1000 begin kb_rdy = 1'b1; testcode = 8'h12; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h1c; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h1c; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h12; end
#80 kb_rdy = 1'b0;
// press "c"
#1000 begin kb_rdy = 1'b1; testcode = 8'h21; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h21; end
#80 kb_rdy = 1'b0;
// ctrl "a"
#1000 begin kb_rdy = 1'b1; testcode = 8'h14; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h1c; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h1c; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h14; end
#80 kb_rdy = 1'b0;
// press "d"
#1000 begin kb_rdy = 1'b1; testcode = 8'h23; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'hf0; end
#80 kb_rdy = 1'b0;
#1000 begin kb_rdy = 1'b1; testcode = 8'h23; end
#80 kb_rdy = 1'b0;
#5000 $finish;
end
always
begin
#20 clk = 1'b0;
#20 clk = 1'b1;
end
endmodule
`endif