Added debounced PS/2 keyboard interface and A1 top-level selection between keyboard and UART RX

This commit is contained in:
Niels Moseley 2018-02-08 23:47:09 +01:00
parent 14743ed0de
commit 894c50ff4e
4 changed files with 352 additions and 305 deletions

View File

@ -360,6 +360,14 @@ set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_CTS
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_RXD
set_global_assignment -name ENABLE_SIGNALTAP ON
set_global_assignment -name USE_SIGNALTAP_FILE output_files/stp1.stp
set_global_assignment -name USE_CONFIGURATION_DEVICE OFF
set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF
set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO"
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall
set_global_assignment -name VERILOG_FILE ../../rtl/ps2keyboard/debounce.v
set_global_assignment -name VERILOG_FILE ../../rtl/vga/vram.v
set_global_assignment -name VERILOG_FILE ../../rtl/vga/vga.v
set_global_assignment -name VERILOG_FILE ../../rtl/vga/font_rom.v
@ -378,11 +386,4 @@ set_global_assignment -name VERILOG_FILE ../../rtl/uart/uart.v
set_global_assignment -name VERILOG_FILE ../../rtl/uart/async_tx_rx.v
set_global_assignment -name VERILOG_FILE ../../rtl/rom_wozmon.v
set_global_assignment -name VERILOG_FILE ../../rtl/ram.v
set_global_assignment -name USE_CONFIGURATION_DEVICE OFF
set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF
set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO"
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@ -0,0 +1,72 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// Description: PS/2 keyboard debounce logic to be used for the
// clock line
//
// Author.....: Niels A. Moseley
// Date.......: 8-2-2018
//
module debounce(
input clk25, // 25MHz clock
input rst, // active high reset
input sig_in, // input signal
output reg sig_out // debounced output signal
);
wire clk_enb; // enable triggering at clk25 divided by 64
reg [5:0] clk_div; // clock divider counter
reg sig_ff1; // first input signal synchronizer
reg sig_ff2; // second input signal synchronizer
assign clk_enb = (clk_div == 6'd0);
// clock divider
always @(posedge clk25 or posedge rst)
begin
if (rst)
clk_div <= 6'd0;
else
clk_div <= clk_div + 6'd1;
end
// debounce timer
always @(posedge clk25 or posedge rst)
begin
if (rst)
begin
sig_out <= 1'b0;
sig_ff1 <= 1'b0;
sig_ff2 <= 1'b0;
end
else if (clk_enb)
begin
// this runs ar approximately 391k Hz
// giving a debounce time of around 2.5us
sig_ff1 <= sig_in;
sig_ff2 <= sig_ff1;
if ((sig_ff1 ^ sig_ff2) == 1'd0)
begin
sig_out <= sig_ff2;
end
end
end
endmodule

View File

@ -35,20 +35,15 @@ module ps2keyboard (
output reg [7:0] dout // 8-bit output bus.
);
// ************************************************************
// signals in the slow PS/2 clock domain
// ************************************************************
reg [3:0] rxcnt; // count how many bits have been shift into rxshiftbuf
reg [10:0] rxshiftbuf; // 11 bit shift receive register
reg rx_flag = 0; // this flag changes state (0->1 or 1->0) when
reg rx_flag = 0; // this flag is 1 when
// valid data is available in rxshiftbuf
// ************************************************************
// signals in the high-speed clock (clk25) domain
// ************************************************************
reg [7:0] rx; // receive buffer
reg rxflag_ff; // flip-flop state for clk domain xing
reg rx_rdy; // data ready to be read
reg [7:0] rx; // scancode receive buffer
wire ps2_clkdb; // debounced PS/2 clock signal
reg prev_ps2_clkdb; // previous clock state (in clk25 domain)
// keyboard translation signals
reg [7:0] ascii; // ASCII code of received character
@ -58,24 +53,30 @@ module ps2keyboard (
reg [2:0] next_state;
reg [15:0] debounce_timer;
//
// PS/2 data from a device changes when the clock
// is low, so we latch when the clock transitions
// to a high state
//
always @(negedge key_clk or posedge rst)
debounce ps2clk_debounce
(
.clk25(clk25),
.rst(rst),
.sig_in(key_clk),
.sig_out(ps2_clkdb)
);
always @(posedge clk25 or posedge rst)
begin
if (rst == 1'b1)
if (rst)
begin
// reset the serial buffer
rxshiftbuf <= 11'b0;
rxcnt <= 0;
rx_flag <= 0;
prev_ps2_clkdb <= 1'b0;
rx_flag <= 1'b0;
end
else
begin
// shift in LSB first from keyboard
rx_flag <= 1'b0; // reset the new data flag register
// check for negative edge of PS/2 clock
// and sample the state of the PS/2 data line
if ((prev_ps2_clkdb == 1'b1) && (ps2_clkdb == 1'b0))
begin
rxshiftbuf <= {key_din, rxshiftbuf[10:1]};
rxcnt <= rxcnt + 4'b1;
if (rxcnt == 4'd10)
@ -85,25 +86,21 @@ begin
// scan code here, including
// start, parity and stop bits.
rxcnt <= 0;
rx_flag <= !rx_flag; // change state to signal new data
end
// signal new data is present
// note: this signal will only remain high for one
// clock cycle!
//
// TODO: check parity here?
rx_flag <= 1'b1;
end
end
//
// clock domain crossing from slow PS/2 clock to
// high-speed clock domain:
//
// --------------| |
// | _______ | XOR |----> rx_valid_stb
// flag ---| D Q |----| |
// | |
// clk ----|> |
// |_______|
//
// when flag toggles state, tx_valid_stb will become
// '1' for exactly one (high-speed) clock cycle.
//
// update previous clock state
prev_ps2_clkdb <= ps2_clkdb;
end
end
//
// IBM Keyboard code page translation
@ -121,32 +118,13 @@ always @(posedge clk25 or posedge rst)
begin
if (rst)
begin
rxflag_ff <= 0;
rx <= 0;
rx_rdy <= 0;
ascii_rdy <= 0;
shift <= 0;
cur_state <= S_KEYNORMAL;
end
else
begin
// check for new RX data from the keyboard
rxflag_ff <= rx_flag;
if ((rxflag_ff ^ rx_flag) == 1'b1)
begin
// we detected a change in the rx_flag
// so we have valid data in the rxshiftbuf
// bits 8 .. 1 contain the actual keyboard
// scan code. The other bits are start/parity
// and stop bits.
//
// TODO: do a parity check! ..
rx <= rxshiftbuf[8:1];
rx_rdy <= 1;
end
// handle I/O from CPU
if (cs == 1'b1)
begin
@ -163,16 +141,12 @@ begin
end
end
// handle the debounce timer
if (debounce_timer != 16'd0)
begin
debounce_timer <= debounce_timer - 16'd1;
end
// keyboard translation state machine
if (rx_rdy == 1'b1)
if (rx_flag == 1'b1)
begin
rx_rdy <= 1'b0;
// latch data from the serial buffer into
// the rx scancode buffer.
rx <= rxshiftbuf[8:1];
case(cur_state)
S_KEYNORMAL:
begin
@ -190,11 +164,11 @@ begin
// key, but let's try this first to see if it works
// ok...
if (debounce_timer == 16'd0)
begin
//if (debounce_timer == 16'd0)
//begin
ascii_rdy <= 1'b1; // new key has arrived!
debounce_timer <= 16'hFFFF; // reset the debounce timer
end
//debounce_timer <= 16'hFFFF; // reset the debounce timer
//end
// check for a SHIFT key
if ((rx == 8'h59) || (rx == 8'h12))
@ -245,7 +219,7 @@ begin
8'h4E: ascii <= "-";
8'h55: ascii <= "=";
8'h5D: ascii <= "\\ "; // extra spaced needed by Quartus
8'h5D: ascii <= 8'h34; // backslash
8'h66: ascii <= 8'd8; // backspace
8'h29: ascii <= " ";
@ -348,7 +322,7 @@ begin
end
else
begin
next_state = cur_state;
next_state = cur_state; // deliberate blocking assingment!
end
cur_state <= next_state;