From 4b49d65e54adfdec8822a524271a7b2e18830de0 Mon Sep 17 00:00:00 2001 From: antoniovillena <_@antoniovillena.es> Date: Tue, 31 May 2022 15:23:43 +0200 Subject: [PATCH] add changes by gitlab.com/emax73g --- cores/Spectrum/common/ps2_port.v | 548 +++++++++++++++---------------- firmware/firmware.asm | 14 + 2 files changed, 286 insertions(+), 276 deletions(-) diff --git a/cores/Spectrum/common/ps2_port.v b/cores/Spectrum/common/ps2_port.v index 255e34e..8e9b90f 100644 --- a/cores/Spectrum/common/ps2_port.v +++ b/cores/Spectrum/common/ps2_port.v @@ -1,11 +1,11 @@ -`timescale 1ns / 1ps -`default_nettype none - -// This file is part of the ZXUNO Spectrum core. -// Creation date is 20:16:31 2014-12-26 by Miguel Angel Rodriguez Jodar -// (c)2014-2020 ZXUNO association. -// ZXUNO official repository: http://svn.zxuno.com/svn/zxuno -// Username: guest Password: zxuno +`timescale 1ns / 1ps +`default_nettype none + +// This file is part of the ZXUNO Spectrum core. +// Creation date is 20:16:31 2014-12-26 by Miguel Angel Rodriguez Jodar +// (c)2014-2020 ZXUNO association. +// ZXUNO official repository: http://svn.zxuno.com/svn/zxuno +// Username: guest Password: zxuno // Github repository for this core: https://github.com/mcleod-ideafix/zxuno_spectrum_core // // ZXUNO Spectrum core is free software: you can redistribute it and/or modify @@ -19,271 +19,267 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with the ZXUNO Spectrum core. If not, see . -// -// Any distributed copy of this file must keep this notice intact. - -module ps2_port ( - input wire clk, // se recomienda 1 MHz <= clk <= 600 MHz - input wire enable_rcv, // habilitar la maquina de estados de recepcion - input wire kb_or_mouse, // 0: kb, 1: mouse - input wire ps2clk_ext, - input wire ps2data_ext, - output wire kb_interrupt, // a 1 durante 1 clk para indicar nueva tecla recibida - output reg [7:0] scancode, // make o breakcode de la tecla - output wire released, // soltada=1, pulsada=0 - output wire extended // extendida=1, no extendida=0 - ); - - localparam RCVSTART = 2'b00, - RCVDATA = 2'b01, - RCVPARITY = 2'b10, - RCVSTOP = 2'b11; - - reg [7:0] key = 8'h00; - - // Fase de sincronizacion de señales externas con el reloj del sistema - reg [1:0] ps2clk_synchr; - reg [1:0] ps2dat_synchr; - wire ps2clk = ps2clk_synchr[1]; - wire ps2data = ps2dat_synchr[1]; - always @(posedge clk) begin - ps2clk_synchr[0] <= ps2clk_ext; - ps2clk_synchr[1] <= ps2clk_synchr[0]; - ps2dat_synchr[0] <= ps2data_ext; - ps2dat_synchr[1] <= ps2dat_synchr[0]; - end - - // De-glitcher. Sólo detecto flanco de bajada - reg [15:0] negedgedetect = 16'h0000; - always @(posedge clk) begin - negedgedetect <= {negedgedetect[14:0], ps2clk}; - end - wire ps2clkedge = (negedgedetect == 16'hF000)? 1'b1 : 1'b0; - - // Paridad instantánea de los bits recibidos - wire paritycalculated = ^key; - - // Contador de time-out. Al llegar a 16777216 ciclos sin que ocurra - // un flanco de bajada en PS2CLK, volvemos al estado inicial - reg [23:0] timeoutcnt = 24'h000000; - - reg [1:0] state = RCVSTART; - reg [1:0] regextended = 2'b00; - reg [1:0] regreleased = 2'b00; - reg rkb_interrupt = 1'b0; - assign released = regreleased[1]; - assign extended = regextended[1]; - assign kb_interrupt = rkb_interrupt; - - always @(posedge clk) begin - if (rkb_interrupt == 1'b1) begin - rkb_interrupt <= 1'b0; - end - if (ps2clkedge && enable_rcv) begin - timeoutcnt <= 24'h000000; - case (state) - RCVSTART: begin - if (ps2data == 1'b0) begin - state <= RCVDATA; - key <= 8'h80; - end - end - RCVDATA: begin - key <= {ps2data, key[7:1]}; - if (key[0] == 1'b1) begin - state <= RCVPARITY; - end - end - RCVPARITY: begin - if (ps2data^paritycalculated == 1'b1) begin - state <= RCVSTOP; - end - else begin - state <= RCVSTART; - end - end - RCVSTOP: begin - state <= RCVSTART; - if (ps2data == 1'b1) begin - scancode <= key; - if (kb_or_mouse == 1'b1) begin - rkb_interrupt <= 1'b1; // no se requiere mirar E0 o F0 - end - else begin - if (key == 8'hE0) begin - regextended <= 2'b01; - end - else if (key == 8'hF0) begin - regreleased <= 2'b01; - end - else begin - regextended <= {regextended[0], 1'b0}; - regreleased <= {regreleased[0], 1'b0}; - rkb_interrupt <= 1'b1; - end - end - end - end - default: state <= RCVSTART; - endcase - end - else begin - timeoutcnt <= timeoutcnt + 24'd1; - if (timeoutcnt == 24'hFFFFFF) begin - state <= RCVSTART; - end - end - end -endmodule - - -module ps2_host_to_kb ( - input wire clk, // calibrado para 28 MHz - inout wire ps2clk_ext, - inout wire ps2data_ext, - input wire [7:0] data, - input wire dataload, - output wire ps2busy, - output wire ps2error - ); - - `define PULLCLKLOW 3'b000 - `define PULLDATALOW 3'b001 - `define SENDDATA 3'b010 - `define SENDPARITY 3'b011 - `define RCVACK 3'b100 - `define RCVIDLE 3'b101 - `define SENDFINISHED 3'b110 - - reg initial_kb_reset = 1'b1; - reg busy = 1'b0; - reg error = 1'b0; - assign ps2busy = busy; - assign ps2error = error; - - // Fase de sincronizacion de señales externas con el reloj del sistema - reg [1:0] ps2clk_synchr; - reg [1:0] ps2dat_synchr; - wire ps2clk = ps2clk_synchr[1]; - wire ps2data_in = ps2dat_synchr[1]; - always @(posedge clk) begin - ps2clk_synchr[0] <= ps2clk_ext; - ps2clk_synchr[1] <= ps2clk_synchr[0]; - ps2dat_synchr[0] <= ps2data_ext; - ps2dat_synchr[1] <= ps2dat_synchr[0]; - end - - // De-glitcher. Sólo detecto flanco de bajada - reg [15:0] edgedetect = 16'h0000; - always @(posedge clk) begin - edgedetect <= {edgedetect[14:0], ps2clk}; - end - wire ps2clknedge = (edgedetect == 16'hF000)? 1'b1 : 1'b0; - wire ps2clkpedge = (edgedetect == 16'h0FFF)? 1'b1 : 1'b0; - - // Contador de time-out. Al llegar a 16777216 ciclos sin que ocurra - // un flanco de bajada en PS2CLK, volvemos al estado inicial - reg [23:0] timeoutcnt = 24'h000000; - - reg [2:0] state = `SENDFINISHED; - reg [7:0] shiftreg = 8'h00; - reg [2:0] cntbits = 3'd0; - - // Dato a enviar se guarda en rdata - reg [7:0] rdata = 8'h00; - - // Paridad instantánea de los bits a enviar - wire paritycalculated = ~(^rdata); - - always @(posedge clk) begin - // Carga de rdata desde el exterior - `ifdef INITIAL_KB_RESET - if (initial_kb_reset) begin // Reset inicial de teclado para establecer el SET 2 - initial_kb_reset <= 1'b0; - rdata <= 8'hFF; - busy <= 1'b1; - error <= 1'b0; - timeoutcnt <= 24'h000000; - state <= `PULLCLKLOW; - end - `endif - if (dataload) begin - rdata <= data; - busy <= 1'b1; - error <= 1'b0; - timeoutcnt <= 24'h000000; - state <= `PULLCLKLOW; - end - - if (!ps2clknedge) begin - timeoutcnt <= timeoutcnt + 24'd1; - if (timeoutcnt == 24'hFFFFFF && state != `SENDFINISHED) begin - error <= 1'b1; - state <= `SENDFINISHED; - end - end - - case (state) - `PULLCLKLOW: begin // 280000 cuentas son 10ms para 28 MHz - if (timeoutcnt >= 24'd280000) begin - state <= `PULLDATALOW; - shiftreg <= rdata; - cntbits <= 3'd0; - timeoutcnt <= 24'h000000; - end - end - `PULLDATALOW: begin - if (ps2clknedge) begin - state <= `SENDDATA; - timeoutcnt <= 24'h000000; - end - end - `SENDDATA: begin - if (ps2clknedge) begin - timeoutcnt <= 24'h000000; - shiftreg <= {1'b0, shiftreg[7:1]}; - cntbits <= cntbits + 1; - if (cntbits == 3'd7) - state <= `SENDPARITY; - end - end - `SENDPARITY: begin - if (ps2clknedge) begin - state <= `RCVIDLE; - timeoutcnt <= 24'h000000; - end - end - `RCVIDLE: begin - if (ps2clknedge) begin - state <= `RCVACK; - timeoutcnt <= 24'h000000; - end - end - `RCVACK: begin - if (ps2clknedge) begin - state <= `SENDFINISHED; - timeoutcnt <= 24'h000000; - end - end - `SENDFINISHED: begin - busy <= 1'b0; - timeoutcnt <= 24'h000000; - end - default: begin - timeoutcnt <= timeoutcnt + 1; - if (timeoutcnt == 24'hFFFFFF && state != `SENDFINISHED) begin - error <= 1'b1; - state <= `SENDFINISHED; - end - end - endcase - end - - assign ps2data_ext = (state == `PULLCLKLOW || state == `PULLDATALOW) ? 1'b0 : - (state == `SENDDATA && shiftreg[0] == 1'b0) ? 1'b0 : - (state == `SENDPARITY && paritycalculated == 1'b0) ? 1'b0 : // si lo que se va a enviar es un 1 - 1'bZ; // no se manda, sino que se pone la línea a alta impedancia - assign ps2clk_ext = (state == `PULLCLKLOW) ? 1'b0 : - 1'bZ; -endmodule +// along with the ZXUNO Spectrum core. If not, see . +// +// Any distributed copy of this file must keep this notice intact. + +module ps2_port ( + input wire clk, // se recomienda 1 MHz <= clk <= 600 MHz + input wire enable_rcv, // habilitar la maquina de estados de recepcion + input wire kb_or_mouse, // 0: kb, 1: mouse + input wire ps2clk_ext, + input wire ps2data_ext, + output wire kb_interrupt, // a 1 durante 1 clk para indicar nueva tecla recibida + output reg [7:0] scancode, // make o breakcode de la tecla + output wire released, // soltada=1, pulsada=0 + output wire extended // extendida=1, no extendida=0 + ); + + localparam RCVSTART = 2'b00, + RCVDATA = 2'b01, + RCVPARITY = 2'b10, + RCVSTOP = 2'b11; + + reg [7:0] key = 8'h00; + + // Fase de sincronizacion de señales externas con el reloj del sistema + reg [1:0] ps2clk_synchr; + reg [1:0] ps2dat_synchr; + wire ps2clk = ps2clk_synchr[1]; + wire ps2data = ps2dat_synchr[1]; + always @(posedge clk) begin + ps2clk_synchr[0] <= ps2clk_ext; + ps2clk_synchr[1] <= ps2clk_synchr[0]; + ps2dat_synchr[0] <= ps2data_ext; + ps2dat_synchr[1] <= ps2dat_synchr[0]; + end + + // De-glitcher. Sólo detecto flanco de bajada + reg [15:0] negedgedetect = 16'h0000; + always @(posedge clk) begin + negedgedetect <= {negedgedetect[14:0], ps2clk}; + end + wire ps2clkedge = (negedgedetect == 16'hF000)? 1'b1 : 1'b0; + + // Paridad instantánea de los bits recibidos + wire paritycalculated = ^key; + + // Contador de time-out. Al llegar a 16777216 ciclos sin que ocurra + // un flanco de bajada en PS2CLK, volvemos al estado inicial + reg [23:0] timeoutcnt = 24'h000000; + + reg [1:0] state = RCVSTART; + reg [1:0] regextended = 2'b00; + reg [1:0] regreleased = 2'b00; + reg rkb_interrupt = 1'b0; + assign released = regreleased[1]; + assign extended = regextended[1]; + assign kb_interrupt = rkb_interrupt; + + always @(posedge clk) begin + if (rkb_interrupt == 1'b1) begin + rkb_interrupt <= 1'b0; + end + if (ps2clkedge && enable_rcv) begin + timeoutcnt <= 24'h000000; + case (state) + RCVSTART: begin + if (ps2data == 1'b0) begin + state <= RCVDATA; + key <= 8'h80; + end + end + RCVDATA: begin + key <= {ps2data, key[7:1]}; + if (key[0] == 1'b1) begin + state <= RCVPARITY; + end + end + RCVPARITY: begin + if (ps2data^paritycalculated == 1'b1) begin + state <= RCVSTOP; + end + else begin + state <= RCVSTART; + end + end + RCVSTOP: begin + state <= RCVSTART; + if (ps2data == 1'b1) begin + scancode <= key; + if (kb_or_mouse == 1'b1) begin + rkb_interrupt <= 1'b1; // no se requiere mirar E0 o F0 + end + else begin + if (key == 8'hE0) begin + regextended <= 2'b01; + end + else if (key == 8'hF0) begin + regreleased <= 2'b01; + end + else begin + regextended <= {regextended[0], 1'b0}; + regreleased <= {regreleased[0], 1'b0}; + rkb_interrupt <= 1'b1; + end + end + end + end + default: state <= RCVSTART; + endcase + end + else begin + timeoutcnt <= timeoutcnt + 24'd1; + if (timeoutcnt == 24'hFFFFFF) begin + state <= RCVSTART; + end + end + end +endmodule + + +module ps2_host_to_kb ( + input wire clk, // calibrado para 28 MHz + inout wire ps2clk_ext, + inout wire ps2data_ext, + input wire [7:0] data, + input wire dataload, + output wire ps2busy, + output wire ps2error + ); + + `define PULLCLKLOW 3'b000 + `define PULLCLKDATALOW 3'b001 + `define PULLDATALOW 3'b010 + `define SENDDATA 3'b011 + `define SENDPARITY 3'b100 + `define RCVACK 3'b101 + `define RCVIDLE 3'b110 + `define SENDFINISHED 3'b111 + + reg busy = 1'b0; + reg error = 1'b0; + assign ps2busy = busy; + assign ps2error = error; + + // Fase de sincronizacion de señales externas con el reloj del sistema + reg [1:0] ps2clk_synchr; + reg [1:0] ps2dat_synchr; + wire ps2clk = ps2clk_synchr[1]; + wire ps2data_in = ps2dat_synchr[1]; + always @(posedge clk) begin + ps2clk_synchr[0] <= ps2clk_ext; + ps2clk_synchr[1] <= ps2clk_synchr[0]; + ps2dat_synchr[0] <= ps2data_ext; + ps2dat_synchr[1] <= ps2dat_synchr[0]; + end + + // De-glitcher. Sólo detecto flanco de bajada + reg [15:0] edgedetect = 16'h0000; + always @(posedge clk) begin + edgedetect <= {edgedetect[14:0], ps2clk}; + end + wire ps2clknedge = (edgedetect == 16'hF000)? 1'b1 : 1'b0; + wire ps2clkpedge = (edgedetect == 16'h0FFF)? 1'b1 : 1'b0; + + // Contador de time-out. Al llegar a 16777216 ciclos sin que ocurra + // un flanco de bajada en PS2CLK, volvemos al estado inicial + reg [23:0] timeoutcnt = 24'h000000; + + reg [2:0] state = `SENDFINISHED; + reg [7:0] shiftreg = 8'h00; + reg [2:0] cntbits = 3'd0; + + // Dato a enviar se guarda en rdata + reg [7:0] rdata = 8'h00; + + // Paridad instantánea de los bits a enviar + wire paritycalculated = ~(^rdata); + + always @(posedge clk) begin + // Carga de rdata desde el exterior + if (dataload) begin + rdata <= data; + busy <= 1'b1; + error <= 1'b0; + timeoutcnt <= 24'h000000; + state <= `PULLCLKLOW; + end + + if (!ps2clknedge) begin + timeoutcnt <= timeoutcnt + 24'd1; + if (timeoutcnt == 24'hFFFFFF && state != `SENDFINISHED) begin + error <= 1'b1; + state <= `SENDFINISHED; + end + end + + case (state) + `PULLCLKLOW: begin // 280000 cuentas son 10ms para 28 MHz + if (timeoutcnt >= 24'd3360) begin + state <= `PULLCLKDATALOW; + timeoutcnt <= 24'h000000; + end + end + `PULLCLKDATALOW: begin + if (timeoutcnt >= 24'd280) begin + state <= `PULLDATALOW; + shiftreg <= rdata; + cntbits <= 3'd0; + timeoutcnt <= 24'h000000; + end + end + `PULLDATALOW: begin + if (ps2clknedge) begin + state <= `SENDDATA; + timeoutcnt <= 24'h000000; + end + end + `SENDDATA: begin + if (ps2clknedge) begin + timeoutcnt <= 24'h000000; + shiftreg <= {1'b0, shiftreg[7:1]}; + cntbits <= cntbits + 1; + if (cntbits == 3'd7) + state <= `SENDPARITY; + end + end + `SENDPARITY: begin + if (ps2clknedge) begin + state <= `RCVIDLE; + timeoutcnt <= 24'h000000; + end + end + `RCVIDLE: begin + if (ps2clknedge) begin + state <= `RCVACK; + timeoutcnt <= 24'h000000; + end + end + `RCVACK: begin + if (ps2clknedge) begin + state <= `SENDFINISHED; + timeoutcnt <= 24'h000000; + end + end + `SENDFINISHED: begin + busy <= 1'b0; + timeoutcnt <= 24'h000000; + end + default: begin + timeoutcnt <= timeoutcnt + 1; + if (timeoutcnt == 24'hFFFFFF && state != `SENDFINISHED) begin + error <= 1'b1; + state <= `SENDFINISHED; + end + end + endcase + end + + assign ps2data_ext = (state == `PULLCLKDATALOW || state == `PULLDATALOW) ? 1'b0 : + (state == `SENDDATA && shiftreg[0] == 1'b0) ? 1'b0 : + (state == `SENDPARITY && paritycalculated == 1'b0) ? 1'b0 : // si lo que se va a enviar es un 1 + 1'bZ; // no se manda, sino que se pone la línea a alta impedancia + assign ps2clk_ext = (state == `PULLCLKLOW || state == `PULLCLKDATALOW) ? 1'b0 : + 1'bZ; +endmodule diff --git a/firmware/firmware.asm b/firmware/firmware.asm index 8a0c12e..275d29d 100644 --- a/firmware/firmware.asm +++ b/firmware/firmware.asm @@ -250,6 +250,17 @@ kemp defb $1f, $1e, $1d, $1c, $0d ; Right Left Down Up Enter start ld bc, chrend-sdtab ldir + wreg scan_code, $f6 ; $f6 = kb set defaults + halt + halt + wreg scan_code, $f0 ; $f0 + 2 = Set scan code set 2 + halt + halt + wreg scan_code, $02 + ld c, $05 ; 100msec delay +delay1 halt + dec c + jr nz, delay1 IF recovery=0 call alto loadch ld hl, (scanli) @@ -463,7 +474,10 @@ star16 djnz star18 halt wreg scan_code, $ed ; $ed + 2 = kb set leds + numlock halt + halt wreg scan_code, $02 + halt + halt IF vertical=0 ld hl, $0017 ; Si se acaba el temporizador borrar ld de, $2001 ; lo de presione Break