mirror of
https://github.com/jscrane/r65emu.git
synced 2025-02-12 17:32:08 +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:
parent
474d5c82d0
commit
4fa4faa278
2
CPU.h
2
CPU.h
@ -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;
|
||||
|
39
hardware.cpp
39
hardware.cpp
@ -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;
|
||||
|
13
hardware.h
13
hardware.h
@ -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
28
hw_serial_kbd.cpp
Normal 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
20
hw_serial_kbd.h
Normal 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
|
18
keyboard.h
18
keyboard.h
@ -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
88
ps2_raw_kbd.cpp
Normal 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
36
ps2_raw_kbd.h
Normal 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
40
ps2_serial_kbd.cpp
Normal 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
11
ps2_serial_kbd.h
Normal 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
|
95
ps2drv.cpp
95
ps2drv.cpp
@ -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
|
70
ps2drv.h
70
ps2drv.h
@ -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
|
6
r65emu.h
6
r65emu.h
@ -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
20
serial_kbd.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user