Timings work on all four platforms.
This commit is contained in:
parent
91fcd49f6f
commit
2eaa16a815
3 changed files with 88 additions and 22 deletions
|
|
@ -24,6 +24,8 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <exec/types.h>
|
||||
#include <exec/interrupts.h>
|
||||
#include <hardware/intbits.h>
|
||||
#include <intuition/intuition.h>
|
||||
#include <intuition/screens.h>
|
||||
#include <graphics/copper.h>
|
||||
|
|
@ -45,6 +47,13 @@
|
|||
|
||||
extern struct Custom custom;
|
||||
|
||||
|
||||
// Frame-counter VBL server lives at end of file; forward-declare so
|
||||
// halInit / halShutdown can install / remove it without C inferring
|
||||
// implicit non-static linkage at the call sites.
|
||||
static void installVblServer(void);
|
||||
static void removeVblServer(void);
|
||||
|
||||
// ----- Constants -----
|
||||
|
||||
#define AMIGA_BITPLANES 4
|
||||
|
|
@ -444,6 +453,7 @@ bool halInit(const JoeyConfigT *config) {
|
|||
// do nothing -- their palette[0] writes the same COLOR00 once the
|
||||
// first LoadRGB4 fires from uploadScbAndPalette.
|
||||
SetRGB4(&gScreen->ViewPort, 0, 0, 0, 0);
|
||||
installVblServer();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -509,26 +519,55 @@ void halWaitVBL(void) {
|
|||
}
|
||||
|
||||
|
||||
// VPOSR ($DFF004) upper byte: low 3 bits = vertical scanline bits
|
||||
// 8..10. The bit-8 transition from 1 -> 0 marks "vertical wrap" --
|
||||
// a fresh frame. Edge-detected per call so caller (UBER, etc.)
|
||||
// just polls; no IRQ server needed.
|
||||
#define AMIGA_VPOSR ((volatile uint16_t *)0xDFF004UL)
|
||||
// Frame counter via a VBL interrupt server (AddIntServer on
|
||||
// INTB_VERTB). Polling VPOSR/VHPOSR is unreliable across chipsets
|
||||
// and OS versions -- the bit positions vary and the polling rate has
|
||||
// to win against the high-bit window per frame, which it doesn't
|
||||
// when the caller's loop body is long. The interrupt server fires
|
||||
// exactly once per VBlank regardless of caller cadence.
|
||||
//
|
||||
// halFrameCount just reads the volatile counter -- no edge detection
|
||||
// needed in the polling path.
|
||||
|
||||
static volatile uint16_t gFrameCount = 0;
|
||||
static struct Interrupt gVblIntServer;
|
||||
static bool gVblInstalled = false;
|
||||
|
||||
// Server protocol: called by the interrupt dispatcher with A1 =
|
||||
// is_Data, A6 = ExecBase. __saveds gives us the libnix data base in
|
||||
// A4 so we can reference gFrameCount through the small-data ABI.
|
||||
// Return Z=0 (non-zero result) to keep the chain going so other
|
||||
// VBL servers further down the priority list still fire.
|
||||
static __saveds ULONG vblServer(void) {
|
||||
gFrameCount = (uint16_t)(gFrameCount + 1u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void installVblServer(void) {
|
||||
if (gVblInstalled) {
|
||||
return;
|
||||
}
|
||||
gVblIntServer.is_Node.ln_Type = NT_INTERRUPT;
|
||||
gVblIntServer.is_Node.ln_Pri = -60;
|
||||
gVblIntServer.is_Node.ln_Name = (char *)"joeyFrameCount";
|
||||
gVblIntServer.is_Data = NULL;
|
||||
gVblIntServer.is_Code = (void (*)())vblServer;
|
||||
AddIntServer(INTB_VERTB, &gVblIntServer);
|
||||
gVblInstalled = true;
|
||||
}
|
||||
|
||||
|
||||
static void removeVblServer(void) {
|
||||
if (!gVblInstalled) {
|
||||
return;
|
||||
}
|
||||
RemIntServer(INTB_VERTB, &gVblIntServer);
|
||||
gVblInstalled = false;
|
||||
}
|
||||
|
||||
static uint16_t gFrameCount = 0;
|
||||
static uint8_t gPrevVbHi = 0;
|
||||
|
||||
uint16_t halFrameCount(void) {
|
||||
uint8_t now;
|
||||
|
||||
/* Bit 0 of the upper byte = scanline bit 8. PAL frame is ~313
|
||||
* lines, NTSC ~263 -- both wrap bit 8 once per frame, which is
|
||||
* what we want as the "frame edge" signal. */
|
||||
now = (uint8_t)((*AMIGA_VPOSR >> 8) & 1u);
|
||||
if (gPrevVbHi && !now) {
|
||||
gFrameCount++;
|
||||
}
|
||||
gPrevVbHi = now;
|
||||
return gFrameCount;
|
||||
}
|
||||
|
||||
|
|
@ -541,6 +580,9 @@ uint16_t halFrameHz(void) {
|
|||
|
||||
|
||||
void halShutdown(void) {
|
||||
// Tear down the VBL server before closing the screen so the
|
||||
// interrupt chain is clean if anything else is watching.
|
||||
removeVblServer();
|
||||
if (gScreen != NULL) {
|
||||
// CloseScreen should free attached UCopList, but be explicit
|
||||
// to catch any case where the screen close path skips it.
|
||||
|
|
|
|||
|
|
@ -323,15 +323,28 @@ void halWaitVBL(void) {
|
|||
// caller (UBER, animation loops) polls fast enough that we never
|
||||
// miss a VBL transition. No IRQ involvement; safe in the S16 takeover
|
||||
// context where ToolBox interrupt setup would be intrusive.
|
||||
//
|
||||
// gFrameCount uses an explicit lda+adc+sta read-modify-write rather
|
||||
// than `gFrameCount++` because ORCA-C lowers the post-increment to
|
||||
// `inc |gFrameCount` (the only INC abs form on 65816 -- there is no
|
||||
// INC long-abs). With this file in the DRAWPRIMS load segment but
|
||||
// halFrameCount called from CORESYS via JSL, DBR isn't pointing at
|
||||
// DRAWPRIMS's data bank, so the abs INC silently mutates the wrong
|
||||
// byte and the counter never advances. The explicit lda > / sta >
|
||||
// pattern uses long-mode addressing throughout, which is
|
||||
// DBR-independent.
|
||||
static uint16_t gFrameCount = 0;
|
||||
static uint8_t gPrevInVbl = 0;
|
||||
|
||||
uint16_t halFrameCount(void) {
|
||||
uint8_t now;
|
||||
uint8_t now;
|
||||
uint16_t cnt;
|
||||
|
||||
now = (*IIGS_VBL_STATUS & VBL_BAR_BIT) == 0;
|
||||
if (now && !gPrevInVbl) {
|
||||
gFrameCount++;
|
||||
cnt = gFrameCount;
|
||||
cnt = (uint16_t)(cnt + 1u);
|
||||
gFrameCount = cnt;
|
||||
}
|
||||
gPrevInVbl = now;
|
||||
return gFrameCount;
|
||||
|
|
|
|||
|
|
@ -322,11 +322,22 @@ static void pollJoystick(void) {
|
|||
|
||||
// Update auto-disconnect counter. Both axes failing => probably no
|
||||
// stick. One resolves => stick is present, reset the counter.
|
||||
//
|
||||
// gJoyConsecutiveTimeouts uses a local-var read-modify-write rather
|
||||
// than `++`. ORCA-C lowers `++` to `inc abs` (the only INC abs form
|
||||
// on 65816), which depends on DBR pointing at this static's bank.
|
||||
// Cross-segment JSL doesn't update DBR, so a caller in a different
|
||||
// load segment would silently mutate the wrong byte. Long-mode
|
||||
// lda+sta is DBR-independent.
|
||||
if (!xResolved && !yResolved) {
|
||||
if (gJoyConsecutiveTimeouts < 0xFFFFu) {
|
||||
gJoyConsecutiveTimeouts++;
|
||||
uint16_t timeouts;
|
||||
|
||||
timeouts = gJoyConsecutiveTimeouts;
|
||||
if (timeouts < 0xFFFFu) {
|
||||
timeouts = (uint16_t)(timeouts + 1u);
|
||||
gJoyConsecutiveTimeouts = timeouts;
|
||||
}
|
||||
if (gJoyConsecutiveTimeouts >= JOY_DISCONNECT_THRESHOLD) {
|
||||
if (timeouts >= JOY_DISCONNECT_THRESHOLD) {
|
||||
gJoyDisconnectLatched = true;
|
||||
}
|
||||
gJoyAxisX[JOYSTICK_0] = 0;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue