diff --git a/boards/terasic_de0/apple-one.qsf b/boards/terasic_de0/apple-one.qsf index d575ad8..1ffdfbe 100644 --- a/boards/terasic_de0/apple-one.qsf +++ b/boards/terasic_de0/apple-one.qsf @@ -361,6 +361,7 @@ 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 VERILOG_FILE ../../rtl/ps2keyboard/ps2keyboard.v set_global_assignment -name VERILOG_FILE ../../rtl/boards/terasic_de0/segmentdisplay.v set_global_assignment -name VERILOG_FILE ../../rtl/cpu/arlet/cpu.v set_global_assignment -name VERILOG_FILE ../../rtl/cpu/arlet/ALU.v diff --git a/rtl/apple1.v b/rtl/apple1.v index faa1fe2..13ff6d0 100644 --- a/rtl/apple1.v +++ b/rtl/apple1.v @@ -79,7 +79,7 @@ module apple1( else if (cpu_clken) begin if (!pwr_up_reset) - reset_cnt <= reset_cnt + 1; + reset_cnt <= reset_cnt + 6'b1; hard_reset <= pwr_up_reset; end diff --git a/rtl/boards/terasic_de0/apple1_de0_top.v b/rtl/boards/terasic_de0/apple1_de0_top.v index fb8687a..a5f653f 100644 --- a/rtl/boards/terasic_de0/apple1_de0_top.v +++ b/rtl/boards/terasic_de0/apple1_de0_top.v @@ -35,7 +35,9 @@ module apple1_de0_top( output [6:0] HEX0_D, output [6:0] HEX1_D, output [6:0] HEX2_D, - output [6:0] HEX3_D + output [6:0] HEX3_D, + input PS2_KBCLK, + input PS2_KBDAT ); ////////////////////////////////////////////////////////////////////////// @@ -91,4 +93,17 @@ module apple1_de0_top( .display_out(HEX3_D) ); -endmodule \ No newline at end of file + ////////////////////////////////////////////////////////////////////////// + // Experimental PS/2 interface + + ps2keyboard keys( + .clk25(clk25), + .reset(~BUTTON[0]), + .key_clk(PS2_KBCLK), + .key_din(PS2_KBDAT), + .cs(1'b1), + .address(1'b0), + .dout(LEDG[7:0]) + ); + +endmodule diff --git a/rtl/ps2keyboard/ps2keyboard.v b/rtl/ps2keyboard/ps2keyboard.v new file mode 100644 index 0000000..b573683 --- /dev/null +++ b/rtl/ps2keyboard/ps2keyboard.v @@ -0,0 +1,136 @@ +// 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 interface +// +// Author.....: Niels A. Moseley +// Date.......: 28-1-2018 +// + +module ps2keyboard ( + input clk25, // 25MHz clock + input reset, // active high reset + + // I/O interface to keyboard + input key_clk, // clock input from keyboard / device + input key_din, // data input from keyboard / device + + // I/O interface to computer + input cs, // chip select, active high + input address, // =0 RX buffer, =1 RX status + 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 + // 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 + +// +// PS/2 data from a device changes when the clock +// is low, so we latch when the clock transitions +// to a high state +// + +always @(posedge key_clk or posedge reset) +begin + if (reset == 1'b1) + begin + // reset the serial buffer + rxshiftbuf <= 11'b0; + rxcnt <= 0; + rx_flag <= 0; + end + else + begin + // shift in LSB first from keyboard + rxshiftbuf <= {key_din, rxshiftbuf[10:1]}; + rxcnt <= rxcnt + 4'b1; + if (rxcnt == 4'd10) + begin + // 10 bits have been shifted in + // we should have a complete + // scan code here, including + // start, parity and stop bits. + rxcnt <= 0; + rx_flag <= !rx_flag; // change state to signal new data + end + 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. +// + +always @(posedge clk25 or posedge reset) +begin + if (reset) + begin + rxflag_ff <= 0; + rx <= 0; + rx_rdy <= 0; + 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 + rx <= rxshiftbuf[8:1]; + rx_rdy <= 1; + end + + // handle I/O from CPU + if (cs == 1'b1) + begin + if (address == 1'b0) + begin + // RX buffer address + dout <= rx; + rx_rdy <= 1'b0; + end + else + begin + // RX status register + dout <= {rx_rdy, 7'b0}; + end + end + end +end + +endmodule +