1
0
mirror of https://github.com/jscrane/r65emu.git synced 2024-10-28 07:25:06 +00:00

Keyboards (#26)

* ps/2 and hardware serial keyboards

* serial keyboard

* add ps2_kbd shim

* hardware_run() and hardware_debug_cpu()

* ...

* ...

* updates

* refactoring

* refactoring

* run instructions
This commit is contained in:
Stephen Crane 2024-08-22 15:58:45 +01:00 committed by GitHub
parent 474d5c82d0
commit 4fa4faa278
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 290 additions and 196 deletions

2
CPU.h
View File

@ -16,7 +16,7 @@ public:
virtual void run(unsigned instructions) =0;
virtual void reset() =0;
virtual void raise(uint8_t level) =0;
virtual char *status(char *buf, size_t n, bool hdr) =0;
virtual char *status(char *buf, size_t n, bool hdr = false) =0;
virtual void checkpoint(Stream &s) = 0;
virtual void restore(Stream &s) = 0;

View File

@ -1,3 +1,4 @@
#include <Arduino.h>
#include <stdint.h>
#include <stddef.h>
#include "hardware.h"
@ -26,11 +27,6 @@ spiram sram(SPIRAM_SIZE);
Memory memory;
#if defined(USE_PS2_KBD) && !defined(USE_OWN_KBD)
#include "ps2drv.h"
PS2Driver ps2;
#endif
static CPU *_cpu;
bool hardware_reset() {
@ -75,8 +71,8 @@ void hardware_init(CPU &cpu) {
_cpu = &cpu;
memory.begin();
#if defined(USE_PS2_KBD) && !defined(USE_OWN_KBD)
ps2.begin(PS2_KBD_DATA, PS2_KBD_IRQ);
#if defined(DEBUGGING) || defined(CPU_DEBUG)
Serial.begin(TERMINAL_SPEED);
#endif
#if defined(TFT_BACKLIGHT)
@ -94,6 +90,35 @@ void hardware_init(CPU &cpu) {
#endif
}
#if defined(CPU_DEBUG)
bool cpu_debug = CPU_DEBUG;
#endif
bool hardware_debug_cpu() {
#if defined(CPU_DEBUG)
cpu_debug = !cpu_debug;
return cpu_debug;
#else
return false;
#endif
}
bool hardware_run(unsigned instructions) {
#if defined(CPU_DEBUG)
if (cpu_debug) {
char buf[256];
Serial.println(_cpu->status(buf, sizeof(buf)));
_cpu->run(1);
} else
_cpu->run(instructions);
#else
_cpu->run(instructions);
#endif
return !_cpu->halted();
}
#if !defined(NO_CHECKPOINT)
void hardware_checkpoint(Stream &s) {
unsigned ds = 0;

View File

@ -10,14 +10,21 @@
#include "hw/user.h"
#endif
#if !defined(CPU_INSTRUCTIONS)
#define CPU_INSTRUCTIONS 1000
#endif
#if !defined(TERMINAL_SPEED)
#define TERMINAL_SPEED 115200
#endif
bool hardware_reset();
void hardware_init(class CPU &);
void hardware_checkpoint(class Stream &);
void hardware_restore(class Stream &);
bool hardware_run(unsigned instructions = CPU_INSTRUCTIONS);
bool hardware_debug_cpu();
#if defined(__PS2DRV_H__) && defined(USE_PS2_KBD)
extern class PS2Driver ps2;
#endif
#if defined(__SPIRAM_H__) && defined(USE_SPIRAM)
extern class spiram sram;
#endif

28
hw_serial_kbd.cpp Normal file
View File

@ -0,0 +1,28 @@
#include <Arduino.h>
#include "hardware.h"
#if defined(HW_SERIAL_KBD)
#include "serial_kbd.h"
#include "hw_serial_kbd.h"
int hw_serial_kbd::read() {
if (!_serial.available())
return -1;
int k = _serial.read();
if ((k >= 0x0e) && (k <= 0x19)) {
fnkey(k - 0x0d);
return -1;
}
return k;
}
bool hw_serial_kbd::available() {
return _serial.available();
}
void hw_serial_kbd::reset() {
_serial.begin(TERMINAL_SPEED);
}
#endif

20
hw_serial_kbd.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef __HW_SERIAL_KBD_H__
#define __HW_SERIAL_KBD_H__
/*
* A serial keyboard based around the hardware serial port ("Serial")
* 12 Function keys: ^N .. ^Y inclusive
*/
class hw_serial_kbd: public serial_kbd {
public:
hw_serial_kbd(HardwareSerial &serial): _serial(serial) {}
int read();
bool available();
void reset();
private:
HardwareSerial &_serial;
};
#endif

View File

@ -1,18 +0,0 @@
#ifndef __KEYBOARD_H__
#define __KEYBOARD_H__
class Keyboard {
public:
virtual void up(uint8_t) = 0;
virtual void down(uint8_t) = 0;
virtual void reset() = 0;
static inline bool isshift(uint8_t scan) {
return scan == 0x12 || scan == 0x59;
}
static inline bool isctrl(uint8_t scan) {
return scan == 0x14;
}
};
#endif

88
ps2_raw_kbd.cpp Normal file
View File

@ -0,0 +1,88 @@
#include <stdint.h>
#include "hardware.h"
#if defined(USE_PS2_KBD)
#include <PS2KeyRaw.h>
#include "ps2_raw_kbd.h"
static PS2KeyRaw keyboard;
bool ps2_raw_kbd::available() {
return keyboard.available();
}
#define PS2_F1 0x05
#define PS2_F2 0x06
#define PS2_F3 0x04
#define PS2_F4 0x0C
#define PS2_F5 0x03
#define PS2_F6 0x0B
#define PS2_F7 0x83
#define PS2_F8 0x0A
#define PS2_F9 0x01
#define PS2_F10 0x09
#define PS2_F11 0x78
#define PS2_F12 0x07
static uint8_t fn(uint8_t key) {
switch(key) {
case PS2_F1: return 1;
case PS2_F2: return 2;
case PS2_F3: return 3;
case PS2_F4: return 4;
case PS2_F5: return 5;
case PS2_F6: return 6;
case PS2_F7: return 7;
case PS2_F8: return 8;
case PS2_F9: return 9;
case PS2_F10: return 01;
case PS2_F11: return 11;
case PS2_F12: return 12;
}
return 0;
}
static bool brk = false;
uint16_t ps2_raw_kbd::read() {
if (!available())
return 0;
int s = keyboard.read();
if (s < 0)
return 0;
uint8_t k = (s & 0xff);
if (k == 0xf0) {
brk = true;
return 0;
}
uint8_t f = fn(k);
if (f >= 1 && brk) {
fnkey(f);
brk = false;
return 0;
}
uint16_t r = brk? (0x8000 | k): k;
brk = false;
return r;
}
void ps2_raw_kbd::reset() {
keyboard.begin(PS2_KBD_DATA, PS2_KBD_IRQ);
_m.reset();
}
void ps2_raw_kbd::poll() {
if (available()) {
uint16_t scan = read();
uint8_t k = (scan & 0xff);
if (scan & 0x8000)
_m.up(k);
else
_m.down(k);
}
}
#endif

36
ps2_raw_kbd.h Normal file
View File

@ -0,0 +1,36 @@
#if !defined(__PS2_KBD_H__)
#define __PS2_KBD_H__
class matrix_keyboard {
public:
virtual void up(uint8_t) = 0;
virtual void down(uint8_t) = 0;
virtual void reset() {}
};
inline bool is_ps2_shift(uint16_t scan) { return scan == 0x12 || scan == 0x59; }
inline bool is_ps2_ctrl(uint16_t scan) { return scan == 0x14; }
typedef void (*fnkey_handler)(uint8_t);
class ps2_raw_kbd {
public:
ps2_raw_kbd(matrix_keyboard &m): _m(m) {}
void register_fnkey_handler(fnkey_handler f) { _f = f; }
void poll();
void reset();
protected:
void fnkey(uint8_t k) { if (_f) _f(k); }
private:
uint16_t read();
bool available();
fnkey_handler _f;
matrix_keyboard &_m;
};
#endif

40
ps2_serial_kbd.cpp Normal file
View File

@ -0,0 +1,40 @@
#include <Arduino.h>
#include "hardware.h"
#if defined(PS2_SERIAL_KBD)
#include <PS2KeyAdvanced.h>
#include <PS2KeyMap.h>
#include "serial_kbd.h"
#include "ps2_serial_kbd.h"
PS2KeyAdvanced keyboard;
PS2KeyMap keymap;
void ps2_serial_kbd::reset() {
keyboard.begin(PS2_KBD_DATA, PS2_KBD_IRQ);
keyboard.setNoBreak(1);
keymap.selectMap(PS2_SERIAL_KBD);
}
bool ps2_serial_kbd::available() {
return keyboard.available();
}
int ps2_serial_kbd::read() {
if (!keyboard.available())
return -1;
uint16_t key = keyboard.read();
if (key & PS2_FUNCTION) {
uint8_t k = key & 0xff;
if ((k >= PS2_KEY_F1) && (k <= PS2_KEY_F12)) {
fnkey(k - 0x60);
return -1;
}
}
uint16_t code = keymap.remapKey(key);
return code == 0? -1: (code & 0xff);
}
#endif

11
ps2_serial_kbd.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __PS2_SERIAL_KBD_H__
#define __PS2_SERIAL_KBD_H__
class ps2_serial_kbd: public serial_kbd {
public:
int read();
bool available();
void reset();
};
#endif

View File

@ -1,95 +0,0 @@
#include <Arduino.h>
#include "hardware.h"
#if defined(USE_PS2_KBD)
#include "ps2drv.h"
#if !defined(KBD_BUFFER)
#define KBD_BUFFER 16
#endif
static volatile uint8_t buffer[KBD_BUFFER];
static volatile uint8_t head, tail;
static uint8_t DataPin;
// The ISR for the external interrupt
#if defined(ESP32) || defined(ESP8266)
IRAM_ATTR
#endif
void ps2interrupt_handler(void)
{
static uint8_t bitcount=0;
static uint8_t incoming=0;
static uint32_t prev_ms=0;
uint32_t now_ms;
uint8_t n, val;
val = digitalRead(DataPin);
now_ms = millis();
if (now_ms - prev_ms > 250) {
bitcount = 0;
incoming = 0;
}
prev_ms = now_ms;
n = bitcount - 1;
if (n <= 7) {
incoming |= (val << n);
}
bitcount++;
if (bitcount == 11) {
uint8_t i = head + 1;
if (i == KBD_BUFFER) i = 0;
if (i != tail) {
buffer[i] = incoming;
head = i;
}
bitcount = 0;
incoming = 0;
}
}
bool PS2Driver::available() {
if (head == tail)
return false;
uint8_t i = tail+1;
if (i == KBD_BUFFER) i = 0;
if (buffer[i] == 0xf0)
return i != head;
return true;
}
unsigned PS2Driver::read2() {
if (head == tail)
return 0;
uint8_t i = tail+1;
if (i == KBD_BUFFER) i = 0;
tail = i;
if (buffer[i] != 0xf0)
return buffer[i];
return 0xf000 | read2();
}
unsigned PS2Driver::peek() {
if (head == tail)
return 0;
uint8_t i = tail+1;
if (i == KBD_BUFFER) i = 0;
if (buffer[i] == 0xf0) {
if (++i == KBD_BUFFER) i = 0;
return 0xf000 | buffer[i];
}
return buffer[i];
}
void PS2Driver::begin(uint8_t data_pin, uint8_t irq_pin)
{
DataPin = data_pin;
pinMode(irq_pin, INPUT_PULLUP);
pinMode(data_pin, INPUT_PULLUP);
attachInterrupt(irq_pin, ps2interrupt_handler, FALLING);
head = tail = 0;
}
#endif

View File

@ -1,70 +0,0 @@
#ifndef __PS2DRV_H__
#define __PS2DRV_H__
class PS2Driver
{
public:
PS2Driver() {}
/**
* Starts the keyboard "service" by registering the external interrupt.
* setting the pin modes correctly and driving those needed to high.
* The propably best place to call this method is in the setup routine.
*/
void begin(uint8_t dataPin, uint8_t irq_pin);
/**
* Returns true if there is a char to be read, false if not.
*/
bool available();
/**
* Returns the scancode last received from the keyboard.
* If there is no char available, 0 is returned.
*/
unsigned peek();
unsigned read2();
};
#define is_down(scan) ((scan) < 0x100)
#undef PS2_F1
#undef PS2_F2
#undef PS2_F3
#undef PS2_F4
#undef PS2_F5
#undef PS2_F6
#undef PS2_F7
#undef PS2_F8
#undef PS2_F9
#undef PS2_F10
#undef PS2_F11
#undef PS2_F12
#define PS2_F1 0x05
#define PS2_F2 0x06
#define PS2_F3 0x04
#define PS2_F4 0x0C
#define PS2_F5 0x03
#define PS2_F6 0x0B
#define PS2_F7 0x83
#define PS2_F8 0x0A
#define PS2_F9 0x01
#define PS2_F10 0x09
#define PS2_F11 0x78
#define PS2_F12 0x07
#define PS2_KP_DOT 0x71
#define PS2_KP_0 0x70
#define PS2_KP_1 0x69
#define PS2_KP_2 0x72
#define PS2_KP_3 0x7a
#define PS2_KP_4 0x6b
#define PS2_KP_5 0x73
#define PS2_KP_6 0x74
#define PS2_KP_7 0x6c
#define PS2_KP_8 0x75
#define PS2_KP_9 0x7d
#endif

View File

@ -6,9 +6,7 @@
#include "ram.h"
#include "spiram.h"
#include "prom.h"
#include "ps2drv.h"
#include "display.h"
#include "keyboard.h"
#include "serialio.h"
#include "filer.h"
#include "flash_filer.h"
@ -17,5 +15,9 @@
#include "timed.h"
#include "hardware.h"
#include "sound_dac.h"
#include "ps2_raw_kbd.h"
#include "serial_kbd.h"
#include "ps2_serial_kbd.h"
#include "hw_serial_kbd.h"
#endif

20
serial_kbd.h Normal file
View File

@ -0,0 +1,20 @@
#if !defined(__SERIAL_KBD_H__)
#define __SERIAL_KBD_H__
typedef void (*fnkey_handler)(uint8_t);
class serial_kbd {
public:
virtual int read() = 0;
virtual bool available() = 0;
virtual void reset() {}
virtual void register_fnkey_handler(fnkey_handler f) { _f = f; }
protected:
void fnkey(uint8_t k) { if (_f) _f(k); }
private:
fnkey_handler _f;
};
#endif