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 <string.h>
|
||||||
|
|
||||||
#include <exec/types.h>
|
#include <exec/types.h>
|
||||||
|
#include <exec/interrupts.h>
|
||||||
|
#include <hardware/intbits.h>
|
||||||
#include <intuition/intuition.h>
|
#include <intuition/intuition.h>
|
||||||
#include <intuition/screens.h>
|
#include <intuition/screens.h>
|
||||||
#include <graphics/copper.h>
|
#include <graphics/copper.h>
|
||||||
|
|
@ -45,6 +47,13 @@
|
||||||
|
|
||||||
extern struct Custom custom;
|
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 -----
|
// ----- Constants -----
|
||||||
|
|
||||||
#define AMIGA_BITPLANES 4
|
#define AMIGA_BITPLANES 4
|
||||||
|
|
@ -444,6 +453,7 @@ bool halInit(const JoeyConfigT *config) {
|
||||||
// do nothing -- their palette[0] writes the same COLOR00 once the
|
// do nothing -- their palette[0] writes the same COLOR00 once the
|
||||||
// first LoadRGB4 fires from uploadScbAndPalette.
|
// first LoadRGB4 fires from uploadScbAndPalette.
|
||||||
SetRGB4(&gScreen->ViewPort, 0, 0, 0, 0);
|
SetRGB4(&gScreen->ViewPort, 0, 0, 0, 0);
|
||||||
|
installVblServer();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -509,26 +519,55 @@ void halWaitVBL(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// VPOSR ($DFF004) upper byte: low 3 bits = vertical scanline bits
|
// Frame counter via a VBL interrupt server (AddIntServer on
|
||||||
// 8..10. The bit-8 transition from 1 -> 0 marks "vertical wrap" --
|
// INTB_VERTB). Polling VPOSR/VHPOSR is unreliable across chipsets
|
||||||
// a fresh frame. Edge-detected per call so caller (UBER, etc.)
|
// and OS versions -- the bit positions vary and the polling rate has
|
||||||
// just polls; no IRQ server needed.
|
// to win against the high-bit window per frame, which it doesn't
|
||||||
#define AMIGA_VPOSR ((volatile uint16_t *)0xDFF004UL)
|
// 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) {
|
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;
|
return gFrameCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -541,6 +580,9 @@ uint16_t halFrameHz(void) {
|
||||||
|
|
||||||
|
|
||||||
void halShutdown(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) {
|
if (gScreen != NULL) {
|
||||||
// CloseScreen should free attached UCopList, but be explicit
|
// CloseScreen should free attached UCopList, but be explicit
|
||||||
// to catch any case where the screen close path skips it.
|
// 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
|
// caller (UBER, animation loops) polls fast enough that we never
|
||||||
// miss a VBL transition. No IRQ involvement; safe in the S16 takeover
|
// miss a VBL transition. No IRQ involvement; safe in the S16 takeover
|
||||||
// context where ToolBox interrupt setup would be intrusive.
|
// 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 uint16_t gFrameCount = 0;
|
||||||
static uint8_t gPrevInVbl = 0;
|
static uint8_t gPrevInVbl = 0;
|
||||||
|
|
||||||
uint16_t halFrameCount(void) {
|
uint16_t halFrameCount(void) {
|
||||||
uint8_t now;
|
uint8_t now;
|
||||||
|
uint16_t cnt;
|
||||||
|
|
||||||
now = (*IIGS_VBL_STATUS & VBL_BAR_BIT) == 0;
|
now = (*IIGS_VBL_STATUS & VBL_BAR_BIT) == 0;
|
||||||
if (now && !gPrevInVbl) {
|
if (now && !gPrevInVbl) {
|
||||||
gFrameCount++;
|
cnt = gFrameCount;
|
||||||
|
cnt = (uint16_t)(cnt + 1u);
|
||||||
|
gFrameCount = cnt;
|
||||||
}
|
}
|
||||||
gPrevInVbl = now;
|
gPrevInVbl = now;
|
||||||
return gFrameCount;
|
return gFrameCount;
|
||||||
|
|
|
||||||
|
|
@ -322,11 +322,22 @@ static void pollJoystick(void) {
|
||||||
|
|
||||||
// Update auto-disconnect counter. Both axes failing => probably no
|
// Update auto-disconnect counter. Both axes failing => probably no
|
||||||
// stick. One resolves => stick is present, reset the counter.
|
// 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 (!xResolved && !yResolved) {
|
||||||
if (gJoyConsecutiveTimeouts < 0xFFFFu) {
|
uint16_t timeouts;
|
||||||
gJoyConsecutiveTimeouts++;
|
|
||||||
|
timeouts = gJoyConsecutiveTimeouts;
|
||||||
|
if (timeouts < 0xFFFFu) {
|
||||||
|
timeouts = (uint16_t)(timeouts + 1u);
|
||||||
|
gJoyConsecutiveTimeouts = timeouts;
|
||||||
}
|
}
|
||||||
if (gJoyConsecutiveTimeouts >= JOY_DISCONNECT_THRESHOLD) {
|
if (timeouts >= JOY_DISCONNECT_THRESHOLD) {
|
||||||
gJoyDisconnectLatched = true;
|
gJoyDisconnectLatched = true;
|
||||||
}
|
}
|
||||||
gJoyAxisX[JOYSTICK_0] = 0;
|
gJoyAxisX[JOYSTICK_0] = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue