1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-02-07 00:17:07 +00:00
Files
mist-devel.mist-board/cores/bbc/rtl/keyboard.v
2017-02-26 19:18:59 +00:00

285 lines
11 KiB
Verilog

`timescale 1 ns / 1 ns
// BBC keyboard implementation with interface to PS/2
//
// Copyright (c) 2011 Mike Stirling
// Copyright (c) 2015 Stephen J. Leary
//
// All rights reserved
//
// Redistribution and use in source and synthezised forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in synthesized form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of the author nor the names of other contributors may
// be used to endorse or promote products derived from this software without
// specific prior written agreement from the author.
//
// * License is granted for non-commercial use only. A fee may not be charged
// for redistributions as source code or in synthesized/hardware form without
// specific prior written agreement from the author.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
module keyboard (
input CLOCK,
input nRESET,
input CLKEN_1MHZ,
input PS2_CLK,
input PS2_DATA,
input AUTOSCAN,
input [3:0] COLUMN,
input [2:0] ROW,
output KEYPRESS,
output INT,
// external SHIFT key
input SHIFT,
// BREAK key output - 1 when pressed
output reg BREAK_OUT,
// DIP switch inputs
input [7:0] DIP_SWITCH
);
// Interface to PS/2 block
wire [7:0] keyb_data;
wire keyb_valid;
wire keyb_error;
// Internal signals
reg [7:0] keys [0:15];
reg [3:0] col;
reg _release_;
reg extended;
reg ext_shift;
// Shortcut to current key column
ps2_intf PS2 (
.CLK ( CLOCK ),
.nRESET ( nRESET ),
.PS2_CLK ( PS2_CLK ),
.PS2_DATA ( PS2_DATA ),
.DATA ( keyb_data ),
.VALID ( keyb_valid )
);
always @(posedge CLOCK) begin
if (nRESET === 1'b 0) begin
col <= 'd0;;
end else begin
if (AUTOSCAN === 1'b 0) begin
// If autoscan disabled then transfer current COLUMN to counter
// immediately (don't wait for next 1 MHz cycle)
col <= COLUMN;
end else if (CLKEN_1MHZ === 1'b 1 ) begin
// Otherwise increment the counter once per 1 MHz tick
col <= col + 1;
end
end
end
// Generate interrupt if any key in currently scanned column is pressed
// (apart from in row 0). Output selected key status if autoscan disabled.
// Column counts automatically when AUTOSCAN is enabled, otherwise
// value is loaded from external input
wire [7:0] k = keys[col];
assign INT = k[7] | k[6] | k[5] | k[4] | k[3] | k[2] | k[1];
assign KEYPRESS = AUTOSCAN === 1'b0 ? k[ROW] : 1'b0;
// Decode PS/2 data
always @(posedge CLOCK) begin
if (nRESET === 1'b 0) begin
_release_ <= 1'b 0;
extended <= 1'b 0;
BREAK_OUT <= 1'b 0;
keys[0] <= 'd0;
keys[1] <= 'd0;
keys[2] <= 'd0;
keys[3] <= 'd0;
keys[4] <= 'd0;
keys[5] <= 'd0;
keys[6] <= 'd0;
keys[7] <= 'd0;
keys[8] <= 'd0;
keys[9] <= 'd0;
// These non-existent rows are used in the BBC master
keys[10] <= 'd0;
keys[11] <= 'd0;
keys[12] <= 'd0;
keys[13] <= 'd0;
keys[14] <= 'd0;
keys[15] <= 'd0;
end else begin
// map external shift key onto left shift
ext_shift <= SHIFT;
if(SHIFT || ext_shift)
keys[0][0] <= SHIFT;
// Copy DIP switches through to row 0
keys[2][0] <= DIP_SWITCH[7];
keys[3][0] <= DIP_SWITCH[6];
keys[4][0] <= DIP_SWITCH[5];
keys[5][0] <= DIP_SWITCH[4];
keys[6][0] <= DIP_SWITCH[3];
keys[7][0] <= DIP_SWITCH[2];
keys[8][0] <= DIP_SWITCH[1];
keys[9][0] <= DIP_SWITCH[0];
if (keyb_valid === 1'b 1) begin
// Decode keyboard input
if (keyb_data === 8'h e0) begin
// Extended key code follows
extended <= 1'b 1;
end else if (keyb_data === 8'h f0 ) begin
// Release code follows
_release_ <= 1'b 1;
// Cancel extended/release flags for next time
end else if (extended === 1'b1) begin // Extended keys.
_release_ <= 1'b 0;
extended <= 1'b 0;
// PRNT SCRN is used for the BREAK key, which in the real BBC asserts
// reset. Here we pass this out to the top level which may
// optionally OR it in to the system reset
// Decode scan codes
case (keyb_data)
8'h 7c: BREAK_OUT <= ~_release_; // PRNT SCRN (BREAK)
8'h 6B: keys[9][1] <= ~_release_; // LEFT
8'h 72: keys[9][2] <= ~_release_; // DOWN
8'h 75: keys[9][3] <= ~_release_; // UP
8'h 74: keys[9][7] <= ~_release_; // RIGHT
8'h 69: keys[9][6] <= ~_release_; // END (COPY)
endcase
end else begin
_release_ <= 1'b 0;
extended <= 1'b 0;
// Decode scan codes
case (keyb_data)
8'h 12: keys[0][0] <= ~_release_; // Left SHIFT
8'h 59: keys[0][0] <= ~_release_; // Right SHIFT
8'h 15: keys[0][1] <= ~_release_; // Q
8'h 09: keys[0][2] <= ~_release_; // F10 (F0)
8'h 16: keys[0][3] <= ~_release_; // 1
8'h 58: keys[0][4] <= ~_release_; // CAPS LOCK
8'h 11: keys[0][5] <= ~_release_; // LEFT ALT (SHIFT LOCK)
8'h 0D: keys[0][6] <= ~_release_; // TAB
8'h 76: keys[0][7] <= ~_release_; // ESCAPE
8'h 14: keys[1][0] <= ~_release_; // LEFT/RIGHT CTRL (CTRL)
8'h 26: keys[1][1] <= ~_release_; // 3
8'h 1D: keys[1][2] <= ~_release_; // W
8'h 1E: keys[1][3] <= ~_release_; // 2
8'h 1C: keys[1][4] <= ~_release_; // A
8'h 1B: keys[1][5] <= ~_release_; // S
8'h 1A: keys[1][6] <= ~_release_; // Z
8'h 05: keys[1][7] <= ~_release_; // F1
8'h 25: keys[2][1] <= ~_release_; // 4
8'h 24: keys[2][2] <= ~_release_; // E
8'h 23: keys[2][3] <= ~_release_; // D
8'h 22: keys[2][4] <= ~_release_; // X
8'h 21: keys[2][5] <= ~_release_; // C
8'h 29: keys[2][6] <= ~_release_; // SPACE
8'h 06: keys[2][7] <= ~_release_; // F2
8'h 2E: keys[3][1] <= ~_release_; // 5
8'h 2C: keys[3][2] <= ~_release_; // T
8'h 2D: keys[3][3] <= ~_release_; // R
8'h 2B: keys[3][4] <= ~_release_; // F
8'h 34: keys[3][5] <= ~_release_; // G
8'h 2A: keys[3][6] <= ~_release_; // V
8'h 04: keys[3][7] <= ~_release_; // F3
8'h 0C: keys[4][1] <= ~_release_; // F4
8'h 3D: keys[4][2] <= ~_release_; // 7
8'h 36: keys[4][3] <= ~_release_; // 6
8'h 35: keys[4][4] <= ~_release_; // Y
8'h 33: keys[4][5] <= ~_release_; // H
8'h 32: keys[4][6] <= ~_release_; // B
8'h 03: keys[4][7] <= ~_release_; // F5
8'h 3E: keys[5][1] <= ~_release_; // 8
8'h 43: keys[5][2] <= ~_release_; // I
8'h 3C: keys[5][3] <= ~_release_; // U
8'h 3B: keys[5][4] <= ~_release_; // J
8'h 31: keys[5][5] <= ~_release_; // N
8'h 3A: keys[5][6] <= ~_release_; // M
8'h 0B: keys[5][7] <= ~_release_; // F6
8'h 83: keys[6][1] <= ~_release_; // F7
8'h 46: keys[6][2] <= ~_release_; // 9
8'h 44: keys[6][3] <= ~_release_; // O
8'h 42: keys[6][4] <= ~_release_; // K
8'h 4B: keys[6][5] <= ~_release_; // L
8'h 41: keys[6][6] <= ~_release_; // ,
8'h 0A: keys[6][7] <= ~_release_; // F8
8'h 4E: keys[7][1] <= ~_release_; // -
8'h 45: keys[7][2] <= ~_release_; // 0
8'h 4D: keys[7][3] <= ~_release_; // P
8'h 0E: keys[7][4] <= ~_release_; // ` (@)
8'h 4C: keys[7][5] <= ~_release_; // ;
8'h 49: keys[7][6] <= ~_release_; // .
8'h 01: keys[7][7] <= ~_release_; // F9
8'h 55: keys[8][1] <= ~_release_; // = (^)
8'h 5D: keys[8][2] <= ~_release_; // # (_)
8'h 54: keys[8][3] <= ~_release_; // [
8'h 52: keys[8][4] <= ~_release_; // '
8'h 5B: keys[8][5] <= ~_release_; // ]
8'h 4A: keys[8][6] <= ~_release_; // /
8'h 61: keys[8][7] <= ~_release_; // \
8'h 5A: keys[9][4] <= ~_release_; // RETURN
8'h 66: keys[9][5] <= ~_release_; // BACKSPACE (DELETE)
endcase
end
end
end
end
endmodule // module keyboard