Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for Pico Keyboard #72

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[submodule "platform/libpicofe"]
path = platform/libpicofe
url = https://github.com/irixxxx/libpicofe.git
url = https://github.com/qufb/libpicofe.git
[submodule "cpu/cyclone"]
path = cpu/cyclone
url = https://github.com/notaz/cyclone68000.git
Expand Down
32 changes: 32 additions & 0 deletions pico/pico.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ typedef struct PicoInterface

void (*mcdTrayOpen)(void);
void (*mcdTrayClose)(void);

unsigned int ps2; // PS/2 peripherals, e.g. Pico Keyboard
} PicoInterface;

extern PicoInterface PicoIn;
Expand All @@ -140,6 +142,32 @@ struct PicoEState;

// pico.c
#define XPCM_BUFFER_SIZE (320+160)
enum {
KEY_RELEASED = 0,
KEY_DOWN,
KEY_UP,
};
enum {
SHIFT_RELEASED = 0,
SHIFT_DOWN,
SHIFT_UP_HELD_DOWN,
SHIFT_RELEASED_HELD_DOWN,
SHIFT_UP
};
typedef struct
{
uint8_t i;
uint8_t mode;
uint8_t neg;
uint8_t has_read;
uint8_t caps_lock;
uint8_t has_caps_lock;
uint32_t mem;
uint64_t start_time_keydown;
uint64_t time_keydown;
uint8_t key_state;
uint8_t shift_state;
} picohw_kb;
typedef struct
{
int pen_pos[2];
Expand All @@ -152,6 +180,10 @@ typedef struct
unsigned short r1, r12;
unsigned char xpcm_buffer[XPCM_BUFFER_SIZE+4];
unsigned char *xpcm_ptr;
int is_kb_active;
int is_pen_overlay_active;
int inp_mode;
picohw_kb kb;
} picohw_state;
extern picohw_state PicoPicohw;

Expand Down
209 changes: 207 additions & 2 deletions pico/pico/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
*/
#include "../pico_int.h"
#include "../memory.h"
#include <platform/common/input_pico.h>
#include <sys/time.h>

/*
void dump(u16 w)
Expand All @@ -24,6 +26,20 @@ void dump(u16 w)
}
*/

u64 get_ticks(void)
{
struct timeval tv;
u64 ret;

gettimeofday(&tv, NULL);

ret = (unsigned)tv.tv_sec * 1000;
/* approximate /= 1000 */
ret += ((unsigned)tv.tv_usec * 4195) >> 22;

return ret;
}

static u32 PicoRead8_pico(u32 a)
{
u32 d = 0;
Expand All @@ -43,7 +59,13 @@ static u32 PicoRead8_pico(u32 a)
case 0x07: d = PicoPicohw.pen_pos[0] & 0xff; break;
case 0x09: d = (PicoPicohw.pen_pos[1] >> 8); break;
case 0x0b: d = PicoPicohw.pen_pos[1] & 0xff; break;
case 0x0d: d = (1 << (PicoPicohw.page & 7)) - 1; break;
case 0x0d:
if (PicoPicohw.page == 7) {
d = 0x2a; // 0b00101010
} else {
d = ((1 << (PicoPicohw.page & 7)) - 1);
}
break;
case 0x12: d = PicoPicohw.fifo_bytes == 0 ? 0x80 : 0; break; // guess
default:
goto unhandled;
Expand Down Expand Up @@ -106,6 +128,182 @@ static void PicoWrite16_pico(u32 a, u32 d)
elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc);
}

static u32 PicoRead8_pico_kb(u32 a)
{
u32 d = 0;
if (PicoPicohw.is_kb_active == 0) {
elprintf(EL_PICOHW, "kb: r @%06X %04X = %04X\n", SekPc, a, d);
return d;
}

PicoPicohw.kb.has_read = 1;

u32 key_shift = (PicoIn.ps2 & 0xff00) >> 8;
u32 key = (PicoIn.ps2 & 0x00ff);

// The Shift key requires 2 key up events to be registered:
// SHIFT_UP_HELD_DOWN to allow the game to register the key down event
// for the next held down key(s), and SHIFT_UP when the Shift key
// is no longer held down.
//
// For the second key up event, we need to
// override the parsed key code with PEVB_PICO_PS2_LSHIFT,
// otherwise it will be zero and the game won't clear its Shift key state.
u32 key_code = (key_shift
&& !key
&& PicoPicohw.kb.key_state != KEY_UP
&& PicoPicohw.kb.shift_state != SHIFT_UP_HELD_DOWN)
? key_shift
: PicoPicohw.kb.shift_state == SHIFT_UP ? PEVB_PICO_PS2_LSHIFT : key;
u32 key_code_7654 = (key_code & 0xf0) >> 4;
u32 key_code_3210 = (key_code & 0x0f);
switch(PicoPicohw.kb.i) {
case 0x0: d = 1; // m5id
break;
case 0x1: d = 3; // m6id
break;
case 0x2: d = 4; // data size
break;
case 0x3: d = 0; // pad1 rldu
break;
case 0x4: d = 0; // pad2 sacb
break;
case 0x5: d = 0; // pad3 rxyz
break;
case 0x6: d = 0; // l&kbtype
break;
case 0x7: // cap/num/scr
if (PicoPicohw.inp_mode == 3) {
if (key == PEVB_PICO_PS2_CAPSLOCK && PicoPicohw.kb.has_caps_lock == 1) {
PicoPicohw.kb.caps_lock = PicoPicohw.kb.caps_lock == 4 ? 0 : 4;
PicoPicohw.kb.has_caps_lock = 0;
}
d = PicoPicohw.kb.caps_lock;
}
break;
case 0x8:
d = 6;
if (PicoPicohw.inp_mode == 3) {
if (key) {
PicoPicohw.kb.key_state = KEY_DOWN;
}
if (!key) {
PicoPicohw.kb.key_state = !PicoPicohw.kb.key_state ? 0 : (PicoPicohw.kb.key_state + 1) % (KEY_UP + 1);
PicoPicohw.kb.start_time_keydown = 0;
}
if (key_shift && !key) {
if (PicoPicohw.kb.shift_state < SHIFT_RELEASED_HELD_DOWN) {
PicoPicohw.kb.shift_state++;
}
PicoPicohw.kb.start_time_keydown = 0;
}
if (!key_shift) {
PicoPicohw.kb.shift_state = !PicoPicohw.kb.shift_state ? 0 : (PicoPicohw.kb.shift_state + 1) % (SHIFT_UP + 1);
}

if (PicoPicohw.kb.key_state == KEY_DOWN || PicoPicohw.kb.shift_state == SHIFT_DOWN) {
if (PicoPicohw.kb.start_time_keydown == 0) {
d |= 8; // Send key down a.k.a. make
PicoPicohw.kb.time_keydown = 0;
PicoPicohw.kb.start_time_keydown = get_ticks();
if (PicoPicohw.kb.key_state == KEY_DOWN)
elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: KEY DOWN\n");
else
elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: SHIFT DOWN\n");
}
// Simulate key repeat while held down a.k.a. typematic
PicoPicohw.kb.time_keydown = get_ticks() - PicoPicohw.kb.start_time_keydown;
if (PicoPicohw.kb.time_keydown > 350
// Modifier keys don't have typematic
&& key_code != PEVB_PICO_PS2_CAPSLOCK
&& key_code != PEVB_PICO_PS2_LSHIFT) {
d |= 8; // Send key down a.k.a. make
if (PicoPicohw.kb.key_state == KEY_DOWN)
elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: KEY DOWN\n");
else
elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: SHIFT DOWN\n");
}
// Must register key up while typematic not active (expected by Kibodeu Piko)
if ((d & 8) == 0) {
d |= 1; // Send key up a.k.a. break
}
}
if (PicoPicohw.kb.key_state == KEY_UP
|| PicoPicohw.kb.shift_state == SHIFT_UP_HELD_DOWN
|| PicoPicohw.kb.shift_state == SHIFT_UP) {
d |= 1; // Send key up a.k.a. break
PicoPicohw.kb.start_time_keydown = 0;
if (PicoPicohw.kb.key_state == KEY_UP)
elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: KEY UP\n");
else
elprintf(EL_PICOHW, "PicoPicohw.kb.key_state: SHIFT UP\n");
}
}
break;
case 0x9: d = key_code_7654; // data 7654
break;
case 0xa: d = key_code_3210; // data 3210
break;
case 0xb: d = 0; // ?
break;
case 0xc: d = 0; // ?
break;
default:
d = 0;
break;
}

if (PicoPicohw.kb.neg) {
d |= 0xfffffff0;
}

elprintf(EL_PICOHW, "kb: r @%06X %04X = %04X\n", SekPc, a, d);
return d;
}

static u32 PicoRead16_pico_kb(u32 a)
{
u32 d = PicoPicohw.kb.mem;

elprintf(EL_PICOHW, "kb: r16 @%06X %04X = %04X\n", SekPc, a, d);
return d;
}

static void PicoWrite8_pico_kb(u32 a, u32 d)
{
elprintf(EL_PICOHW, "kb: w @%06X %04X = %04X\n", SekPc, a, d);

switch(d) {
case 0x0:
PicoPicohw.kb.neg = 0;
PicoPicohw.kb.i++;
break;
case 0x20:
PicoPicohw.kb.neg = 1;
if (PicoPicohw.kb.has_read == 1) {
PicoPicohw.kb.i++;
}
break;
case 0x40:
break;
case 0x60:
PicoPicohw.kb.mode = !PicoPicohw.kb.mode;
PicoPicohw.kb.i = 0;
PicoPicohw.kb.has_read = 0;
break;
default:
break;
}

PicoPicohw.kb.mem = (PicoPicohw.kb.mem & 0xff00) | d;
}

static void PicoWrite16_pico_kb(u32 a, u32 d)
{
elprintf(EL_PICOHW, "kb: w16 @%06X %04X = %04X\n", SekPc, a, d);

PicoPicohw.kb.mem = d;
}

PICO_INTERNAL void PicoMemSetupPico(void)
{
Expand All @@ -119,5 +317,12 @@ PICO_INTERNAL void PicoMemSetupPico(void)
cpu68k_map_set(m68k_read16_map, 0x800000, 0x80ffff, PicoRead16_pico, 1);
cpu68k_map_set(m68k_write8_map, 0x800000, 0x80ffff, PicoWrite8_pico, 1);
cpu68k_map_set(m68k_write16_map, 0x800000, 0x80ffff, PicoWrite16_pico, 1);
}

m68k_map_unmap(0x200000, 0x20ffff);

// map Pico PS/2 Peripheral I/O
cpu68k_map_set(m68k_read8_map, 0x200000, 0x20ffff, PicoRead8_pico_kb, 1);
cpu68k_map_set(m68k_read16_map, 0x200000, 0x20ffff, PicoRead16_pico_kb, 1);
cpu68k_map_set(m68k_write8_map, 0x200000, 0x20ffff, PicoWrite8_pico_kb, 1);
cpu68k_map_set(m68k_write16_map, 0x200000, 0x20ffff, PicoWrite16_pico_kb, 1);
}
1 change: 1 addition & 0 deletions pico/pico/pico.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ PICO_INTERNAL void PicoInitPico(void)

PicoIn.AHW = PAHW_PICO;
memset(&PicoPicohw, 0, sizeof(PicoPicohw));
memset(&(PicoPicohw.kb), 0, sizeof(picohw_kb));
PicoPicohw.pen_pos[0] = 0x03c + 320/2;
PicoPicohw.pen_pos[1] = 0x200 + 240/2;
prev_line_cnt_irq3 = prev_line_cnt_irq5 = 0;
Expand Down
Loading