From 0dfd096c71cc30f28ef6d904968f68a80e55a57e Mon Sep 17 00:00:00 2001
From: Miro Kropacek <[EMAIL REDACTED]>
Date: Wed, 30 Sep 2026 22:39:09 +1000
Subject: [PATCH] atari:events: hook on ikbdsys instead of ACIA
The routine replaces ikbdsys in the Kbdvbase() table rather than the
ACIA interrupt vector at 0x118. Both ACIAs share the edge triggered MFP
GPIP4 line; the OS interrupt handler calls midisys and ikbdsys in a loop
until the line is released, so an interrupt raised by either ACIA while
the handler runs is not lost.
---
README.MiNT | 63 +++---
src/video/ataricommon/SDL_atarievents.c | 5 +
src/video/ataricommon/SDL_ikbdinterrupt.S | 256 +++++-----------------
3 files changed, 95 insertions(+), 229 deletions(-)
diff --git a/README.MiNT b/README.MiNT
index a175edef..b30c0fd2 100644
--- a/README.MiNT
+++ b/README.MiNT
@@ -72,12 +72,13 @@ to report this type event.
V. Environment variables:
SDL_VIDEODRIVER:
- Set to 'xbios' to force xbios video driver. Uses XBIOS/Ikbd events driver.
+ Set to 'xbios' to force xbios video driver. Uses XBIOS/Ikbd events
+ driver.
Set to 'gem' to force gem video driver. Uses an internal events driver.
SDL_VIDEO_ALIGNED_WINDOWS:
- Set to force aligning of the window's x coordinate to a 16-pixel boundary
- (e.g. for speed reasons)
+ Set to force aligning of the window's x coordinate to a 16-pixel
+ boundary (e.g. for speed reasons)
SDL_AUDIODRIVER:
Set to 'xbios' to force Atari Xbios audio driver
@@ -133,9 +134,9 @@ VI. More informations about drivers:
OpenGL:
OpenGL is provided by a statically linked OSMesa (libOSMesa.a), the
- OpenGL context is taken care of by SDL itself, you just have to use gl*
- functions. Programs not calling any gl* function don't link OSMesa at all.
- SDL_GL_LoadLibrary() accepts only NULL, i.e. the linked OSMesa.
+ OpenGL context is taken care of by SDL itself, you just have to use
+ gl* functions. Programs not calling any gl* function don't link OSMesa
+ at all. SDL_GL_LoadLibrary() accepts only NULL, i.e. the linked OSMesa.
Xbios video:
Video chip is detected using the _VDO cookie.
@@ -143,8 +144,8 @@ Xbios video:
them.
ST, STE, Mega ST, Mega STE:
- 320x200x4 bits, shades of grey, available only for the purpose of
- testing SDL.
+ 320x200x4 bits, shades of grey, available only for the purpose
+ of testing SDL.
TT:
320x480x8 and 320x240x8 (software double-lined mode).
Falcon:
@@ -152,11 +153,12 @@ Xbios video:
BlowUp and Centscreen: Extended modes.
ScreenBlaster 3: Only current mode.
Supervidel: Extended modes.
- CTPCI: Only the modes supported by XBIOS (640x480, 800x600, 1024x768,
- 1280x960, 1600x1200 in 8/16/32 bpp).
+ CTPCI: Only the modes supported by XBIOS (640x480, 800x600,
+ 1024x768, 1280x960, 1600x1200 in 8/16/32 bpp).
Milan:
- Nearly identical with CTPCI driver. Works only on Milan with S3 video
- card driver (which should be newer than 12.1.2000). To be verified.
+ Nearly identical with CTPCI driver. Works only on Milan with S3
+ video card driver (which should be newer than 12.1.2000). To be
+ verified.
Any machine with NOVA video card:
All modes with 8 bits or higher depth.
Clones and any machine with monochrome monitor:
@@ -171,9 +173,10 @@ Xbios video:
called.
The decision should depend on how the framebuffer is used. If the SDL
- application already maintains its own framebuffer and SDL is used merely as
- a display device, use SDL_HWSURFACE. If the framebuffer is accessed on a
- per-pixel basis —or if pixels are read multiple times— prefer SDL_SWSURFACE.
+ application already maintains its own framebuffer and SDL is used
+ merely as a display device, use SDL_HWSURFACE. If the framebuffer is
+ accessed on a per-pixel basis —or if pixels are read multiple times—
+ prefer SDL_SWSURFACE.
Gem video:
Automatically used if xbios not available.
@@ -185,25 +188,27 @@ Keyboard, mouse and joystick driver:
When unset, XBIOS video uses XBIOS where available (TOS >= 2.x and/or in
MagiC) and IKBD otherwise, GEM video uses GEM.
+ The IKBD driver hooks the ikbdsys vector from Kbdvbase() instead of the
+ ACIA interrupt vector at 0x118, so MIDI interrupts keep being serviced.
+ It is not available on FireTOS, whose ACIA handler never calls ikbdsys.
+
In ideal circumstances, XBIOS video supports selection of XBIOS and IKBD
- events while GEM video supports selection of XBIOS and GEM events. Otherwise
- XBIOS video is stuck with IKBD events and GEM video with GEM events.
+ events while GEM video supports selection of XBIOS and GEM events.
+ Otherwise XBIOS video is stuck with IKBD events and GEM video with GEM
+ events.
With GEM video the choice only decides where keyboard events come from:
- AES message loop or XBIOS keyboard vector (which reports key press/release
- events). Mouse buttons, relative motion and the joystick always come from the
- XBIOS vectors (which are available on every machine).
-
- The AES reports key presses and their repeats but no releases, so the GEM
- driver considers a key released once its next repeat is overdue, using
- the delay and rate set in the Control Panel. Only the last pressed key
- repeats, so keys held together are released early; use
+ AES message loop or XBIOS keyboard vector (which reports key
+ press/release events). Mouse buttons, relative motion and the joystick
+ always come from the XBIOS vectors (which are available on every
+ machine).
+
+ The AES reports key presses and their repeats but no releases, so the
+ GEM driver considers a key released once its next repeat is overdue,
+ using the delay and rate set in the Control Panel. Only the last
+ pressed key repeats, so keys held together are released early; use
SDL_ATARI_EVENTSDRIVER=xbios where available.
- As XBIOS video driver is not available on Hades, it is forced to use the
- implicit GEM driver despite the fact that it has both IKBD and XBIOS
- features available.
-
Joypad driver:
Available if _MCH cookie is STE or Falcon. Supports teamtap.
diff --git a/src/video/ataricommon/SDL_atarievents.c b/src/video/ataricommon/SDL_atarievents.c
index 5b707c00..f39bbd06 100644
--- a/src/video/ataricommon/SDL_atarievents.c
+++ b/src/video/ataricommon/SDL_atarievents.c
@@ -117,6 +117,11 @@ static SDL_bool IsIkbdSupported(void)
{
long cookie_mch = SDL_Atari_GetMch();
+ /* FireTOS reports a Falcon but its ACIA interrupt handler never calls
+ kb_kbdsys, which the IKBD driver replaces */
+ if (Getcookie(C__CF_, NULL) == C_FOUND)
+ return SDL_FALSE;
+
/* The IKBD driver talks to the keyboard chip directly, which only
Atari hardware and its emulators provide */
return (cookie_mch == MCH_ST<<16) || ((cookie_mch>>16) == MCH_STE) ||
diff --git a/src/video/ataricommon/SDL_ikbdinterrupt.S b/src/video/ataricommon/SDL_ikbdinterrupt.S
index a4f15f10..be30a806 100644
--- a/src/video/ataricommon/SDL_ikbdinterrupt.S
+++ b/src/video/ataricommon/SDL_ikbdinterrupt.S
@@ -41,7 +41,7 @@
.globl SYM(Atari_UnhookXbra)
-/*--- Install our IKBD vector ---*/
+/*--- Install our kb_kbdsys vector ---*/
SYM(SDL_AtariIkbd_Install):
| KBDVBASE *Kbdvbase(void);
@@ -62,6 +62,7 @@ SYM(SDL_AtariIkbd_Install):
moveml sp@+,d2/a2
#endif
movel d0,a1
+ movel a1,ikbd_kbdvecs
processing_ikbd_packet_install:
@@ -78,59 +79,28 @@ processing_ikbd_packet_install:
bras processing_ikbd_packet_install
no_ikbd_packet_install:
- | Save MFP registers used for keyboard
-
- lea 0xfffffa00:w,a0
- btst #6,a0@(0x09)
-#if defined(__mcoldfire__)
- sne d0
- move.b d0,ikbd_ierb
-#else
- sne ikbd_ierb
-#endif
- btst #6,a0@(0x15)
-#if defined(__mcoldfire__)
- sne d0
- move.b d0,ikbd_imrb
-#else
- sne ikbd_imrb
-#endif
-
| Set our routine
-#if defined(__mcoldfire__)
- movel 0x118:w,d0
+ lea ikbd_packet_start,a0
+ movel a0,ikbd_state
+
+ movel a1@(32),d0
movel d0,old_ikbd
lea ikbd,a0
- movel a0,0x118:w
- moveql #6,d0
- bset d0,0xfffffa09:w | IERB
- bset d0,0xfffffa15:w | IMRB
-#else
- movel 0x118:w,old_ikbd
- movel #ikbd,0x118:w
- bset #6,0xfffffa09:w | IERB
- bset #6,0xfffffa15:w | IMRB
-#endif
+ movel a0,a1@(32)
| Set mouse relative mode
-#if defined(__mcoldfire__)
moveql #8,d0
moveb d0,0xfffffc02:w
-#else
- moveb #8,0xfffffc02:w
-#endif
| Reenable interrupts
movew d1,sr
- | Interrupts done
-
rts
-/*--- Uninstall our IKBD vector ---*/
+/*--- Uninstall our kb_kbdsys vector ---*/
SYM(SDL_AtariIkbd_Restore):
tstl old_ikbd
@@ -143,34 +113,12 @@ ikbd_installed:
movew sr,d1
movew #0x2700,sr
- | Restore previous MFP registers
-
- lea 0xfffffa00:w,a0
-
- bclr #6,a0@(0x09)
- tstb ikbd_ierb
- beqs ikbd_restoreierb
- bset #6,a0@(0x09)
-ikbd_restoreierb:
-
- bclr #6,a0@(0x15)
- tstb ikbd_imrb
- beqs ikbd_restoreimrb
- bset #6,a0@(0x15)
-ikbd_restoreimrb:
-
-#if defined(__mcoldfire__)
- movel #ikbd,d0
- movel d0,0x118:w
-#else
- movel #ikbd,0x118:w
-#endif
-
movew d1,sp@-
- pea ikbd(pc)
+ pea ikbd
movel #0x4c53444c,sp@- /* "LSDL" */
- pea 0x118/4:w
+ movel ikbd_kbdvecs,a0
+ pea a0@(32)
jsr SYM(Atari_UnhookXbra)
lea sp@(12),sp
@@ -190,20 +138,20 @@ ikbd_finbuffer:
movew d1,sr
- | Interrupts done
-
clrl old_ikbd
rts
.bss
.even
-ikbd_ierb:
- .ds.b 1
-ikbd_imrb:
- .ds.b 1
+ikbd_kbdvecs:
+ .ds.l 1
+ikbd_state:
+ .ds.l 1
+ikbd_mouse_entry:
+ .ds.l 1
-/*--- Our custom IKBD vector ---*/
+/*--- Our custom kb_kbdsys vector ---*/
.text
.even
@@ -219,16 +167,26 @@ ikbd:
moveml d0-d1/a0,sp@-
#endif
- | Check if source is IKBD or MIDI
-#if defined(__mcoldfire__)
- moveql #0,d0
- btst d0,0xfffffc00.w
-#else
- btst #0,0xfffffc00.w
-#endif
- beq ikbd_oldmidi
+ | Interrupt request from the IKBD ACIA?
+
+ moveb 0xfffffc00:w,d1
+ bpl ikbd_end
+
+ | Reading the data register clears both a received byte and an
+ | overrun, releasing the ACIA's interrupt line
moveb 0xfffffc02:w,d0
+ btst #0,d1
+ beq ikbd_end
+
+ | Continue the packet in progress
+
+ movel ikbd_state,a0
+ jmp a0@
+
+ | First byte of a packet
+
+ikbd_packet_start:
| Joystick packet ?
@@ -248,7 +206,7 @@ ikbd_yes_mouse:
andl #3,d0
movew d0,SYM(SDL_Atari_mouseb)
- | Start the queue entry, dx and dy follow in the next two packets
+ | Start the queue entry, dx and dy follow in the next two bytes
moveql #ATARI_QUEUE_MOUSE,d1
lsll #8,d1
@@ -256,24 +214,14 @@ ikbd_yes_mouse:
swap d1
movel d1,ikbd_mouse_entry
-#if defined(__mcoldfire__)
- movel #ikbd_mousex,d0
- movel d0,0x118:w
-#else
- movel #ikbd_mousex,0x118:w
-#endif
- bras ikbd_endit_stack
+ lea ikbd_mousex,a0
+ bras ikbd_next_state
| Joystick packet, byte #1
ikbd_yes_joystick:
-#if defined(__mcoldfire__)
- movel #ikbd_joystick,d0
- movel d0,0x118:w
-#else
- movel #ikbd_joystick,0x118:w
-#endif
- bras ikbd_endit_stack
+ lea ikbd_joystick,a0
+ bras ikbd_next_state
| Keyboard press/release
@@ -284,132 +232,40 @@ ikbd_no_mouse:
moveb d1,d0
swap d0
ATARI_QUEUE_PUSH
-
- | End of interrupt
-
-ikbd_endit_stack:
-#if defined(__mcoldfire__)
- moveql #6,d0
- bclr d0,0xfffffa11:w
-
- moveml sp@,d0-d1/a0
- lea sp@(12),sp
-#else
- moveml sp@+,d0-d1/a0
-
- bclr #6,0xfffffa11:w
-#endif
- rte
-
- | Call old MIDI interrupt
-
-ikbd_oldmidi:
-#if defined(__mcoldfire__)
- moveml sp@,d0-d1/a0
- lea sp@(12),sp
-#else
- moveml sp@+,d0-d1/a0
-#endif
-
- movel old_ikbd,sp@-
- rts
+ bras ikbd_end
| Mouse packet, byte #2
ikbd_mousex:
-#if defined(__mcoldfire__)
- lea sp@(-12),sp
- moveml d0-d1/a0,sp@
-#else
- moveml d0-d1/a0,sp@-
-#endif
-
- | Check if source is IKBD or MIDI
-#if defined(__mcoldfire__)
- moveql #0,d0
- btst d0,0xfffffc00.w
-#else
- btst #0,0xfffffc00.w
-#endif
- beq ikbd_oldmidi
-
- moveb 0xfffffc02:w,d0
moveb d0,ikbd_mouse_entry+2
-#if defined(__mcoldfire__)
- movel #ikbd_mousey,d0
- movel d0,0x118:w
-#else
- movel #ikbd_mousey,0x118:w
-#endif
- bra ikbd_endit_stack
+ lea ikbd_mousey,a0
+ bras ikbd_next_state
| Mouse packet, byte #3
ikbd_mousey:
-#if defined(__mcoldfire__)
- lea sp@(-12),sp
- moveml d0-d1/a0,sp@
-#else
- moveml d0-d1/a0,sp@-
-#endif
-
- | Check if source is IKBD or MIDI
-#if defined(__mcoldfire__)
- moveql #0,d0
- btst d0,0xfffffc00.w
-#else
- btst #0,0xfffffc00.w
-#endif
- beq ikbd_oldmidi
-
- moveb 0xfffffc02:w,d0
moveb d0,ikbd_mouse_entry+3
movel ikbd_mouse_entry,d0
ATARI_QUEUE_PUSH
-
-#if defined(__mcoldfire__)
- movel #ikbd,d0
- movel d0,0x118:w
-#else
- movel #ikbd,0x118:w
-#endif
- bra ikbd_endit_stack
+ bras ikbd_packet_done
| Joystick packet, byte #2
ikbd_joystick:
-#if defined(__mcoldfire__)
- lea sp@(-12),sp
- moveml d0-d1/a0,sp@
-#else
- moveml d0-d1/a0,sp@-
-#endif
+ moveb d0,SYM(SDL_Atari_joystick)
- | Check if source is IKBD or MIDI
-#if defined(__mcoldfire__)
- moveql #0,d0
- btst d0,0xfffffc00.w
-#else
- btst #0,0xfffffc00.w
-#endif
- beq ikbd_oldmidi
+ikbd_packet_done:
+ lea ikbd_packet_start,a0
-#if defined(__mcoldfire__)
- moveb 0xfffffc02:w,d0
- moveb d0,SYM(SDL_Atari_joystick)
+ikbd_next_state:
+ movel a0,ikbd_state
- movel #ikbd,d0
- movel d0,0x118:w
+ikbd_end:
+#if defined(__mcoldfire__)
+ moveml sp@,d0-d1/a0
+ lea sp@(12),sp
#else
- moveb 0xfffffc02:w,SYM(SDL_Atari_joystick)
-
- movel #ikbd,0x118:w
+ moveml sp@+,d0-d1/a0
#endif
- bra ikbd_endit_stack
-
- .bss
-
- .even
-ikbd_mouse_entry:
- .ds.l 1
+ rts