Compare commits

...

3 commits

Author SHA1 Message Date
d44474c24e Enable absolute mouse (todo: add flag to turn it off)
&& fix(?) a crash if mouse events were delivered too early
2025-08-01 16:11:05 -05:00
d86ebf1bb8 Turbocharge mouse movement
.. by storing directly into the vars used by the mac plus ROM,
rather than working through the IRQ & I/O subsystems.
2025-08-01 15:41:43 -05:00
d7d30c5608 Add PV UART read (into emulator) 2025-08-01 15:30:54 -05:00
6 changed files with 114 additions and 87 deletions

View file

@ -35,6 +35,8 @@ void scc_write(unsigned int address, uint8_t data);
uint8_t scc_read(unsigned int address);
/* Set a new state for the DCD pins: */
void scc_set_dcd(int a, int b);
/* check if scc master interrupt is enabled */
int scc_get_mie();
#endif

View file

@ -34,6 +34,7 @@ int umac_loop(void);
void umac_reset(void);
void umac_opt_disassemble(int enable);
void umac_mouse(int deltax, int deltay, int button);
void umac_absmouse(int x, int y, int button);
void umac_kbd_event(uint8_t scancode, int down);
static inline void umac_vsync_event(void)

View file

@ -16,6 +16,7 @@
#include "m68k.h"
#include "machw.h"
#undef DEBUG
#ifdef DEBUG
#define DDBG(...) printf(__VA_ARGS__)
#else

View file

@ -82,6 +82,8 @@ static int disassemble = 0;
static void update_overlay_layout(void);
extern int pv_uart_read();
////////////////////////////////////////////////////////////////////////////////
static int m68k_dump_regs(char *buf, int len)
@ -246,7 +248,6 @@ static void kbd_rx(uint8_t data)
int evt = KBD_RSP_NULL;
if (ringbuf_avail(&kbd_pending_evt)) {
evt = ringbuf_get(&kbd_pending_evt);
printf("via sr rx %s %02x\n", data == KBD_CMD_INSTANT ? "INSTANT" : "inquiry", evt);
}
via_sr_rx(evt);
}
@ -401,6 +402,10 @@ unsigned int FAST_FUNC(cpu_read_word)(unsigned int address)
if (IS_ROM(address))
return ROM_RD16(address & (ROM_SIZE - 1));
if (address == PV_UART_ADDR) {
return pv_uart_read();
}
if (IS_TESTSW(address))
return 0;
@ -476,11 +481,7 @@ void FAST_FUNC(cpu_write_byte)(unsigned int address, unsigned int value)
return;
}
if (address == PV_UART_ADDR) {
if(value < 32 && value != '\r' && value != '\n') {
printf("0x%02x", value);
} else {
putchar(value);
}
putchar(value);
fflush(stdout);
return;
}
@ -614,10 +615,35 @@ void umac_opt_disassemble(int enable)
disassemble = enable;
}
#define MOUSE_MAX_PENDING_PIX 30
/* Provide mouse input (movement, button) data.
*
* X is positive going right; Y is positive going upwards.
*/
void umac_absmouse(int x, int y, int button)
{
if (!scc_get_mie()) return;
#define MTemp_h 0x82a
#define MTemp_v 0x828
#define CrsrNew 0x8ce
#define CrsrCouple 0x8cf
static int pending_mouse_deltax = 0;
static int pending_mouse_deltay = 0;
int oldx = RAM_RD16(MTemp_h);
int oldy = RAM_RD16(MTemp_v);
if(x != oldx) {
RAM_WR16(MTemp_h, x);
}
if (y != oldy) {
RAM_WR16(MTemp_v, y);
}
if(x != oldx || y != oldy) {
RAM_WR8(CrsrNew, RAM_RD8(CrsrCouple));
}
via_mouse_pressed = button;
}
/* Provide mouse input (movement, button) data.
*
@ -625,83 +651,22 @@ static int pending_mouse_deltay = 0;
*/
void umac_mouse(int deltax, int deltay, int button)
{
pending_mouse_deltax += deltax;
pending_mouse_deltay += deltay;
/* Clamp if the UI has flooded with lots and lots of steps!
*/
if (pending_mouse_deltax > MOUSE_MAX_PENDING_PIX)
pending_mouse_deltax = MOUSE_MAX_PENDING_PIX;
if (pending_mouse_deltax < -MOUSE_MAX_PENDING_PIX)
pending_mouse_deltax = -MOUSE_MAX_PENDING_PIX;
if (pending_mouse_deltay > MOUSE_MAX_PENDING_PIX)
pending_mouse_deltay = MOUSE_MAX_PENDING_PIX;
if (pending_mouse_deltay < -MOUSE_MAX_PENDING_PIX)
pending_mouse_deltay = -MOUSE_MAX_PENDING_PIX;
/* FIXME: The movement might take a little time, but this
* posts the button status immediately. Probably OK, but the
* mismatch might be perceptible.
*/
via_mouse_pressed = button;
}
static void mouse_tick(void)
{
/* Periodically, check if the mouse X/Y deltas are non-zero.
* If a movement is required, encode one step in X and/or Y
* and deduct from the pending delta.
*
* The step ultimately posts an SCC IRQ, so we _don't_ try to
* make any more steps while an IRQ is currently pending.
* (Currently, that means a previous step's DCD IRQ event
* hasn't yet been consumed by the OS handler. In future, if
* SCC is extended with other IRQ types, then just checking
* the IRQ status is technically too crude, but should still
* be fine given the timeframes.)
*/
if (pending_mouse_deltax == 0 && pending_mouse_deltay == 0)
return;
if (scc_irq_state == 1)
return;
static int old_dcd_a = 0;
static int old_dcd_b = 0;
/* Mouse X/Y quadrature signals are wired to:
* VIA Port B[4] & SCC DCD_A for X
* VIA Port B[5] & SCC DCD_B for Y
*
* As VIA mouse signals aren't sampled until IRQ, can do this
* in one step, toggling existing DCD states and setting VIA
* either equal or opposite to DCD:
*/
int dcd_a = old_dcd_a;
int dcd_b = old_dcd_b;
int deltax = pending_mouse_deltax;
int deltay = pending_mouse_deltay;
uint8_t qb = via_quadbits;
if (deltax) {
dcd_a = !dcd_a;
qb = (qb & ~0x10) | ((deltax < 0) == dcd_a ? 0x10 : 0);
pending_mouse_deltax += (deltax > 0) ? -1 : 1;
MDBG(" px %d, oldpx %d", pending_mouse_deltax, deltax);
if (!scc_get_mie()) return;
if(deltax) {
int16_t temp_h = RAM_RD16(MTemp_h) + deltax;
RAM_WR16(MTemp_h, temp_h);
}
if (deltay) {
dcd_b = !dcd_b;
qb = (qb & ~0x20) | ((deltay < 0) == dcd_b ? 0x20 : 0);
pending_mouse_deltay += (deltay > 0) ? -1 : 1;
MDBG(" py %d, oldpy %d", pending_mouse_deltay, deltay);
int16_t temp_v = RAM_RD16(MTemp_v) - deltay;
RAM_WR16(MTemp_v, temp_v);
}
MDBG("\n");
via_quadbits = qb;
old_dcd_a = dcd_a;
old_dcd_b = dcd_b;
scc_set_dcd(dcd_a, dcd_b);
if(deltax || deltay) {
RAM_WR8(CrsrNew, RAM_RD8(CrsrCouple));
}
via_mouse_pressed = button;
}
void umac_reset(void)
@ -733,7 +698,6 @@ int umac_loop(void)
// Device polling
via_tick(global_time_us);
mouse_tick();
disc_tick();
kbd_check_work();

View file

@ -126,6 +126,8 @@ static void scc_wr3(int AnB, uint8_t data)
}
}
int scc_get_mie() { return scc_mie; }
// WR9: Master Interrupt control and reset commands
static void scc_wr9(uint8_t data)
{

View file

@ -196,6 +196,43 @@ static int open_disc(unix_disc_descr_t *desc, int slot, int opt_write, const cha
}
}
// from micropython
#include <termios.h>
#include <unistd.h>
#include <poll.h>
static struct termios orig_termios;
static void stdio_mode_raw(void) {
// save and set terminal settings
tcgetattr(0, &orig_termios);
static struct termios termios;
termios = orig_termios;
termios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
termios.c_cflag = (termios.c_cflag & ~(CSIZE | PARENB)) | CS8;
termios.c_lflag = 0;
termios.c_cc[VMIN] = 1;
termios.c_cc[VTIME] = 0;
tcsetattr(0, TCSAFLUSH, &termios);
}
static void stdio_mode_orig(void) {
// restore terminal settings
tcsetattr(0, TCSAFLUSH, &orig_termios);
}
int pv_uart_read() {
struct pollfd p = { .fd = 0, .events = POLLIN };
int r = poll(&p, 1, 0);
if (r > 0) {
unsigned char result;
r = read(0, &result, 1);
if (r == 1) return result;
}
return EOF;
}
/**********************************************************************/
/* The emulator core expects to be given ROM and RAM pointers,
@ -346,8 +383,14 @@ int main(int argc, char *argv[])
perror("SDL window");
return 1;
}
SDL_SetWindowGrab(window, SDL_TRUE);
SDL_SetRelativeMouseMode(SDL_TRUE);
static const int absmouse = 1;
if (!absmouse) {
SDL_SetWindowGrab(window, SDL_TRUE);
SDL_SetRelativeMouseMode(SDL_TRUE);
} else {
SDL_ShowCursor(SDL_DISABLE);
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
@ -371,10 +414,12 @@ int main(int argc, char *argv[])
umac_init(ram_base, rom_base, discs);
umac_opt_disassemble(opt_disassemble);
stdio_mode_raw();
////////////////////////////////////////////////////////////////////////
// Main loop
int done = 0;
int mouse_button = 0;
uint64_t last_vsync = 0;
@ -384,7 +429,8 @@ int main(int argc, char *argv[])
SDL_Event event;
int mousex = 0;
int mousey = 0;
int send_mouse = 0;
static int absmousex, absmousey;
if (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
@ -395,27 +441,37 @@ int main(int argc, char *argv[])
case SDL_KEYUP: {
int c = SDLScan2MacKeyCode(event.key.keysym.scancode);
c = (c << 1) | 1;
printf("Key 0x%x -> 0x%x\n", event.key.keysym.scancode, c);
if (c != MKC_None)
umac_kbd_event(c, (event.type == SDL_KEYDOWN));
} break;
case SDL_MOUSEMOTION:
send_mouse = 1;
absmousex = event.motion.x / DISP_SCALE;
absmousey = event.motion.y / DISP_SCALE;
mousex = event.motion.xrel;
mousey = -event.motion.yrel;
break;
case SDL_MOUSEBUTTONDOWN:
send_mouse = 1;
mouse_button = 1;
break;
case SDL_MOUSEBUTTONUP:
send_mouse = 1;
mouse_button = 0;
break;
}
}
umac_mouse(mousex, mousey, mouse_button);
if (send_mouse) {
if(absmouse) {
umac_absmouse(absmousex, absmousey, mouse_button);
} else {
umac_mouse(mousex, mousey, mouse_button);
}
}
done |= umac_loop();
@ -441,5 +497,6 @@ int main(int argc, char *argv[])
}
} while (!done);
stdio_mode_orig();
return 0;
}