diff options
author | aiju <devnull@localhost> | 2015-04-01 16:17:17 +0200 |
---|---|---|
committer | aiju <devnull@localhost> | 2015-04-01 16:17:17 +0200 |
commit | edfdc4ac07fe2748b72d36ea455876907227c4c3 (patch) | |
tree | db91323d23fc9d170cb4cafc7f3aec781adcd9a1 /sys/src/games | |
parent | 0b001e265cac185947c0b0c919dbab6afec2f72c (diff) |
new games/gb: better emulation and gbc support
Diffstat (limited to 'sys/src/games')
-rw-r--r-- | sys/src/games/gb/apu.c | 382 | ||||
-rw-r--r-- | sys/src/games/gb/audio.c | 231 | ||||
-rw-r--r-- | sys/src/games/gb/cpu.c | 1114 | ||||
-rw-r--r-- | sys/src/games/gb/daa.c | 465 | ||||
-rw-r--r-- | sys/src/games/gb/dat.h | 205 | ||||
-rw-r--r-- | sys/src/games/gb/disasm.c | 811 | ||||
-rw-r--r-- | sys/src/games/gb/ev.c | 122 | ||||
-rw-r--r-- | sys/src/games/gb/fns.h | 33 | ||||
-rw-r--r-- | sys/src/games/gb/gb.c | 642 | ||||
-rw-r--r-- | sys/src/games/gb/mem.c | 681 | ||||
-rw-r--r-- | sys/src/games/gb/mkfile | 7 | ||||
-rw-r--r-- | sys/src/games/gb/ppu.c | 465 | ||||
-rw-r--r-- | sys/src/games/gb/state.c | 219 |
13 files changed, 2415 insertions, 2962 deletions
diff --git a/sys/src/games/gb/apu.c b/sys/src/games/gb/apu.c new file mode 100644 index 000000000..007a1612f --- /dev/null +++ b/sys/src/games/gb/apu.c @@ -0,0 +1,382 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include "dat.h" +#include "fns.h" + +Event evsamp, evenv; +s16int sbuf[2*4000], *sbufp; +enum { + Freq = 44100, + SRATEDIV = 8388608 / Freq, + ENVDIV = 8388608 / 512 +}; +static int fd; + +u16int envmod; +u8int sweepen, sweepctr; +u16int sweepfreq; +typedef struct chan chan; +struct chan { + u8int n, ectr; + u16int len; + u8int *env, *freq; + u16int fctr, fthr; + u32int finc; + u8int vol; +}; +u8int wave[32]; +u8int wpos; +u16int lfsr; + +chan sndch[4] = { + { + .n = 0, + .env = reg + NR12, + .freq = reg + NR14, + }, + { + .n = 1, + .env = reg + NR22, + .freq = reg + NR24, + }, + { + .n = 2, + }, + { + .n = 3, + .env = reg + NR42, + .freq = reg + NR44, + } +}; + +Var apuvars[] = { + VAR(envmod), VAR(sweepen), + VAR(sweepctr), VAR(sweepfreq), ARR(wave), VAR(wpos), VAR(lfsr), + VAR(sndch[0].ectr), VAR(sndch[0].len), VAR(sndch[0].fctr), VAR(sndch[0].fthr), VAR(sndch[0].finc), VAR(sndch[0].vol), + VAR(sndch[1].ectr), VAR(sndch[1].len), VAR(sndch[1].fctr), VAR(sndch[1].fthr), VAR(sndch[1].finc), VAR(sndch[1].vol), + VAR(sndch[2].ectr), VAR(sndch[2].len), VAR(sndch[2].fctr), VAR(sndch[2].fthr), VAR(sndch[2].finc), VAR(sndch[2].vol), + VAR(sndch[3].ectr), VAR(sndch[3].len), VAR(sndch[3].fctr), VAR(sndch[3].fthr), VAR(sndch[3].finc), VAR(sndch[3].vol), + {nil, 0, 0}, +}; + +void +rate(int i, u16int v) +{ + switch(i){ + case 0: case 1: + sndch[i].finc = 131072ULL * 65536 / (Freq * (2048 - (v & 0x7ff))); + break; + case 2: + sndch[2].finc = 2097152ULL * 65536 / (Freq * (2048 - (v & 0x7ff))); + break; + case 3: + sndch[3].finc = 524288ULL * 65536 / Freq; + if((v & 7) != 0) + sndch[3].finc /= v & 7; + else + sndch[3].finc <<= 1; + sndch[3].finc >>= (v >> 4 & 15) + 1; + } +} + +void +env(chan *c) +{ + if((envmod & 1) == 0 && c->len > 0 && (*c->freq & 1<<6) != 0) + --c->len; + if(c->len == 0){ + c->vol = 0; + return; + } + if((envmod & 7) != 7 || c->ectr == 0 || --c->ectr != 0) + return; + c->ectr = *c->env & 7; + if((*c->env & 1<<3) != 0){ + if(c->vol < 15) + c->vol++; + }else + if(c->vol > 0) + c->vol--; +} + +s8int +wavesamp(void) +{ + s8int x; + int v; + + sndch[2].fctr = v = sndch[2].fctr + sndch[2].finc; + if(sndch[2].len == 0 || (reg[NR30] & 1<<7) == 0) + return 0; + for(;;){ + x = wave[wpos]; + v -= 0x10000; + if(v < 0) + break; + wpos = wpos + 1 & 31; + } + if((reg[NR32] & 3<<5) == 0) + x = 0; + else + x = x >> (reg[NR32] >> 5 & 3) - 1; + return x; +} + +s8int +lfsrsamp(void) +{ + int v; + u16int l; + + sndch[3].fctr = v = sndch[3].fctr + sndch[3].finc; + for(;;){ + l = lfsr; + v -= 0x10000; + if(v < 0) + break; + lfsr >>= 1; + if(((l ^ lfsr) & 1) != 0) + if((reg[0x7c/2] & 1<<3) != 0) + lfsr |= 0x40; + else + lfsr |= 0x4000; + } + if((l & 1) != 0) + return -sndch[3].vol; + else + return sndch[3].vol; +} + +void +sweep(int wb) +{ + u16int fr; + int d; + u16int cnt; + + cnt = reg[NR10]; + d = sweepfreq >> (cnt & 7); + if((cnt & 1<<3) != 0) + d = -d; + fr = sweepfreq + d; + if(fr > 2047){ + sndch[0].len = 0; + sndch[0].vol = 0; + sweepen = 0; + }else if(wb){ + sweepfreq = fr; + reg[NR13] = fr; + reg[NR14] = reg[NR14] & 0xf8 | fr >> 8; + rate(0, fr); + sweep(0); + } +} + +void +sndstart(chan *c, u16int v) +{ + u8int cnt; + + c->vol = *c->env >> 4; + c->ectr = *c->env & 7; + if(c->len == 0) + c->len = 64; + if(c == sndch){ + cnt = reg[NR10]; + sweepen = (cnt & 0x07) != 0 && (cnt & 0x70) != 0; + sweepctr = cnt >> 4 & 7; + sweepfreq = v & 0x7ff; + if((cnt & 0x07) != 0) + sweep(0); + } +} + +void +envtick(void *) +{ + addevent(&evenv, ENVDIV); + + env(&sndch[0]); + env(&sndch[1]); + if((envmod & 1) == 0 && sndch[2].len > 0 && (reg[NR34] & 0x40) != 0) + sndch[2].len--; + env(&sndch[3]); + if((envmod & 3) == 2 && sweepen && --sweepctr == 0){ + sweepctr = reg[NR10] >> 4 & 7; + sweep(1); + } + envmod++; +} + +void +sampletick(void *) +{ + u8int cntl, cnth; + s16int ch[4]; + s16int s[2]; + int i; + + addevent(&evsamp, SRATEDIV); + + sndch[0].fctr += sndch[0].finc; + if(sndch[0].fctr >= sndch[0].fthr) + ch[0] = sndch[0].vol; + else + ch[0] = -sndch[0].vol; + sndch[1].fctr += sndch[1].finc; + if(sndch[1].fctr >= sndch[1].fthr) + ch[1] = sndch[1].vol; + else + ch[1] = -sndch[1].vol; + ch[2] = wavesamp(); + ch[3] = lfsrsamp(); + + cntl = reg[NR50]; + cnth = reg[NR51]; + s[0] = 0; + s[1] = 0; + for(i = 0; i < 4; i++){ + if((cnth & 1<<i) != 0) + s[1] += ch[i] * (1 + (cntl & 7)); + if((cnth & 1<<4<<i) != 0) + s[0] += ch[i] * (1 + (cntl >> 4 & 7)); + } + if(s[0] < -0x200) s[0] = -0x200; + else if(s[0] > 0x1ff) s[0] = 0x1ff; + if(s[1] < -0x200) s[1] = -0x200; + else if(s[1] > 0x1ff) s[1] = 0x1ff; + + if(sbufp < sbuf + nelem(sbuf)){ + sbufp[0] = s[0] << 6; + sbufp[1] = s[1] << 6; + sbufp += 2; + } +} + +void +sndwrite(u8int a, u8int v) +{ + static u16int thr[4] = {0x2000, 0x4000, 0x8000, 0xC000}; + + if((reg[NR52] & 0x80) == 0 && a != NR52) + return; + switch(a){ + case NR11: + sndch[0].fthr = thr[v >> 6 & 3]; + sndch[0].len = 64 - (v & 63); + break; + case NR13: + rate(0, reg[NR14] << 8 & 0x700 | v); + break; + case NR14: + rate(0, v << 8 & 0x700 | reg[NR13]); + if((v & 1<<7) != 0) + sndstart(&sndch[0], v); + break; + case NR21: + sndch[1].fthr = thr[v >> 6 & 3]; + break; + case NR23: + rate(1, reg[NR24] << 8 & 0x700 | v); + break; + case NR24: + rate(1, v << 8 & 0x700 | reg[NR23]); + if((v & 1<<7) != 0) + sndstart(&sndch[1], v); + break; + case NR30: + if((v & 1<<7) != 0 && sndch[2].len == 0) + sndch[2].len = 256; + break; + case NR31: + sndch[2].len = 256 - (v & 0xff); + break; + case NR33: + rate(2, reg[NR34] << 8 & 0x700 | v); + break; + case NR34: + rate(2, v << 8 & 0x700 | reg[NR33]); + break; + case NR43: + rate(3, v); + break; + case NR44: + if((v & 1<<7) != 0){ + if((reg[NR43] & 1<<3) != 0) + lfsr = 0x7f; + else + lfsr = 0x7fff; + sndstart(&sndch[3], v); + } + break; + case NR52: + if((v & 0x80) == 0){ + memset(reg + NR10, 0, NR52 - NR10); + sndch[0].len = 0; + sndch[1].len = 0; + sndch[2].len = 0; + sndch[3].len = 0; + } + } +} + +int +apuread(void) +{ + u8int v; + + v = reg[NR52] & 0xf0; + if(sndch[0].len != 0) v |= 1; + if(sndch[1].len != 0) v |= 2; + if(sndch[2].len != 0) v |= 4; + if(sndch[3].len != 0) v |= 8; + return v; +} + +u8int +waveread(u8int a) +{ + a <<= 1; + return wave[a + wpos & 31] << 4 | wave[a + wpos + 1 & 31]; +} + +void +wavewrite(u8int a, u8int v) +{ + a <<= 1; + wave[a + wpos & 31] = v >> 4; + wave[a + wpos + 1 & 31] = v & 0x0f; +} + +void +audioinit(void) +{ + fd = open("/dev/audio", OWRITE); + if(fd < 0) + sysfatal("open: %r"); + sbufp = sbuf; + evsamp.f = sampletick; + addevent(&evsamp, SRATEDIV); + evenv.f = envtick; + addevent(&evenv, ENVDIV); +} + +int +audioout(void) +{ + int rc; + static int cl; + + if(sbufp == nil) + return -1; + if(sbufp == sbuf) + return 0; + cl = clock; + rc = write(fd, sbuf, (sbufp - sbuf) * 2); + if(rc > 0) + sbufp -= (rc+1)/2; + if(sbufp < sbuf) + sbufp = sbuf; + return 0; +} diff --git a/sys/src/games/gb/audio.c b/sys/src/games/gb/audio.c deleted file mode 100644 index 4ee36457d..000000000 --- a/sys/src/games/gb/audio.c +++ /dev/null @@ -1,231 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <thread.h> -#include <draw.h> -#include "dat.h" -#include "fns.h" - -static int fd; -static int sc, ch1c, ch2c, ch3c, ch4c, ch4sr = 1, ch1vec, ch2vec, ch4vec, ch1v, ch2v, ch4v; -extern int paused; - -static short sbuf[2*2000], *sbufp; - -static int -thresh(int f, int b) -{ - switch(b){ - case 0: return f/8; - case 1: return f/4; - case 2: return f/2; - default: return 3*f/4; - } -} - -static int -freq(int lower) -{ - int f; - - f = mem[lower+1] & 7; - f = (f << 8) | mem[lower]; - f = muldiv(2048 - f, SAMPLE, 131072); - return f; -} - -static void -soundlen(int len, int ctrl, int n) -{ - if(mem[ctrl] & 128){ - mem[0xFF26] |= (1<<n); - mem[ctrl] &= ~128; - switch(n){ - case 0: - ch1v = mem[0xFF12]; - break; - case 1: - ch2v = mem[0xFF17]; - break; - case 3: - ch4v = mem[0xFF21]; - break; - } - } - if((mem[ctrl] & 64) == 0){ - mem[0xFF26] |= (1<<n); - return; - } - if((mem[0xFF26] & (1<<n)) == 0) - return; - if(mem[len] == ((n == 2) ? 255 : 63)){ - mem[0xFF26] &= ~(1<<n); - return; - } - mem[len]++; -} - -static void -envelope(int *v, int *c) -{ - int f; - - f = (*v & 7) * SAMPLE / 64; - if(f == 0) - return; - if(*c >= f){ - if(*v & 8){ - if((*v >> 4) < 0xF) - *v += 0x10; - }else - if((*v >> 4) > 0) - *v -= 0x10; - *c = 0; - } - (*c)++; -} - -void -audiosample(void) -{ - int ch1s, ch2s, ch3s, ch4s, ch1f, ch2f, ch3f, ch4f, k, r, s; - u8int f; - - if(sbufp == nil) - return; - if(sc >= SAMPLE/256){ - soundlen(0xFF11, 0xFF14, 0); - soundlen(0xFF16, 0xFF19, 1); - soundlen(0xFF1B, 0xFF1E, 2); - soundlen(0xFF20, 0xFF23, 3); - sc = 0; - } - sc++; - envelope(&ch1v, &ch1vec); - envelope(&ch2v, &ch2vec); - envelope(&ch4v, &ch4vec); - - ch1f = freq(0xFF13); - if(ch1c >= ch1f) - ch1c = 0; - if(ch1c >= thresh(ch1f, mem[0xFF11] >> 6)) - ch1s = 1; - else - ch1s = -1; - ch1s *= ch1v >> 4; - ch1s *= 8000 / 0xF; - ch1c++; - - ch2f = freq(0xFF18); - if(ch2c >= ch2f) - ch2c = 0; - if(ch2c >= thresh(ch1f, mem[0xFF16] >> 6)) - ch2s = 1; - else - ch2s = -1; - ch2s *= ch2v >> 4; - ch2s *= 8000 / 0xF; - ch2c++; - - ch3f = freq(0xFF1D) * 100 / 32; - if(ch3f == 0) - ch3f = 1; - ch3s = 0; - if(mem[0xFF1A] & 0x80){ - if(ch3c >= freq(0xFF1D)) - ch3c = 0; - k = ch3c * 100 / ch3f; - ch3s = mem[0xFF30 + (k >> 1)]; - if(k & 1) - ch3s &= 0xF; - else - ch3s >>= 4; - switch(mem[0xFF1C]){ - case 0: - ch3s = 0; - break; - case 2: - ch3s >>= 1; - break; - case 3: - ch3s >>= 2; - break; - } - ch3s *= 8000 / 0xF; - ch3c++; - } - - r = mem[0xFF22] & 7; - s = mem[0xFF22] >> 4; - if(r != 0) - ch4f = 524288 / r; - else - ch4f = 524288 * 2; - ch4f >>= s+1; - if(ch4f == 0) - ch4f = 1; - ch4f = SAMPLE / ch4f; - if(ch4c >= ch4f){ - ch4sr <<= 1; - if(mem[0xFF22] & 4) - k = ((ch4sr >> 6) ^ (ch4sr >> 7)) & 1; - else - k = ((ch4sr >> 14) ^ (ch4sr >> 15)) & 1; - ch4sr |= k; - ch4c = 0; - } - ch4c++; - if(ch4sr & 1) - ch4s = -1; - else - ch4s = 1; - ch4s *= ch4v >> 4; - ch4s *= 8000 / 0xF; - - f = mem[0xFF25]; - r = mem[0xFF26] & 15; - r = r | (r << 4); - f &= r; - if(sbufp < sbuf + nelem(sbuf) - 1){ - *sbufp = 0; - if(f & 0x01) *sbufp += ch1s; - if(f & 0x02) *sbufp += ch2s; - if(f & 0x04) *sbufp += ch3s; - if(f & 0x08) *sbufp += ch4s; - *++sbufp = 0; - if(f & 0x10) *sbufp += ch1s; - if(f & 0x20) *sbufp += ch2s; - if(f & 0x40) *sbufp += ch3s; - if(f & 0x80) *sbufp += ch4s; - sbufp++; - } -} - -int -audioout(void) -{ - int rc; - - if(sbufp == nil) - return -1; - if(sbufp == sbuf) - return 0; - rc = write(fd, sbuf, (sbufp - sbuf) * 2); - if(rc > 0) - sbufp -= (rc+1)/2; - if(sbufp < sbuf) - sbufp = sbuf; - return 0; -} - -void -initaudio(void) -{ - mem[0xFF26] = 0xF; - ch1v = 0xF0; - ch2v = 0xF0; - ch4v = 0xF0; - fd = open("/dev/audio", OWRITE); - if(fd < 0) - return; - sbufp = sbuf; -} diff --git a/sys/src/games/gb/cpu.c b/sys/src/games/gb/cpu.c index 315cf1336..88900ea0b 100644 --- a/sys/src/games/gb/cpu.c +++ b/sys/src/games/gb/cpu.c @@ -1,21 +1,25 @@ #include <u.h> #include <libc.h> #include <thread.h> -#include <draw.h> #include "dat.h" #include "fns.h" -#define lohi(L, H) (((u16int)L) | (((u16int)H) << 8)) +u8int r[8], ime; +u16int pc, curpc, sp; +int halt, trace; -u8int R[8], Fl; -u16int pc, sp, curpc; -int halt, IME; +enum { + FLAGC = 0x10, + FLAGH = 0x20, + FLAGN = 0x40, + FLAGZ = 0x80 +}; +enum { rB, rC, rD, rE, rH, rL, rHL, rA, rF = rHL }; +#define BC() (r[rB] << 8 | r[rC]) +#define DE() (r[rD] << 8 | r[rE]) +#define HL() (r[rH] << 8 | r[rL]) -static void -invalid(void) -{ - sysfatal("invalid instruction %.2x (pc = %.4x)", memread(curpc), curpc); -} +Var cpuvars[] = { ARR(r), VAR(ime), VAR(pc), VAR(curpc), VAR(sp), VAR(halt), {nil, 0, 0} }; static u8int fetch8(void) @@ -26,24 +30,23 @@ fetch8(void) static u16int fetch16(void) { - u16int r; + u16int u; - r = lohi(memread(pc), memread(pc+1)); - pc += 2; - return r; + u = memread(pc++); + return u | memread(pc++) << 8; } static void -push8(u8int n) +push8(u8int u) { - memwrite(--sp, n); + memwrite(--sp, u); } static void -push16(u16int n) +push16(u16int u) { - memwrite(--sp, n >> 8); - memwrite(--sp, n); + memwrite(--sp, u >> 8); + memwrite(--sp, u); } static u8int @@ -55,792 +58,497 @@ pop8(void) static u16int pop16(void) { - u8int a, b; + u16int v; - b = pop8(); - a = pop8(); - return lohi(b, a); + v = memread(sp++); + return v | memread(sp++) << 8; } -static int -ld01(u8int op) +static u16int +read16(u16int n) { - u8int val, a, b; - int time; - - a = (op & 0x38) >> 3; - b = op & 7; - time = 4; - if(a == rHL && b == rHL){ - halt = 1; - return 4; - } - if(b == rHL){ - val = memread(lohi(R[rL], R[rH])); - time = 8; - }else{ - val = R[b]; - } - if(a == rHL){ - memwrite(lohi(R[rL], R[rH]), val); - time = 8; - }else{ - R[a] = val; - } - return time; + return memread(n) | memread(n+1) << 8; } -static int -ldi(u8int op) +static void +write16(u16int n, u16int v) { - u8int val, a; - - val = fetch8(); - a = (op & 0x38) >> 3; - if(a == rHL){ - memwrite(lohi(R[rL], R[rH]), val); - return 12; - }else{ - R[a] = val; - return 8; - } + memwrite(n++, v); + memwrite(n, v >> 8); } static int -ld16(u8int op) +move(u8int dst, u8int src) { - u16int val; - u8int a; - - val = fetch16(); - a = (op & 0x30) >> 4; - switch(a){ - case 0: - R[rB] = val >> 8; - R[rC] = val; - break; - case 1: - R[rD] = val >> 8; - R[rE] = val; - break; - case 2: - R[rH] = val >> 8; - R[rL] = val; - break; - case 3: - sp = val; - break; + if(dst == rHL){ + if(src == rHL){ + halt = 1; + return 4; + } + memwrite(HL(), r[src]); + return 8; } - return 12; -} - -static int -add16(u8int op) -{ - u16int val1, val2; - u8int a; - u32int val32; - - a = (op & 0x30) >> 4; - switch(a){ - case 0: - val1 = lohi(R[rC], R[rB]); - break; - case 1: - val1 = lohi(R[rE], R[rD]); - break; - case 2: - val1 = lohi(R[rL], R[rH]); - break; - default: - val1 = sp; + if(src == rHL){ + r[dst] = memread(HL()); + return 8; } - Fl &= FLAGZ; - val2 = lohi(R[rL], R[rH]); - val32 = (u32int)(val1) + (u32int)(val2); - if(val32 > 0xFFFF) - Fl |= FLAGC; - if(((val1&0xFFF)+(val2&0xFFF)) > 0xFFF) - Fl |= FLAGH; - R[rL] = val32; - R[rH] = val32 >> 8; - return 8; + r[dst] = r[src]; + return 4; } static int -ldin(u8int op) +alu(u8int op, u8int n) { - u16int addr; + u8int v4; + u8int u; + u16int v; + int t; - switch(op >> 4){ - case 0: - addr = lohi(R[rC], R[rB]); - break; - case 1: - addr = lohi(R[rE], R[rD]); + switch(n){ + case 8: u = fetch8(); t = 8; break; + case rHL: + u = memread(HL()); + t = 8; break; default: - addr = lohi(R[rL], R[rH]); - } - if(op & 8){ - R[rA] = memread(addr); - }else{ - memwrite(addr, R[rA]); - } - if((op >> 4) > 1){ - if(op & 16) - addr--; - else - addr++; - R[rL] = addr; - R[rH] = addr >> 8; + u = r[n]; + t = 4; } - return 8; -} - -static int -inc16(u8int op) -{ - u16int val; - u8int a; - - a = (op & 0x38) >> 3; - switch(a >> 1){ - case 0: - val = lohi(R[rC], R[rB]); - break; - case 1: - val = lohi(R[rE], R[rD]); - break; - case 2: - val = lohi(R[rL], R[rH]); - break; + v4 = 0; + switch(op){ default: - val = sp; - } - if(a & 1) - val--; - else - val++; - switch(a >> 1){ - case 0: - R[rB] = val >> 8; - R[rC] = val; + v4 = (r[rA] & 0x0f) + (u & 0x0f); + v = r[rA] + u; break; case 1: - R[rD] = val >> 8; - R[rE] = val; + v4 = (r[rA] & 0x0f) + (u & 0x0f) + (r[rF] >> 4 & 1); + v = r[rA] + u + (r[rF] >> 4 & 1); break; case 2: - R[rH] = val >> 8; - R[rL] = val; + case 7: + v4 = (r[rA] & 0x0f) + (~u & 0x0f) + 1; + v = r[rA] + (u ^ 0xff) + 1; break; - default: - sp = val; + case 3: + v4 = (r[rA] & 0x0f) + (~u & 0x0f) + (~r[rF] >> 4 & 1); + v = r[rA] + (u ^ 0xff) + (~r[rF] >> 4 & 1); + break; + case 4: v = r[rA] & u; break; + case 5: v = r[rA] ^ u; break; + case 6: v = r[rA] | u; break; } - return 8; + r[rF] = 0; + if((u8int)v == 0) + r[rF] |= FLAGZ; + if(op < 2){ + if((v & 0x100) != 0) + r[rF] |= FLAGC; + if((v4 & 0x10) != 0) + r[rF] |= FLAGH; + }else if(op < 4 || op == 7){ + r[rF] |= FLAGN; + if((v & 0x100) == 0) + r[rF] |= FLAGC; + if((v4 & 0x10) == 0) + r[rF] |= FLAGH; + }else + if(op == 4) + r[rF] |= FLAGH; + if(op != 7) + r[rA] = v; + return t; } static int -inc8(u8int op) +branch(int cc, int t) { - u8int val, a; - int time; + u16int v; - a = (op & 0x38) >> 3; - if(a == rHL){ - val = memread(lohi(R[rL], R[rH])); - time = 12; - }else{ - val = R[a]; - time = 4; - } - if(a == rHL){ - memwrite(lohi(R[rL], R[rH]), val+1); - }else{ - R[a] = val + 1; - } - Fl &= FLAGC; - if(val == 0xFF) - Fl |= FLAGZ; - if((val & 0xF) == 0xF) - Fl |= FLAGH; - return time; + v = (s8int)fetch8(); + if(!cc) + return t + 8; + pc += v; + return t + 12; } -static int -dec8(u8int op) +static u8int +inc(u8int v) { - u8int val, a; - int time; - - a = (op & 0x38) >> 3; - if(a == rHL){ - val = memread(lohi(R[rL], R[rH])); - time = 12; - }else{ - val = R[a]; - time = 4; - } - if(a == rHL){ - memwrite(lohi(R[rL], R[rH]), val - 1); - }else{ - R[a] = val - 1; - } - Fl = (Fl & FLAGC) | FLAGN; - if(val == 1) - Fl |= FLAGZ; - if((val & 0xF) == 0) - Fl |= FLAGH; - return time; + r[rF] &= FLAGC; + ++v; + if(v == 0) + r[rF] |= FLAGZ; + if((v & 0xf) == 0) + r[rF] |= FLAGH; + return v; } -static int -alu(u8int op) +static u8int +dec(u8int v) { - u8int val4, val8, a, b; - short val16; - int time; - - a = op & 7; - b = (op & 0x38) >> 3; - if((op >> 6) == 3){ - val8 = fetch8(); - time = 8; - }else if(a == rHL){ - val8 = memread(lohi(R[rL], R[rH])); - time = 8; - }else{ - val8 = R[a]; - time = 4; - } - switch(b){ - case 0: - case 1: - val16 = (ushort)(R[rA]) + (ushort)(val8); - val4 = (R[rA] & 0xF) + (val8 & 0xF); - if(b == 1 && (Fl & FLAGC)){ - val16++; - val4++; - } - Fl = 0; - val8 = val16; - if(val16 >= 0x100) - Fl |= FLAGC; - if(val4 >= 0x10) - Fl |= FLAGH; - break; - case 2: - case 3: - case 7: - val16 = (ushort)R[rA]; - val16 -= (ushort)val8; - val4 = val8 & 0xF; - if(b == 3 && (Fl & FLAGC)){ - val16--; - val4++; - } - val8 = val16; - Fl = FLAGN; - if(val16 < 0) - Fl |= FLAGC; - if(val4 > (R[rA] & 0xF)) - Fl |= FLAGH; - break; - case 4: - val8 &= R[rA]; - Fl = FLAGH; - break; - case 5: - val8 ^= R[rA]; - Fl = 0; - break; - default: - Fl = 0; - val8 |= R[rA]; - } - if(val8 == 0) - Fl |= FLAGZ; - if(b != 7) - R[rA] = val8; - return time; + --v; + r[rF] = r[rF] & FLAGC | FLAGN; + if(v == 0) + r[rF] |= FLAGZ; + if((v & 0xf) == 0xf) + r[rF] |= FLAGH; + return v; } static int -jr(u8int op) +addhl(u16int u) { - u8int a; - u16int addr; - short step; + u32int v; - a = (op & 0x38) >> 3; - switch(a){ - case 0: - return 4; - case 1: - addr = fetch16(); - memwrite(addr, sp); - memwrite(addr + 1, sp >> 8); - return 8; - } - step = (short)(schar)fetch8(); - switch(a){ - case 2: - return 4; - case 4: - if(Fl & FLAGZ) - return 8; - break; - case 5: - if((Fl & FLAGZ) == 0) - return 8; - break; - case 6: - if(Fl & FLAGC) - return 8; - break; - case 7: - if((Fl & FLAGC) == 0) - return 8; - } - pc += step; + r[rF] &= ~(FLAGN|FLAGC|FLAGH); + v = HL() + u; + if((v & 0x10000) != 0) + r[rF] |= FLAGC; + if((HL() & 0xfff) + (u & 0xfff) >= 0x1000) + r[rF] |= FLAGH; + r[rL] = v; + r[rH] = v >> 8; return 8; } -static int -jp(u8int op) +static void +adchl(u16int u) { - u16int addr; + u32int v, v4; - addr = fetch16(); - if(op != 0xC3){ - switch((op & 0x38) >> 3){ - case 0: - if(Fl & FLAGZ) - return 12; - break; - case 1: - if((Fl & FLAGZ) == 0) - return 12; - break; - case 2: - if(Fl & FLAGC) - return 12; - break; - case 3: - if((Fl & FLAGC) == 0) - return 12; - break; - } - } - pc = addr; - return 12; + v = HL() + u + (r[rF] & FLAGC); + v4 = (HL() & 0xfff) + (u & 0xfff) + (r[rF] & FLAGC); + r[rF] = 0; + if((v & 0x10000) != 0) + r[rF] |= FLAGC; + if((v4 & 0x1000) != 0) + r[rF] |= FLAGH; + if((u16int)v == 0) + r[rF] |= FLAGZ; + r[rL] = v; + r[rH] = v >> 8; } -static int -call(u8int op) +static void +sbchl(u16int u) { - u16int addr; + u32int v, v4; - addr = fetch16(); - if(op != 0xCD){ - switch((op & 0x38) >> 3){ - case 0: - if(Fl & FLAGZ) - return 12; - break; - case 1: - if((Fl & FLAGZ) == 0) - return 12; - break; - case 2: - if(Fl & FLAGC) - return 12; - break; - case 3: - if((Fl & FLAGC) == 0) - return 12; - break; - } - } - push16(pc); - pc = addr; - return 12; -} - -static int -rst(u8int op) -{ - u16int addr; - - addr = op & 0x38; - push16(pc); - pc = addr; - return 32; + v = HL() + (u16int)~u + (~r[rF] & FLAGC); + v4 = (HL() & 0xfff) + (~u & 0xfff) + (~r[rF] & FLAGC); + r[rF] = FLAGN; + if((v & 0x10000) == 0) + r[rF] |= FLAGC; + if((v4 & 0x1000) == 0) + r[rF] |= FLAGH; + if((u16int)v == 0) + r[rF] |= FLAGZ; + r[rL] = v; + r[rH] = v >> 8; } static int -ret(u8int op) +jump(int cc) { - if(op != 0xC9 && op!= 0xD9){ - switch((op & 0x38) >> 3){ - case 0: - if(Fl & FLAGZ) - return 8; - break; - case 1: - if((Fl & FLAGZ) == 0) - return 8; - break; - case 2: - if(Fl & FLAGC) - return 8; - break; - case 3: - if((Fl & FLAGC) == 0) - return 8; - break; - } - } - pc = pop16(); - if(op == 0xD9) - IME = 1; - return 8; -} - -static int -push(u8int op) -{ - u8int a; - - a = (op & 0x38) >> 4; - switch(a){ - case 0: - push8(R[rB]); - push8(R[rC]); - break; - case 1: - push8(R[rD]); - push8(R[rE]); - break; - case 2: - push8(R[rH]); - push8(R[rL]); - break; - default: - push8(R[rA]); - push8(Fl); - break; - } + u16int v; + + v = fetch16(); + if(!cc) + return 12; + pc = v; return 16; } static int -pop(u8int op) +call(u16int a, int cc) { - u8int a; - - a = (op & 0x38) >> 4; - switch(a){ - case 0: - R[rC] = pop8(); - R[rB] = pop8(); - break; - case 1: - R[rE] = pop8(); - R[rD] = pop8(); - break; - case 2: - R[rL] = pop8(); - R[rH] = pop8(); - break; - default: - Fl = pop8() & 0xF0; - R[rA] = pop8(); - } - return 12; + if(!cc) + return 12; + push16(pc); + pc = a; + return cc < 0 ? 16 : 24; } static int -shift(u8int op, int cb) +bits(void) { - u16int val; - u8int a, b; - int time; + u8int op, v, n, m, c; + u16int a; + int t; - a = (op & 0x38) >> 3; - b = op & 7; - if(b == rHL){ - val = memread(lohi(R[rL], R[rH])); - time = 16; + op = fetch8(); + n = op & 7; + m = op >> 3 & 7; + a = HL(); + if(n == 6){ + v = memread(a); + t = 16; }else{ - val = R[b]; - time = 8; + v = r[n]; + t = 8; } - switch(a){ + switch(op >> 6){ case 0: - Fl = 0; - if(val & 0x80) - Fl = FLAGC; - val = (val << 1) | (val >> 7); + c = r[rF] >> 4 & 1; + switch(m){ + default: r[rF] = v >> 3 & 0x10; v = v << 1 | v >> 7; break; + case 1: r[rF] = v << 4 & 0x10; v = v >> 1 | v << 7; break; + case 2: r[rF] = v >> 3 & 0x10; v = v << 1 | c; break; + case 3: r[rF] = v << 4 & 0x10; v = v >> 1 | c << 7; break; + case 4: r[rF] = v >> 3 & 0x10; v = v << 1; break; + case 5: r[rF] = v << 4 & 0x10; v = v & 0x80 | v >> 1; break; + case 6: r[rF] = 0; v = v << 4 | v >> 4; break; + case 7: r[rF] = v << 4 & 0x10; v >>= 1; break; + } + if(v == 0) + r[rF] |= FLAGZ; break; case 1: - Fl = 0; - if(val & 1) - Fl = FLAGC; - val = (val >> 1) | (val << 7); - break; + r[rF] = r[rF] & ~(FLAGN|FLAGZ) | FLAGH; + if((v & 1<<m) == 0) + r[rF] |= FLAGZ; + if(n == 6) + t = 12; + return t; case 2: - val <<= 1; - if(Fl & FLAGC) - val |= 1; - Fl = 0; - if(val & 0x100) - Fl = FLAGC; + v &= ~(1<<m); break; case 3: - if(Fl & FLAGC) - val |= 0x100; - Fl = 0; - if(val & 1) - Fl = FLAGC; - val >>= 1; - break; - case 4: - Fl = 0; - if(val & 0x80) - Fl = FLAGC; - val <<= 1; - break; - case 5: - Fl = 0; - if(val & 1) - Fl = FLAGC; - val = (val >> 1) | (val & 0x80); - break; - case 6: - val = (val << 4) | (val >> 4); - Fl = 0; - break; - default: - Fl = 0; - if(val & 1) - Fl = FLAGC; - val >>= 1; + v |= (1<<m); } - if((val & 0xFF) == 0) - Fl |= FLAGZ; - if(b == rHL) - memwrite(lohi(R[rL], R[rH]), val); + if(n == 6) + memwrite(a, v); else - R[b] = val; - if(!cb) - Fl &= FLAGC; - return time; -} - -static int -bit(u8int op) -{ - u8int val, a, b; - int time; - - a = (op & 0x38) >> 3; - b = op & 7; - if(b == rHL){ - val = memread(lohi(R[rL], R[rH])), - time = 16; - }else{ - val = R[b]; - time = 8; - } - Fl = (Fl & FLAGC) | FLAGH; - if((val & (1<<a)) == 0) - Fl |= FLAGZ; - return time; -} - -static int -setres(u8int op) -{ - u8int val, a, b; - int time; - - a = (op & 0x38) >> 3; - b = op & 7; - if(b == rHL){ - val = memread(lohi(R[rL], R[rH])); - time = 16; - }else{ - val = R[b]; - time = 8; - } - if(op & 0x40) - val |= (1 << a); - else - val &= ~(1 << a); - if(b == rHL) - memwrite(lohi(R[rL], R[rH]), val); - else - R[b] = val; - return time; -} - -static int -cb(void) -{ - u8int op; - - op = fetch8(); - if((op & 0xC0) == 0) - return shift(op, 1); - if((op & 0xC0) == 0x40) - return bit(op); - return setres(op); + r[n] = v; + return t; } void -interrupt(u8int t) +reset(void) { - mem[IF] |= (1 << t); + r[rA] = 0x01; + r[rF] = 0xb0; + r[rC] = 0x13; + r[rE] = 0xd8; + r[rL] = 0x4d; + r[rH] = 0x01; + if((mode & COL) == COL) + r[rA] = 0x11; + sp = 0xfffe; + pc = 0x100; } int step(void) { - u8int op; - ushort val; - extern u8int daa[]; - int val32, i; + u8int op, v4; + u16int v, w; + s8int s; - if(halt){ - if(mem[IF] & mem[IE]) + if(halt) + if((reg[IF] & reg[IE]) != 0) halt = 0; else return 4; + if((reg[IF] & reg[IE]) != 0 && ime != 0){ + push16(pc); + ime = 0; + v4 = reg[IF] & reg[IE]; + v4 &= -v4; + reg[IF] &= ~v4; + for(pc = 0x40; v4 != 1; pc += 8) + v4 >>= 1; + return 12; } - if(IME && (mem[IF] & mem[IE])) - for(i = 0; i < 5; i++) - if(mem[IF] & mem[IE] & (1<<i)){ - mem[IF] &= ~(1<<i); - push16(pc); - IME = 0; - halt = 0; - pc = 0x40 + 8 * i; - break; - } curpc = pc; op = fetch8(); - if(0){ - print("%.4x A %.2x B %.2x C %.2x D %.2x E %.2x HL %.2x%.2x SP %.4x F %.2x ", curpc, R[rA], R[rB], R[rC], R[rD], R[rE], R[rH], R[rL], sp, Fl); - disasm(curpc); + if(trace) + print("%.4x %.2x AF %.2x%.2x BC %.2x%.2x DE %.2x%.2x HL %.2x%.2x SP %.4x\n", curpc, op, r[rA], r[rF], r[rB], r[rC], r[rD], r[rE], r[rH], r[rL], sp); + switch(op >> 6){ + case 1: return move(op >> 3 & 7, op & 7); + case 2: return alu(op >> 3 & 7, op & 7); } - if((op & 0xC7) == 0x00) - return jr(op); - if((op & 0xCF) == 0x01) - return ld16(op); - if((op & 0xCF) == 0x09) - return add16(op); - if((op & 0xC7) == 0x02) - return ldin(op); - if((op & 0xC7) == 0x03) - return inc16(op); - if((op & 0xC7) == 0x04) - return inc8(op); - if((op & 0xC7) == 0x05) - return dec8(op); - if((op & 0xC7) == 0x06) - return ldi(op); - if((op & 0xE7) == 0x07) - return shift(op, 0); - if((op & 0xC0) == 0x40) - return ld01(op); - if((op & 0xC0) == 0x80 || (op & 0xC7) == 0xC6) - return alu(op); - if((op & 0xE7) == 0xC0 || op == 0xC9 || op == 0xD9) - return ret(op); - if((op & 0xCF) == 0xC1) - return pop(op); - if((op & 0xE7) == 0xC2 || op == 0xC3) - return jp(op); - if((op & 0xE7) == 0xC4 || op == 0xCD) - return call(op); - if((op & 0xCF) == 0xC5) - return push(op); - if((op & 0xC7) == 0xC7) - return rst(op); switch(op){ - case 0x27: - i = (((int)R[rA]) + (((int)Fl) * 16)) * 2; - R[rA] = daa[i]; - Fl = daa[i+1]; + case 0x00: return 4; + case 0x10: + if((mode & CGB) != 0 && (reg[KEY1] & 1) != 0){ + reg[DIV] += divclock - clock >> 7 - ((mode & TURBO) != 0); + divclock = clock; + mode ^= TURBO; + timertac(reg[TAC], 1); + reg[KEY1] ^= 0x81; + return 4; + } + print("STOP ignored (pc=%.4ux)\n", curpc); return 4; - case 0x2F: - R[rA] = ~R[rA]; - Fl |= FLAGN | FLAGH; + case 0x20: return branch((r[rF] & FLAGZ) == 0, 0); + case 0x30: return branch((r[rF] & FLAGC) == 0, 0); + case 0x01: r[rC] = fetch8(); r[rB] = fetch8(); return 12; + case 0x11: r[rE] = fetch8(); r[rD] = fetch8(); return 12; + case 0x21: r[rL] = fetch8(); r[rH] = fetch8(); return 12; + case 0x31: sp = fetch16(); return 12; + case 0x02: memwrite(BC(), r[rA]); return 8; + case 0x12: memwrite(DE(), r[rA]); return 8; + case 0x22: memwrite(HL(), r[rA]); if(++r[rL] == 0) r[rH]++; return 8; + case 0x32: memwrite(HL(), r[rA]); if(r[rL]-- == 0) r[rH]--; return 8; + case 0x03: if(++r[rC] == 0) r[rB]++; return 8; + case 0x13: if(++r[rE] == 0) r[rD]++; return 8; + case 0x23: if(++r[rL] == 0) r[rH]++; return 8; + case 0x33: sp++; return 8; + case 0x04: inc(r[rB]++); return 4; + case 0x14: inc(r[rD]++); return 4; + case 0x24: inc(r[rH]++); return 4; + case 0x34: memwrite(HL(), inc(memread(HL()))); return 12; + case 0x05: dec(r[rB]--); return 4; + case 0x15: dec(r[rD]--); return 4; + case 0x25: dec(r[rH]--); return 4; + case 0x35: memwrite(HL(), dec(memread(HL()))); return 12; + case 0x06: r[rB] = fetch8(); return 8; + case 0x16: r[rD] = fetch8(); return 8; + case 0x26: r[rH] = fetch8(); return 8; + case 0x36: memwrite(HL(), fetch8()); return 12; + case 0x07: + r[rF] = r[rA] >> 3 & 0x10; + r[rA] = r[rA] << 1 | r[rA] >> 7; return 4; - case 0x37: - Fl = (Fl & FLAGZ) | FLAGC; + case 0x17: + v = r[rF] >> 4 & 1; + r[rF] = r[rA] >> 3 & 0x10; + r[rA] = r[rA] << 1 | v; return 4; - case 0x3F: - Fl &= FLAGZ | FLAGC; - Fl ^= FLAGC; + case 0x27: + if(r[rA] > 0x99 && (r[rF] & FLAGN) == 0 || (r[rF] & FLAGC) != 0){ + r[rF] |= FLAGC; + v = 0x60; + }else{ + r[rF] &= ~FLAGC; + v = 0; + } + if((r[rA] & 0xf) > 9 && (r[rF] & FLAGN) == 0 || (r[rF] & FLAGH) != 0) + v |= 6; + if((r[rF] & FLAGN) != 0) + r[rA] -= v; + else + r[rA] += v; + r[rF] &= ~(FLAGZ|FLAGH); + if(r[rA] == 0) + r[rF] |= FLAGZ; return 4; - case 0xE0: - memwrite(lohi(fetch8(), 0xFF), R[rA]); - return 8; - case 0xE2: - memwrite(lohi(R[rC], 0xFF), R[rA]); - return 8; - case 0xE8: - val = (short)(schar)fetch8(); - val32 = (uint)sp + (uint)val; - Fl = 0; - if(((sp & 0xFF) + (val & 0xFF)) > 0xFF) - Fl |= FLAGC; - if(((sp & 0xF) + (val & 0xF)) > 0xF) - Fl |= FLAGH; - sp = val32; - return 16; - case 0xE9: - pc = lohi(R[rL], R[rH]); + case 0x37: r[rF] = r[rF] & ~(FLAGN | FLAGH) | FLAGC; return 4; + case 0x08: write16(fetch16(), sp); return 20; + case 0x18: return branch(1, 0); + case 0x28: return branch((r[rF] & FLAGZ) != 0, 0); + case 0x38: return branch((r[rF] & FLAGC) != 0, 0); + case 0x09: return addhl(BC()); + case 0x19: return addhl(DE()); + case 0x29: return addhl(HL()); + case 0x39: return addhl(sp); + case 0x0a: r[rA] = memread(BC()); return 8; + case 0x1a: r[rA] = memread(DE()); return 8; + case 0x2a: r[rA] = memread(HL()); if(++r[rL] == 0) r[rH]++; return 8; + case 0x3a: r[rA] = memread(HL()); if(r[rL]-- == 0) r[rH]--; return 8; + case 0x0b: if(r[rC]-- == 0) r[rB]--; return 8; + case 0x1b: if(r[rE]-- == 0) r[rD]--; return 8; + case 0x2b: if(r[rL]-- == 0) r[rH]--; return 8; + case 0x3b: sp--; return 8; + case 0x0c: inc(r[rC]++); return 4; + case 0x1c: inc(r[rE]++); return 4; + case 0x2c: inc(r[rL]++); return 4; + case 0x3c: inc(r[rA]++); return 4; + case 0x0d: dec(r[rC]--); return 4; + case 0x1d: dec(r[rE]--); return 4; + case 0x2d: dec(r[rL]--); return 4; + case 0x3d: dec(r[rA]--); return 4; + case 0x0e: r[rC] = fetch8(); return 8; + case 0x1e: r[rE] = fetch8(); return 8; + case 0x2e: r[rL] = fetch8(); return 8; + case 0x3e: r[rA] = fetch8(); return 8; + case 0x0f: + r[rF] = r[rA] << 4 & 0x10; + r[rA] = r[rA] >> 1 | r[rA] << 7; return 4; - case 0xEA: - memwrite(fetch16(), R[rA]); - return 16; - case 0xF0: - R[rA] = memread(lohi(fetch8(), 0xFF)); - return 12; - case 0xFA: - R[rA] = memread(fetch16()); - return 16; - case 0xF2: - R[rA] = memread(lohi(R[rC], 0xFF)); - return 8; - case 0xCB: - return cb(); - case 0xF3: - IME= 0; + case 0x1f: + v = r[rF] << 3 & 0x80; + r[rF] = r[rA] << 4 & 0x10; + r[rA] = r[rA] >> 1 | v; return 4; - case 0xF8: - val = (short)(schar)fetch8(); - val32 = (uint)sp + (uint)val; - Fl = 0; - if(((sp & 0xFF) + (val & 0xFF)) > 0xFF) - Fl |= FLAGC; - if(((sp & 0xF) + (val & 0xF)) > 0xF) - Fl |= FLAGH; - R[rL] = val32; - R[rH] = val32 >> 8; - return 12; - case 0xF9: - sp = lohi(R[rL], R[rH]); - return 8; - case 0xFB: - IME = 1; + case 0x2f: + r[rF] |= FLAGN|FLAGH; + r[rA] ^= 0xff; return 4; - default: - invalid(); + case 0x3f: + r[rF] = r[rF] & ~(FLAGN|FLAGH) ^ FLAGC; + return 4; + case 0xc0: if((r[rF] & FLAGZ) == 0) {pc = pop16(); return 20;} return 8; + case 0xd0: if((r[rF] & FLAGC) == 0) {pc = pop16(); return 20;} return 8; + case 0xe0: memwrite(0xff00 | fetch8(), r[rA]); return 12; + case 0xf0: r[rA] = memread(0xff00 | fetch8()); return 12; + case 0xc1: r[rC] = pop8(); r[rB] = pop8(); return 12; + case 0xd1: r[rE] = pop8(); r[rD] = pop8(); return 12; + case 0xe1: r[rL] = pop8(); r[rH] = pop8(); return 12; + case 0xf1: r[rF] = pop8() & 0xf0; r[rA] = pop8(); return 12; + case 0xc2: return jump((r[rF] & FLAGZ) == 0); + case 0xd2: return jump((r[rF] & FLAGC) == 0); + case 0xe2: memwrite(0xff00 | r[rC], r[rA]); return 8; + case 0xf2: r[rA] = memread(0xff00 | r[rC]); return 8; + case 0xc3: return jump(1); + case 0xf3: ime = 0; return 4; + case 0xc4: return call(fetch16(), (r[rF] & FLAGZ) == 0); + case 0xd4: return call(fetch16(), (r[rF] & FLAGC) == 0); + case 0xc5: push8(r[rB]); push8(r[rC]); return 16; + case 0xd5: push8(r[rD]); push8(r[rE]); return 16; + case 0xe5: push8(r[rH]); push8(r[rL]); return 16; + case 0xf5: push8(r[rA]); push8(r[rF]); return 16; + case 0xc6: return alu(0, 8); + case 0xd6: return alu(2, 8); + case 0xe6: return alu(4, 8); + case 0xf6: return alu(6, 8); + case 0xc7: return call(0x00, -1); + case 0xd7: return call(0x10, -1); + case 0xe7: return call(0x20, -1); + case 0xf7: return call(0x30, -1); + case 0xc8: if((r[rF] & FLAGZ) != 0) {pc = pop16(); return 20;} return 8; + case 0xd8: if((r[rF] & FLAGC) != 0) {pc = pop16(); return 20;} return 8; + case 0xe8: case 0xf8: + s = fetch8(); + v = sp + s; + v4 = (sp & 0xf) + (s & 0xf); + w = (sp & 0xff) + (s & 0xff); + r[rF] = 0; + if(v4 >= 0x10) + r[rF] |= FLAGH; + if(w >= 0x100) + r[rF] |= FLAGC; + if(op == 0xe8){ + sp = v; + return 16; + }else{ + r[rL] = v; + r[rH] = v >> 8; + return 12; + } + case 0xc9: pc = pop16(); return 16; + case 0xd9: pc = pop16(); ime = 1; return 16; + case 0xe9: pc = HL(); return 4; + case 0xf9: sp = HL(); return 8; + case 0xca: return jump((r[rF] & FLAGZ) != 0); + case 0xda: return jump((r[rF] & FLAGC) != 0); + case 0xea: memwrite(fetch16(), r[rA]); return 16; + case 0xfa: r[rA] = memread(fetch16()); return 16; + case 0xcb: return bits(); + case 0xfb: ime = 1; return 4; + case 0xcc: return call(fetch16(), (r[rF] & FLAGZ) != 0); + case 0xdc: return call(fetch16(), (r[rF] & FLAGC) != 0); + case 0xcd: return call(fetch16(), 1); + case 0xce: return alu(1, 8); + case 0xde: return alu(3, 8); + case 0xee: return alu(5, 8); + case 0xfe: return alu(7, 8); + case 0xcf: return call(0x08, -1); + case 0xdf: return call(0x18, -1); + case 0xef: return call(0x28, -1); + case 0xff: return call(0x38, -1); } + sysfatal("undefined opcode %#.2x at pc=%#.4x", op, curpc); return 0; } diff --git a/sys/src/games/gb/daa.c b/sys/src/games/gb/daa.c deleted file mode 100644 index 83a72d1af..000000000 --- a/sys/src/games/gb/daa.c +++ /dev/null @@ -1,465 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <thread.h> -#include <draw.h> -#include "dat.h" -#include "fns.h" - -u8int daa[] = { - 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, - 0x09, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x10, 0x00, 0x11, 0x00, - 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x20, 0x00, - 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, - 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x28, 0x00, 0x29, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, - 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, - 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, - 0x45, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, - 0x48, 0x00, 0x49, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x50, 0x00, - 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, - 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, 0x65, 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, - 0x63, 0x00, 0x64, 0x00, 0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x71, 0x00, - 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, - 0x75, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, - 0x84, 0x00, 0x85, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, - 0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, - 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, - 0x99, 0x00, 0x00, 0x90, 0x01, 0x10, 0x02, 0x10, 0x03, 0x10, 0x04, 0x10, 0x05, 0x10, 0x00, 0x90, 0x01, 0x10, - 0x02, 0x10, 0x03, 0x10, 0x04, 0x10, 0x05, 0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, 0x09, 0x10, 0x10, 0x10, - 0x11, 0x10, 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, 0x15, 0x10, 0x10, 0x10, 0x11, 0x10, 0x12, 0x10, 0x13, 0x10, - 0x14, 0x10, 0x15, 0x10, 0x16, 0x10, 0x17, 0x10, 0x18, 0x10, 0x19, 0x10, 0x20, 0x10, 0x21, 0x10, 0x22, 0x10, - 0x23, 0x10, 0x24, 0x10, 0x25, 0x10, 0x20, 0x10, 0x21, 0x10, 0x22, 0x10, 0x23, 0x10, 0x24, 0x10, 0x25, 0x10, - 0x26, 0x10, 0x27, 0x10, 0x28, 0x10, 0x29, 0x10, 0x30, 0x10, 0x31, 0x10, 0x32, 0x10, 0x33, 0x10, 0x34, 0x10, - 0x35, 0x10, 0x30, 0x10, 0x31, 0x10, 0x32, 0x10, 0x33, 0x10, 0x34, 0x10, 0x35, 0x10, 0x36, 0x10, 0x37, 0x10, - 0x38, 0x10, 0x39, 0x10, 0x40, 0x10, 0x41, 0x10, 0x42, 0x10, 0x43, 0x10, 0x44, 0x10, 0x45, 0x10, 0x40, 0x10, - 0x41, 0x10, 0x42, 0x10, 0x43, 0x10, 0x44, 0x10, 0x45, 0x10, 0x46, 0x10, 0x47, 0x10, 0x48, 0x10, 0x49, 0x10, - 0x50, 0x10, 0x51, 0x10, 0x52, 0x10, 0x53, 0x10, 0x54, 0x10, 0x55, 0x10, 0x50, 0x10, 0x51, 0x10, 0x52, 0x10, - 0x53, 0x10, 0x54, 0x10, 0x55, 0x10, 0x56, 0x10, 0x57, 0x10, 0x58, 0x10, 0x59, 0x10, 0x60, 0x10, 0x61, 0x10, - 0x62, 0x10, 0x63, 0x10, 0x64, 0x10, 0x65, 0x10, 0x60, 0x10, 0x61, 0x10, 0x62, 0x10, 0x63, 0x10, 0x64, 0x10, - 0x65, 0x10, 0x66, 0x10, 0x67, 0x10, 0x68, 0x10, 0x69, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72, 0x10, 0x73, 0x10, - 0x74, 0x10, 0x75, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72, 0x10, 0x73, 0x10, 0x74, 0x10, 0x75, 0x10, 0x76, 0x10, - 0x77, 0x10, 0x78, 0x10, 0x79, 0x10, 0x80, 0x10, 0x81, 0x10, 0x82, 0x10, 0x83, 0x10, 0x84, 0x10, 0x85, 0x10, - 0x80, 0x10, 0x81, 0x10, 0x82, 0x10, 0x83, 0x10, 0x84, 0x10, 0x85, 0x10, 0x86, 0x10, 0x87, 0x10, 0x88, 0x10, - 0x89, 0x10, 0x90, 0x10, 0x91, 0x10, 0x92, 0x10, 0x93, 0x10, 0x94, 0x10, 0x95, 0x10, 0x90, 0x10, 0x91, 0x10, - 0x92, 0x10, 0x93, 0x10, 0x94, 0x10, 0x95, 0x10, 0x96, 0x10, 0x97, 0x10, 0x98, 0x10, 0x99, 0x10, 0xA0, 0x10, - 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, 0xA5, 0x10, 0xA0, 0x10, 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, - 0xA4, 0x10, 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10, 0xA9, 0x10, 0xB0, 0x10, 0xB1, 0x10, 0xB2, 0x10, - 0xB3, 0x10, 0xB4, 0x10, 0xB5, 0x10, 0xB0, 0x10, 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, 0xB5, 0x10, - 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10, 0xB9, 0x10, 0xC0, 0x10, 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, - 0xC5, 0x10, 0xC0, 0x10, 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xC5, 0x10, 0xC6, 0x10, 0xC7, 0x10, - 0xC8, 0x10, 0xC9, 0x10, 0xD0, 0x10, 0xD1, 0x10, 0xD2, 0x10, 0xD3, 0x10, 0xD4, 0x10, 0xD5, 0x10, 0xD0, 0x10, - 0xD1, 0x10, 0xD2, 0x10, 0xD3, 0x10, 0xD4, 0x10, 0xD5, 0x10, 0xD6, 0x10, 0xD7, 0x10, 0xD8, 0x10, 0xD9, 0x10, - 0xE0, 0x10, 0xE1, 0x10, 0xE2, 0x10, 0xE3, 0x10, 0xE4, 0x10, 0xE5, 0x10, 0xE0, 0x10, 0xE1, 0x10, 0xE2, 0x10, - 0xE3, 0x10, 0xE4, 0x10, 0xE5, 0x10, 0xE6, 0x10, 0xE7, 0x10, 0xE8, 0x10, 0xE9, 0x10, 0xF0, 0x10, 0xF1, 0x10, - 0xF2, 0x10, 0xF3, 0x10, 0xF4, 0x10, 0xF5, 0x10, 0xF0, 0x10, 0xF1, 0x10, 0xF2, 0x10, 0xF3, 0x10, 0xF4, 0x10, - 0xF5, 0x10, 0xF6, 0x10, 0xF7, 0x10, 0xF8, 0x10, 0xF9, 0x10, 0x00, 0x90, 0x01, 0x10, 0x02, 0x10, 0x03, 0x10, - 0x04, 0x10, 0x05, 0x10, 0x00, 0x90, 0x01, 0x10, 0x02, 0x10, 0x03, 0x10, 0x04, 0x10, 0x05, 0x10, 0x06, 0x10, - 0x07, 0x10, 0x08, 0x10, 0x09, 0x10, 0x10, 0x10, 0x11, 0x10, 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, 0x15, 0x10, - 0x10, 0x10, 0x11, 0x10, 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, 0x15, 0x10, 0x16, 0x10, 0x17, 0x10, 0x18, 0x10, - 0x19, 0x10, 0x20, 0x10, 0x21, 0x10, 0x22, 0x10, 0x23, 0x10, 0x24, 0x10, 0x25, 0x10, 0x20, 0x10, 0x21, 0x10, - 0x22, 0x10, 0x23, 0x10, 0x24, 0x10, 0x25, 0x10, 0x26, 0x10, 0x27, 0x10, 0x28, 0x10, 0x29, 0x10, 0x30, 0x10, - 0x31, 0x10, 0x32, 0x10, 0x33, 0x10, 0x34, 0x10, 0x35, 0x10, 0x30, 0x10, 0x31, 0x10, 0x32, 0x10, 0x33, 0x10, - 0x34, 0x10, 0x35, 0x10, 0x36, 0x10, 0x37, 0x10, 0x38, 0x10, 0x39, 0x10, 0x40, 0x10, 0x41, 0x10, 0x42, 0x10, - 0x43, 0x10, 0x44, 0x10, 0x45, 0x10, 0x40, 0x10, 0x41, 0x10, 0x42, 0x10, 0x43, 0x10, 0x44, 0x10, 0x45, 0x10, - 0x46, 0x10, 0x47, 0x10, 0x48, 0x10, 0x49, 0x10, 0x50, 0x10, 0x51, 0x10, 0x52, 0x10, 0x53, 0x10, 0x54, 0x10, - 0x55, 0x10, 0x50, 0x10, 0x51, 0x10, 0x52, 0x10, 0x53, 0x10, 0x54, 0x10, 0x55, 0x10, 0x56, 0x10, 0x57, 0x10, - 0x58, 0x10, 0x59, 0x10, 0x60, 0x10, 0x61, 0x10, 0x62, 0x10, 0x63, 0x10, 0x64, 0x10, 0x65, 0x10, 0x06, 0x00, - 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, - 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, - 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00, 0x20, 0x00, 0x21, 0x00, - 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, - 0x2B, 0x00, 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, - 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00, 0x3C, 0x00, - 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, - 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, - 0x4F, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, - 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00, 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00, 0x60, 0x00, - 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, 0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, - 0x6A, 0x00, 0x6B, 0x00, 0x6C, 0x00, 0x6D, 0x00, 0x6E, 0x00, 0x6F, 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, - 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7A, 0x00, 0x7B, 0x00, - 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, - 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0x8D, 0x00, - 0x8E, 0x00, 0x8F, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, - 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00, 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00, - 0x00, 0x90, 0x01, 0x10, 0x02, 0x10, 0x03, 0x10, 0x04, 0x10, 0x05, 0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, - 0x09, 0x10, 0x0A, 0x10, 0x0B, 0x10, 0x0C, 0x10, 0x0D, 0x10, 0x0E, 0x10, 0x0F, 0x10, 0x10, 0x10, 0x11, 0x10, - 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, 0x15, 0x10, 0x16, 0x10, 0x17, 0x10, 0x18, 0x10, 0x19, 0x10, 0x1A, 0x10, - 0x1B, 0x10, 0x1C, 0x10, 0x1D, 0x10, 0x1E, 0x10, 0x1F, 0x10, 0x20, 0x10, 0x21, 0x10, 0x22, 0x10, 0x23, 0x10, - 0x24, 0x10, 0x25, 0x10, 0x26, 0x10, 0x27, 0x10, 0x28, 0x10, 0x29, 0x10, 0x2A, 0x10, 0x2B, 0x10, 0x2C, 0x10, - 0x2D, 0x10, 0x2E, 0x10, 0x2F, 0x10, 0x30, 0x10, 0x31, 0x10, 0x32, 0x10, 0x33, 0x10, 0x34, 0x10, 0x35, 0x10, - 0x36, 0x10, 0x37, 0x10, 0x38, 0x10, 0x39, 0x10, 0x3A, 0x10, 0x3B, 0x10, 0x3C, 0x10, 0x3D, 0x10, 0x3E, 0x10, - 0x3F, 0x10, 0x40, 0x10, 0x41, 0x10, 0x42, 0x10, 0x43, 0x10, 0x44, 0x10, 0x45, 0x10, 0x46, 0x10, 0x47, 0x10, - 0x48, 0x10, 0x49, 0x10, 0x4A, 0x10, 0x4B, 0x10, 0x4C, 0x10, 0x4D, 0x10, 0x4E, 0x10, 0x4F, 0x10, 0x50, 0x10, - 0x51, 0x10, 0x52, 0x10, 0x53, 0x10, 0x54, 0x10, 0x55, 0x10, 0x56, 0x10, 0x57, 0x10, 0x58, 0x10, 0x59, 0x10, - 0x5A, 0x10, 0x5B, 0x10, 0x5C, 0x10, 0x5D, 0x10, 0x5E, 0x10, 0x5F, 0x10, 0x60, 0x10, 0x61, 0x10, 0x62, 0x10, - 0x63, 0x10, 0x64, 0x10, 0x65, 0x10, 0x66, 0x10, 0x67, 0x10, 0x68, 0x10, 0x69, 0x10, 0x6A, 0x10, 0x6B, 0x10, - 0x6C, 0x10, 0x6D, 0x10, 0x6E, 0x10, 0x6F, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72, 0x10, 0x73, 0x10, 0x74, 0x10, - 0x75, 0x10, 0x76, 0x10, 0x77, 0x10, 0x78, 0x10, 0x79, 0x10, 0x7A, 0x10, 0x7B, 0x10, 0x7C, 0x10, 0x7D, 0x10, - 0x7E, 0x10, 0x7F, 0x10, 0x80, 0x10, 0x81, 0x10, 0x82, 0x10, 0x83, 0x10, 0x84, 0x10, 0x85, 0x10, 0x86, 0x10, - 0x87, 0x10, 0x88, 0x10, 0x89, 0x10, 0x8A, 0x10, 0x8B, 0x10, 0x8C, 0x10, 0x8D, 0x10, 0x8E, 0x10, 0x8F, 0x10, - 0x90, 0x10, 0x91, 0x10, 0x92, 0x10, 0x93, 0x10, 0x94, 0x10, 0x95, 0x10, 0x96, 0x10, 0x97, 0x10, 0x98, 0x10, - 0x99, 0x10, 0x9A, 0x10, 0x9B, 0x10, 0x9C, 0x10, 0x9D, 0x10, 0x9E, 0x10, 0x9F, 0x10, 0xA0, 0x10, 0xA1, 0x10, - 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10, 0xA9, 0x10, 0xAA, 0x10, - 0xAB, 0x10, 0xAC, 0x10, 0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10, 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, - 0xB4, 0x10, 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10, 0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10, - 0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10, 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xC5, 0x10, - 0xC6, 0x10, 0xC7, 0x10, 0xC8, 0x10, 0xC9, 0x10, 0xCA, 0x10, 0xCB, 0x10, 0xCC, 0x10, 0xCD, 0x10, 0xCE, 0x10, - 0xCF, 0x10, 0xD0, 0x10, 0xD1, 0x10, 0xD2, 0x10, 0xD3, 0x10, 0xD4, 0x10, 0xD5, 0x10, 0xD6, 0x10, 0xD7, 0x10, - 0xD8, 0x10, 0xD9, 0x10, 0xDA, 0x10, 0xDB, 0x10, 0xDC, 0x10, 0xDD, 0x10, 0xDE, 0x10, 0xDF, 0x10, 0xE0, 0x10, - 0xE1, 0x10, 0xE2, 0x10, 0xE3, 0x10, 0xE4, 0x10, 0xE5, 0x10, 0xE6, 0x10, 0xE7, 0x10, 0xE8, 0x10, 0xE9, 0x10, - 0xEA, 0x10, 0xEB, 0x10, 0xEC, 0x10, 0xED, 0x10, 0xEE, 0x10, 0xEF, 0x10, 0xF0, 0x10, 0xF1, 0x10, 0xF2, 0x10, - 0xF3, 0x10, 0xF4, 0x10, 0xF5, 0x10, 0xF6, 0x10, 0xF7, 0x10, 0xF8, 0x10, 0xF9, 0x10, 0xFA, 0x10, 0xFB, 0x10, - 0xFC, 0x10, 0xFD, 0x10, 0xFE, 0x10, 0xFF, 0x10, 0x00, 0x90, 0x01, 0x10, 0x02, 0x10, 0x03, 0x10, 0x04, 0x10, - 0x05, 0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, 0x09, 0x10, 0x0A, 0x10, 0x0B, 0x10, 0x0C, 0x10, 0x0D, 0x10, - 0x0E, 0x10, 0x0F, 0x10, 0x10, 0x10, 0x11, 0x10, 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, 0x15, 0x10, 0x16, 0x10, - 0x17, 0x10, 0x18, 0x10, 0x19, 0x10, 0x1A, 0x10, 0x1B, 0x10, 0x1C, 0x10, 0x1D, 0x10, 0x1E, 0x10, 0x1F, 0x10, - 0x20, 0x10, 0x21, 0x10, 0x22, 0x10, 0x23, 0x10, 0x24, 0x10, 0x25, 0x10, 0x26, 0x10, 0x27, 0x10, 0x28, 0x10, - 0x29, 0x10, 0x2A, 0x10, 0x2B, 0x10, 0x2C, 0x10, 0x2D, 0x10, 0x2E, 0x10, 0x2F, 0x10, 0x30, 0x10, 0x31, 0x10, - 0x32, 0x10, 0x33, 0x10, 0x34, 0x10, 0x35, 0x10, 0x36, 0x10, 0x37, 0x10, 0x38, 0x10, 0x39, 0x10, 0x3A, 0x10, - 0x3B, 0x10, 0x3C, 0x10, 0x3D, 0x10, 0x3E, 0x10, 0x3F, 0x10, 0x40, 0x10, 0x41, 0x10, 0x42, 0x10, 0x43, 0x10, - 0x44, 0x10, 0x45, 0x10, 0x46, 0x10, 0x47, 0x10, 0x48, 0x10, 0x49, 0x10, 0x4A, 0x10, 0x4B, 0x10, 0x4C, 0x10, - 0x4D, 0x10, 0x4E, 0x10, 0x4F, 0x10, 0x50, 0x10, 0x51, 0x10, 0x52, 0x10, 0x53, 0x10, 0x54, 0x10, 0x55, 0x10, - 0x56, 0x10, 0x57, 0x10, 0x58, 0x10, 0x59, 0x10, 0x5A, 0x10, 0x5B, 0x10, 0x5C, 0x10, 0x5D, 0x10, 0x5E, 0x10, - 0x5F, 0x10, 0x60, 0x10, 0x61, 0x10, 0x62, 0x10, 0x63, 0x10, 0x64, 0x10, 0x65, 0x10, 0x00, 0xC0, 0x01, 0x40, - 0x02, 0x40, 0x03, 0x40, 0x04, 0x40, 0x05, 0x40, 0x06, 0x40, 0x07, 0x40, 0x08, 0x40, 0x09, 0x40, 0x0A, 0x40, - 0x0B, 0x40, 0x0C, 0x40, 0x0D, 0x40, 0x0E, 0x40, 0x0F, 0x40, 0x10, 0x40, 0x11, 0x40, 0x12, 0x40, 0x13, 0x40, - 0x14, 0x40, 0x15, 0x40, 0x16, 0x40, 0x17, 0x40, 0x18, 0x40, 0x19, 0x40, 0x1A, 0x40, 0x1B, 0x40, 0x1C, 0x40, - 0x1D, 0x40, 0x1E, 0x40, 0x1F, 0x40, 0x20, 0x40, 0x21, 0x40, 0x22, 0x40, 0x23, 0x40, 0x24, 0x40, 0x25, 0x40, - 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2A, 0x40, 0x2B, 0x40, 0x2C, 0x40, 0x2D, 0x40, 0x2E, 0x40, - 0x2F, 0x40, 0x30, 0x40, 0x31, 0x40, 0x32, 0x40, 0x33, 0x40, 0x34, 0x40, 0x35, 0x40, 0x36, 0x40, 0x37, 0x40, - 0x38, 0x40, 0x39, 0x40, 0x3A, 0x40, 0x3B, 0x40, 0x3C, 0x40, 0x3D, 0x40, 0x3E, 0x40, 0x3F, 0x40, 0x40, 0x40, - 0x41, 0x40, 0x42, 0x40, 0x43, 0x40, 0x44, 0x40, 0x45, 0x40, 0x46, 0x40, 0x47, 0x40, 0x48, 0x40, 0x49, 0x40, - 0x4A, 0x40, 0x4B, 0x40, 0x4C, 0x40, 0x4D, 0x40, 0x4E, 0x40, 0x4F, 0x40, 0x50, 0x40, 0x51, 0x40, 0x52, 0x40, - 0x53, 0x40, 0x54, 0x40, 0x55, 0x40, 0x56, 0x40, 0x57, 0x40, 0x58, 0x40, 0x59, 0x40, 0x5A, 0x40, 0x5B, 0x40, - 0x5C, 0x40, 0x5D, 0x40, 0x5E, 0x40, 0x5F, 0x40, 0x60, 0x40, 0x61, 0x40, 0x62, 0x40, 0x63, 0x40, 0x64, 0x40, - 0x65, 0x40, 0x66, 0x40, 0x67, 0x40, 0x68, 0x40, 0x69, 0x40, 0x6A, 0x40, 0x6B, 0x40, 0x6C, 0x40, 0x6D, 0x40, - 0x6E, 0x40, 0x6F, 0x40, 0x70, 0x40, 0x71, 0x40, 0x72, 0x40, 0x73, 0x40, 0x74, 0x40, 0x75, 0x40, 0x76, 0x40, - 0x77, 0x40, 0x78, 0x40, 0x79, 0x40, 0x7A, 0x40, 0x7B, 0x40, 0x7C, 0x40, 0x7D, 0x40, 0x7E, 0x40, 0x7F, 0x40, - 0x80, 0x40, 0x81, 0x40, 0x82, 0x40, 0x83, 0x40, 0x84, 0x40, 0x85, 0x40, 0x86, 0x40, 0x87, 0x40, 0x88, 0x40, - 0x89, 0x40, 0x8A, 0x40, 0x8B, 0x40, 0x8C, 0x40, 0x8D, 0x40, 0x8E, 0x40, 0x8F, 0x40, 0x90, 0x40, 0x91, 0x40, - 0x92, 0x40, 0x93, 0x40, 0x94, 0x40, 0x95, 0x40, 0x96, 0x40, 0x97, 0x40, 0x98, 0x40, 0x99, 0x40, 0x9A, 0x40, - 0x9B, 0x40, 0x9C, 0x40, 0x9D, 0x40, 0x9E, 0x40, 0x9F, 0x40, 0xA0, 0x40, 0xA1, 0x40, 0xA2, 0x40, 0xA3, 0x40, - 0xA4, 0x40, 0xA5, 0x40, 0xA6, 0x40, 0xA7, 0x40, 0xA8, 0x40, 0xA9, 0x40, 0xAA, 0x40, 0xAB, 0x40, 0xAC, 0x40, - 0xAD, 0x40, 0xAE, 0x40, 0xAF, 0x40, 0xB0, 0x40, 0xB1, 0x40, 0xB2, 0x40, 0xB3, 0x40, 0xB4, 0x40, 0xB5, 0x40, - 0xB6, 0x40, 0xB7, 0x40, 0xB8, 0x40, 0xB9, 0x40, 0xBA, 0x40, 0xBB, 0x40, 0xBC, 0x40, 0xBD, 0x40, 0xBE, 0x40, - 0xBF, 0x40, 0xC0, 0x40, 0xC1, 0x40, 0xC2, 0x40, 0xC3, 0x40, 0xC4, 0x40, 0xC5, 0x40, 0xC6, 0x40, 0xC7, 0x40, - 0xC8, 0x40, 0xC9, 0x40, 0xCA, 0x40, 0xCB, 0x40, 0xCC, 0x40, 0xCD, 0x40, 0xCE, 0x40, 0xCF, 0x40, 0xD0, 0x40, - 0xD1, 0x40, 0xD2, 0x40, 0xD3, 0x40, 0xD4, 0x40, 0xD5, 0x40, 0xD6, 0x40, 0xD7, 0x40, 0xD8, 0x40, 0xD9, 0x40, - 0xDA, 0x40, 0xDB, 0x40, 0xDC, 0x40, 0xDD, 0x40, 0xDE, 0x40, 0xDF, 0x40, 0xE0, 0x40, 0xE1, 0x40, 0xE2, 0x40, - 0xE3, 0x40, 0xE4, 0x40, 0xE5, 0x40, 0xE6, 0x40, 0xE7, 0x40, 0xE8, 0x40, 0xE9, 0x40, 0xEA, 0x40, 0xEB, 0x40, - 0xEC, 0x40, 0xED, 0x40, 0xEE, 0x40, 0xEF, 0x40, 0xF0, 0x40, 0xF1, 0x40, 0xF2, 0x40, 0xF3, 0x40, 0xF4, 0x40, - 0xF5, 0x40, 0xF6, 0x40, 0xF7, 0x40, 0xF8, 0x40, 0xF9, 0x40, 0xFA, 0x40, 0xFB, 0x40, 0xFC, 0x40, 0xFD, 0x40, - 0xFE, 0x40, 0xFF, 0x40, 0xA0, 0x50, 0xA1, 0x50, 0xA2, 0x50, 0xA3, 0x50, 0xA4, 0x50, 0xA5, 0x50, 0xA6, 0x50, - 0xA7, 0x50, 0xA8, 0x50, 0xA9, 0x50, 0xAA, 0x50, 0xAB, 0x50, 0xAC, 0x50, 0xAD, 0x50, 0xAE, 0x50, 0xAF, 0x50, - 0xB0, 0x50, 0xB1, 0x50, 0xB2, 0x50, 0xB3, 0x50, 0xB4, 0x50, 0xB5, 0x50, 0xB6, 0x50, 0xB7, 0x50, 0xB8, 0x50, - 0xB9, 0x50, 0xBA, 0x50, 0xBB, 0x50, 0xBC, 0x50, 0xBD, 0x50, 0xBE, 0x50, 0xBF, 0x50, 0xC0, 0x50, 0xC1, 0x50, - 0xC2, 0x50, 0xC3, 0x50, 0xC4, 0x50, 0xC5, 0x50, 0xC6, 0x50, 0xC7, 0x50, 0xC8, 0x50, 0xC9, 0x50, 0xCA, 0x50, - 0xCB, 0x50, 0xCC, 0x50, 0xCD, 0x50, 0xCE, 0x50, 0xCF, 0x50, 0xD0, 0x50, 0xD1, 0x50, 0xD2, 0x50, 0xD3, 0x50, - 0xD4, 0x50, 0xD5, 0x50, 0xD6, 0x50, 0xD7, 0x50, 0xD8, 0x50, 0xD9, 0x50, 0xDA, 0x50, 0xDB, 0x50, 0xDC, 0x50, - 0xDD, 0x50, 0xDE, 0x50, 0xDF, 0x50, 0xE0, 0x50, 0xE1, 0x50, 0xE2, 0x50, 0xE3, 0x50, 0xE4, 0x50, 0xE5, 0x50, - 0xE6, 0x50, 0xE7, 0x50, 0xE8, 0x50, 0xE9, 0x50, 0xEA, 0x50, 0xEB, 0x50, 0xEC, 0x50, 0xED, 0x50, 0xEE, 0x50, - 0xEF, 0x50, 0xF0, 0x50, 0xF1, 0x50, 0xF2, 0x50, 0xF3, 0x50, 0xF4, 0x50, 0xF5, 0x50, 0xF6, 0x50, 0xF7, 0x50, - 0xF8, 0x50, 0xF9, 0x50, 0xFA, 0x50, 0xFB, 0x50, 0xFC, 0x50, 0xFD, 0x50, 0xFE, 0x50, 0xFF, 0x50, 0x00, 0xD0, - 0x01, 0x50, 0x02, 0x50, 0x03, 0x50, 0x04, 0x50, 0x05, 0x50, 0x06, 0x50, 0x07, 0x50, 0x08, 0x50, 0x09, 0x50, - 0x0A, 0x50, 0x0B, 0x50, 0x0C, 0x50, 0x0D, 0x50, 0x0E, 0x50, 0x0F, 0x50, 0x10, 0x50, 0x11, 0x50, 0x12, 0x50, - 0x13, 0x50, 0x14, 0x50, 0x15, 0x50, 0x16, 0x50, 0x17, 0x50, 0x18, 0x50, 0x19, 0x50, 0x1A, 0x50, 0x1B, 0x50, - 0x1C, 0x50, 0x1D, 0x50, 0x1E, 0x50, 0x1F, 0x50, 0x20, 0x50, 0x21, 0x50, 0x22, 0x50, 0x23, 0x50, 0x24, 0x50, - 0x25, 0x50, 0x26, 0x50, 0x27, 0x50, 0x28, 0x50, 0x29, 0x50, 0x2A, 0x50, 0x2B, 0x50, 0x2C, 0x50, 0x2D, 0x50, - 0x2E, 0x50, 0x2F, 0x50, 0x30, 0x50, 0x31, 0x50, 0x32, 0x50, 0x33, 0x50, 0x34, 0x50, 0x35, 0x50, 0x36, 0x50, - 0x37, 0x50, 0x38, 0x50, 0x39, 0x50, 0x3A, 0x50, 0x3B, 0x50, 0x3C, 0x50, 0x3D, 0x50, 0x3E, 0x50, 0x3F, 0x50, - 0x40, 0x50, 0x41, 0x50, 0x42, 0x50, 0x43, 0x50, 0x44, 0x50, 0x45, 0x50, 0x46, 0x50, 0x47, 0x50, 0x48, 0x50, - 0x49, 0x50, 0x4A, 0x50, 0x4B, 0x50, 0x4C, 0x50, 0x4D, 0x50, 0x4E, 0x50, 0x4F, 0x50, 0x50, 0x50, 0x51, 0x50, - 0x52, 0x50, 0x53, 0x50, 0x54, 0x50, 0x55, 0x50, 0x56, 0x50, 0x57, 0x50, 0x58, 0x50, 0x59, 0x50, 0x5A, 0x50, - 0x5B, 0x50, 0x5C, 0x50, 0x5D, 0x50, 0x5E, 0x50, 0x5F, 0x50, 0x60, 0x50, 0x61, 0x50, 0x62, 0x50, 0x63, 0x50, - 0x64, 0x50, 0x65, 0x50, 0x66, 0x50, 0x67, 0x50, 0x68, 0x50, 0x69, 0x50, 0x6A, 0x50, 0x6B, 0x50, 0x6C, 0x50, - 0x6D, 0x50, 0x6E, 0x50, 0x6F, 0x50, 0x70, 0x50, 0x71, 0x50, 0x72, 0x50, 0x73, 0x50, 0x74, 0x50, 0x75, 0x50, - 0x76, 0x50, 0x77, 0x50, 0x78, 0x50, 0x79, 0x50, 0x7A, 0x50, 0x7B, 0x50, 0x7C, 0x50, 0x7D, 0x50, 0x7E, 0x50, - 0x7F, 0x50, 0x80, 0x50, 0x81, 0x50, 0x82, 0x50, 0x83, 0x50, 0x84, 0x50, 0x85, 0x50, 0x86, 0x50, 0x87, 0x50, - 0x88, 0x50, 0x89, 0x50, 0x8A, 0x50, 0x8B, 0x50, 0x8C, 0x50, 0x8D, 0x50, 0x8E, 0x50, 0x8F, 0x50, 0x90, 0x50, - 0x91, 0x50, 0x92, 0x50, 0x93, 0x50, 0x94, 0x50, 0x95, 0x50, 0x96, 0x50, 0x97, 0x50, 0x98, 0x50, 0x99, 0x50, - 0x9A, 0x50, 0x9B, 0x50, 0x9C, 0x50, 0x9D, 0x50, 0x9E, 0x50, 0x9F, 0x50, 0xFA, 0x40, 0xFB, 0x40, 0xFC, 0x40, - 0xFD, 0x40, 0xFE, 0x40, 0xFF, 0x40, 0x00, 0xC0, 0x01, 0x40, 0x02, 0x40, 0x03, 0x40, 0x04, 0x40, 0x05, 0x40, - 0x06, 0x40, 0x07, 0x40, 0x08, 0x40, 0x09, 0x40, 0x0A, 0x40, 0x0B, 0x40, 0x0C, 0x40, 0x0D, 0x40, 0x0E, 0x40, - 0x0F, 0x40, 0x10, 0x40, 0x11, 0x40, 0x12, 0x40, 0x13, 0x40, 0x14, 0x40, 0x15, 0x40, 0x16, 0x40, 0x17, 0x40, - 0x18, 0x40, 0x19, 0x40, 0x1A, 0x40, 0x1B, 0x40, 0x1C, 0x40, 0x1D, 0x40, 0x1E, 0x40, 0x1F, 0x40, 0x20, 0x40, - 0x21, 0x40, 0x22, 0x40, 0x23, 0x40, 0x24, 0x40, 0x25, 0x40, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, - 0x2A, 0x40, 0x2B, 0x40, 0x2C, 0x40, 0x2D, 0x40, 0x2E, 0x40, 0x2F, 0x40, 0x30, 0x40, 0x31, 0x40, 0x32, 0x40, - 0x33, 0x40, 0x34, 0x40, 0x35, 0x40, 0x36, 0x40, 0x37, 0x40, 0x38, 0x40, 0x39, 0x40, 0x3A, 0x40, 0x3B, 0x40, - 0x3C, 0x40, 0x3D, 0x40, 0x3E, 0x40, 0x3F, 0x40, 0x40, 0x40, 0x41, 0x40, 0x42, 0x40, 0x43, 0x40, 0x44, 0x40, - 0x45, 0x40, 0x46, 0x40, 0x47, 0x40, 0x48, 0x40, 0x49, 0x40, 0x4A, 0x40, 0x4B, 0x40, 0x4C, 0x40, 0x4D, 0x40, - 0x4E, 0x40, 0x4F, 0x40, 0x50, 0x40, 0x51, 0x40, 0x52, 0x40, 0x53, 0x40, 0x54, 0x40, 0x55, 0x40, 0x56, 0x40, - 0x57, 0x40, 0x58, 0x40, 0x59, 0x40, 0x5A, 0x40, 0x5B, 0x40, 0x5C, 0x40, 0x5D, 0x40, 0x5E, 0x40, 0x5F, 0x40, - 0x60, 0x40, 0x61, 0x40, 0x62, 0x40, 0x63, 0x40, 0x64, 0x40, 0x65, 0x40, 0x66, 0x40, 0x67, 0x40, 0x68, 0x40, - 0x69, 0x40, 0x6A, 0x40, 0x6B, 0x40, 0x6C, 0x40, 0x6D, 0x40, 0x6E, 0x40, 0x6F, 0x40, 0x70, 0x40, 0x71, 0x40, - 0x72, 0x40, 0x73, 0x40, 0x74, 0x40, 0x75, 0x40, 0x76, 0x40, 0x77, 0x40, 0x78, 0x40, 0x79, 0x40, 0x7A, 0x40, - 0x7B, 0x40, 0x7C, 0x40, 0x7D, 0x40, 0x7E, 0x40, 0x7F, 0x40, 0x80, 0x40, 0x81, 0x40, 0x82, 0x40, 0x83, 0x40, - 0x84, 0x40, 0x85, 0x40, 0x86, 0x40, 0x87, 0x40, 0x88, 0x40, 0x89, 0x40, 0x8A, 0x40, 0x8B, 0x40, 0x8C, 0x40, - 0x8D, 0x40, 0x8E, 0x40, 0x8F, 0x40, 0x90, 0x40, 0x91, 0x40, 0x92, 0x40, 0x93, 0x40, 0x94, 0x40, 0x95, 0x40, - 0x96, 0x40, 0x97, 0x40, 0x98, 0x40, 0x99, 0x40, 0x9A, 0x40, 0x9B, 0x40, 0x9C, 0x40, 0x9D, 0x40, 0x9E, 0x40, - 0x9F, 0x40, 0xA0, 0x40, 0xA1, 0x40, 0xA2, 0x40, 0xA3, 0x40, 0xA4, 0x40, 0xA5, 0x40, 0xA6, 0x40, 0xA7, 0x40, - 0xA8, 0x40, 0xA9, 0x40, 0xAA, 0x40, 0xAB, 0x40, 0xAC, 0x40, 0xAD, 0x40, 0xAE, 0x40, 0xAF, 0x40, 0xB0, 0x40, - 0xB1, 0x40, 0xB2, 0x40, 0xB3, 0x40, 0xB4, 0x40, 0xB5, 0x40, 0xB6, 0x40, 0xB7, 0x40, 0xB8, 0x40, 0xB9, 0x40, - 0xBA, 0x40, 0xBB, 0x40, 0xBC, 0x40, 0xBD, 0x40, 0xBE, 0x40, 0xBF, 0x40, 0xC0, 0x40, 0xC1, 0x40, 0xC2, 0x40, - 0xC3, 0x40, 0xC4, 0x40, 0xC5, 0x40, 0xC6, 0x40, 0xC7, 0x40, 0xC8, 0x40, 0xC9, 0x40, 0xCA, 0x40, 0xCB, 0x40, - 0xCC, 0x40, 0xCD, 0x40, 0xCE, 0x40, 0xCF, 0x40, 0xD0, 0x40, 0xD1, 0x40, 0xD2, 0x40, 0xD3, 0x40, 0xD4, 0x40, - 0xD5, 0x40, 0xD6, 0x40, 0xD7, 0x40, 0xD8, 0x40, 0xD9, 0x40, 0xDA, 0x40, 0xDB, 0x40, 0xDC, 0x40, 0xDD, 0x40, - 0xDE, 0x40, 0xDF, 0x40, 0xE0, 0x40, 0xE1, 0x40, 0xE2, 0x40, 0xE3, 0x40, 0xE4, 0x40, 0xE5, 0x40, 0xE6, 0x40, - 0xE7, 0x40, 0xE8, 0x40, 0xE9, 0x40, 0xEA, 0x40, 0xEB, 0x40, 0xEC, 0x40, 0xED, 0x40, 0xEE, 0x40, 0xEF, 0x40, - 0xF0, 0x40, 0xF1, 0x40, 0xF2, 0x40, 0xF3, 0x40, 0xF4, 0x40, 0xF5, 0x40, 0xF6, 0x40, 0xF7, 0x40, 0xF8, 0x40, - 0xF9, 0x40, 0x9A, 0x50, 0x9B, 0x50, 0x9C, 0x50, 0x9D, 0x50, 0x9E, 0x50, 0x9F, 0x50, 0xA0, 0x50, 0xA1, 0x50, - 0xA2, 0x50, 0xA3, 0x50, 0xA4, 0x50, 0xA5, 0x50, 0xA6, 0x50, 0xA7, 0x50, 0xA8, 0x50, 0xA9, 0x50, 0xAA, 0x50, - 0xAB, 0x50, 0xAC, 0x50, 0xAD, 0x50, 0xAE, 0x50, 0xAF, 0x50, 0xB0, 0x50, 0xB1, 0x50, 0xB2, 0x50, 0xB3, 0x50, - 0xB4, 0x50, 0xB5, 0x50, 0xB6, 0x50, 0xB7, 0x50, 0xB8, 0x50, 0xB9, 0x50, 0xBA, 0x50, 0xBB, 0x50, 0xBC, 0x50, - 0xBD, 0x50, 0xBE, 0x50, 0xBF, 0x50, 0xC0, 0x50, 0xC1, 0x50, 0xC2, 0x50, 0xC3, 0x50, 0xC4, 0x50, 0xC5, 0x50, - 0xC6, 0x50, 0xC7, 0x50, 0xC8, 0x50, 0xC9, 0x50, 0xCA, 0x50, 0xCB, 0x50, 0xCC, 0x50, 0xCD, 0x50, 0xCE, 0x50, - 0xCF, 0x50, 0xD0, 0x50, 0xD1, 0x50, 0xD2, 0x50, 0xD3, 0x50, 0xD4, 0x50, 0xD5, 0x50, 0xD6, 0x50, 0xD7, 0x50, - 0xD8, 0x50, 0xD9, 0x50, 0xDA, 0x50, 0xDB, 0x50, 0xDC, 0x50, 0xDD, 0x50, 0xDE, 0x50, 0xDF, 0x50, 0xE0, 0x50, - 0xE1, 0x50, 0xE2, 0x50, 0xE3, 0x50, 0xE4, 0x50, 0xE5, 0x50, 0xE6, 0x50, 0xE7, 0x50, 0xE8, 0x50, 0xE9, 0x50, - 0xEA, 0x50, 0xEB, 0x50, 0xEC, 0x50, 0xED, 0x50, 0xEE, 0x50, 0xEF, 0x50, 0xF0, 0x50, 0xF1, 0x50, 0xF2, 0x50, - 0xF3, 0x50, 0xF4, 0x50, 0xF5, 0x50, 0xF6, 0x50, 0xF7, 0x50, 0xF8, 0x50, 0xF9, 0x50, 0xFA, 0x50, 0xFB, 0x50, - 0xFC, 0x50, 0xFD, 0x50, 0xFE, 0x50, 0xFF, 0x50, 0x00, 0xD0, 0x01, 0x50, 0x02, 0x50, 0x03, 0x50, 0x04, 0x50, - 0x05, 0x50, 0x06, 0x50, 0x07, 0x50, 0x08, 0x50, 0x09, 0x50, 0x0A, 0x50, 0x0B, 0x50, 0x0C, 0x50, 0x0D, 0x50, - 0x0E, 0x50, 0x0F, 0x50, 0x10, 0x50, 0x11, 0x50, 0x12, 0x50, 0x13, 0x50, 0x14, 0x50, 0x15, 0x50, 0x16, 0x50, - 0x17, 0x50, 0x18, 0x50, 0x19, 0x50, 0x1A, 0x50, 0x1B, 0x50, 0x1C, 0x50, 0x1D, 0x50, 0x1E, 0x50, 0x1F, 0x50, - 0x20, 0x50, 0x21, 0x50, 0x22, 0x50, 0x23, 0x50, 0x24, 0x50, 0x25, 0x50, 0x26, 0x50, 0x27, 0x50, 0x28, 0x50, - 0x29, 0x50, 0x2A, 0x50, 0x2B, 0x50, 0x2C, 0x50, 0x2D, 0x50, 0x2E, 0x50, 0x2F, 0x50, 0x30, 0x50, 0x31, 0x50, - 0x32, 0x50, 0x33, 0x50, 0x34, 0x50, 0x35, 0x50, 0x36, 0x50, 0x37, 0x50, 0x38, 0x50, 0x39, 0x50, 0x3A, 0x50, - 0x3B, 0x50, 0x3C, 0x50, 0x3D, 0x50, 0x3E, 0x50, 0x3F, 0x50, 0x40, 0x50, 0x41, 0x50, 0x42, 0x50, 0x43, 0x50, - 0x44, 0x50, 0x45, 0x50, 0x46, 0x50, 0x47, 0x50, 0x48, 0x50, 0x49, 0x50, 0x4A, 0x50, 0x4B, 0x50, 0x4C, 0x50, - 0x4D, 0x50, 0x4E, 0x50, 0x4F, 0x50, 0x50, 0x50, 0x51, 0x50, 0x52, 0x50, 0x53, 0x50, 0x54, 0x50, 0x55, 0x50, - 0x56, 0x50, 0x57, 0x50, 0x58, 0x50, 0x59, 0x50, 0x5A, 0x50, 0x5B, 0x50, 0x5C, 0x50, 0x5D, 0x50, 0x5E, 0x50, - 0x5F, 0x50, 0x60, 0x50, 0x61, 0x50, 0x62, 0x50, 0x63, 0x50, 0x64, 0x50, 0x65, 0x50, 0x66, 0x50, 0x67, 0x50, - 0x68, 0x50, 0x69, 0x50, 0x6A, 0x50, 0x6B, 0x50, 0x6C, 0x50, 0x6D, 0x50, 0x6E, 0x50, 0x6F, 0x50, 0x70, 0x50, - 0x71, 0x50, 0x72, 0x50, 0x73, 0x50, 0x74, 0x50, 0x75, 0x50, 0x76, 0x50, 0x77, 0x50, 0x78, 0x50, 0x79, 0x50, - 0x7A, 0x50, 0x7B, 0x50, 0x7C, 0x50, 0x7D, 0x50, 0x7E, 0x50, 0x7F, 0x50, 0x80, 0x50, 0x81, 0x50, 0x82, 0x50, - 0x83, 0x50, 0x84, 0x50, 0x85, 0x50, 0x86, 0x50, 0x87, 0x50, 0x88, 0x50, 0x89, 0x50, 0x8A, 0x50, 0x8B, 0x50, - 0x8C, 0x50, 0x8D, 0x50, 0x8E, 0x50, 0x8F, 0x50, 0x90, 0x50, 0x91, 0x50, 0x92, 0x50, 0x93, 0x50, 0x94, 0x50, - 0x95, 0x50, 0x96, 0x50, 0x97, 0x50, 0x98, 0x50, 0x99, 0x50, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, - 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, - 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, - 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, - 0x25, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, - 0x28, 0x00, 0x29, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x30, 0x00, - 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, - 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, - 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x50, 0x00, 0x51, 0x00, - 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, - 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, - 0x64, 0x00, 0x65, 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, 0x65, 0x00, 0x66, 0x00, - 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, - 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, - 0x79, 0x00, 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x80, 0x00, 0x81, 0x00, - 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x90, 0x00, - 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, - 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x00, 0x90, 0x01, 0x10, 0x02, 0x10, - 0x03, 0x10, 0x04, 0x10, 0x05, 0x10, 0x00, 0x90, 0x01, 0x10, 0x02, 0x10, 0x03, 0x10, 0x04, 0x10, 0x05, 0x10, - 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, 0x09, 0x10, 0x10, 0x10, 0x11, 0x10, 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, - 0x15, 0x10, 0x10, 0x10, 0x11, 0x10, 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, 0x15, 0x10, 0x16, 0x10, 0x17, 0x10, - 0x18, 0x10, 0x19, 0x10, 0x20, 0x10, 0x21, 0x10, 0x22, 0x10, 0x23, 0x10, 0x24, 0x10, 0x25, 0x10, 0x20, 0x10, - 0x21, 0x10, 0x22, 0x10, 0x23, 0x10, 0x24, 0x10, 0x25, 0x10, 0x26, 0x10, 0x27, 0x10, 0x28, 0x10, 0x29, 0x10, - 0x30, 0x10, 0x31, 0x10, 0x32, 0x10, 0x33, 0x10, 0x34, 0x10, 0x35, 0x10, 0x30, 0x10, 0x31, 0x10, 0x32, 0x10, - 0x33, 0x10, 0x34, 0x10, 0x35, 0x10, 0x36, 0x10, 0x37, 0x10, 0x38, 0x10, 0x39, 0x10, 0x40, 0x10, 0x41, 0x10, - 0x42, 0x10, 0x43, 0x10, 0x44, 0x10, 0x45, 0x10, 0x40, 0x10, 0x41, 0x10, 0x42, 0x10, 0x43, 0x10, 0x44, 0x10, - 0x45, 0x10, 0x46, 0x10, 0x47, 0x10, 0x48, 0x10, 0x49, 0x10, 0x50, 0x10, 0x51, 0x10, 0x52, 0x10, 0x53, 0x10, - 0x54, 0x10, 0x55, 0x10, 0x50, 0x10, 0x51, 0x10, 0x52, 0x10, 0x53, 0x10, 0x54, 0x10, 0x55, 0x10, 0x56, 0x10, - 0x57, 0x10, 0x58, 0x10, 0x59, 0x10, 0x60, 0x10, 0x61, 0x10, 0x62, 0x10, 0x63, 0x10, 0x64, 0x10, 0x65, 0x10, - 0x60, 0x10, 0x61, 0x10, 0x62, 0x10, 0x63, 0x10, 0x64, 0x10, 0x65, 0x10, 0x66, 0x10, 0x67, 0x10, 0x68, 0x10, - 0x69, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72, 0x10, 0x73, 0x10, 0x74, 0x10, 0x75, 0x10, 0x70, 0x10, 0x71, 0x10, - 0x72, 0x10, 0x73, 0x10, 0x74, 0x10, 0x75, 0x10, 0x76, 0x10, 0x77, 0x10, 0x78, 0x10, 0x79, 0x10, 0x80, 0x10, - 0x81, 0x10, 0x82, 0x10, 0x83, 0x10, 0x84, 0x10, 0x85, 0x10, 0x80, 0x10, 0x81, 0x10, 0x82, 0x10, 0x83, 0x10, - 0x84, 0x10, 0x85, 0x10, 0x86, 0x10, 0x87, 0x10, 0x88, 0x10, 0x89, 0x10, 0x90, 0x10, 0x91, 0x10, 0x92, 0x10, - 0x93, 0x10, 0x94, 0x10, 0x95, 0x10, 0x90, 0x10, 0x91, 0x10, 0x92, 0x10, 0x93, 0x10, 0x94, 0x10, 0x95, 0x10, - 0x96, 0x10, 0x97, 0x10, 0x98, 0x10, 0x99, 0x10, 0xA0, 0x10, 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, - 0xA5, 0x10, 0xA0, 0x10, 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, - 0xA8, 0x10, 0xA9, 0x10, 0xB0, 0x10, 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, 0xB5, 0x10, 0xB0, 0x10, - 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10, 0xB9, 0x10, - 0xC0, 0x10, 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xC5, 0x10, 0xC0, 0x10, 0xC1, 0x10, 0xC2, 0x10, - 0xC3, 0x10, 0xC4, 0x10, 0xC5, 0x10, 0xC6, 0x10, 0xC7, 0x10, 0xC8, 0x10, 0xC9, 0x10, 0xD0, 0x10, 0xD1, 0x10, - 0xD2, 0x10, 0xD3, 0x10, 0xD4, 0x10, 0xD5, 0x10, 0xD0, 0x10, 0xD1, 0x10, 0xD2, 0x10, 0xD3, 0x10, 0xD4, 0x10, - 0xD5, 0x10, 0xD6, 0x10, 0xD7, 0x10, 0xD8, 0x10, 0xD9, 0x10, 0xE0, 0x10, 0xE1, 0x10, 0xE2, 0x10, 0xE3, 0x10, - 0xE4, 0x10, 0xE5, 0x10, 0xE0, 0x10, 0xE1, 0x10, 0xE2, 0x10, 0xE3, 0x10, 0xE4, 0x10, 0xE5, 0x10, 0xE6, 0x10, - 0xE7, 0x10, 0xE8, 0x10, 0xE9, 0x10, 0xF0, 0x10, 0xF1, 0x10, 0xF2, 0x10, 0xF3, 0x10, 0xF4, 0x10, 0xF5, 0x10, - 0xF0, 0x10, 0xF1, 0x10, 0xF2, 0x10, 0xF3, 0x10, 0xF4, 0x10, 0xF5, 0x10, 0xF6, 0x10, 0xF7, 0x10, 0xF8, 0x10, - 0xF9, 0x10, 0x00, 0x90, 0x01, 0x10, 0x02, 0x10, 0x03, 0x10, 0x04, 0x10, 0x05, 0x10, 0x00, 0x90, 0x01, 0x10, - 0x02, 0x10, 0x03, 0x10, 0x04, 0x10, 0x05, 0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, 0x09, 0x10, 0x10, 0x10, - 0x11, 0x10, 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, 0x15, 0x10, 0x10, 0x10, 0x11, 0x10, 0x12, 0x10, 0x13, 0x10, - 0x14, 0x10, 0x15, 0x10, 0x16, 0x10, 0x17, 0x10, 0x18, 0x10, 0x19, 0x10, 0x20, 0x10, 0x21, 0x10, 0x22, 0x10, - 0x23, 0x10, 0x24, 0x10, 0x25, 0x10, 0x20, 0x10, 0x21, 0x10, 0x22, 0x10, 0x23, 0x10, 0x24, 0x10, 0x25, 0x10, - 0x26, 0x10, 0x27, 0x10, 0x28, 0x10, 0x29, 0x10, 0x30, 0x10, 0x31, 0x10, 0x32, 0x10, 0x33, 0x10, 0x34, 0x10, - 0x35, 0x10, 0x30, 0x10, 0x31, 0x10, 0x32, 0x10, 0x33, 0x10, 0x34, 0x10, 0x35, 0x10, 0x36, 0x10, 0x37, 0x10, - 0x38, 0x10, 0x39, 0x10, 0x40, 0x10, 0x41, 0x10, 0x42, 0x10, 0x43, 0x10, 0x44, 0x10, 0x45, 0x10, 0x40, 0x10, - 0x41, 0x10, 0x42, 0x10, 0x43, 0x10, 0x44, 0x10, 0x45, 0x10, 0x46, 0x10, 0x47, 0x10, 0x48, 0x10, 0x49, 0x10, - 0x50, 0x10, 0x51, 0x10, 0x52, 0x10, 0x53, 0x10, 0x54, 0x10, 0x55, 0x10, 0x50, 0x10, 0x51, 0x10, 0x52, 0x10, - 0x53, 0x10, 0x54, 0x10, 0x55, 0x10, 0x56, 0x10, 0x57, 0x10, 0x58, 0x10, 0x59, 0x10, 0x60, 0x10, 0x61, 0x10, - 0x62, 0x10, 0x63, 0x10, 0x64, 0x10, 0x65, 0x10, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, - 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, - 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, 0x1C, 0x00, - 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, - 0x26, 0x00, 0x27, 0x00, 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00, 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, - 0x2F, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, - 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00, 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40, 0x00, - 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, - 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, - 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00, - 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, - 0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B, 0x00, 0x6C, 0x00, 0x6D, 0x00, - 0x6E, 0x00, 0x6F, 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, - 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7A, 0x00, 0x7B, 0x00, 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00, - 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, 0x88, 0x00, - 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00, 0x90, 0x00, 0x91, 0x00, - 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, - 0x9B, 0x00, 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00, 0x00, 0x90, 0x01, 0x10, 0x02, 0x10, 0x03, 0x10, - 0x04, 0x10, 0x05, 0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, 0x09, 0x10, 0x0A, 0x10, 0x0B, 0x10, 0x0C, 0x10, - 0x0D, 0x10, 0x0E, 0x10, 0x0F, 0x10, 0x10, 0x10, 0x11, 0x10, 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, 0x15, 0x10, - 0x16, 0x10, 0x17, 0x10, 0x18, 0x10, 0x19, 0x10, 0x1A, 0x10, 0x1B, 0x10, 0x1C, 0x10, 0x1D, 0x10, 0x1E, 0x10, - 0x1F, 0x10, 0x20, 0x10, 0x21, 0x10, 0x22, 0x10, 0x23, 0x10, 0x24, 0x10, 0x25, 0x10, 0x26, 0x10, 0x27, 0x10, - 0x28, 0x10, 0x29, 0x10, 0x2A, 0x10, 0x2B, 0x10, 0x2C, 0x10, 0x2D, 0x10, 0x2E, 0x10, 0x2F, 0x10, 0x30, 0x10, - 0x31, 0x10, 0x32, 0x10, 0x33, 0x10, 0x34, 0x10, 0x35, 0x10, 0x36, 0x10, 0x37, 0x10, 0x38, 0x10, 0x39, 0x10, - 0x3A, 0x10, 0x3B, 0x10, 0x3C, 0x10, 0x3D, 0x10, 0x3E, 0x10, 0x3F, 0x10, 0x40, 0x10, 0x41, 0x10, 0x42, 0x10, - 0x43, 0x10, 0x44, 0x10, 0x45, 0x10, 0x46, 0x10, 0x47, 0x10, 0x48, 0x10, 0x49, 0x10, 0x4A, 0x10, 0x4B, 0x10, - 0x4C, 0x10, 0x4D, 0x10, 0x4E, 0x10, 0x4F, 0x10, 0x50, 0x10, 0x51, 0x10, 0x52, 0x10, 0x53, 0x10, 0x54, 0x10, - 0x55, 0x10, 0x56, 0x10, 0x57, 0x10, 0x58, 0x10, 0x59, 0x10, 0x5A, 0x10, 0x5B, 0x10, 0x5C, 0x10, 0x5D, 0x10, - 0x5E, 0x10, 0x5F, 0x10, 0x60, 0x10, 0x61, 0x10, 0x62, 0x10, 0x63, 0x10, 0x64, 0x10, 0x65, 0x10, 0x66, 0x10, - 0x67, 0x10, 0x68, 0x10, 0x69, 0x10, 0x6A, 0x10, 0x6B, 0x10, 0x6C, 0x10, 0x6D, 0x10, 0x6E, 0x10, 0x6F, 0x10, - 0x70, 0x10, 0x71, 0x10, 0x72, 0x10, 0x73, 0x10, 0x74, 0x10, 0x75, 0x10, 0x76, 0x10, 0x77, 0x10, 0x78, 0x10, - 0x79, 0x10, 0x7A, 0x10, 0x7B, 0x10, 0x7C, 0x10, 0x7D, 0x10, 0x7E, 0x10, 0x7F, 0x10, 0x80, 0x10, 0x81, 0x10, - 0x82, 0x10, 0x83, 0x10, 0x84, 0x10, 0x85, 0x10, 0x86, 0x10, 0x87, 0x10, 0x88, 0x10, 0x89, 0x10, 0x8A, 0x10, - 0x8B, 0x10, 0x8C, 0x10, 0x8D, 0x10, 0x8E, 0x10, 0x8F, 0x10, 0x90, 0x10, 0x91, 0x10, 0x92, 0x10, 0x93, 0x10, - 0x94, 0x10, 0x95, 0x10, 0x96, 0x10, 0x97, 0x10, 0x98, 0x10, 0x99, 0x10, 0x9A, 0x10, 0x9B, 0x10, 0x9C, 0x10, - 0x9D, 0x10, 0x9E, 0x10, 0x9F, 0x10, 0xA0, 0x10, 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, 0xA5, 0x10, - 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10, 0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10, 0xAD, 0x10, 0xAE, 0x10, - 0xAF, 0x10, 0xB0, 0x10, 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, - 0xB8, 0x10, 0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10, 0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10, - 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xC5, 0x10, 0xC6, 0x10, 0xC7, 0x10, 0xC8, 0x10, 0xC9, 0x10, - 0xCA, 0x10, 0xCB, 0x10, 0xCC, 0x10, 0xCD, 0x10, 0xCE, 0x10, 0xCF, 0x10, 0xD0, 0x10, 0xD1, 0x10, 0xD2, 0x10, - 0xD3, 0x10, 0xD4, 0x10, 0xD5, 0x10, 0xD6, 0x10, 0xD7, 0x10, 0xD8, 0x10, 0xD9, 0x10, 0xDA, 0x10, 0xDB, 0x10, - 0xDC, 0x10, 0xDD, 0x10, 0xDE, 0x10, 0xDF, 0x10, 0xE0, 0x10, 0xE1, 0x10, 0xE2, 0x10, 0xE3, 0x10, 0xE4, 0x10, - 0xE5, 0x10, 0xE6, 0x10, 0xE7, 0x10, 0xE8, 0x10, 0xE9, 0x10, 0xEA, 0x10, 0xEB, 0x10, 0xEC, 0x10, 0xED, 0x10, - 0xEE, 0x10, 0xEF, 0x10, 0xF0, 0x10, 0xF1, 0x10, 0xF2, 0x10, 0xF3, 0x10, 0xF4, 0x10, 0xF5, 0x10, 0xF6, 0x10, - 0xF7, 0x10, 0xF8, 0x10, 0xF9, 0x10, 0xFA, 0x10, 0xFB, 0x10, 0xFC, 0x10, 0xFD, 0x10, 0xFE, 0x10, 0xFF, 0x10, - 0x00, 0x90, 0x01, 0x10, 0x02, 0x10, 0x03, 0x10, 0x04, 0x10, 0x05, 0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, - 0x09, 0x10, 0x0A, 0x10, 0x0B, 0x10, 0x0C, 0x10, 0x0D, 0x10, 0x0E, 0x10, 0x0F, 0x10, 0x10, 0x10, 0x11, 0x10, - 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, 0x15, 0x10, 0x16, 0x10, 0x17, 0x10, 0x18, 0x10, 0x19, 0x10, 0x1A, 0x10, - 0x1B, 0x10, 0x1C, 0x10, 0x1D, 0x10, 0x1E, 0x10, 0x1F, 0x10, 0x20, 0x10, 0x21, 0x10, 0x22, 0x10, 0x23, 0x10, - 0x24, 0x10, 0x25, 0x10, 0x26, 0x10, 0x27, 0x10, 0x28, 0x10, 0x29, 0x10, 0x2A, 0x10, 0x2B, 0x10, 0x2C, 0x10, - 0x2D, 0x10, 0x2E, 0x10, 0x2F, 0x10, 0x30, 0x10, 0x31, 0x10, 0x32, 0x10, 0x33, 0x10, 0x34, 0x10, 0x35, 0x10, - 0x36, 0x10, 0x37, 0x10, 0x38, 0x10, 0x39, 0x10, 0x3A, 0x10, 0x3B, 0x10, 0x3C, 0x10, 0x3D, 0x10, 0x3E, 0x10, - 0x3F, 0x10, 0x40, 0x10, 0x41, 0x10, 0x42, 0x10, 0x43, 0x10, 0x44, 0x10, 0x45, 0x10, 0x46, 0x10, 0x47, 0x10, - 0x48, 0x10, 0x49, 0x10, 0x4A, 0x10, 0x4B, 0x10, 0x4C, 0x10, 0x4D, 0x10, 0x4E, 0x10, 0x4F, 0x10, 0x50, 0x10, - 0x51, 0x10, 0x52, 0x10, 0x53, 0x10, 0x54, 0x10, 0x55, 0x10, 0x56, 0x10, 0x57, 0x10, 0x58, 0x10, 0x59, 0x10, - 0x5A, 0x10, 0x5B, 0x10, 0x5C, 0x10, 0x5D, 0x10, 0x5E, 0x10, 0x5F, 0x10, 0x60, 0x10, 0x61, 0x10, 0x62, 0x10, - 0x63, 0x10, 0x64, 0x10, 0x65, 0x10, 0x00, 0xC0, 0x01, 0x40, 0x02, 0x40, 0x03, 0x40, 0x04, 0x40, 0x05, 0x40, - 0x06, 0x40, 0x07, 0x40, 0x08, 0x40, 0x09, 0x40, 0x0A, 0x40, 0x0B, 0x40, 0x0C, 0x40, 0x0D, 0x40, 0x0E, 0x40, - 0x0F, 0x40, 0x10, 0x40, 0x11, 0x40, 0x12, 0x40, 0x13, 0x40, 0x14, 0x40, 0x15, 0x40, 0x16, 0x40, 0x17, 0x40, - 0x18, 0x40, 0x19, 0x40, 0x1A, 0x40, 0x1B, 0x40, 0x1C, 0x40, 0x1D, 0x40, 0x1E, 0x40, 0x1F, 0x40, 0x20, 0x40, - 0x21, 0x40, 0x22, 0x40, 0x23, 0x40, 0x24, 0x40, 0x25, 0x40, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, - 0x2A, 0x40, 0x2B, 0x40, 0x2C, 0x40, 0x2D, 0x40, 0x2E, 0x40, 0x2F, 0x40, 0x30, 0x40, 0x31, 0x40, 0x32, 0x40, - 0x33, 0x40, 0x34, 0x40, 0x35, 0x40, 0x36, 0x40, 0x37, 0x40, 0x38, 0x40, 0x39, 0x40, 0x3A, 0x40, 0x3B, 0x40, - 0x3C, 0x40, 0x3D, 0x40, 0x3E, 0x40, 0x3F, 0x40, 0x40, 0x40, 0x41, 0x40, 0x42, 0x40, 0x43, 0x40, 0x44, 0x40, - 0x45, 0x40, 0x46, 0x40, 0x47, 0x40, 0x48, 0x40, 0x49, 0x40, 0x4A, 0x40, 0x4B, 0x40, 0x4C, 0x40, 0x4D, 0x40, - 0x4E, 0x40, 0x4F, 0x40, 0x50, 0x40, 0x51, 0x40, 0x52, 0x40, 0x53, 0x40, 0x54, 0x40, 0x55, 0x40, 0x56, 0x40, - 0x57, 0x40, 0x58, 0x40, 0x59, 0x40, 0x5A, 0x40, 0x5B, 0x40, 0x5C, 0x40, 0x5D, 0x40, 0x5E, 0x40, 0x5F, 0x40, - 0x60, 0x40, 0x61, 0x40, 0x62, 0x40, 0x63, 0x40, 0x64, 0x40, 0x65, 0x40, 0x66, 0x40, 0x67, 0x40, 0x68, 0x40, - 0x69, 0x40, 0x6A, 0x40, 0x6B, 0x40, 0x6C, 0x40, 0x6D, 0x40, 0x6E, 0x40, 0x6F, 0x40, 0x70, 0x40, 0x71, 0x40, - 0x72, 0x40, 0x73, 0x40, 0x74, 0x40, 0x75, 0x40, 0x76, 0x40, 0x77, 0x40, 0x78, 0x40, 0x79, 0x40, 0x7A, 0x40, - 0x7B, 0x40, 0x7C, 0x40, 0x7D, 0x40, 0x7E, 0x40, 0x7F, 0x40, 0x80, 0x40, 0x81, 0x40, 0x82, 0x40, 0x83, 0x40, - 0x84, 0x40, 0x85, 0x40, 0x86, 0x40, 0x87, 0x40, 0x88, 0x40, 0x89, 0x40, 0x8A, 0x40, 0x8B, 0x40, 0x8C, 0x40, - 0x8D, 0x40, 0x8E, 0x40, 0x8F, 0x40, 0x90, 0x40, 0x91, 0x40, 0x92, 0x40, 0x93, 0x40, 0x94, 0x40, 0x95, 0x40, - 0x96, 0x40, 0x97, 0x40, 0x98, 0x40, 0x99, 0x40, 0x9A, 0x40, 0x9B, 0x40, 0x9C, 0x40, 0x9D, 0x40, 0x9E, 0x40, - 0x9F, 0x40, 0xA0, 0x40, 0xA1, 0x40, 0xA2, 0x40, 0xA3, 0x40, 0xA4, 0x40, 0xA5, 0x40, 0xA6, 0x40, 0xA7, 0x40, - 0xA8, 0x40, 0xA9, 0x40, 0xAA, 0x40, 0xAB, 0x40, 0xAC, 0x40, 0xAD, 0x40, 0xAE, 0x40, 0xAF, 0x40, 0xB0, 0x40, - 0xB1, 0x40, 0xB2, 0x40, 0xB3, 0x40, 0xB4, 0x40, 0xB5, 0x40, 0xB6, 0x40, 0xB7, 0x40, 0xB8, 0x40, 0xB9, 0x40, - 0xBA, 0x40, 0xBB, 0x40, 0xBC, 0x40, 0xBD, 0x40, 0xBE, 0x40, 0xBF, 0x40, 0xC0, 0x40, 0xC1, 0x40, 0xC2, 0x40, - 0xC3, 0x40, 0xC4, 0x40, 0xC5, 0x40, 0xC6, 0x40, 0xC7, 0x40, 0xC8, 0x40, 0xC9, 0x40, 0xCA, 0x40, 0xCB, 0x40, - 0xCC, 0x40, 0xCD, 0x40, 0xCE, 0x40, 0xCF, 0x40, 0xD0, 0x40, 0xD1, 0x40, 0xD2, 0x40, 0xD3, 0x40, 0xD4, 0x40, - 0xD5, 0x40, 0xD6, 0x40, 0xD7, 0x40, 0xD8, 0x40, 0xD9, 0x40, 0xDA, 0x40, 0xDB, 0x40, 0xDC, 0x40, 0xDD, 0x40, - 0xDE, 0x40, 0xDF, 0x40, 0xE0, 0x40, 0xE1, 0x40, 0xE2, 0x40, 0xE3, 0x40, 0xE4, 0x40, 0xE5, 0x40, 0xE6, 0x40, - 0xE7, 0x40, 0xE8, 0x40, 0xE9, 0x40, 0xEA, 0x40, 0xEB, 0x40, 0xEC, 0x40, 0xED, 0x40, 0xEE, 0x40, 0xEF, 0x40, - 0xF0, 0x40, 0xF1, 0x40, 0xF2, 0x40, 0xF3, 0x40, 0xF4, 0x40, 0xF5, 0x40, 0xF6, 0x40, 0xF7, 0x40, 0xF8, 0x40, - 0xF9, 0x40, 0xFA, 0x40, 0xFB, 0x40, 0xFC, 0x40, 0xFD, 0x40, 0xFE, 0x40, 0xFF, 0x40, 0xA0, 0x50, 0xA1, 0x50, - 0xA2, 0x50, 0xA3, 0x50, 0xA4, 0x50, 0xA5, 0x50, 0xA6, 0x50, 0xA7, 0x50, 0xA8, 0x50, 0xA9, 0x50, 0xAA, 0x50, - 0xAB, 0x50, 0xAC, 0x50, 0xAD, 0x50, 0xAE, 0x50, 0xAF, 0x50, 0xB0, 0x50, 0xB1, 0x50, 0xB2, 0x50, 0xB3, 0x50, - 0xB4, 0x50, 0xB5, 0x50, 0xB6, 0x50, 0xB7, 0x50, 0xB8, 0x50, 0xB9, 0x50, 0xBA, 0x50, 0xBB, 0x50, 0xBC, 0x50, - 0xBD, 0x50, 0xBE, 0x50, 0xBF, 0x50, 0xC0, 0x50, 0xC1, 0x50, 0xC2, 0x50, 0xC3, 0x50, 0xC4, 0x50, 0xC5, 0x50, - 0xC6, 0x50, 0xC7, 0x50, 0xC8, 0x50, 0xC9, 0x50, 0xCA, 0x50, 0xCB, 0x50, 0xCC, 0x50, 0xCD, 0x50, 0xCE, 0x50, - 0xCF, 0x50, 0xD0, 0x50, 0xD1, 0x50, 0xD2, 0x50, 0xD3, 0x50, 0xD4, 0x50, 0xD5, 0x50, 0xD6, 0x50, 0xD7, 0x50, - 0xD8, 0x50, 0xD9, 0x50, 0xDA, 0x50, 0xDB, 0x50, 0xDC, 0x50, 0xDD, 0x50, 0xDE, 0x50, 0xDF, 0x50, 0xE0, 0x50, - 0xE1, 0x50, 0xE2, 0x50, 0xE3, 0x50, 0xE4, 0x50, 0xE5, 0x50, 0xE6, 0x50, 0xE7, 0x50, 0xE8, 0x50, 0xE9, 0x50, - 0xEA, 0x50, 0xEB, 0x50, 0xEC, 0x50, 0xED, 0x50, 0xEE, 0x50, 0xEF, 0x50, 0xF0, 0x50, 0xF1, 0x50, 0xF2, 0x50, - 0xF3, 0x50, 0xF4, 0x50, 0xF5, 0x50, 0xF6, 0x50, 0xF7, 0x50, 0xF8, 0x50, 0xF9, 0x50, 0xFA, 0x50, 0xFB, 0x50, - 0xFC, 0x50, 0xFD, 0x50, 0xFE, 0x50, 0xFF, 0x50, 0x00, 0xD0, 0x01, 0x50, 0x02, 0x50, 0x03, 0x50, 0x04, 0x50, - 0x05, 0x50, 0x06, 0x50, 0x07, 0x50, 0x08, 0x50, 0x09, 0x50, 0x0A, 0x50, 0x0B, 0x50, 0x0C, 0x50, 0x0D, 0x50, - 0x0E, 0x50, 0x0F, 0x50, 0x10, 0x50, 0x11, 0x50, 0x12, 0x50, 0x13, 0x50, 0x14, 0x50, 0x15, 0x50, 0x16, 0x50, - 0x17, 0x50, 0x18, 0x50, 0x19, 0x50, 0x1A, 0x50, 0x1B, 0x50, 0x1C, 0x50, 0x1D, 0x50, 0x1E, 0x50, 0x1F, 0x50, - 0x20, 0x50, 0x21, 0x50, 0x22, 0x50, 0x23, 0x50, 0x24, 0x50, 0x25, 0x50, 0x26, 0x50, 0x27, 0x50, 0x28, 0x50, - 0x29, 0x50, 0x2A, 0x50, 0x2B, 0x50, 0x2C, 0x50, 0x2D, 0x50, 0x2E, 0x50, 0x2F, 0x50, 0x30, 0x50, 0x31, 0x50, - 0x32, 0x50, 0x33, 0x50, 0x34, 0x50, 0x35, 0x50, 0x36, 0x50, 0x37, 0x50, 0x38, 0x50, 0x39, 0x50, 0x3A, 0x50, - 0x3B, 0x50, 0x3C, 0x50, 0x3D, 0x50, 0x3E, 0x50, 0x3F, 0x50, 0x40, 0x50, 0x41, 0x50, 0x42, 0x50, 0x43, 0x50, - 0x44, 0x50, 0x45, 0x50, 0x46, 0x50, 0x47, 0x50, 0x48, 0x50, 0x49, 0x50, 0x4A, 0x50, 0x4B, 0x50, 0x4C, 0x50, - 0x4D, 0x50, 0x4E, 0x50, 0x4F, 0x50, 0x50, 0x50, 0x51, 0x50, 0x52, 0x50, 0x53, 0x50, 0x54, 0x50, 0x55, 0x50, - 0x56, 0x50, 0x57, 0x50, 0x58, 0x50, 0x59, 0x50, 0x5A, 0x50, 0x5B, 0x50, 0x5C, 0x50, 0x5D, 0x50, 0x5E, 0x50, - 0x5F, 0x50, 0x60, 0x50, 0x61, 0x50, 0x62, 0x50, 0x63, 0x50, 0x64, 0x50, 0x65, 0x50, 0x66, 0x50, 0x67, 0x50, - 0x68, 0x50, 0x69, 0x50, 0x6A, 0x50, 0x6B, 0x50, 0x6C, 0x50, 0x6D, 0x50, 0x6E, 0x50, 0x6F, 0x50, 0x70, 0x50, - 0x71, 0x50, 0x72, 0x50, 0x73, 0x50, 0x74, 0x50, 0x75, 0x50, 0x76, 0x50, 0x77, 0x50, 0x78, 0x50, 0x79, 0x50, - 0x7A, 0x50, 0x7B, 0x50, 0x7C, 0x50, 0x7D, 0x50, 0x7E, 0x50, 0x7F, 0x50, 0x80, 0x50, 0x81, 0x50, 0x82, 0x50, - 0x83, 0x50, 0x84, 0x50, 0x85, 0x50, 0x86, 0x50, 0x87, 0x50, 0x88, 0x50, 0x89, 0x50, 0x8A, 0x50, 0x8B, 0x50, - 0x8C, 0x50, 0x8D, 0x50, 0x8E, 0x50, 0x8F, 0x50, 0x90, 0x50, 0x91, 0x50, 0x92, 0x50, 0x93, 0x50, 0x94, 0x50, - 0x95, 0x50, 0x96, 0x50, 0x97, 0x50, 0x98, 0x50, 0x99, 0x50, 0x9A, 0x50, 0x9B, 0x50, 0x9C, 0x50, 0x9D, 0x50, - 0x9E, 0x50, 0x9F, 0x50, 0xFA, 0x40, 0xFB, 0x40, 0xFC, 0x40, 0xFD, 0x40, 0xFE, 0x40, 0xFF, 0x40, 0x00, 0xC0, - 0x01, 0x40, 0x02, 0x40, 0x03, 0x40, 0x04, 0x40, 0x05, 0x40, 0x06, 0x40, 0x07, 0x40, 0x08, 0x40, 0x09, 0x40, - 0x0A, 0x40, 0x0B, 0x40, 0x0C, 0x40, 0x0D, 0x40, 0x0E, 0x40, 0x0F, 0x40, 0x10, 0x40, 0x11, 0x40, 0x12, 0x40, - 0x13, 0x40, 0x14, 0x40, 0x15, 0x40, 0x16, 0x40, 0x17, 0x40, 0x18, 0x40, 0x19, 0x40, 0x1A, 0x40, 0x1B, 0x40, - 0x1C, 0x40, 0x1D, 0x40, 0x1E, 0x40, 0x1F, 0x40, 0x20, 0x40, 0x21, 0x40, 0x22, 0x40, 0x23, 0x40, 0x24, 0x40, - 0x25, 0x40, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2A, 0x40, 0x2B, 0x40, 0x2C, 0x40, 0x2D, 0x40, - 0x2E, 0x40, 0x2F, 0x40, 0x30, 0x40, 0x31, 0x40, 0x32, 0x40, 0x33, 0x40, 0x34, 0x40, 0x35, 0x40, 0x36, 0x40, - 0x37, 0x40, 0x38, 0x40, 0x39, 0x40, 0x3A, 0x40, 0x3B, 0x40, 0x3C, 0x40, 0x3D, 0x40, 0x3E, 0x40, 0x3F, 0x40, - 0x40, 0x40, 0x41, 0x40, 0x42, 0x40, 0x43, 0x40, 0x44, 0x40, 0x45, 0x40, 0x46, 0x40, 0x47, 0x40, 0x48, 0x40, - 0x49, 0x40, 0x4A, 0x40, 0x4B, 0x40, 0x4C, 0x40, 0x4D, 0x40, 0x4E, 0x40, 0x4F, 0x40, 0x50, 0x40, 0x51, 0x40, - 0x52, 0x40, 0x53, 0x40, 0x54, 0x40, 0x55, 0x40, 0x56, 0x40, 0x57, 0x40, 0x58, 0x40, 0x59, 0x40, 0x5A, 0x40, - 0x5B, 0x40, 0x5C, 0x40, 0x5D, 0x40, 0x5E, 0x40, 0x5F, 0x40, 0x60, 0x40, 0x61, 0x40, 0x62, 0x40, 0x63, 0x40, - 0x64, 0x40, 0x65, 0x40, 0x66, 0x40, 0x67, 0x40, 0x68, 0x40, 0x69, 0x40, 0x6A, 0x40, 0x6B, 0x40, 0x6C, 0x40, - 0x6D, 0x40, 0x6E, 0x40, 0x6F, 0x40, 0x70, 0x40, 0x71, 0x40, 0x72, 0x40, 0x73, 0x40, 0x74, 0x40, 0x75, 0x40, - 0x76, 0x40, 0x77, 0x40, 0x78, 0x40, 0x79, 0x40, 0x7A, 0x40, 0x7B, 0x40, 0x7C, 0x40, 0x7D, 0x40, 0x7E, 0x40, - 0x7F, 0x40, 0x80, 0x40, 0x81, 0x40, 0x82, 0x40, 0x83, 0x40, 0x84, 0x40, 0x85, 0x40, 0x86, 0x40, 0x87, 0x40, - 0x88, 0x40, 0x89, 0x40, 0x8A, 0x40, 0x8B, 0x40, 0x8C, 0x40, 0x8D, 0x40, 0x8E, 0x40, 0x8F, 0x40, 0x90, 0x40, - 0x91, 0x40, 0x92, 0x40, 0x93, 0x40, 0x94, 0x40, 0x95, 0x40, 0x96, 0x40, 0x97, 0x40, 0x98, 0x40, 0x99, 0x40, - 0x9A, 0x40, 0x9B, 0x40, 0x9C, 0x40, 0x9D, 0x40, 0x9E, 0x40, 0x9F, 0x40, 0xA0, 0x40, 0xA1, 0x40, 0xA2, 0x40, - 0xA3, 0x40, 0xA4, 0x40, 0xA5, 0x40, 0xA6, 0x40, 0xA7, 0x40, 0xA8, 0x40, 0xA9, 0x40, 0xAA, 0x40, 0xAB, 0x40, - 0xAC, 0x40, 0xAD, 0x40, 0xAE, 0x40, 0xAF, 0x40, 0xB0, 0x40, 0xB1, 0x40, 0xB2, 0x40, 0xB3, 0x40, 0xB4, 0x40, - 0xB5, 0x40, 0xB6, 0x40, 0xB7, 0x40, 0xB8, 0x40, 0xB9, 0x40, 0xBA, 0x40, 0xBB, 0x40, 0xBC, 0x40, 0xBD, 0x40, - 0xBE, 0x40, 0xBF, 0x40, 0xC0, 0x40, 0xC1, 0x40, 0xC2, 0x40, 0xC3, 0x40, 0xC4, 0x40, 0xC5, 0x40, 0xC6, 0x40, - 0xC7, 0x40, 0xC8, 0x40, 0xC9, 0x40, 0xCA, 0x40, 0xCB, 0x40, 0xCC, 0x40, 0xCD, 0x40, 0xCE, 0x40, 0xCF, 0x40, - 0xD0, 0x40, 0xD1, 0x40, 0xD2, 0x40, 0xD3, 0x40, 0xD4, 0x40, 0xD5, 0x40, 0xD6, 0x40, 0xD7, 0x40, 0xD8, 0x40, - 0xD9, 0x40, 0xDA, 0x40, 0xDB, 0x40, 0xDC, 0x40, 0xDD, 0x40, 0xDE, 0x40, 0xDF, 0x40, 0xE0, 0x40, 0xE1, 0x40, - 0xE2, 0x40, 0xE3, 0x40, 0xE4, 0x40, 0xE5, 0x40, 0xE6, 0x40, 0xE7, 0x40, 0xE8, 0x40, 0xE9, 0x40, 0xEA, 0x40, - 0xEB, 0x40, 0xEC, 0x40, 0xED, 0x40, 0xEE, 0x40, 0xEF, 0x40, 0xF0, 0x40, 0xF1, 0x40, 0xF2, 0x40, 0xF3, 0x40, - 0xF4, 0x40, 0xF5, 0x40, 0xF6, 0x40, 0xF7, 0x40, 0xF8, 0x40, 0xF9, 0x40, 0x9A, 0x50, 0x9B, 0x50, 0x9C, 0x50, - 0x9D, 0x50, 0x9E, 0x50, 0x9F, 0x50, 0xA0, 0x50, 0xA1, 0x50, 0xA2, 0x50, 0xA3, 0x50, 0xA4, 0x50, 0xA5, 0x50, - 0xA6, 0x50, 0xA7, 0x50, 0xA8, 0x50, 0xA9, 0x50, 0xAA, 0x50, 0xAB, 0x50, 0xAC, 0x50, 0xAD, 0x50, 0xAE, 0x50, - 0xAF, 0x50, 0xB0, 0x50, 0xB1, 0x50, 0xB2, 0x50, 0xB3, 0x50, 0xB4, 0x50, 0xB5, 0x50, 0xB6, 0x50, 0xB7, 0x50, - 0xB8, 0x50, 0xB9, 0x50, 0xBA, 0x50, 0xBB, 0x50, 0xBC, 0x50, 0xBD, 0x50, 0xBE, 0x50, 0xBF, 0x50, 0xC0, 0x50, - 0xC1, 0x50, 0xC2, 0x50, 0xC3, 0x50, 0xC4, 0x50, 0xC5, 0x50, 0xC6, 0x50, 0xC7, 0x50, 0xC8, 0x50, 0xC9, 0x50, - 0xCA, 0x50, 0xCB, 0x50, 0xCC, 0x50, 0xCD, 0x50, 0xCE, 0x50, 0xCF, 0x50, 0xD0, 0x50, 0xD1, 0x50, 0xD2, 0x50, - 0xD3, 0x50, 0xD4, 0x50, 0xD5, 0x50, 0xD6, 0x50, 0xD7, 0x50, 0xD8, 0x50, 0xD9, 0x50, 0xDA, 0x50, 0xDB, 0x50, - 0xDC, 0x50, 0xDD, 0x50, 0xDE, 0x50, 0xDF, 0x50, 0xE0, 0x50, 0xE1, 0x50, 0xE2, 0x50, 0xE3, 0x50, 0xE4, 0x50, - 0xE5, 0x50, 0xE6, 0x50, 0xE7, 0x50, 0xE8, 0x50, 0xE9, 0x50, 0xEA, 0x50, 0xEB, 0x50, 0xEC, 0x50, 0xED, 0x50, - 0xEE, 0x50, 0xEF, 0x50, 0xF0, 0x50, 0xF1, 0x50, 0xF2, 0x50, 0xF3, 0x50, 0xF4, 0x50, 0xF5, 0x50, 0xF6, 0x50, - 0xF7, 0x50, 0xF8, 0x50, 0xF9, 0x50, 0xFA, 0x50, 0xFB, 0x50, 0xFC, 0x50, 0xFD, 0x50, 0xFE, 0x50, 0xFF, 0x50, - 0x00, 0xD0, 0x01, 0x50, 0x02, 0x50, 0x03, 0x50, 0x04, 0x50, 0x05, 0x50, 0x06, 0x50, 0x07, 0x50, 0x08, 0x50, - 0x09, 0x50, 0x0A, 0x50, 0x0B, 0x50, 0x0C, 0x50, 0x0D, 0x50, 0x0E, 0x50, 0x0F, 0x50, 0x10, 0x50, 0x11, 0x50, - 0x12, 0x50, 0x13, 0x50, 0x14, 0x50, 0x15, 0x50, 0x16, 0x50, 0x17, 0x50, 0x18, 0x50, 0x19, 0x50, 0x1A, 0x50, - 0x1B, 0x50, 0x1C, 0x50, 0x1D, 0x50, 0x1E, 0x50, 0x1F, 0x50, 0x20, 0x50, 0x21, 0x50, 0x22, 0x50, 0x23, 0x50, - 0x24, 0x50, 0x25, 0x50, 0x26, 0x50, 0x27, 0x50, 0x28, 0x50, 0x29, 0x50, 0x2A, 0x50, 0x2B, 0x50, 0x2C, 0x50, - 0x2D, 0x50, 0x2E, 0x50, 0x2F, 0x50, 0x30, 0x50, 0x31, 0x50, 0x32, 0x50, 0x33, 0x50, 0x34, 0x50, 0x35, 0x50, - 0x36, 0x50, 0x37, 0x50, 0x38, 0x50, 0x39, 0x50, 0x3A, 0x50, 0x3B, 0x50, 0x3C, 0x50, 0x3D, 0x50, 0x3E, 0x50, - 0x3F, 0x50, 0x40, 0x50, 0x41, 0x50, 0x42, 0x50, 0x43, 0x50, 0x44, 0x50, 0x45, 0x50, 0x46, 0x50, 0x47, 0x50, - 0x48, 0x50, 0x49, 0x50, 0x4A, 0x50, 0x4B, 0x50, 0x4C, 0x50, 0x4D, 0x50, 0x4E, 0x50, 0x4F, 0x50, 0x50, 0x50, - 0x51, 0x50, 0x52, 0x50, 0x53, 0x50, 0x54, 0x50, 0x55, 0x50, 0x56, 0x50, 0x57, 0x50, 0x58, 0x50, 0x59, 0x50, - 0x5A, 0x50, 0x5B, 0x50, 0x5C, 0x50, 0x5D, 0x50, 0x5E, 0x50, 0x5F, 0x50, 0x60, 0x50, 0x61, 0x50, 0x62, 0x50, - 0x63, 0x50, 0x64, 0x50, 0x65, 0x50, 0x66, 0x50, 0x67, 0x50, 0x68, 0x50, 0x69, 0x50, 0x6A, 0x50, 0x6B, 0x50, - 0x6C, 0x50, 0x6D, 0x50, 0x6E, 0x50, 0x6F, 0x50, 0x70, 0x50, 0x71, 0x50, 0x72, 0x50, 0x73, 0x50, 0x74, 0x50, - 0x75, 0x50, 0x76, 0x50, 0x77, 0x50, 0x78, 0x50, 0x79, 0x50, 0x7A, 0x50, 0x7B, 0x50, 0x7C, 0x50, 0x7D, 0x50, - 0x7E, 0x50, 0x7F, 0x50, 0x80, 0x50, 0x81, 0x50, 0x82, 0x50, 0x83, 0x50, 0x84, 0x50, 0x85, 0x50, 0x86, 0x50, - 0x87, 0x50, 0x88, 0x50, 0x89, 0x50, 0x8A, 0x50, 0x8B, 0x50, 0x8C, 0x50, 0x8D, 0x50, 0x8E, 0x50, 0x8F, 0x50, - 0x90, 0x50, 0x91, 0x50, 0x92, 0x50, 0x93, 0x50, 0x94, 0x50, 0x95, 0x50, 0x96, 0x50, 0x97, 0x50, 0x98, 0x50, - 0x99, 0x50 -}; diff --git a/sys/src/games/gb/dat.h b/sys/src/games/gb/dat.h index 6c5509453..8ce259acb 100644 --- a/sys/src/games/gb/dat.h +++ b/sys/src/games/gb/dat.h @@ -1,81 +1,156 @@ -extern u16int pc, curpc, sp; -extern u8int R[8], Fl; -extern int halt, IME, keys; -extern int clock, ppuclock, divclock, timerclock, timerfreq, timer; -extern int rombank, rambank, ramen, battery, ramrom; +typedef char s8int; +typedef short s16int; +typedef long s32int; +typedef struct Event Event; +typedef struct MBC3Timer MBC3Timer; -extern uchar mem[], *ram; +extern int trace; +extern u16int curpc; -extern uchar *cart; -extern int mbc, rombanks, rambanks; +extern uchar *rom, *back, reg[256], oam[256]; +extern MBC3Timer timer; +extern uchar vram[16384]; +extern int nrom, nback, nbackbank; +extern u32int pal[64]; +extern s8int dma; +extern u32int divclock; -extern int scale; +extern Event *elist; +extern ulong clock; + +extern u8int ppuy, ppustate; + +extern u8int mode; +extern u8int mbc, feat; +extern int keys; enum { - rB, - rC, - rD, - rE, - rH, - rL, - rHL, - rA + JOYP = 0x00, + SB = 0x01, + SC = 0x02, + DIV = 0x04, + TIMA = 0x05, + TMA = 0x06, + TAC = 0x07, + IF = 0x0F, + NR10 = 0x10, + NR11 = 0x11, + NR12 = 0x12, + NR13 = 0x13, + NR14 = 0x14, + NR21 = 0x16, + NR22 = 0x17, + NR23 = 0x18, + NR24 = 0x19, + NR30 = 0x1A, + NR31 = 0x1B, + NR32 = 0x1C, + NR33 = 0x1D, + NR34 = 0x1E, + NR41 = 0x20, + NR42 = 0x21, + NR43 = 0x22, + NR44 = 0x23, + NR50 = 0x24, + NR51 = 0x25, + NR52 = 0x26, + WAVE = 0x30, + LCDC = 0x40, + STAT = 0x41, + SCY = 0x42, + SCX = 0x43, + LY = 0x44, + LYC = 0x45, + DMA = 0x46, + BGP = 0x47, + OBP0 = 0x48, + OBP1 = 0x49, + WY = 0x4A, + WX = 0x4B, + KEY1 = 0x4D, + VBK = 0x4F, + HDMASL = 0x51, + HDMASH = 0x52, + HDMADL = 0x53, + HDMADH = 0x54, + HDMAC = 0x55, + + BCPS = 0x68, + BCPD = 0x69, + OCPS = 0x6A, + OCPD = 0x6B, + SVBK = 0x70, + IE = 0xFF }; enum { - FLAGC = 0x10, - FLAGH = 0x20, - FLAGN = 0x40, - FLAGZ = 0x80, + LCDEN = 0x80, + WINMAP = 0x40, + WINEN = 0x20, + BGTILE = 0x10, + BGMAP = 0x08, + SPR16 = 0x04, + SPREN = 0x02, + BGEN = 0x01, + BGPRI = 0x01, + + IRQLYC = 0x40, + IRQM2 = 0x20, + IRQM1 = 0x10, + IRQM0 = 0x08, + + IRQVBL = 1, + IRQLCDS = 2, + IRQTIM = 4, + IRQSER = 8, + IRQJOY = 16, }; enum { - /* interrupt types */ - INTVBLANK = 0, - INTLCDC = 1, - INTTIMER = 2, - INTSIO = 3, - INTIRQ = 4, - - /* I/O registers */ - DIV = 0xFF04, - TIMA = 0xFF05, - TMA = 0xFF06, - TAC = 0xFF07, - LY = 0xFF44, - LCDC = 0xFF40, - STAT = 0xFF41, - SCY = 0xFF42, - SCX = 0xFF43, - LYC = 0xFF45, - BGP = 0xFF47, - OBP0 = 0xFF48, - OBP1 = 0xFF49, - WY = 0xFF4A, - WX = 0xFF4B, + CGB = 1, + COL = 2, + TURBO = 4, + FORCEDMG = 8, - /* LCDC */ - BGDISP = 1, - SPRITEDISP = 2, - SPRITE16 = 4, - BGTILEMAP = 8, - BGTILEDATA = 16, - WINDOWDISP = 32, - WINDOWTILEMAP = 64, - LCDOP = 128, - - /* LCD STAT */ - MODEHBLANK = 0, - MODEVBLANK = 1, - MODEOAM = 2, - MODELCD = 3, - - /* others */ - IF = 0xFF0F, - IE = 0xFFFF, - CPUFREQ = 4194304, + FEATRAM = 1, + FEATBAT = 2, + FEATTIM = 4, + INIT = -1, + SAVE = -2, + RSTR = -3, + READ = -4, +}; + +enum { + TIMERSIZ = 18, + PICW = 160, + PICH = 144, MILLION = 1000000, BILLION = 1000000000, - SAMPLE = 44100, }; + +struct Event { + int time; + void (*f)(void *); + Event *next; + void *aux; +}; +extern Event *elist; + +struct MBC3Timer { + vlong ns; + u8int sec, min, hr, dl, dh; +}; + +typedef struct Var Var; + +struct Var { + void *a; + int s, n; +}; +#define VAR(a) {&a, sizeof(a), 1} +#define ARR(a) {a, sizeof(*a), nelem(a)} +enum { NEVENT = 5 }; +extern int (*mapper)(int, int); +extern u32int moncols[4]; diff --git a/sys/src/games/gb/disasm.c b/sys/src/games/gb/disasm.c deleted file mode 100644 index 08e9b877a..000000000 --- a/sys/src/games/gb/disasm.c +++ /dev/null @@ -1,811 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <thread.h> -#include <draw.h> -#include "dat.h" -#include "fns.h" - -static char *opcodes[256] = { - [0x00] "NOP", - [0x01] "LD BC,%.4x", - [0x02] "LD (BC),A", - [0x03] "INC BC", - [0x04] "INC B", - [0x05] "DEC B", - [0x06] "LD B,%.2x", - [0x07] "RLCA ", - [0x08] "LD (%.4x),SP", - [0x09] "ADD HL,BC", - [0x0A] "LD A,(BC)", - [0x0B] "DEC BC", - [0x0C] "INC C", - [0x0D] "DEC C", - [0x0E] "LD C,%.2x", - [0x0F] "RRCA ", - [0x10] "STOP", - [0x11] "LD DE,%.4x", - [0x12] "LD (DE),A", - [0x13] "INC DE", - [0x14] "INC D", - [0x15] "DEC D", - [0x16] "LD D,%.2x", - [0x17] "RLA ", - [0x18] "JR %.2x", - [0x19] "ADD HL,DE", - [0x1A] "LD A,(DE)", - [0x1B] "DEC DE", - [0x1C] "INC E", - [0x1D] "DEC E", - [0x1E] "LD E,%.2x", - [0x1F] "RRA ", - [0x20] "JR NZ,%.2x", - [0x21] "LD HL,%.4x", - [0x22] "LD (HLI),A", - [0x23] "INC HL", - [0x24] "INC H", - [0x25] "DEC H", - [0x26] "LD H,%.2x", - [0x27] "DAA ", - [0x28] "JR Z,%.2x", - [0x29] "ADD HL,HL", - [0x2A] "LD A,(HLI)", - [0x2B] "DEC HL", - [0x2C] "INC L", - [0x2D] "DEC L", - [0x2E] "LD L,%.2x", - [0x2F] "CPL ", - [0x30] "JR NC,%.2x", - [0x31] "LD SP,%.4x", - [0x32] "LD (HLD),A", - [0x33] "INC SP", - [0x34] "INC (HL)", - [0x35] "DEC (HL)", - [0x36] "LD (HL),%.2x", - [0x37] "SCF ", - [0x38] "JR C,%.2x", - [0x39] "ADD HL,SP", - [0x3A] "LD A,(HLD)", - [0x3B] "DEC SP", - [0x3C] "INC A", - [0x3D] "DEC A", - [0x3E] "LD A,%.2x", - [0x3F] "CCF ", - [0x40] "LD B,B", - [0x41] "LD B,C", - [0x42] "LD B,D", - [0x43] "LD B,E", - [0x44] "LD B,H", - [0x45] "LD B,L", - [0x46] "LD B,(HL)", - [0x47] "LD B,A", - [0x48] "LD C,B", - [0x49] "LD C,C", - [0x4A] "LD C,D", - [0x4B] "LD C,E", - [0x4C] "LD C,H", - [0x4D] "LD C,L", - [0x4E] "LD C,(HL)", - [0x4F] "LD C,A", - [0x50] "LD D,B", - [0x51] "LD D,C", - [0x52] "LD D,D", - [0x53] "LD D,E", - [0x54] "LD D,H", - [0x55] "LD D,L", - [0x56] "LD D,(HL)", - [0x57] "LD D,A", - [0x58] "LD E,B", - [0x59] "LD E,C", - [0x5A] "LD E,D", - [0x5B] "LD E,E", - [0x5C] "LD E,H", - [0x5D] "LD E,L", - [0x5E] "LD E,(HL)", - [0x5F] "LD E,A", - [0x60] "LD H,B", - [0x61] "LD H,C", - [0x62] "LD H,D", - [0x63] "LD H,E", - [0x64] "LD H,H", - [0x65] "LD H,L", - [0x66] "LD H,(HL)", - [0x67] "LD H,A", - [0x68] "LD L,B", - [0x69] "LD L,C", - [0x6A] "LD L,D", - [0x6B] "LD L,E", - [0x6C] "LD L,H", - [0x6D] "LD L,L", - [0x6E] "LD L,(HL)", - [0x6F] "LD L,A", - [0x70] "LD (HL),B", - [0x71] "LD (HL),C", - [0x72] "LD (HL),D", - [0x73] "LD (HL),E", - [0x74] "LD (HL),H", - [0x75] "LD (HL),L", - [0x76] "HALT ", - [0x77] "LD (HL),A", - [0x78] "LD A,B", - [0x79] "LD A,C", - [0x7A] "LD A,D", - [0x7B] "LD A,E", - [0x7C] "LD A,H", - [0x7D] "LD A,L", - [0x7E] "LD A,(HL)", - [0x7F] "LD A,A", - [0x80] "ADD A,B", - [0x81] "ADD A,C", - [0x82] "ADD A,D", - [0x83] "ADD A,E", - [0x84] "ADD A,H", - [0x85] "ADD A,L", - [0x86] "ADD A,(HL)", - [0x87] "ADD A,A", - [0x88] "ADC A,B", - [0x89] "ADC A,C", - [0x8A] "ADC A,D", - [0x8B] "ADC A,E", - [0x8C] "ADC A,H", - [0x8D] "ADC A,L", - [0x8E] "ADC A,(HL)", - [0x8F] "ADC A,A", - [0x90] "SUB B", - [0x91] "SUB C", - [0x92] "SUB D", - [0x93] "SUB E", - [0x94] "SUB H", - [0x95] "SUB L", - [0x96] "SUB (HL)", - [0x97] "SUB A", - [0x98] "SBC B", - [0x99] "SBC C", - [0x9A] "SBC D", - [0x9B] "SBC E", - [0x9C] "SBC H", - [0x9D] "SBC L", - [0x9E] "SBC (HL)", - [0x9F] "SBC A", - [0xA0] "AND B", - [0xA1] "AND C", - [0xA2] "AND D", - [0xA3] "AND E", - [0xA4] "AND H", - [0xA5] "AND L", - [0xA6] "AND (HL)", - [0xA7] "AND A", - [0xA8] "XOR B", - [0xA9] "XOR C", - [0xAA] "XOR D", - [0xAB] "XOR E", - [0xAC] "XOR H", - [0xAD] "XOR L", - [0xAE] "XOR (HL)", - [0xAF] "XOR A", - [0xB0] "OR B", - [0xB1] "OR C", - [0xB2] "OR D", - [0xB3] "OR E", - [0xB4] "OR H", - [0xB5] "OR L", - [0xB6] "OR (HL)", - [0xB7] "OR A", - [0xB8] "CP B", - [0xB9] "CP C", - [0xBA] "CP D", - [0xBB] "CP E", - [0xBC] "CP H", - [0xBD] "CP L", - [0xBE] "CP (HL)", - [0xBF] "CP A", - [0xC0] "RET NZ", - [0xC1] "POP BC", - [0xC2] "JP NZ,%.4x", - [0xC3] "JP %.4x", - [0xC4] "CALL NZ,%.4x", - [0xC5] "PUSH BC", - [0xC6] "ADD A,%.2x", - [0xC7] "RST 00H", - [0xC8] "RET Z", - [0xC9] "RET ", - [0xCA] "JP Z,%.4x", - [0xCB] "#CB ", - [0xCC] "CALL Z,%.4x", - [0xCD] "CALL %.4x", - [0xCE] "ADC A,%.2x", - [0xCF] "RST 08H", - [0xD0] "RET NC", - [0xD1] "POP DE", - [0xD2] "JP NC,%.4x", - [0xD3] "---", - [0xD4] "CALL NC,%.4x", - [0xD5] "PUSH DE", - [0xD6] "SUB %.2x", - [0xD7] "RST 10H", - [0xD8] "RET C", - [0xD9] "RETI", - [0xDA] "JP C,%.4x", - [0xDB] "---", - [0xDC] "CALL C,%.4x", - [0xDD] "---", - [0xDE] "SBC A,%.2x", - [0xDF] "RST 18H", - [0xE0] "LD (ff%.2x),A", - [0xE1] "POP HL", - [0xE2] "LD (C),A", - [0xE3] "---", - [0xE4] "---", - [0xE5] "PUSH HL", - [0xE6] "AND %.2x", - [0xE7] "RST 20H", - [0xE8] "ADD SP,%.2x", - [0xE9] "JP (HL)", - [0xEA] "LD (%.4x),A", - [0xEB] "---", - [0xEC] "---", - [0xED] "#ED ", - [0xEE] "XOR %.2x", - [0xEF] "RST 28H", - [0xF0] "LD A,(ff%.2x)", - [0xF1] "POP AF", - [0xF2] "LD A, (C)", - [0xF3] "DI ", - [0xF4] "---", - [0xF5] "PUSH AF", - [0xF6] "OR %.2x", - [0xF7] "RST 30H", - [0xF8] "LDHL SP,%.2x", - [0xF9] "LD SP,HL", - [0xFA] "LD A,(%.4x)", - [0xFB] "EI ", - [0xFC] "---", - [0xFD] "---", - [0xFE] "CP %.2x", - [0xFF] "RST 38H", -}; - -static int operands[256] = { - [0x00] 0, - [0x01] 2, - [0x02] 0, - [0x03] 0, - [0x04] 0, - [0x05] 0, - [0x06] 1, - [0x07] 0, - [0x08] 0, - [0x09] 0, - [0x0A] 0, - [0x0B] 0, - [0x0C] 0, - [0x0D] 0, - [0x0E] 1, - [0x0F] 0, - [0x10] 0, - [0x11] 2, - [0x12] 0, - [0x13] 0, - [0x14] 0, - [0x15] 0, - [0x16] 1, - [0x17] 0, - [0x18] 1, - [0x19] 0, - [0x1A] 0, - [0x1B] 0, - [0x1C] 0, - [0x1D] 0, - [0x1E] 1, - [0x1F] 0, - [0x20] 1, - [0x21] 2, - [0x22] 0, - [0x23] 0, - [0x24] 0, - [0x25] 0, - [0x26] 1, - [0x27] 0, - [0x28] 1, - [0x29] 0, - [0x2A] 0, - [0x2B] 0, - [0x2C] 0, - [0x2D] 0, - [0x2E] 1, - [0x2F] 0, - [0x30] 1, - [0x31] 2, - [0x32] 0, - [0x33] 0, - [0x34] 0, - [0x35] 0, - [0x36] 1, - [0x37] 0, - [0x38] 1, - [0x39] 0, - [0x3A] 2, - [0x3B] 0, - [0x3C] 0, - [0x3D] 0, - [0x3E] 1, - [0x3F] 0, - [0x40] 0, - [0x41] 0, - [0x42] 0, - [0x43] 0, - [0x44] 0, - [0x45] 0, - [0x46] 0, - [0x47] 0, - [0x48] 0, - [0x49] 0, - [0x4A] 0, - [0x4B] 0, - [0x4C] 0, - [0x4D] 0, - [0x4E] 0, - [0x4F] 0, - [0x50] 0, - [0x51] 0, - [0x52] 0, - [0x53] 0, - [0x54] 0, - [0x55] 0, - [0x56] 0, - [0x57] 0, - [0x58] 0, - [0x59] 0, - [0x5A] 0, - [0x5B] 0, - [0x5C] 0, - [0x5D] 0, - [0x5E] 0, - [0x5F] 0, - [0x60] 0, - [0x61] 0, - [0x62] 0, - [0x63] 0, - [0x64] 0, - [0x65] 0, - [0x66] 0, - [0x67] 0, - [0x68] 0, - [0x69] 0, - [0x6A] 0, - [0x6B] 0, - [0x6C] 0, - [0x6D] 0, - [0x6E] 0, - [0x6F] 0, - [0x70] 0, - [0x71] 0, - [0x72] 0, - [0x73] 0, - [0x74] 0, - [0x75] 0, - [0x76] 0, - [0x77] 0, - [0x78] 0, - [0x79] 0, - [0x7A] 0, - [0x7B] 0, - [0x7C] 0, - [0x7D] 0, - [0x7E] 0, - [0x7F] 0, - [0x80] 0, - [0x81] 0, - [0x82] 0, - [0x83] 0, - [0x84] 0, - [0x85] 0, - [0x86] 0, - [0x87] 0, - [0x88] 0, - [0x89] 0, - [0x8A] 0, - [0x8B] 0, - [0x8C] 0, - [0x8D] 0, - [0x8E] 0, - [0x8F] 0, - [0x90] 0, - [0x91] 0, - [0x92] 0, - [0x93] 0, - [0x94] 0, - [0x95] 0, - [0x96] 0, - [0x97] 0, - [0x98] 0, - [0x99] 0, - [0x9A] 0, - [0x9B] 0, - [0x9C] 0, - [0x9D] 0, - [0x9E] 0, - [0x9F] 0, - [0xA0] 0, - [0xA1] 0, - [0xA2] 0, - [0xA3] 0, - [0xA4] 0, - [0xA5] 0, - [0xA6] 0, - [0xA7] 0, - [0xA8] 0, - [0xA9] 0, - [0xAA] 0, - [0xAB] 0, - [0xAC] 0, - [0xAD] 0, - [0xAE] 0, - [0xAF] 0, - [0xB0] 0, - [0xB1] 0, - [0xB2] 0, - [0xB3] 0, - [0xB4] 0, - [0xB5] 0, - [0xB6] 0, - [0xB7] 0, - [0xB8] 0, - [0xB9] 0, - [0xBA] 0, - [0xBB] 0, - [0xBC] 0, - [0xBD] 0, - [0xBE] 0, - [0xBF] 0, - [0xC0] 0, - [0xC1] 0, - [0xC2] 2, - [0xC3] 2, - [0xC4] 2, - [0xC5] 0, - [0xC6] 1, - [0xC7] 0, - [0xC8] 0, - [0xC9] 0, - [0xCA] 2, - [0xCB] 0, - [0xCC] 2, - [0xCD] 2, - [0xCE] 1, - [0xCF] 0, - [0xD0] 0, - [0xD1] 0, - [0xD2] 2, - [0xD3] 1, - [0xD4] 2, - [0xD5] 0, - [0xD6] 1, - [0xD7] 0, - [0xD8] 0, - [0xD9] 0, - [0xDA] 2, - [0xDB] 1, - [0xDC] 2, - [0xDD] 0, - [0xDE] 1, - [0xDF] 0, - [0xE0] 1, - [0xE1] 0, - [0xE2] 0, - [0xE3] 0, - [0xE4] 2, - [0xE5] 0, - [0xE6] 1, - [0xE7] 0, - [0xE8] 1, - [0xE9] 0, - [0xEA] 2, - [0xEB] 0, - [0xEC] 2, - [0xED] 0, - [0xEE] 1, - [0xEF] 0, - [0xF0] 1, - [0xF1] 0, - [0xF2] 0, - [0xF3] 0, - [0xF4] 2, - [0xF5] 0, - [0xF6] 1, - [0xF7] 0, - [0xF8] 1, - [0xF9] 0, - [0xFA] 2, - [0xFB] 0, - [0xFC] 2, - [0xFD] 0, - [0xFE] 1, - [0xFF] 0, -}; - -static char *cbopcodes[256] = { - [0x00] "RLC B", - [0x01] "RLC C", - [0x02] "RLC D", - [0x03] "RLC E", - [0x04] "RLC H", - [0x05] "RLC L", - [0x06] "RLC (HL)", - [0x07] "RLC A", - [0x08] "RRC B", - [0x09] "RRC C", - [0x0A] "RRC D", - [0x0B] "RRC E", - [0x0C] "RRC H", - [0x0D] "RRC L", - [0x0E] "RRC (HL)", - [0x0F] "RRC A", - [0x10] "RL B", - [0x11] "RL C", - [0x12] "RL D", - [0x13] "RL E", - [0x14] "RL H", - [0x15] "RL L", - [0x16] "RL (HL)", - [0x17] "RL A", - [0x18] "RR B", - [0x19] "RR C", - [0x1A] "RR D", - [0x1B] "RR E", - [0x1C] "RR H", - [0x1D] "RR L", - [0x1E] "RR (HL)", - [0x1F] "RR A", - [0x20] "SLA B", - [0x21] "SLA C", - [0x22] "SLA D", - [0x23] "SLA E", - [0x24] "SLA H", - [0x25] "SLA L", - [0x26] "SLA (HL)", - [0x27] "SLA A", - [0x28] "SRA B", - [0x29] "SRA C", - [0x2A] "SRA D", - [0x2B] "SRA E", - [0x2C] "SRA H", - [0x2D] "SRA L", - [0x2E] "SRA (HL)", - [0x2F] "SRA A", - [0x30] "SWAP B", - [0x31] "SWAP C", - [0x32] "SWAP D", - [0x33] "SWAP E", - [0x34] "SWAP H", - [0x35] "SWAP L", - [0x36] "SWAP (HL)", - [0x37] "SWAP A", - [0x38] "SRL B", - [0x39] "SRL C", - [0x3A] "SRL D", - [0x3B] "SRL E", - [0x3C] "SRL H", - [0x3D] "SRL L", - [0x3E] "SRL (HL)", - [0x3F] "SRL A", - [0x40] "BIT 0,B", - [0x41] "BIT 0,C", - [0x42] "BIT 0,D", - [0x43] "BIT 0,E", - [0x44] "BIT 0,H", - [0x45] "BIT 0,L", - [0x46] "BIT 0,(HL)", - [0x47] "BIT 0,A", - [0x48] "BIT 1,B", - [0x49] "BIT 1,C", - [0x4A] "BIT 1,D", - [0x4B] "BIT 1,E", - [0x4C] "BIT 1,H", - [0x4D] "BIT 1,L", - [0x4E] "BIT 1,(HL)", - [0x4F] "BIT 1,A", - [0x50] "BIT 2,B", - [0x51] "BIT 2,C", - [0x52] "BIT 2,D", - [0x53] "BIT 2,E", - [0x54] "BIT 2,H", - [0x55] "BIT 2,L", - [0x56] "BIT 2,(HL)", - [0x57] "BIT 2,A", - [0x58] "BIT 3,B", - [0x59] "BIT 3,C", - [0x5A] "BIT 3,D", - [0x5B] "BIT 3,E", - [0x5C] "BIT 3,H", - [0x5D] "BIT 3,L", - [0x5E] "BIT 3,(HL)", - [0x5F] "BIT 3,A", - [0x60] "BIT 4,B", - [0x61] "BIT 4,C", - [0x62] "BIT 4,D", - [0x63] "BIT 4,E", - [0x64] "BIT 4,H", - [0x65] "BIT 4,L", - [0x66] "BIT 4,(HL)", - [0x67] "BIT 4,A", - [0x68] "BIT 5,B", - [0x69] "BIT 5,C", - [0x6A] "BIT 5,D", - [0x6B] "BIT 5,E", - [0x6C] "BIT 5,H", - [0x6D] "BIT 5,L", - [0x6E] "BIT 5,(HL)", - [0x6F] "BIT 5,A", - [0x70] "BIT 6,B", - [0x71] "BIT 6,C", - [0x72] "BIT 6,D", - [0x73] "BIT 6,E", - [0x74] "BIT 6,H", - [0x75] "BIT 6,L", - [0x76] "BIT 6,(HL)", - [0x77] "BIT 6,A", - [0x78] "BIT 7,B", - [0x79] "BIT 7,C", - [0x7A] "BIT 7,D", - [0x7B] "BIT 7,E", - [0x7C] "BIT 7,H", - [0x7D] "BIT 7,L", - [0x7E] "BIT 7,(HL)", - [0x7F] "BIT 7,A", - [0x80] "RES 0,B", - [0x81] "RES 0,C", - [0x82] "RES 0,D", - [0x83] "RES 0,E", - [0x84] "RES 0,H", - [0x85] "RES 0,L", - [0x86] "RES 0,(HL)", - [0x87] "RES 0,A", - [0x88] "RES 1,B", - [0x89] "RES 1,C", - [0x8A] "RES 1,D", - [0x8B] "RES 1,E", - [0x8C] "RES 1,H", - [0x8D] "RES 1,L", - [0x8E] "RES 1,(HL)", - [0x8F] "RES 1,A", - [0x90] "RES 2,B", - [0x91] "RES 2,C", - [0x92] "RES 2,D", - [0x93] "RES 2,E", - [0x94] "RES 2,H", - [0x95] "RES 2,L", - [0x96] "RES 2,(HL)", - [0x97] "RES 2,A", - [0x98] "RES 3,B", - [0x99] "RES 3,C", - [0x9A] "RES 3,D", - [0x9B] "RES 3,E", - [0x9C] "RES 3,H", - [0x9D] "RES 3,L", - [0x9E] "RES 3,(HL)", - [0x9F] "RES 3,A", - [0xA0] "RES 4,B", - [0xA1] "RES 4,C", - [0xA2] "RES 4,D", - [0xA3] "RES 4,E", - [0xA4] "RES 4,H", - [0xA5] "RES 4,L", - [0xA6] "RES 4,(HL)", - [0xA7] "RES 4,A", - [0xA8] "RES 5,B", - [0xA9] "RES 5,C", - [0xAA] "RES 5,D", - [0xAB] "RES 5,E", - [0xAC] "RES 5,H", - [0xAD] "RES 5,L", - [0xAE] "RES 5,(HL)", - [0xAF] "RES 5,A", - [0xB0] "RES 6,B", - [0xB1] "RES 6,C", - [0xB2] "RES 6,D", - [0xB3] "RES 6,E", - [0xB4] "RES 6,H", - [0xB5] "RES 6,L", - [0xB6] "RES 6,(HL)", - [0xB7] "RES 6,A", - [0xB8] "RES 7,B", - [0xB9] "RES 7,C", - [0xBA] "RES 7,D", - [0xBB] "RES 7,E", - [0xBC] "RES 7,H", - [0xBD] "RES 7,L", - [0xBE] "RES 7,(HL)", - [0xBF] "RES 7,A", - [0xC0] "SET 0,B", - [0xC1] "SET 0,C", - [0xC2] "SET 0,D", - [0xC3] "SET 0,E", - [0xC4] "SET 0,H", - [0xC5] "SET 0,L", - [0xC6] "SET 0,(HL)", - [0xC7] "SET 0,A", - [0xC8] "SET 1,B", - [0xC9] "SET 1,C", - [0xCA] "SET 1,D", - [0xCB] "SET 1,E", - [0xCC] "SET 1,H", - [0xCD] "SET 1,L", - [0xCE] "SET 1,(HL)", - [0xCF] "SET 1,A", - [0xD0] "SET 2,B", - [0xD1] "SET 2,C", - [0xD2] "SET 2,D", - [0xD3] "SET 2,E", - [0xD4] "SET 2,H", - [0xD5] "SET 2,L", - [0xD6] "SET 2,(HL)", - [0xD7] "SET 2,A", - [0xD8] "SET 3,B", - [0xD9] "SET 3,C", - [0xDA] "SET 3,D", - [0xDB] "SET 3,E", - [0xDC] "SET 3,H", - [0xDD] "SET 3,L", - [0xDE] "SET 3,(HL)", - [0xDF] "SET 3,A", - [0xE0] "SET 4,B", - [0xE1] "SET 4,C", - [0xE2] "SET 4,D", - [0xE3] "SET 4,E", - [0xE4] "SET 4,H", - [0xE5] "SET 4,L", - [0xE6] "SET 4,(HL)", - [0xE7] "SET 4,A", - [0xE8] "SET 5,B", - [0xE9] "SET 5,C", - [0xEA] "SET 5,D", - [0xEB] "SET 5,E", - [0xEC] "SET 5,H", - [0xED] "SET 5,L", - [0xEE] "SET 5,(HL)", - [0xEF] "SET 5,A", - [0xF0] "SET 6,B", - [0xF1] "SET 6,C", - [0xF2] "SET 6,D", - [0xF3] "SET 6,E", - [0xF4] "SET 6,H", - [0xF5] "SET 6,L", - [0xF6] "SET 6,(HL)", - [0xF7] "SET 6,A", - [0xF8] "SET 7,B", - [0xF9] "SET 7,C", - [0xFA] "SET 7,D", - [0xFB] "SET 7,E", - [0xFC] "SET 7,H", - [0xFD] "SET 7,L", - [0xFE] "SET 7,(HL)", - [0xFF] "SET 7,A", -}; - -void -disasm(u16int addr) -{ - u8int op; - int x; - - op = memread(addr); - if(op == 0xCB){ - op = memread(addr + 1); - print("%s\n", cbopcodes[op]); - return; - } - switch(operands[op]){ - case 0: - print(opcodes[op]); - break; - case 1: - print(opcodes[op], (int)(memread(addr + 1))); - break; - case 2: - x = (uint)memread(addr + 2); - x <<= 8; - x |= (uint)memread(addr + 1); - print(opcodes[op], x); - } - print("\n"); -} diff --git a/sys/src/games/gb/ev.c b/sys/src/games/gb/ev.c new file mode 100644 index 000000000..b70cb974e --- /dev/null +++ b/sys/src/games/gb/ev.c @@ -0,0 +1,122 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include "dat.h" +#include "fns.h" + +Event evhblank, evtimer, evnever; +extern Event evsamp, evenv; +Event *events[NEVENT] = {&evhblank, &evtimer, &evnever, &evsamp, &evenv}; +Event *elist; +static int timshtab[4] = {12, 4, 6, 8}, timsh; +ulong timclock; +Var evvars[] = {VAR(timsh), VAR(timclock), {nil, 0, 0}}; + +void +addevent(Event *ev, int time) +{ + Event **p, *e; + int t; + + assert(time >= 0); + t = time; + for(p = &elist; (e = *p) != nil; p = &e->next){ + if(t < e->time){ + e->time -= t; + break; + } + t -= e->time; + } + ev->next = e; + ev->time = t; + *p = ev; +} + +void +delevent(Event *ev) +{ + Event **p, *e; + + for(p = &elist; (e = *p) != nil; p = &e->next) + if(e == ev){ + *p = e->next; + if(e->next != nil) + e->next->time += e->time; + return; + } +} + +void +popevent(void) +{ + Event *e; + int t; + + do{ + e = elist; + t = e->time; + elist = e->next; + e->f(e->aux); + }while((elist->time += t) <= 0); +} + +void +timerset(void) +{ + timclock = clock & -(1<<timsh); + if((reg[TAC] & 4) != 0){ + delevent(&evtimer); + addevent(&evtimer, 0x100 - reg[TIMA] << timsh);// | -clock & (1<<timsh)-1); + } +} + +void +timertac(u8int n, int t) +{ + if((reg[TAC] & 7) == (n & 7) && !t) + return; + if((reg[TAC] & 4) != 0){ + delevent(&evtimer); + reg[TIMA] += clock - timclock >> timsh; + } + timclock = clock & -(1<<timsh); + timsh = timshtab[n & 3]; + if((mode & TURBO) == 0) + timsh++; + if((n & 4) != 0) + addevent(&evtimer, 0x100 - reg[TIMA] << timsh | -clock & (1<<timsh)-1); +} + +u8int +timread(void) +{ + if((reg[TAC] & 4) == 0) + return reg[TIMA]; + return reg[TIMA] + (clock - timclock >> timsh); +} + +void +timertick(void *) +{ + reg[TIMA] = reg[TMA]; + addevent(&evtimer, 0x100 - reg[TIMA] << timsh); + reg[IF] |= IRQTIM; +} + +void +nevertick(void *) +{ + addevent(&evnever, 10000000); +} + +void +eventinit(void) +{ + extern void hblanktick(void *); + + evhblank.f = hblanktick; + addevent(&evhblank, 240*4); + evtimer.f = timertick; + evnever.f = nevertick; + addevent(&evnever, 10000000); +} diff --git a/sys/src/games/gb/fns.h b/sys/src/games/gb/fns.h index 42b7203c6..237327057 100644 --- a/sys/src/games/gb/fns.h +++ b/sys/src/games/gb/fns.h @@ -1,14 +1,29 @@ u8int memread(u16int); void memwrite(u16int, u8int); +void addevent(Event *, int); +void delevent(Event *); +void popevent(void); +void eventinit(void); +void meminit(void); +void reset(void); int step(void); -void ppustep(void); -void disasm(u16int); -void interrupt(u8int); -void message(char *, ...); -void flushram(void); -void savestate(char *); +void ppusync(void); +void ppuinit(void); +void flush(void); +void timertac(u8int, int); +void timerset(void); +void writeback(void); void loadstate(char *); -void initaudio(void); -void audiosample(void); +void savestate(char *); +void flushback(void); +void getvars(Var *); +void putvars(Var *); +void memload(void); +int dmastep(void); +void audioinit(void); int audioout(void); -void flush(void); +void sndwrite(u8int, u8int); +int apuread(void); +u8int waveread(u8int); +void wavewrite(u8int, u8int); +u8int timread(void); diff --git a/sys/src/games/gb/gb.c b/sys/src/games/gb/gb.c index b7382b38d..3268634e9 100644 --- a/sys/src/games/gb/gb.c +++ b/sys/src/games/gb/gb.c @@ -1,196 +1,262 @@ #include <u.h> #include <libc.h> -#include <draw.h> #include <thread.h> +#include <draw.h> #include <mouse.h> -#include <cursor.h> #include <keyboard.h> #include "dat.h" #include "fns.h" -uchar *cart, *ram; -int mbc, rombanks, rambanks, clock, ppuclock, divclock, timerclock, audioclock, msgclock, timerfreq, timer, keys, savefd, savereq, loadreq, scale, paused; +int cpuhalt; +int scale, profile; Rectangle picr; Image *bg, *tmp; Mousectl *mc; +int keys, paused, framestep, backup; QLock pauselock; +int savefd = -1, saveframes; +ulong clock; +int savereq, loadreq; +u8int mbc, feat, mode; +extern MBC3Timer timer, timerl; -void -message(char *fmt, ...) +void * +emalloc(ulong sz) { - va_list va; - char buf[512]; + void *v; - va_start(va, fmt); - vsnprint(buf, sizeof buf, fmt, va); - string(screen, Pt(10, 10), display->black, ZP, display->defaultfont, buf); - msgclock = CPUFREQ; - va_end(va); + v = malloc(sz); + if(v == nil) + sysfatal("malloc: %r"); + setmalloctag(v, getcallerpc(&sz)); + return v; +} + +void +writeback(void) +{ + if(saveframes == 0) + saveframes = 15; +} + +void +timerload(char *buf) +{ + timer.ns = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24 | (uvlong)buf[4] << 32 | (uvlong)buf[5] << 40 | (uvlong)buf[6] << 48LL | (uvlong)buf[7] << 56LL; + timer.sec = buf[8]; + timer.min = buf[9]; + timer.hr = buf[10]; + timer.dl = buf[11]; + timer.dh = buf[12]; + timerl.sec = buf[13]; + timerl.min = buf[14]; + timerl.hr = buf[15]; + timerl.dl = buf[16]; + timerl.dh = buf[17]; +} + +void +timersave(char *buf) +{ + buf[0] = timer.ns; + buf[1] = timer.ns >> 8; + buf[2] = timer.ns >> 16; + buf[3] = timer.ns >> 24; + buf[4] = timer.ns >> 32; + buf[5] = timer.ns >> 40; + buf[6] = timer.ns >> 48; + buf[7] = timer.ns >> 56; + buf[8] = timer.sec; + buf[9] = timer.min; + buf[10] = timer.hr; + buf[11] = timer.dl; + buf[12] = timer.dh; + buf[13] = timerl.sec; + buf[14] = timerl.min; + buf[15] = timerl.hr; + buf[16] = timerl.dl; + buf[17] = timerl.dh; +} + +void +flushback(void) +{ + char buf[TIMERSIZ]; + + if(savefd >= 0){ + pwrite(savefd, back, nback, 0); + timersave(buf); + pwrite(savefd, buf, TIMERSIZ, nback); + } + saveframes = 0; +} + +void +loadsave(char *file) +{ + char *buf, *p; + char tim[TIMERSIZ]; + + buf = emalloc(strlen(file) + 4); + strcpy(buf, file); + p = strchr(buf, '.'); + if(p == nil) + p = buf + strlen(buf); + strcpy(p, ".sav"); + savefd = open(buf, ORDWR); + if(savefd < 0){ + savefd = create(buf, OWRITE, 0664); + if(savefd < 0){ + fprint(2, "create: %r"); + free(buf); + return; + } + back = emalloc(nback); + memset(back, 0, nback); + write(savefd, back, nback); + free(buf); + if((feat & FEATTIM) != 0){ + timer.ns = nsec(); + timersave(tim); + write(savefd, tim, TIMERSIZ); + } + atexit(flushback); + return; + } + back = emalloc(nback); + readn(savefd, back, nback); + if((feat & FEATTIM) != 0){ + readn(savefd, tim, TIMERSIZ); + timerload(buf); + } + atexit(flushback); + free(buf); } void loadrom(char *file) { - int fd, i; - vlong len; - u8int ck; - char buf[512]; - char title[17]; - Point p; - char *s; - extern int battery, ramen; + int fd; + vlong sz; + static uchar nintendo[24] = { + 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, + 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E + }; + static u8int mbctab[31] = { + 0, 1, 1, 1, -1, 2, 2, -1, + 0, 0, -1, 6, 6, 6, -1, 3, + 3, 3, 3, 3, -1, 4, 4, 4, + -1, 5, 5, 5, 5, 5, 5}; + static u8int feattab[31] = { + 0, 0, FEATRAM, FEATRAM|FEATBAT, 0, FEATRAM, FEATRAM|FEATBAT, 0, + FEATRAM, FEATRAM|FEATBAT, 0, 0, FEATRAM, FEATRAM|FEATBAT, 0, FEATTIM|FEATBAT, + FEATTIM|FEATRAM|FEATBAT, 0, FEATRAM, FEATRAM|FEATBAT, 0, 0, FEATRAM, FEATRAM|FEATBAT, + 0, 0, FEATRAM, FEATRAM|FEATBAT, 0, FEATRAM, FEATRAM|FEATBAT + }; fd = open(file, OREAD); if(fd < 0) sysfatal("open: %r"); - len = seek(fd, 0, 2); - if(len < 0) - sysfatal("seek: %r"); - if(len == 0 || len > 16*1048576) - sysfatal("are you sure this is a ROM?"); - cart = malloc(len); - if(cart == nil) - sysfatal("malloc: %r"); + sz = seek(fd, 0, 2); + if(sz <= 0 || sz > 32*1024*1024) + sysfatal("invalid file size"); seek(fd, 0, 0); - if(readn(fd, cart, len) < len) + nrom = sz; + rom = emalloc(nrom); + if(readn(fd, rom, sz) < sz) sysfatal("read: %r"); close(fd); - - ck = 0; - for(i = 0x134; i <= 0x14C; i++) - ck -= cart[i] + 1; - if(ck != cart[0x14D]) - sysfatal("checksum mismatch: %.2x != %.2x", ck, cart[0x14D]); - memcpy(mem, cart, 32768); - memset(title, 0, sizeof(title)); - memcpy(title, cart+0x134, 16); - battery = 0; - switch(cart[0x147]){ - case 0x09: - battery = 1; - case 0x08: - ramen = 1; - case 0x00: - mbc = 0; - break; - case 0x03: - battery = 1; - case 0x01: case 0x02: - mbc = 1; - break; - case 0x06: - battery = 1; - case 0x05: - mbc = 2; - break; - case 0x0F: case 0x10: case 0x13: - battery = 1; - case 0x11: case 0x12: - mbc = 3; - break; - case 0x1B: case 0x1E: - battery = 1; - case 0x19: case 0x1A: case 0x1C: case 0x1D: - mbc = 5; - break; - default: - sysfatal("%s: unknown cartridge type %.2x", file, cart[0x147]); - } - - switch(cart[0x148]){ - case 0: case 1: case 2: - case 3: case 4: case 5: - case 6: case 7: - rombanks = 2 << (uint)cart[0x148]; - break; - case 52: - rombanks = 72; - break; - case 53: - rombanks = 80; - break; - case 54: - rombanks = 96; - break; - default: - sysfatal("header field 0x148 (%.2x) invalid", cart[0x148]); - } - switch(cart[0x149]){ - case 0: - if(mbc != 2){ - rambanks = 0; + if(memcmp(rom + 0x104, nintendo, 24) != 0) + sysfatal("not a gameboy rom"); + if(rom[0x147] > 0x1f) + sysfatal("unsupported mapper ([0x147] = %.2ux)", rom[0x147]); + mbc = mbctab[rom[0x147]]; + feat = feattab[rom[0x147]]; + if((feat & FEATRAM) != 0){ + switch(rom[0x149]){ + case 0: + if(mbc == 2) + nback = 512; + else + feat &= ~FEATRAM; break; + case 1: nback = 2048; break; + case 2: nback = 8192; break; + case 3: nback = 32768; break; + default: sysfatal("invalid ram size"); } - /*fallthrough*/ - case 1: case 2: - rambanks = 1; - break; - case 3: - rambanks = 4; - break; - default: - sysfatal("header field 0x149 (%.2x) invalid", cart[0x149]); } - if(rambanks > 0){ - ram = mallocz(rambanks * 8192, 1); - if(ram == nil) - sysfatal("malloc: %r"); + if(nback == 0) + nbackbank = 1; + else + nbackbank = nback + 8191 >> 13; + if((feat & (FEATRAM|FEATTIM)) == 0) + feat &= ~FEATBAT; + if((rom[0x143] & 0x80) != 0 && (mode & FORCEDMG) == 0) + mode = CGB|COL; + if((feat & FEATBAT) != 0) + loadsave(file); + switch(mbc){ + case 0: case 1: case 2: case 3: case 5: break; + default: sysfatal("unsupported mbc %d", mbc); } - if(len < rombanks * 0x4000) - sysfatal("cartridge image is too small, %.4x < %.4x", (int)len, rombanks * 0x4000); - initdraw(nil, nil, title); - originwindow(screen, Pt(0, 0), screen->r.min); + +} + +void +screeninit(void) +{ + Point p; + p = divpt(addpt(screen->r.min, screen->r.max), 2); - picr = (Rectangle){subpt(p, Pt(scale * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))}; + picr = (Rectangle){subpt(p, Pt(scale * PICW/2, scale * PICH/2)), addpt(p, Pt(scale * PICW/2, scale * PICH/2))}; + tmp = allocimage(display, Rect(0, 0, scale * PICW, scale > 1 ? 1 : scale * PICH), XRGB32, scale > 1, 0); bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF); - tmp = allocimage(display, Rect(0, 0, scale * 160, scale * 144), XRGB32, 0, 0); - draw(screen, screen->r, bg, nil, ZP); - - if(ram && battery){ - strncpy(buf, file, sizeof buf - 4); - s = buf + strlen(buf) - 3; - if(s < buf || strcmp(s, ".gb") != 0) - s += 3; - strcpy(s, ".gbs"); - savefd = create(buf, ORDWR|OEXCL, 0666); - if(savefd < 0) - savefd = open(buf, ORDWR); - if(savefd < 0) - message("open: %r"); - else - readn(savefd, ram, rambanks * 8192); - atexit(flushram); - } + draw(screen, screen->r, bg, nil, ZP); } void keyproc(void *) { - int fd; - char buf[256], *s; + int fd, k; + static char buf[256]; + char *s; Rune r; - + fd = open("/dev/kbd", OREAD); if(fd < 0) sysfatal("open: %r"); for(;;){ - if(read(fd, buf, 256) <= 0) + if(read(fd, buf, sizeof(buf) - 1) <= 0) sysfatal("read /dev/kbd: %r"); if(buf[0] == 'c'){ - if(utfrune(buf, Kdel)) - threadexitsall(nil); if(utfrune(buf, KF|5)) savereq = 1; if(utfrune(buf, KF|6)) loadreq = 1; + if(utfrune(buf, Kdel)){ + close(fd); + threadexitsall(nil); + } + if(utfrune(buf, 't')) + trace = !trace; } if(buf[0] != 'k' && buf[0] != 'K') continue; s = buf + 1; - keys = 0; + k = 0; while(*s != 0){ s += chartorune(&r, s); switch(r){ + case Kdel: close(fd); threadexitsall(nil); + case 'z': k |= 1<<5; break; + case 'x': k |= 1<<4; break; + case Kshift: k |= 1<<6; break; + case 10: k |= 1<<7; break; + case Kup: k |= 1<<2; break; + case Kdown: k |= 1<<3; break; + case Kleft: k |= 1<<1; break; + case Kright: k |= 1<<0; break; case Kesc: if(paused) qunlock(&pauselock); @@ -198,156 +264,214 @@ keyproc(void *) qlock(&pauselock); paused = !paused; break; - case Kdel: - threadexitsall(nil); - case Kdown: - keys |= 1<<3; - break; - case Kup: - keys |= 1<<2; - break; - case Kleft: - keys |= 1<<1; - break; - case Kright: - keys |= 1<<0; - break; - case 'x': - keys |= 1<<4; - break; - case 'z': - keys |= 1<<5; - break; - case Kshift: - keys |= 1<<6; - break; - case 10: - keys |= 1<<7; + case KF|1: + if(paused){ + qunlock(&pauselock); + paused=0; + } + framestep = !framestep; break; } } + k &= ~(k << 1 & 0x0a | k >> 1 & 0x05); + keys = k; } + } void -threadmain(int argc, char** argv) +timing(void) { - int t; - - scale = 1; - ARGBEGIN{ - case 'a': - initaudio(); - break; - case '2': - scale = 2; - break; - case '3': - scale = 3; - break; - default: - sysfatal("unknown flag -%c", ARGC()); - }ARGEND; - if(argc == 0) - sysfatal("argument missing"); - pc = 0x100; - sp = 0xFFFE; - R[rA] = 0x01; - R[rC] = 0x13; - R[rE] = 0xD8; - R[rL] = 0x4D; - R[rH] = 0x01; - Fl = 0xB0; - loadrom(argv[0]); - mc = initmouse(nil, screen); - if(mc == nil) - sysfatal("init mouse: %r"); - proccreate(keyproc, nil, 8192); - for(;;){ - if(savereq){ - savestate("gb.save"); - savereq = 0; - } - if(loadreq){ - loadstate("gb.save"); - loadreq = 0; - } - if(paused){ - qlock(&pauselock); - qunlock(&pauselock); - } - t = step(); - clock += t; - ppuclock += t; - divclock += t; - audioclock += t; - timerclock += t; - if(ppuclock >= 456){ - ppustep(); - ppuclock -= 456; - } - if(divclock >= 256){ - mem[DIV]++; - divclock = 0; - } - if(audioclock >= CPUFREQ / SAMPLE){ - audiosample(); - audioclock -= CPUFREQ / SAMPLE; - } - if(timer && timerclock >= timerfreq){ - mem[TIMA]++; - if(mem[TIMA] == 0){ - mem[TIMA] = mem[TMA]; - interrupt(INTTIMER); - } - timerclock = 0; - } - if(msgclock > 0){ - msgclock -= t; - if(msgclock <= 0){ - draw(screen, screen->r, bg, nil, ZP); - msgclock = 0; - } - } - } + static int fcount; + static vlong old; + static char buf[32]; + vlong new; + + if(++fcount == 60) + fcount = 0; + else + return; + new = nsec(); + if(new != old) + sprint(buf, "%6.2f%%", 1e11 / (new - old)); + else + buf[0] = 0; + draw(screen, rectaddpt(Rect(10, 10, 200, 30), screen->r.min), bg, nil, ZP); + string(screen, addpt(screen->r.min, Pt(10, 10)), display->black, ZP, display->defaultfont, buf); + old = nsec(); } void flush(void) { - extern uchar pic[160*144*4*3*3]; + extern uchar pic[]; Mouse m; - Point p; - static vlong old; + static vlong old, delta; vlong new, diff; - while(nbrecv(mc->c, &m) > 0) - ; if(nbrecvul(mc->resizec) > 0){ if(getwindow(display, Refnone) < 0) sysfatal("resize failed: %r"); - p = divpt(addpt(screen->r.min, screen->r.max), 2); - picr = (Rectangle){subpt(p, Pt(scale * 80, scale * 72)), addpt(p, Pt(scale * 80, scale * 72))}; - if(bg->chan != screen->chan){ - freeimage(bg); - bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF); - } - draw(screen, screen->r, bg, nil, ZP); + screeninit(); } - if(screen->chan != tmp->chan){ - loadimage(tmp, tmp->r, pic, 160*144*4*scale*scale); + while(nbrecv(mc->c, &m) > 0) + ; + if(scale == 1){ + loadimage(tmp, tmp->r, pic, PICW*PICH*4); draw(screen, picr, tmp, nil, ZP); - }else - loadimage(screen, picr, pic, 160*144*4*scale*scale); + } else { + Rectangle r; + uchar *s; + int w; + + s = pic; + r = picr; + w = PICW*4*scale; + while(r.min.y < picr.max.y){ + loadimage(tmp, tmp->r, s, w); + s += w; + r.max.y = r.min.y+scale; + draw(screen, r, tmp, nil, ZP); + r.min.y = r.max.y; + } + } flushimage(display, 1); - memset(pic, sizeof pic, 0); + if(profile) + timing(); if(audioout() < 0){ new = nsec(); + diff = 0; if(old != 0){ - diff = BILLION/60 - (new - old); + diff = BILLION/60 - (new - old) - delta; if(diff >= MILLION) sleep(diff/MILLION); } old = nsec(); + if(diff != 0){ + diff = (old - new) - (diff / MILLION) * MILLION; + delta += (diff - delta) / 100; + } + } + if(framestep){ + paused = 1; + qlock(&pauselock); + framestep = 0; + } + + if(saveframes > 0 && --saveframes == 0) + flushback(); + if(savereq){ + savestate("gb.save"); + savereq = 0; + } + if(loadreq){ + loadstate("gb.save"); + loadreq = 0; + } +} + +void +usage(void) +{ + fprint(2, "usage: %s [-23aTcd] [-C col0,col1,col2,col3] rom\n", argv0); + exits("usage"); +} + +void +colinit(void) +{ + int i; + union { u8int c[4]; u32int l; } c; + + c.c[3] = 0; + for(i = 0; i < 4; i++){ + c.c[0] = c.c[1] = c.c[2] = i * 0x55; + moncols[i] = c.l; + } +} + +void +colparse(char *p) +{ + int i; + union { u8int c[4]; u32int l; } c; + u32int l; + + c.c[3] = 0; + for(i = 0; i < 4; i++){ + l = strtol(p, &p, 16); + if(*p != (i == 3 ? 0 : ',') || l > 0xffffff) + usage(); + p++; + c.c[0] = l; + c.c[1] = l >> 8; + c.c[2] = l >> 16; + moncols[i] = c.l; + } +} + +void +threadmain(int argc, char **argv) +{ + int t; + + colinit(); + scale = 1; + ARGBEGIN { + case '2': + scale = 2; + break; + case '3': + scale = 3; + break; + case 'a': + audioinit(); + break; + case 'T': + profile++; + break; + case 'c': + mode |= CGB; + break; + case 'd': + mode |= FORCEDMG; + break; + case 'C': + colparse(EARGF(usage())); + break; + default: + usage(); + } ARGEND; + if(argc < 1) + usage(); + + loadrom(argv[0]); + + if(initdraw(nil, nil, nil) < 0) + sysfatal("initdraw: %r"); + mc = initmouse(nil, screen); + if(mc == nil) + sysfatal("initmouse: %r"); + proccreate(keyproc, nil, mainstacksize); + screeninit(); + + eventinit(); + meminit(); + ppuinit(); + reset(); + for(;;){ + if(paused){ + qlock(&pauselock); + qunlock(&pauselock); + } + if(dma > 0) + t = dmastep(); + else + t = step(); + if((mode & TURBO) == 0) + t += t; + clock += t; + if((elist->time -= t) <= 0) + popevent(); } } diff --git a/sys/src/games/gb/mem.c b/sys/src/games/gb/mem.c index f033a8ad5..c5b4bd554 100644 --- a/sys/src/games/gb/mem.c +++ b/sys/src/games/gb/mem.c @@ -1,176 +1,569 @@ #include <u.h> #include <libc.h> #include <thread.h> -#include <draw.h> #include "dat.h" #include "fns.h" -uchar mem[65536]; -int rombank, rambank, ramen, battery, ramrom; -extern int savefd; +u8int *rom; +u8int *romb, *vramb, *wramb, *eramb; +u8int wram[32768], vram[16384], oam[256], reg[256]; +u8int *back; +u8int palm[128]; +u32int pal[64]; +int nrom, nback, nbackbank; +u32int divclock; +int prish; +MBC3Timer timer, timerl; +s8int dma; +u32int white; +u32int moncols[4]; + +Var memvars[] = {ARR(wram), ARR(vram), ARR(oam), ARR(reg), ARR(palm), VAR(clock), VAR(divclock), VAR(mode), VAR(dma), {nil, 0, 0}}; u8int -memread(u16int p) +regread(u8int a) { - extern int keys; - - if((p & 0xFF80) == 0xFF00) - switch(p){ - case 0xFF00: - if((mem[0xFF00] & (1<<5)) == 0) - return (mem[0xFF00] & 0xF0) | ~(keys >> 4); - if((mem[0xFF00] & (1<<6)) == 0) - return (mem[0xFF00] & 0xF0) | ~(keys & 0x0F); - return (mem[0xFF00] & 0xF0) | 0x0F; - } - if(!ramen && ((p & 0xE000) == 0xA000)) - return 0xFF; - return mem[p]; + u8int v; + + switch(a){ + case JOYP: + v = keys & 0x30 | 0xcf; + if((reg[a] & 0x10) == 0) + v &= 0xf0 | ~keys; + if((reg[a] & 0x20) == 0) + v &= 0xf0 | ~(keys >> 4); + return v; + case DIV: + return reg[DIV] + (clock - divclock >> 7 - ((mode & TURBO) != 0)); + case TIMA: + return timread(); + case STAT: + return reg[a] & 0xf8 | (reg[LYC] == ppuy) << 2 | ppustate; + case LY: + return ppuy; + case BCPD: + return palm[reg[BCPS] & 0x3f]; + case OCPD: + return palm[0x40 | reg[OCPS] & 0x3f]; + case NR13: case NR23: case NR31: case NR33: case NR41: + return 0xff; + case NR14: case NR24: case NR34: case NR44: + return reg[a] | 0xbf; + case NR52: + return apuread(); + default: + if((a & 0xf0) == 0x30) + return waveread(a & 0xf); + return reg[a]; + } +} + +void +colcol(int i, u16int v) +{ + union { u8int c[4]; u32int l; } c; + + c.c[0] = v >> 7 & 0xf8; + c.c[1] = v >> 2 & 0xf8; + c.c[2] = v << 3; + c.c[3] = 0; + pal[i] = c.l; +} + +void +regwrite(u8int a, u8int v) +{ + extern Event evhblank; + int i; + u8int u; + + switch(a){ + case DIV: + divclock = clock; + v = 0; + break; + case TIMA: + reg[a] = v; + timerset(); + return; + case TAC: + v |= 0xf8; + timertac(v, 0); + break; + case STAT: + v |= 0x80; + if((v & IRQLYC) != 0 && ppuy == reg[LYC]) + reg[IF] |= IRQLCDS; + break; + case LYC: + if((reg[STAT] & IRQLYC) != 0 && ppuy == v) + reg[IF] |= IRQLCDS; + break; + case LCDC: + ppusync(); + if((~v & reg[a] & LCDEN) != 0) + delevent(&evhblank); + if((v & ~reg[a] & LCDEN) != 0) + addevent(&evhblank, 456*2); + break; + case SCY: case SCX: case WY: case WX: + ppusync(); + break; + case VBK: + if((mode & COL) == 0) + break; + vramb = vram + ((v & 1) << 13); + v |= 0xfe; + break; + case SVBK: + if((mode & COL) == 0) + break; + v &= 7; + wramb = wram + (v + (v - 1 >> 3 & 1) << 12); + v |= 0xf8; + break; + case BGP: + case OBP0: + case OBP1: + if((mode & COL) != 0) + break; + ppusync(); + i = a - BGP << 2; + pal[i] = moncols[~v & 3]; + pal[i+1] = moncols[~v >> 2 & 3]; + pal[i+2] = moncols[~v >> 4 & 3]; + pal[i+3] = moncols[~v >> 6 & 3]; + break; + case DMA: + for(i = 0; i < 160; i++) + oam[i] = memread(v << 8 | i); + break; + case BCPS: v |= 0x40; break; + case OCPS: v |= 0x40; break; + case BCPD: + if((mode & COL) == 0) + break; + ppusync(); + u = reg[BCPS] & 0x3f; + palm[u] = v; + colcol(u / 2, palm[u & 0xfe] | palm[u | 1] << 8); + if((reg[BCPS] & 0x80) != 0) + reg[BCPS] = reg[BCPS] + 1 - (u + 1 & 0x40); + break; + case OCPD: + if((mode & COL) == 0) + break; + ppusync(); + u = 0x40 | reg[OCPS] & 0x3f; + palm[u] = v; + colcol(u / 2, palm[u & 0xfe] | palm[u | 1] << 8); + if((reg[OCPS] & 0x80) != 0) + reg[OCPS] = reg[OCPS] + 1 - ((reg[OCPS] & 0x3f) + 1 & 0x40); + break; + case IF: v |= 0xe0; break; + case KEY1: v |= 0x7e; break; + case HDMAC: + if((mode & COL) == 0) + break; + dma = (v & 0x80) != 0 ? -1 : 1; + break; + case NR10: v |= 0x80; goto snd; + case NR14: case NR24: v |= 0x38; goto snd; + case NR32: v |= 0x9f; goto snd; + case NR41: v |= 0xc0; goto snd; + case NR44: v |= 0x3f; goto snd; + case NR52: v |= 0x70; goto snd; + case NR11: case NR12: case NR13: + case NR21: case NR22: case NR23: + case NR30: case NR31: case NR33: case NR34: + case NR42: case NR43: + case NR50: case NR51: + snd: + sndwrite(a, v); + break; + } + if((a & 0xf0) == 0x30) + wavewrite(a, v); + reg[a] = v; } static void -ramswitch(int state, int bank) +nope(int p) +{ + print("unimplemented mapper function %d (mapper %d)\n", p, mbc); +} + +static int +mbc0(int a, int) { - if(ramen){ - memcpy(ram + 8192 * rambank, mem + 0xA000, 8192); - if(battery && savefd > 0){ - seek(savefd, rambank * 8192, 0); - write(savefd, ram + 8192 * rambank, 8192); + if(a < 0) + switch(a){ + case INIT: + if(nback != 0) + eramb = back; + return 0; + case SAVE: + case RSTR: + return 0; + case READ: + return -1; + default: + nope(a); } - ramen = 0; - } - rambank = bank; - if(state){ - if(bank >= rambanks) - sysfatal("invalid RAM bank %d selected (pc = %.4x)", bank, curpc); - memcpy(mem + 0xA000, ram + 8192 * rambank, 8192); - ramen = 1; - } + return 0; } -void -flushram(void) +static int +mbc1(int a, int v) { + static u8int ramen, b0, b1, romram; + static Var mbc1vars[] = {VAR(ramen), VAR(b0), VAR(b1), VAR(romram), {nil, 0, 0}}; + u16int b; + + if(a < 0) + switch(a){ + case INIT: + return 0; + case SAVE: + putvars(mbc1vars); + break; + case RSTR: + getvars(mbc1vars); + break; + case READ: + return -1; + default: + nope(a); + } + switch(a >> 13){ + case 0: ramen = (v & 0xf) == 0xa; break; + case 1: v &= 0x1f; b0 = v != 0 ? v : 1; break; + case 2: b1 = v & 3; b1 %= nbackbank; break; + case 3: romram = v & 1; break; + } + b = b0; + if(!romram) + b |= b1 << 5; + b %= nrom >> 14; + romb = rom + (b << 14); if(ramen) - ramswitch(ramen, rambank); + if(romram) + eramb = back + (b1 << 13); + else + eramb = back; + else + eramb = nil; + return 0; } -static void -romswitch(int bank) +static int +mbc2(int a, int v) { - if(bank >= rombanks) - sysfatal("invalid ROM bank %d selected (pc = %.4x)", bank, curpc); - rombank = bank; - memcpy(mem + 0x4000, cart + 0x4000 * bank, 0x4000); + static int ramen, b; + static Var mbc2vars[] = {VAR(ramen), VAR(b), {nil, 0, 0}}; + + if(a < 0) + switch(a){ + case INIT: + return 0; + case SAVE: + putvars(mbc2vars); + return 0; + case RSTR: + getvars(mbc2vars); + romb = rom + (b << 14); + return 0; + case READ: + if(ramen) + return back[a & 0x1ff]; + return 0xff; + default: + nope(a); + } + if((a & 0xc100) == 0) + ramen = (v & 0x0f) == 0x0a; + else if((a & 0xc100) == 0x100){ + b = v & 0x0f; + if(b == 0) + b++; + b %= nrom >> 14; + romb = rom + (b << 14); + }else if((a >> 12) == 0xa && ramen) + back[a & 0x1ff] = v | 0xf0; + return 0; } void -memwrite(u16int p, u8int v) +timerforward(MBC3Timer *t) { - if(p < 0x8000){ - switch(mbc){ - case 0: - return; - case 1: - case 2: - switch(p >> 13){ - case 0: - if((v & 0x0F) == 0x0A) - ramswitch(1, rambank); - else - ramswitch(0, rambank); - return; - case 1: - v &= 0x1F; - if(v == 0) - v++; - romswitch((rombank & 0xE0) | v); - return; - case 2: - if(ramrom) - ramswitch(ramen, v & 3); - else - romswitch(((v & 3) << 5) | (rombank & 0x1F)); - return; - case 3: - ramrom = v; - return; - } - return; - case 3: - switch(p >> 13){ - case 0: - if((v & 0x0F) == 0x0A) - ramswitch(1, rambank); - else - ramswitch(0, rambank); - return; - case 1: - v &= 0x7F; - if(v == 0) - v++; - romswitch(v); - return; - case 2: - if(v < 4) - ramswitch(ramen, v); - return; - } - return; - case 5: - switch(p >> 12){ - case 0: case 1: - if((v & 0x0F) == 0x0A) - ramswitch(1, rambank); - else - ramswitch(0, rambank); - return; - case 2: - romswitch((rombank & 0x100) | v); - return; - case 3: - romswitch((((int)v & 1) << 8) | (rombank & 0xFF)); - return; - case 4: - ramswitch(ramen, v & 15); - return; - + vlong n, nd; + int x; + + n = nsec(); + nd = n - t->ns; + if(nd < 0) + return; + if((t->dh & 0x40) != 0){ + t->ns = n; + return; + } + t->ns = n - nd % BILLION; + x = t->sec + t->min * 60 + t->hr * 3600 + t->dl * 86400 + t->dh * (256 * 86400); + x += nd / BILLION; + t->sec = x % 60; + x /= 60; + t->min = x % 60; + x /= 60; + t->hr = x % 24; + x /= 24; + t->dl = x & 0xff; + x >>= 8; + t->dh = t->dh & 0xfe | x & 1; + if(x >= 2) t->dh |= 0x80; +} + +static int +mbc3(int a, int v) +{ + static u8int ramen, b0, b1, latch; + static Var mbc3vars[] = {VAR(ramen), VAR(b0), VAR(b1), VAR(latch), + VAR(timer.ns), VAR(timer.sec), VAR(timer.min), VAR(timer.hr), VAR(timer.dl), VAR(timer.dh), + VAR(timerl.sec), VAR(timerl.min), VAR(timerl.hr), VAR(timerl.dl), VAR(timerl.dh), {nil, 0, 0}}; + + if(a < 0) + switch(a){ + case INIT: + return 0; + case SAVE: + putvars(mbc3vars); + return 0; + case RSTR: + getvars(mbc3vars); + romb = rom + (b0 << 14); + break; + case READ: + if(!ramen) + return -1; + switch(b1){ + case 8: return timerl.sec; + case 9: return timerl.min; + case 10: return timerl.hr; + case 11: return timerl.dl; + case 12: return timerl.dh; } - return; + return -1; default: - sysfatal("mbc %d unimplemented", mbc); + nope(a); } + switch(a >> 13){ + case 0: ramen = (v & 0xf) == 0xa; break; + case 1: + v &= 0x7f; + b0 = v != 0 ? v : 1; + b0 %= nrom >> 14; + romb = rom + (b0 << 14); + return 0; + case 2: b1 = v & 15; b1 %= nbackbank; break; + case 3: + if(latch == 0 && v == 1){ + timerl = timer; + timerforward(&timerl); + } + latch = v; + break; + case 0xa: + if(!ramen) + return 0; + switch(b1){ + case 8: timerforward(&timer); timer.sec = v; break; + case 9: timerforward(&timer); timer.min = v; break; + case 10: timerforward(&timer); timer.hr = v; break; + case 11: timerforward(&timer); timer.dl = v; break; + case 12: timerforward(&timer); timer.dh = v; break; + } + return 0; } - if((p & 0xFF80) == 0xFF00) - switch(p){ - case 0xFF04: - v = 0; - break; - case 0xFF07: - timer = (v & 4) != 0; - switch(v & 3){ - case 0: - timerfreq = 1024; - break; - case 1: - timerfreq = 16; - break; - case 2: - timerfreq = 64; - break; - default: - timerfreq = 256; - } - break; - case 0xFF26: - v = (v & 0xF0) | (mem[p] & 0x0F); - case 0xFF41: - v &= ~7; - v |= mem[p] & 7; - break; - case 0xFF46: - memcpy(mem + 0xFE00, mem + (((int)v) << 8), 0xA0); + eramb = ramen && b1 < 4 ? back + (b1 << 13) : nil; + return 0; +} + +static int +mbc5(int a, int v) +{ + static u8int ramen, b1; + static u16int b0; + static Var mbc5vars[] = {VAR(ramen), VAR(b0), VAR(b1), {nil, 0, 0}}; + + if(a < 0) + switch(a){ + case INIT: + return 0; + case SAVE: + putvars(mbc5vars); + return 0; + case RSTR: + getvars(mbc5vars); break; + case READ: + return -1; + default: + nope(a); + } + switch(a >> 13){ + case 0: ramen = (v & 0xf) == 0xa; break; + case 1: b0 = b0 & 0x100 | v; break; + case 2: b0 = b0 & 0xff | v << 8 & 0x100; break; + case 3: b1 = v & 0xff; b1 %= nbackbank; break; + } + b0 %= nrom >> 14; + romb = rom + (b0 << 14); + eramb = ramen ? back + (b1 << 13) : nil; + return 0; + +} + +int (*mappers[7])(int, int) = {mbc0, mbc1, mbc2, mbc3, mbc0, mbc5, mbc0}; +int (*mapper)(int, int); + +u8int +memread(u16int a) +{ + switch(a >> 12){ + case 0: case 1: case 2: case 3: + return rom[a]; + case 4: case 5: case 6: case 7: + return romb[a - 0x4000]; + case 8: case 9: + return vramb[a - 0x8000]; + case 10: case 11: + if(eramb != nil) + return eramb[a - 0xa000]; + return mapper(READ, a); + case 12: case 14: + return wram[a & 0xfff]; + case 15: + if(a >= 0xff00) + return regread(a); + else if(a >= 0xfe00) + return oam[a - 0xfe00]; + case 13: + return wramb[a & 0xfff]; + } + return 0xff; +} + +void +memwrite(u16int a, u8int v) +{ + switch(a >> 12){ + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + mapper(a, v); + return; + case 8: case 9: + vramb[a - 0x8000] = v; + return; + case 10: case 11: + if(eramb != nil) + eramb[a - 0xa000] = v; + else + mapper(a, v); + writeback(); + return; + case 12: case 14: + wram[a & 0xfff] = v; + return; + case 15: + if(a >= 0xff00){ + regwrite(a, v); + return; + }else if(a >= 0xfe00){ + oam[a - 0xfe00] = v; + return; } - mem[p] = v; + case 13: + wramb[a & 0xfff] = v; + } +} + +void +meminit(void) +{ + union { u8int c[4]; u32int l; } c; + + c.c[0] = c.c[1] = c.c[2] = 0; + c.c[3] = 1; + for(; c.l != 1; prish++) + c.l >>= 1; + + c.c[0] = c.c[1] = c.c[2] = 0xff; + c.c[3] = 0; + white = c.l; + + romb = rom + 0x4000; + wramb = wram + 0x1000; + vramb = vram; + mapper = mappers[mbc]; + mapper(INIT, 0); + + reg[LCDC] = 0x91; + reg[VBK] = 0xfe; + reg[SVBK] = 0xf8; + reg[IF] = 0xe0; +} + +void +memload(void) +{ + int i; + u8int v; + + if((mode & COL) != 0){ + for(i = 0; i < 64; i++) + colcol(i, palm[2*i] | palm[2*i+1] << 8); + vramb = vram + ((reg[VBK] & 1) << 13); + wramb = wram + (reg[SVBK] + (reg[SVBK] - 1 >> 3 & 1) << 12); + }else{ + v = reg[BGP]; + pal[0] = moncols[~v & 3]; + pal[1] = moncols[~v >> 2 & 3]; + pal[2] = moncols[~v >> 4 & 3]; + pal[3] = moncols[~v >> 6 & 3]; + v = reg[OBP0]; + pal[4] = moncols[~v & 3]; + pal[5] = moncols[~v >> 2 & 3]; + pal[6] = moncols[~v >> 4 & 3]; + pal[7] = moncols[~v >> 6 & 3]; + v = reg[OBP1]; + pal[8] = moncols[~v & 3]; + pal[9] = moncols[~v >> 2 & 3]; + pal[10] = moncols[~v >> 4 & 3]; + pal[11] = moncols[~v >> 6 & 3]; + } + +} + +int +dmastep(void) +{ + int i; + u16int sa, da; + + sa = (reg[HDMASL] | reg[HDMASH] << 8) & 0xfff0; + da = (reg[HDMADL] | reg[HDMADH] << 8) & 0x0ff0; + for(i = 0; i < 16; i++) + memwrite(da++, memread(sa++)); + reg[HDMASL] += 16; + if((reg[HDMASL] & 0xf0) == 0) + reg[HDMASH]++; + reg[HDMADL] += 16; + if((reg[HDMADL] & 0xf0) == 0) + reg[HDMADH]++; + if((reg[HDMAC] & 0x7f) == 0) + dma = 0; + else{ + reg[HDMAC]--; + if((reg[HDMAC] & 0x80) != 0) + dma = 1; + } + return 64; } diff --git a/sys/src/games/gb/mkfile b/sys/src/games/gb/mkfile index de0152f66..b9e767497 100644 --- a/sys/src/games/gb/mkfile +++ b/sys/src/games/gb/mkfile @@ -3,14 +3,13 @@ BIN=/$objtype/bin/games TARG=gb OFILES=\ - gb.$O\ cpu.$O\ mem.$O\ - disasm.$O\ + gb.$O\ ppu.$O\ - daa.$O\ + ev.$O\ state.$O\ - audio.$O\ + apu.$O\ HFILES=dat.h fns.h diff --git a/sys/src/games/gb/ppu.c b/sys/src/games/gb/ppu.c index a68781b87..3dbd221d2 100644 --- a/sys/src/games/gb/ppu.c +++ b/sys/src/games/gb/ppu.c @@ -1,217 +1,320 @@ #include <u.h> #include <libc.h> #include <thread.h> -#include <draw.h> #include "dat.h" #include "fns.h" -uchar pic[160*144*4*9]; +u8int ppustate, ppuy; +u32int pic[PICW*PICH]; +ulong hblclock, rendclock; +jmp_buf mainjmp, renderjmp; +static int cyc, done, ppux, ppux0; +extern int prish; +extern u32int white; -static void -resolvetile(u8int tx, u8int ty, u8int toy, int window, u8int* tnl1, u8int *tnl2) -{ - u16int tni, tnli; - u8int tn; +Var ppuvars[] = {VAR(ppustate), VAR(ppuy), VAR(hblclock), VAR(rendclock), {nil, 0, 0}}; + +#define ryield() {if(setjmp(renderjmp) == 0) longjmp(mainjmp, 1);} +#define myield() {if(setjmp(mainjmp) == 0) longjmp(renderjmp, 1);} + +typedef struct sprite sprite; +struct sprite { + u8int dy, x, t; + u8int fetched, pal; + u16int chr; +}; +enum { + SPRPRI = 0x80, + SPRYFL = 0x40, + SPRXFL = 0x20, + SPRPAL = 0x10, + SPRBANK = 0x08, - tni = 0x9800 + 32 * ((u16int)ty) + ((u16int)tx); - if(window){ - if(mem[LCDC] & WINDOWTILEMAP) - tni += 0x400; - }else - if(mem[LCDC] & BGTILEMAP) - tni += 0x400; - tn = mem[tni]; - if(mem[LCDC] & BGTILEDATA) - tnli = 0x8000 + 16 * (u16int)tn; - else - tnli = 0x9000 + 16 * (u16int)(schar)tn; - *tnl1 = mem[tnli + 2 * ((u16int)toy)]; - *tnl2 = mem[tnli + 2 * ((u16int)toy) + 1]; -} + TILCOL0 = 0x01, + TILPRI = 0x02, + TILSPR = 0x04, +}; +sprite spr[10], *sprm; -static void -pixel(int x, int y, int val, int back) +void +ppurender(void) { - int Y; - union { u8int c[4]; u32int l; } u; - u32int *p, l; - - val = (3 - val) * 0x55; - u.c[0] = val; - u.c[1] = val; - u.c[2] = val; - u.c[3] = back ? 0 : 0xFF; - l = u.l; - if(scale == 3){ - p = ((u32int*)pic) + y * 3 * 3 * 160 + 3 * x; - for(Y = 0; Y < 3; Y++){ - *p++ = l; - *p++ = l; - *p = l; - p += 3 * 160 - 2; + int x, y, i, n, m, win; + u16int ta, ca, chr; + u8int tile, attr, pali; + u32int sr[8], *picp; + #define eat(nc) if(cyc <= nc){for(i = 0; i < nc; i++) if(--cyc == 0) ryield();} else cyc -= nc; + + ryield(); + + attr = 0; + for(;;){ + eat(6*2); + m = 168 + (reg[SCX] & 7); + win = 0; + if((reg[LCDC] & WINEN) != 0 && ppuy >= reg[WY] && reg[WX] <= 166) + if(reg[WX] == 0) + m = 7; + else if(reg[WX] == 166) + m = 0; + else{ + m = reg[WX] + (reg[SCX] & 7) + 1; + win = -1; + } + ppux = 0; + ppux0 = 0; + picp = pic + ppuy * PICW; + y = ppuy + reg[SCY] << 1 & 14; + ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3e0 | reg[SCX] >> 3; + x = -(reg[SCX] & 7); + restart: + do{ + tile = vram[ta]; + if((mode & COL) != 0) + attr = vram[8192 + ta]; + if((reg[LCDC] & BGTILE) != 0) + ca = (tile << 4) + y; + else + ca = 0x1000 + ((s32int)(tile << 24) >> 20) + y; + if((attr & 0x40) != 0) + ca ^= 14; + ca |= (attr & 8) << 10; + chr = vram[ca] << 8 | vram[ca+1]; + pali = attr << 2 & 0x1c; + if((attr & 0x20) == 0) + for(i = 0; i < 8; i++){ + sr[i] = pal[pali | chr >> 15 | chr >> 6 & 2] | ((chr & 0x8080) == 0) << prish; + chr <<= 1; + } + else + for(i = 0; i < 8; i++){ + sr[i] = pal[pali | chr << 1 & 2 | chr >> 8 & 1] | ((chr & 0x0101) == 0) << prish; + chr >>= 1; + } + if((attr & 0x80) != 0) + for(i = 0; i < 8; i++) + sr[i] |= 2 << prish; + if((reg[LCDC] & BGEN) == 0 && (mode & COL) == 0 && ((mode & CGB) != 0 || win == 0)) + for(i = 0; i < 8; i++) + sr[i] = white; + if(cyc <= 2*8){ + for(i = 0; i < 2*8; i++) + if(--cyc == 0) + ryield(); + y = ppuy + reg[SCY] << 1 & 14; + ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3e0 | ta & 0x1f; + }else + cyc -= 2*8; + m -= 8; + n = m < 8 ? m : 8; + if((ta & 0x1f) == 0x1f) + ta &= ~0x1f; + else + ta++; + for(i = 0; i < n; i++, x++) + if(x >= 0) + picp[x] = sr[i]; + ppux = x; + }while(m > 8); + if(win == -1){ + win = 1; + ta = 0x1800 | reg[LCDC] << 4 & 0x400 | ppuy - reg[WY] << 2 & 0x3e0; + y = ppuy - reg[WY] << 1 & 14; + cyc += 2; + m = 175 - reg[WX]; + goto restart; } - }else if(scale == 2){ - p = ((u32int*)pic) + y * 2 * 2 * 160 + 2 * x; - *p++ = l; - *p = l; - p += 2 * 160 - 1; - *p++ = l; - *p = l; - }else{ - p = ((u32int*)pic) + y * 160 + x; - *p = l; + done = 1; + ryield(); } } -static void -pixelbelow(int x, int y, int val) -{ - if(pic[y*scale*scale*160*4 + x*scale*4 + 3] == 0) - pixel(x, y, val, 0); -} - -static void -drawbg(void) +void +oamsearch(void) { - u8int Y, x, y, ty, toy, tx, tox, tnl1, tnl2, pal, val,h; + u8int *p; + sprite *q; + int y0, sy; + u8int t, tn; + u8int *chrp; - Y = mem[LY]; - y = Y + mem[SCY]; - ty = y / 8; - toy = y % 8; - tx = mem[SCX] / 8; - tox = mem[SCX] % 8; - resolvetile(tx, ty, toy, 0, &tnl1, &tnl2); - tnl1 <<= (tox+1) % 8; - tnl2 <<= (tox+1) % 8; - pal = mem[BGP]; - for(x = 0; x < 160; x++){ - tox++; - if((tox % 8) == 0){ - tx++; - resolvetile(tx%32, ty, toy, 0, &tnl1, &tnl2); - } - val = ((tnl1 & 0x80) >> 6) | ((tnl2 & 0x80) >> 5); - h = val == 0; - val = (pal >> val) & 3; - pixel(x, Y, val, h); - tnl1 <<= 1; - tnl2 <<= 1; + y0 = ppuy + 16; + sy = (reg[LCDC] & SPR16) != 0 ? 16 : 8; + sprm = spr; + if((reg[LCDC] & SPREN) == 0) + return; + for(p = oam; p < oam + 160; p += 4){ + if((u8int)(y0 - p[0]) >= sy) + continue; + if((mode & COL) == 0){ + for(q = spr; q < sprm; q++) + if(q->x > p[1]){ + if(sprm != spr + 10){ + memmove(q + 1, q, (sprm - q) * sizeof(sprite)); + sprm++; + }else + memmove(q + 1, q, (sprm - 1 - q) * sizeof(sprite)); + goto found; + } + if(q == spr + 10) + continue; + sprm++; + found:; + }else + q = sprm++; + q->dy = y0 - p[0]; + q->x = p[1]; + q->t = t = p[3]; + if((t & SPRYFL) != 0) + q->dy ^= sy - 1; + tn = p[2]; + if(sy == 16) + tn = tn & ~1 | q->dy >> 3; + chrp = vram + (tn << 4 | q->dy << 1 & 14); + if((mode & COL) != 0){ + chrp += t << 10 & 0x2000; + q->pal = 0x20 | t << 2 & 0x1c; + }else + q->pal = 4 + (t >> 2 & 4); + q->chr = chrp[0] << 8 | chrp[1]; + if(p[1] < 8) + if((t & SPRXFL) != 0) + q->chr >>= 8 - p[1]; + else + q->chr <<= 8 - p[1]; + q->fetched = 0; + if((mode & COL) != 0 && sprm == spr + 10) + break; } } -static void -drawsprites(void) +void +sprites(void) { - u8int y, t, tnl1, tnl2, dx, ddx, val, pal; - schar dy; - u16int tnli; - int i, x, big; - struct { u8int y, x, t, f; } *s; + sprite *q; + u8int attr; + u32int *picp; + int x, x1; + u16int chr; - y = mem[LY]; - big = mem[LCDC] & SPRITE16; - s = (void*)(mem + 0xFE00); - for(i = 0; i < 40; i++, s++){ - if(s->y == 0 || s->x == 0) - continue; - dy = y - s->y + 16; - if(dy < 0 || dy >= (big ? 16 : 8)) + picp = pic + ppuy * PICW; + for(q = spr; q < sprm; q++){ + if(q->x <= ppux0 || q->x >= ppux + 8) continue; - pal = (s->f & (1<<4)) ? mem[OBP1] : mem[OBP0]; - if(s->f & (1<<6)) - dy = (big ? 15 : 7) - dy; - t = s->t; - if(big){ - if(dy >= 8){ - t |= 1; - dy -= 8; - }else - t &= ~1; - } - tnli = 0x8000 + 2 * (u16int)dy + 16 * (u16int) t; - tnl1 = mem[tnli]; - tnl2 = mem[tnli + 1]; - x = s->x - 9; - for(dx = 0; dx < 8; dx++, x++){ - ddx = dx; - if((s->f & (1<<5)) == 0) - ddx = 7 - dx; - val = ((tnl1 >> ddx) & 1) | (((tnl2 >> ddx) & 1) << 1); - if(x < 0 || val == 0) - continue; - val = (pal >> (2 * val)) & 3; - if(x >= 160) - break; - if(s->f & (1<<7)) - pixelbelow(x, y, val); + x = q->x - 8; + if(x < ppux0) x = ppux0; + x1 = q->x; + if(x1 > ppux) x1 = ppux; + for(; x < x1; x++){ + attr = picp[x] >> prish; + chr = q->chr; + if((chr & ((q->t & SPRXFL) != 0 ? 0x0101 : 0x8080)) != 0 && (attr & TILSPR) == 0 && + ((mode & COL) != 0 && (reg[LCDC] & BGPRI) == 0 || + (attr & TILPRI) == 0 && ((q->t & SPRPRI) == 0 || (attr & TILCOL0) != 0))) + if((q->t & SPRXFL) == 0) + picp[x] = pal[q->pal | chr >> 15 | chr >> 6 & 2] | TILSPR << prish; + else + picp[x] = pal[q->pal | chr << 1 & 2 | chr >> 8 & 1] | TILSPR << prish; + if((q->t & SPRXFL) != 0) + q->chr >>= 1; else - pixel(x, y, val, 0); + q->chr <<= 1; } } + ppux0 = ppux; } -static void -drawwindow(void) +void +ppusync(void) { - u8int wx, wy, Y, y, ty, toy, tx, tox, tnl1, tnl2, x, val, pal; - if(mem[WX] < 7) - return; - wx = mem[WX] - 7; - wy = mem[WY]; - Y = mem[LY]; - if(Y < wy) + if(ppustate != 3) return; - y = Y - wy; - ty = y / 8; - toy = y % 8; - tx = 0; - tox = 0; - resolvetile(tx, ty, toy, 1, &tnl1, &tnl2); - pal = mem[BGP]; - for(x = wx; x < 160; x++){ - tox++; - if((tox & 7) == 0){ - tx++; - resolvetile(tx, ty, toy, 1, &tnl1, &tnl2); + cyc = clock - rendclock; + if(cyc != 0) + myield(); + sprites(); + rendclock = clock; +} + +int +linelen(void) +{ + int t; + + t = 174 + (reg[SCX] & 7); + if((reg[LCDC] & WINEN) != 0 && ppuy >= reg[WY] && reg[WX] < 166) + if(reg[WX] == 0) + t += 7; + else + t += 6; + return t*2; +} + +void +hblanktick(void *) +{ + extern Event evhblank; + int t; + + switch(ppustate){ + case 0: + hblclock = clock + evhblank.time; + if(++ppuy == 144){ + ppustate = 1; + if((reg[STAT] & IRQM1) != 0) + reg[IF] |= IRQLCDS; + addevent(&evhblank, 456*2); + reg[IF] |= IRQVBL; + flush(); + }else{ + ppustate = 2; + if((reg[STAT] & IRQM2) != 0) + reg[IF] |= IRQLCDS; + addevent(&evhblank, 80*2); } - val = ((tnl1 & 0x80) >> 6) | ((tnl2 & 0x80) >> 5); - val = (pal >> val) & 3; - pixel(x, Y, val, 0); - tnl1 <<= 1; - tnl2 <<= 1; + if((reg[STAT] & IRQLYC) != 0 && ppuy == reg[LYC]) + reg[IF] |= IRQLCDS; + break; + case 1: + hblclock = clock + evhblank.time; + if(++ppuy == 154){ + ppuy = 0; + ppustate = 2; + if((reg[STAT] & IRQM2) != 0) + reg[IF] |= IRQLCDS; + addevent(&evhblank, 80*2); + }else + addevent(&evhblank, 456*2); + if((reg[STAT] & IRQLYC) != 0 && ppuy == reg[LYC]) + reg[IF] |= IRQLCDS; + break; + case 2: + oamsearch(); + rendclock = clock + evhblank.time; + ppustate = 3; + addevent(&evhblank, linelen()); + break; + case 3: + ppusync(); + if(!done) print("not done?!\n"); + done = 0; + ppustate = 0; + if((reg[STAT] & IRQM0) != 0) + reg[IF] |= IRQLCDS; + t = hblclock + 456 * 2 - clock; + addevent(&evhblank, t < 0 ? 456 * 2 : t); + if(dma < 0) + dma = 1; + break; } } void -ppustep(void) +ppuinit(void) { - if(mem[LY] == 144){ - mem[STAT] &= ~3; - mem[STAT] |= 1; - interrupt(INTVBLANK); - } - if(mem[LY] == mem[LYC]){ - mem[STAT] |= 4; - if(mem[STAT] & 64) - interrupt(INTLCDC); - }else - mem[STAT] &= ~4; - if(mem[LY] < 144) - mem[STAT] &= ~3; - if(mem[LY] < 144 && (mem[LCDC] & LCDOP)){ - if(mem[LCDC] & BGDISP) - drawbg(); - if(mem[LCDC] & WINDOWDISP) - drawwindow(); - if(mem[LCDC] & SPRITEDISP) - drawsprites(); - } - mem[LY]++; - if(mem[LY] > 160){ - mem[LY] = 0; - if((mem[LCDC] & LCDOP) == 0) - memset(pic, 0, sizeof(pic)); - flush(); - } + static char ppustack[4096]; + + renderjmp[JMPBUFPC] = (uintptr)ppurender; + renderjmp[JMPBUFSP] = (uintptr)(ppustack + sizeof(ppustack) - 64); + myield(); } diff --git a/sys/src/games/gb/state.c b/sys/src/games/gb/state.c index fcf22a509..67c0ff9c7 100644 --- a/sys/src/games/gb/state.c +++ b/sys/src/games/gb/state.c @@ -2,124 +2,163 @@ #include <libc.h> #include <thread.h> #include <draw.h> +#include <bio.h> #include "dat.h" #include "fns.h" -static int fd; +extern Var cpuvars[], ppuvars[], memvars[], apuvars[], evvars[]; +extern Event *events[NEVENT], *elist; +static Biobuf *bp; +Var apuvars[] = {{nil, 0, 0}}; static void -put8(u8int i) +putevents(void) { - write(fd, &i, 1); + int i, j; + Event *e; + + for(i = 0; i < NEVENT; i++) + if(elist == events[i]) + break; + if(i == NEVENT && elist != nil) + print("unknown event %p in chain\n", elist); + Bputc(bp, i); + for(i = 0; i < NEVENT; i++){ + e = events[i]; + Bputc(bp, e->time); + Bputc(bp, e->time >> 8); + Bputc(bp, e->time >> 16); + Bputc(bp, e->time >> 24); + for(j = 0; j < NEVENT; j++) + if(e->next == events[j]) + break; + if(j == NEVENT && e->next != nil) + print("unknown event %p in chain\n", e->next); + Bputc(bp, j); + } + } static void -put16(u16int i) +getevents(void) { - put8(i); - put8(i >> 8); + int i, j; + Event *e; + + i = Bgetc(bp); + elist = i >= NEVENT ? nil : events[i]; + for(i = 0; i < NEVENT; i++){ + e = events[i]; + e->time = Bgetc(bp); + e->time |= Bgetc(bp) << 8; + e->time |= Bgetc(bp) << 16; + e->time |= Bgetc(bp) << 24; + j = Bgetc(bp); + e->next = j >= NEVENT ? nil : events[j]; + } } -static void -put32(u32int i) +void +getvars(Var *v) { - put8(i); - put8(i >> 8); - put8(i >> 16); - put8(i >> 24); -} + int n; + u16int *p, w; + u32int *q, l; -static int -get8(void) -{ - u8int c; - - read(fd, &c, 1); - return c; -} + for(; v->a != nil; v++) + switch(v->s){ + case 1: + Bread(bp, v->a, v->n); + break; + case 2: + n = v->n; + p = v->a; + while(n--){ + w = Bgetc(bp); + *p++ = w | Bgetc(bp) << 8; + } + break; + case 4: + n = v->n; + q = v->a; + while(n--){ + l = Bgetc(bp); + l |= Bgetc(bp) << 8; + l |= Bgetc(bp) << 16; + *q++ = l | Bgetc(bp) << 24; + } + break; + } -static int -get16(void) -{ - int i; - - i = get8(); - i |= get8() << 8; - return i; } -static int -get32(void) +void +putvars(Var *v) { - int i; - - i = get8(); - i |= get8() << 8; - i |= get8() << 16; - i |= get8() << 24; - return i; + int n; + u16int *p; + u32int *q; + + for(; v->a != nil; v++) + switch(v->s){ + case 1: + Bwrite(bp, v->a, v->n); + break; + case 2: + n = v->n; + p = v->a; + while(n--){ + Bputc(bp, *p & 0xff); + Bputc(bp, *p++ >> 8); + } + break; + case 4: + n = v->n; + q = v->a; + while(n--){ + Bputc(bp, *q); + Bputc(bp, *q >> 8); + Bputc(bp, *q >> 16); + Bputc(bp, *q++ >> 24); + } + break; + } } void -loadstate(char *file) +savestate(char *file) { - flushram(); - fd = open(file, OREAD); - if(fd < 0){ - message("open: %r"); + flushback(); + bp = Bopen(file, OWRITE); + if(bp == nil){ + print("open: %r\n"); return; } - read(fd, mem, 65536); - if(ram != nil) - read(fd, ram, rambanks * 8192); - read(fd, R, sizeof R); - sp = get16(); - pc = get16(); - Fl = get8(); - halt = get32(); - IME = get32(); - clock = get32(); - ppuclock = get32(); - divclock = get32(); - timerclock = get32(); - timerfreq = get32(); - timer = get32(); - rombank = get32(); - rambank = get32(); - ramen = get32(); - battery = get32(); - ramrom = get32(); - close(fd); + putvars(cpuvars); + putvars(ppuvars); + putvars(memvars); + putvars(apuvars); + putvars(evvars); + putevents(); + mapper(SAVE, 0); + Bterm(bp); } void -savestate(char *file) +loadstate(char *file) { - flushram(); - fd = create(file, ORDWR, 0666); - if(fd < 0){ - message("create: %r"); + bp = Bopen(file, OREAD); + if(bp == nil){ + print("open: %r\n"); return; } - write(fd, mem, 65536); - if(ram != nil) - write(fd, ram, rambanks * 8192); - write(fd, R, sizeof R); - put16(sp); - put16(pc); - put8(Fl); - put32(halt); - put32(IME); - put32(clock); - put32(ppuclock); - put32(divclock); - put32(timerclock); - put32(timerfreq); - put32(timer); - put32(rombank); - put32(rambank); - put32(ramen); - put32(battery); - put32(ramrom); - close(fd); + getvars(cpuvars); + getvars(ppuvars); + getvars(memvars); + getvars(apuvars); + getvars(evvars); + getevents(); + mapper(RSTR, 0); + memload(); + Bterm(bp); } |