ref: f881d4f67254359ef348376e092c779993f57ed6
parent: 2259c436be76e22801766f8cd1a056f5b4430139
author: Jacob Moody <moody@posixcafe.org>
date: Sat Feb 24 09:35:33 EST 2024
games/gba: add rtc GPIO implementation
--- a/sys/man/1/nintendo
+++ b/sys/man/1/nintendo
@@ -28,6 +28,9 @@
.B -s
.I savetype
] [
+.B -g
+.I gpiotype
+] [
.B -x
.I scale
]
@@ -127,6 +130,10 @@
Valid formats and corresponding ids are:
flash512 (SST), flash512mx (Macronix 64K), flash512pan (Panasonic), flash512atm (Atmel),
flash1024 (Macronix 128K), flash1024san (Sanyo).
+.TP
+.B -g
+GPIO hardware used by the original game. The only valid type currently is rtc (real time clock).
+By default, the emulator attempts to automatically detect the GPIO hardware using the game code found in the rom header.
.PP
.B nes
options:
--- a/sys/src/games/gba/dat.h
+++ b/sys/src/games/gba/dat.h
@@ -9,7 +9,7 @@
extern u16int reg[];
extern uchar *rom, *back;
extern int nrom, nback, backup;
-extern int flashid;
+extern int flashid, gpiogame;
extern int hblank, ppuy;
--- a/sys/src/games/gba/fns.h
+++ b/sys/src/games/gba/fns.h
@@ -26,3 +26,10 @@
void loadstate(char *);
void savestate(char *);
void cpuload(void);
+void gpioident(void);
+void gpiowdata(u32int);
+void gpiowdir(u32int);
+void gpiowcontrol(u32int);
+u32int gpiordata(void);
+u32int gpiordir(void);
+u32int gpiorcontrol(void);
--- a/sys/src/games/gba/gba.c
+++ b/sys/src/games/gba/gba.c
@@ -255,7 +255,7 @@
void
usage(void)
{
- fprint(2, "usage: %s [-a] [-s savetype] [-b biosfile] [-x scale] rom\n", argv0);
+ fprint(2, "usage: %s [-a] [-s savetype] [-b biosfile] [-x scale] [-g gpiotype] rom\n", argv0);
exits("usage");
}
@@ -281,6 +281,11 @@
case 'x':
fixscale = strtol(EARGF(usage()), nil, 0);
break;
+ case 'g':
+ s = EARGF(usage());
+ if(strcmp(s, "rtc") == 0)
+ gpiogame = 1;
+ break;
default:
usage();
} ARGEND;
@@ -289,6 +294,7 @@
loadbios();
loadrom(argv[0]);
+ gpioident();
initemu(240, 160, 2, CHAN4(CIgnore, 1, CBlue, 5, CGreen, 5, CRed, 5), 1, nil);
regkey("b", 'z', 1<<1);
regkey("a", 'x', 1<<0);
--- /dev/null
+++ b/sys/src/games/gba/gpio.c
@@ -1,0 +1,173 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "../eui.h"
+#include "dat.h"
+#include "fns.h"
+
+int gpiogame;
+static int gpioen;
+static int rtcclk;
+static uchar rtcdata, rtcout;
+static int rtccount;
+static uchar pinstate[3] = { 1, 1, 1 };
+
+enum {
+ RCLK=1<<0,
+ RSIO=1<<1,
+ RCS=1<<2,
+
+ PCLK=0,
+ PSIO=1,
+ PCS=2,
+};
+
+void
+gpioident(void)
+{
+ char code[4];
+
+ memcpy(code, rom+0xAC, 4);
+
+ /* Pokemon E/S/R. RTC only */
+ if(memcmp(code, "BPEE", 4) == 0
+ || memcmp(code, "AXPE", 4) == 0
+ || memcmp(code, "AXVE", 4) == 0)
+ gpiogame = 1;
+
+}
+
+#define BCD(x) (x/10 * 16 + x%10)
+
+static void
+getdate(uchar out[7])
+{
+ static Tzone *zone;
+ static Tm date;
+
+ if(zone == nil)
+ zone = tzload("local");
+ tmnow(&date, zone);
+ date.year -= 100;
+ date.mon++;
+ out[0] = BCD(date.year);
+ out[1] = BCD(date.mon);
+ out[2] = BCD(date.mday);
+ out[3] = BCD(date.wday);
+ out[4] = BCD(date.hour);
+ out[5] = BCD(date.min);
+ out[6] = BCD(date.sec);
+}
+
+// https://html.alldatasheet.com/html-pdf/80559/SII/S-3511/45/1/S-3511.html
+static void
+rtcstate(void)
+{
+ enum { CMD, STATUS, DATETIME };
+ static int state = CMD;
+ enum { WR=0, RD=1 };
+ static int dir = WR;
+ static int datetimepos = 0;
+ static uchar date[7];
+
+ uchar cmd;
+
+ switch(state){
+ case CMD:
+ dir = rtcdata&1;
+ if((rtcdata&0xF0) != 0x60){
+ print("wrong rtc state: %X\n", rtcdata);
+ return;
+ }
+ cmd = (rtcdata&0xF)>>1;
+ switch(cmd){
+ case 0: /* reset */
+ break;
+ case 1: /* status */
+ if(dir == RD)
+ rtcdata = 0b01000000;
+ state = STATUS;
+ break;
+ case 2: /* year → seconds */
+ case 3: /* hour → seconds */
+ getdate(date);
+ datetimepos = (cmd-2)<<2;
+ if(dir == RD)
+ rtcdata = date[datetimepos];
+ datetimepos++;
+ state = DATETIME;
+ break;
+ default:
+ print("unsupported rtc cmd: %d %d\n", dir, cmd);
+ rtcdata = 0;
+ break;
+ }
+ break;
+ case STATUS:
+ state = CMD;
+ if(dir == WR)
+ rtcdata = 0;
+ break;
+ case DATETIME:
+ if(dir == RD)
+ rtcdata = date[datetimepos];
+ else
+ rtcdata = 0;
+ if(++datetimepos == 8){
+ datetimepos = 0;
+ state = CMD;
+ }
+ break;
+ }
+}
+
+void
+gpiowdata(u32int v)
+{
+ if((v&RCLK) == 0 && rtcclk == 1){
+ if(pinstate[PSIO] == 1){
+ rtcdata |= ((v&RSIO)>>1)<<(7-rtccount);
+ } else {
+ rtcout = rtcdata&1;
+ rtcdata >>= 1;
+ }
+ rtccount++;
+ }
+ if(rtccount == 8){
+ rtcstate();
+ rtccount = 0;
+ }
+ rtcclk = v&RCLK;
+}
+
+u32int
+gpiordata(void)
+{
+ return rtcout<<1;
+}
+
+void
+gpiowdir(u32int v)
+{
+ pinstate[PCLK] = v&1;
+ pinstate[PSIO] = (v&2)>>1;
+ pinstate[PCS] = (v&4)>>2;
+}
+
+u32int
+gpiordir(void)
+{
+ return (pinstate[PCS]<<2) | (pinstate[PSIO]<<1) | (u32int)pinstate[PCLK];
+}
+
+void
+gpiowcontrol(u32int v)
+{
+ gpioen = v;
+}
+
+u32int
+gpiorcontrol(void)
+{
+ return gpioen;
+}
--- a/sys/src/games/gba/mem.c
+++ b/sys/src/games/gba/mem.c
@@ -263,7 +263,21 @@
b = a & sizeof(oam) - 1;
cyc++;
return ar16read(oam + b/2, b & 1, n);
- case 8: case 9: case 10: case 11: case 12: case 13:
+ case 8:
+ if(!gpiogame)
+ goto Rom;
+ b = a & 0xffffff;
+ switch(b){
+ case 0xC4:
+ return gpiordata();
+ case 0xC6:
+ return gpiordir();
+ case 0xC8:
+ return gpiorcontrol();
+ }
+ /* fallthrough */
+ case 9: case 10: case 11: case 12: case 13:
+ Rom:
b = a & 0x1ffffff;
cyc += waitst[(a >> 25) - 4 | seq << 2 | (n > 2) << 3];
if(b >= nrom){
@@ -290,7 +304,7 @@
void
memwrite(u32int a, u32int v, int n)
{
- u32int b;
+ u32int b, t;
assert((a & n-1) == 0);
switch(a >> 24){
@@ -342,7 +356,29 @@
if(n != 1)
ar16write(oam + b/2, b & 1, v, n);
return;
- case 8: case 9: case 10: case 11: case 12: case 13:
+ case 8:
+ if(!gpiogame)
+ goto Rom;
+ b = a & 0xffffff;
+ switch(b){
+ case 0xC4:
+ t = v&0xFFFF;
+ gpiowdata(t);
+ if(n <= 2)
+ return;
+ v>>=16;
+ case 0xC6:
+ t = v&0xFFFF;
+ gpiowdir(t);
+ return;
+ case 0xC8:
+ t = v&0xFFFF;
+ gpiowcontrol(t);
+ return;
+ }
+ /* fallthrough */
+ case 9: case 10: case 11: case 12: case 13:
+ Rom:
if(backup == EEPROM){
b = a & 0x01ffffff;
if(b >= eepstart)
--- a/sys/src/games/gba/mkfile
+++ b/sys/src/games/gba/mkfile
@@ -11,6 +11,7 @@
apu.$O\
state.$O\
eui.$O\
+ gpio.$O\
HFILES=dat.h fns.h