mii_emu/src/drivers/mii_mouse.c

188 lines
5.0 KiB
C

#include "mii.h"
// https://github.com/ivanizag/izapple2/blob/master/cardMouse.go
// https://hackaday.io/project/19925-aiie-an-embedded-apple-e-emulator/log/188017-entry-23-here-mousie-mousie-mousie
// https://github.com/ct6502/apple2ts/blob/main/src/emulator/mouse.ts
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mii.h"
#include "mii_bank.h"
enum {
CLAMP_MIN_LO = 0x478,
CLAMP_MIN_HI = 0x578,
CLAMP_MAX_LO = 0x4F8,
CLAMP_MAX_HI = 0x5F8,
// RAM Locations
// (Add $Cn where n is slot to these)
MOUSE_X_LO = 0x03B8,
MOUSE_X_HI = 0x04B8,
MOUSE_Y_LO = 0x0438,
MOUSE_Y_HI = 0x0538,
MOUSE_STATUS = 0x06B8,
MOUSE_MODE = 0x0738,
};
enum {
mouseEnabled = 1,
mouseIntMoveEnabled = 2,
mouseIntButtonEnabled = 4,
mouseIntVBlankEnabled = 8,
};
typedef struct mii_card_mouse_t {
struct mii_slot_t * slot;
uint8_t slot_offset;
uint8_t mode; // cached mode byte
struct {
uint16_t x, y;
bool button;
} last;
} mii_card_mouse_t;
static int
_mii_mouse_init(
mii_t * mii,
struct mii_slot_t *slot )
{
mii_card_mouse_t *c = calloc(1, sizeof(*c));
c->slot = slot;
slot->drv_priv = c;
printf("%s loading in slot %d\n", __func__, slot->id + 1);
c->slot_offset = slot->id + 1 + 0xc0;
uint8_t data[256] = {};
// Identification as a mouse card
// From Technical Note Misc #8, "Pascal 1.1 Firmware Protocol ID Bytes":
data[0x05] = 0x38;
data[0x07] = 0x18;
data[0x0b] = 0x01;
data[0x0c] = 0x20;
// From "AppleMouse // User's Manual", Appendix B:
//data[0x0c] = 0x20
data[0xfb] = 0xd6;
// Set 8 entrypoints to sofstwitches 2 to 1f
for (int i = 0; i < 14; i++) {
uint8_t base = 0x60 + 0x05 * i;
data[0x12+i] = base;
data[base+0] = 0x8D; // STA $C0x2
data[base+1] = 0x82 + i + ((slot->id + 1) << 4);
data[base+2] = 0xC0;
data[base+3] = 0x18; // CLC ;no error
data[base+4] = 0x60; // RTS
}
uint16_t addr = 0xc100 + (slot->id * 0x100);
mii_bank_write(
&mii->bank[MII_BANK_CARD_ROM],
addr, data, 256);
return 0;
}
static uint8_t
_mii_mouse_access(
mii_t * mii,
struct mii_slot_t *slot,
uint16_t addr,
uint8_t byte,
bool write)
{
mii_card_mouse_t *c = slot->drv_priv;
int psw = addr & 0x0F;
mii_bank_t * main = &mii->bank[MII_BANK_MAIN];
switch (psw) {
case 2: {
if (write) {
byte &= 0xf;
mii_bank_poke(main, MOUSE_MODE + c->slot_offset, byte);
printf("%s: mouse mode %02x\n", __func__, byte);
mii->mouse.enabled = byte & mouseEnabled;
printf("Mouse %s\n", mii->mouse.enabled ? "enabled" : "disabled");
printf(" Interupt: %s\n", byte & mouseIntMoveEnabled ? "enabled" : "disabled");
printf(" Button: %s\n", byte & mouseIntButtonEnabled ? "enabled" : "disabled");
printf(" VBlank: %s\n", byte & mouseIntVBlankEnabled ? "enabled" : "disabled");
c->mode = byte;
mii->video.vbl_irq = !!(byte & mouseIntVBlankEnabled);
}
} break;
case 4: {// read mouse
if (!mii->mouse.enabled)
break;
uint8_t status = 0;
if (mii->mouse.button)
status |= 1 << 7;
if (c->last.button) {
status |= 1 << 6;
}
if ((mii->mouse.x != c->last.x) || (mii->mouse.y != c->last.y)) {
status |= 1 << 5;
}
mii_bank_poke(main, MOUSE_X_HI + c->slot_offset, mii->mouse.x >> 8);
mii_bank_poke(main, MOUSE_Y_HI + c->slot_offset, mii->mouse.y >> 8);
mii_bank_poke(main, MOUSE_X_LO + c->slot_offset, mii->mouse.x);
mii_bank_poke(main, MOUSE_Y_LO + c->slot_offset, mii->mouse.y);
mii_bank_poke(main, MOUSE_STATUS + c->slot_offset, status);
// mii_bank_poke(main, MOUSE_MODE + c->slot_offset, 0xf); // already in place
c->last.x = mii->mouse.x;
c->last.y = mii->mouse.y;
c->last.button = mii->mouse.button;
} break;
case 5: // clear mouse
break;
case 7: // set mouse
if (byte == 0) {
mii->mouse.min_x = mii_bank_peek(main, CLAMP_MIN_LO) |
(mii_bank_peek(main, CLAMP_MIN_HI) << 8);
mii->mouse.max_x = mii_bank_peek(main, CLAMP_MAX_LO) |
(mii_bank_peek(main, CLAMP_MAX_HI) << 8);
} else if (byte == 1) {
mii->mouse.min_y = mii_bank_peek(main, CLAMP_MIN_LO) |
(mii_bank_peek(main, CLAMP_MIN_HI) << 8);
mii->mouse.max_y = mii_bank_peek(main, CLAMP_MAX_LO) |
(mii_bank_peek(main, CLAMP_MAX_HI) << 8);
}
printf("Mouse clamp to %d,%d - %d,%d\n",
mii->mouse.min_x, mii->mouse.min_y,
mii->mouse.max_x, mii->mouse.max_y);
break;
case 8: // home mouse
mii->mouse.x = mii->mouse.min_x;
mii->mouse.y = mii->mouse.min_y;
break;
case 0xc: // init mouse
mii->mouse.min_x = mii->mouse.min_y = 0;
mii->mouse.max_x = mii->mouse.max_y = 1023;
mii->mouse.enabled = 0;
mii_bank_poke(main, MOUSE_MODE + c->slot_offset, 0x0);
break;
default:
printf("%s PC:%04x addr %04x %02x wr:%d\n", __func__,
mii->cpu.PC, addr, byte, write);
break;
}
return 0;
}
static mii_slot_drv_t _driver = {
.name = "mouse",
.desc = "Mouse card",
.init = _mii_mouse_init,
.access = _mii_mouse_access,
};
MI_DRIVER_REGISTER(_driver);