mirror of
git://git.9front.org/plan9front/plan9front
synced 2025-01-12 11:10:06 +00:00
games/gba: add rtc GPIO implementation
This commit is contained in:
parent
2259c436be
commit
f881d4f672
7 changed files with 235 additions and 5 deletions
|
@ -28,6 +28,9 @@ gb, gba, nes, snes \- emulators
|
|||
.B -s
|
||||
.I savetype
|
||||
] [
|
||||
.B -g
|
||||
.I gpiotype
|
||||
] [
|
||||
.B -x
|
||||
.I scale
|
||||
]
|
||||
|
@ -127,6 +130,10 @@ Some roms require a specific flash device id which may need to be set manually f
|
|||
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:
|
||||
|
|
|
@ -9,7 +9,7 @@ extern u16int pram[], oam[];
|
|||
extern u16int reg[];
|
||||
extern uchar *rom, *back;
|
||||
extern int nrom, nback, backup;
|
||||
extern int flashid;
|
||||
extern int flashid, gpiogame;
|
||||
|
||||
extern int hblank, ppuy;
|
||||
|
||||
|
|
|
@ -26,3 +26,10 @@ void sndwrite(u16int, u16int);
|
|||
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);
|
||||
|
|
|
@ -255,7 +255,7 @@ flush(void)
|
|||
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 @@ threadmain(int argc, char **argv)
|
|||
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 @@ threadmain(int argc, char **argv)
|
|||
|
||||
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);
|
||||
|
|
173
sys/src/games/gba/gpio.c
Normal file
173
sys/src/games/gba/gpio.c
Normal file
|
@ -0,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;
|
||||
}
|
|
@ -263,7 +263,21 @@ memread(u32int a, int n, int seq)
|
|||
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 @@ memread(u32int a, int n, int seq)
|
|||
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 @@ memwrite(u32int a, u32int v, int n)
|
|||
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)
|
||||
|
|
|
@ -11,6 +11,7 @@ OFILES=\
|
|||
apu.$O\
|
||||
state.$O\
|
||||
eui.$O\
|
||||
gpio.$O\
|
||||
|
||||
HFILES=dat.h fns.h
|
||||
|
||||
|
|
Loading…
Reference in a new issue