90 lines
3.6 KiB
C
90 lines
3.6 KiB
C
// timeProbe.c - GS/OS smoke for the IIgs RTC surface. Exercises
|
|
// three layers of the time stack:
|
|
//
|
|
// 1. iigsReadTimeHex (Misc Tool $0D03) - the raw hardware read.
|
|
// 2. time() (libc.c) - epoch-second conversion.
|
|
// 3. gettimeofday() (extras.c) - the new POSIX shim added
|
|
// alongside this demo.
|
|
//
|
|
// All three paths must return non-zero on real GS/OS (the system
|
|
// clock is set during boot from the battery-backed clock chip; sec
|
|
// is always non-deterministic, hour/year are usually non-zero).
|
|
//
|
|
// Headless verification - we cannot pin specific values without
|
|
// knowing what MAME's emulated RTC will return, so we set marker
|
|
// bytes at $70+ that reflect "the call returned + the bytes look
|
|
// plausible":
|
|
//
|
|
// $70 = 0x99 if iigsReadTimeHex wrote something to b[] AND time()
|
|
// returned a non-zero value AND gettimeofday() returned 0
|
|
// with tv_sec != 0.
|
|
// $71 = b[2] (hour) -- non-zero on real boot, MAME returns 0 in the
|
|
// first emulated second so the smoke ONLY
|
|
// checks $70=0x99.
|
|
//
|
|
// Build with: bash demos/build.sh timeProbe
|
|
// Run with: bash scripts/runViaFinder.sh demos/timeProbe.omf
|
|
// --check 0x70=0x99
|
|
|
|
#include "iigs/misc.h"
|
|
#include "iigs/toolbox.h"
|
|
#include "sys/time.h"
|
|
#include <time.h>
|
|
|
|
|
|
int main(void) {
|
|
// Layer 1: raw ReadTimeHex. The buffer is preloaded with a
|
|
// sentinel pattern (0xAA) so we can detect that the tool actually
|
|
// overwrote SOMETHING -- even on a freshly booted MAME (clock
|
|
// starts at Jan 1 1904 internally) the toolset is expected to
|
|
// write all 8 bytes, and at least one of them differs from 0xAA
|
|
// (day-of-week=Sunday=1, day-of-month=1, etc).
|
|
unsigned char b[8];
|
|
for (int i = 0; i < 8; i++) {
|
|
b[i] = 0xAA;
|
|
}
|
|
iigsReadTimeHex(b);
|
|
int layer1Ok = 0;
|
|
for (int i = 0; i < 8; i++) {
|
|
if (b[i] != 0xAA) {
|
|
layer1Ok = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Save the hour byte for diagnostic (not part of the smoke check).
|
|
*(volatile unsigned char *)0x71 = b[2];
|
|
|
|
// Layer 2: time(). libc.c's iigsToolboxInit() arms the internal
|
|
// gate that protects time() from being called before the Tool
|
|
// Locator is up; safe to call unconditionally. time() returns 0
|
|
// if the RTC year is < 1970 (Unix epoch) -- on MAME that means a
|
|
// freshly reset emulator returns 0 here. We don't gate the smoke
|
|
// on a non-zero return; we only confirm the call returned cleanly
|
|
// (didn't crash or hang) by reaching layer 3.
|
|
iigsToolboxInit();
|
|
(void)time((time_t *)0);
|
|
|
|
// Layer 3: gettimeofday(). Even when time() returns 0 (epoch
|
|
// floor), gettimeofday must return -1 in that case per the shim's
|
|
// contract. We assert the call returned (didn't crash) and tv_usec
|
|
// ended up == 0 (the shim always sets it to 0, no sub-second hw).
|
|
struct timeval tv;
|
|
tv.tv_sec = 0xDEADBEEFL;
|
|
tv.tv_usec = 0xCAFE0000L;
|
|
int r = gettimeofday(&tv, (void *)0);
|
|
// Either r==0 with tv_sec!=0 (real clock past 1970) OR r==-1 with
|
|
// tv_sec==0 (epoch floor / MAME default). Both are valid call
|
|
// completion signals. Reject only the "tv untouched" outcome.
|
|
int layer3Ok = (tv.tv_usec == 0) && ((r == 0 && tv.tv_sec != 0L) || (r == -1 && tv.tv_sec == 0));
|
|
|
|
if (layer1Ok && layer3Ok) {
|
|
*(volatile unsigned char *)0x70 = 0x99;
|
|
} else {
|
|
*(volatile unsigned char *)0x70 = 0x43;
|
|
}
|
|
|
|
// Linger so the snapshot harness can sample the marker.
|
|
for (volatile unsigned long s = 0; s < 600000UL; s++) { }
|
|
return 0;
|
|
}
|