Marcus Comstedt's SoftVMS ported to Pokitto.
Fork of HelloWorld by
Diff: cpu.cpp
- Revision:
- 11:88c459b0ac3a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cpu.cpp Sat Mar 31 19:07:59 2018 +0000 @@ -0,0 +1,1299 @@ +#ifdef WIN32 +#include <windows.h> +#include <io.h> +#define HAVE_FCNTL_H +#define HAVE_ERRNO_H +#endif + +#ifdef __DJGPP__ +#include <io.h> +#include <sys/timeb.h> +#define HAVE_FCNTL_H +#define HAVE_ERRNO_H +#define HAVE_SYS_TIME_H +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif +#ifdef TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#else +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#endif +#endif +#ifdef HAVE_DEVICES_TIMER_H +#include <devices/timer.h> +#undef tv_secs +#undef tv_micro +#define tv_sec tv_secs +#define tv_usec tv_micro +#endif + +#include "prototypes.h" + +#define SGNEXT(n) ((n)&0x80? (n)-0x100:(n)) + +#ifndef BIG +#define BIG +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +// BIG extern const unsigned char flash[]; +#include "flash.h" + +BIG unsigned char bios[0]; +unsigned char ram[2][0x100]; +unsigned char sfr[0x100]; +unsigned char xram[3][0x80]; +unsigned char wram[0x200]; +const unsigned char *rom; + +unsigned char parity[0x100]; + +int pc; +int lcd_updated, lcdon, imask, intreq, hasbios=0; +int spd; +int t0h, t0l, t0base, t0scale; +int t1h, t1l; +int gamesize; + +void keypress(int i) +{ + sfr[0x4c]&=~(1<<i); + if(sfr[0x4e]&4) + sfr[0x4e]|=2; +} + +void keyrelease(int i) +{ + sfr[0x4c]|=(1<<i); + if(sfr[0x4e]&4) + sfr[0x4e]|=2; +} + +int tobcd(int n) +{ + return ((n/10)<<4)|(n%10); +} + +/* +int initflash(int fd) +{ + int r=0, t=0; + memset(flash, 0, sizeof(flash)); + while(t<sizeof(flash) && (r=read(fd, flash+t, sizeof(flash)-t))>0) + t += r; + if(r<0 || t<0x480) + return 0; + return t; +} + +void fakeflash(char *filename, int sz) +{ + unsigned char *root, *fat, *dir; + time_t t = time(NULL); + struct tm *tm = localtime(&t); + int i; + char *fn2; + + if((fn2 = strrchr(filename, '/'))!=NULL) + filename = fn2+1; + else if((fn2 = strrchr(filename, '\\'))!=NULL) + filename = fn2+1; + memset(flash+241*512, 0, sizeof(flash)-241*512); + root = flash+255*512; + fat = flash+254*512; + dir = flash+253*512; + sz = ((sz+511)>>9); + for(i=0; i<256*2; i+=2) { + fat[i] = 0xfc; + fat[i+1] = 0xff; + } + for(i=0; i<sz; i++) { + fat[2*i] = i+1; + fat[2*i+1] = 0; + } + if((--i)>=0) { + fat[2*i] = 0xfa; + fat[2*i+1] = 0xff; + } + fat[254*2] = 0xfa; + fat[254*2+1] = 0xff; + fat[255*2] = 0xfa; + fat[255*2+1] = 0xff; + for(i=253; i>241; --i) { + fat[2*i] = i-1; + fat[2*i+1] = 0; + } + fat[241*2] = 0xfa; + fat[241*2+1] = 0xff; + dir[0] = 0xcc; + strncpy(dir+4, filename, 12); + for(i=strlen(filename); i<12; i++) + dir[4+i]=' '; + dir[0x10] = tobcd(tm->tm_year/100+19); + dir[0x11] = tobcd(tm->tm_year%100); + dir[0x12] = tobcd(tm->tm_mon+1); + dir[0x13] = tobcd(tm->tm_mday); + dir[0x14] = tobcd(tm->tm_hour); + dir[0x15] = tobcd(tm->tm_min); + dir[0x16] = tobcd(tm->tm_sec); + dir[0x17] = tobcd(tm->tm_wday); + dir[0x18] = sz&0xff; + dir[0x19] = sz>>8; + dir[0x1a] = 1; + memset(root, 0x55, 16); + root[0x10] = 1; + memcpy(root+0x30, dir+0x10, 8); + root[0x44] = 255; + root[0x46] = 254; + root[0x48] = 1; + root[0x4a] = 253; + root[0x4c] = 13; + root[0x50] = 200; +} + +void check_gamesize() +{ + unsigned char *root, *fat, *dir; + int i, fatblk, dirblk, dircnt; + root = flash+255*512; + fatblk = (root[0x47]<<8)|root[0x46]; + dirblk = (root[0x4b]<<8)|root[0x4a]; + dircnt = (root[0x4d]<<8)|root[0x4c]; + if(fatblk>=256 || dircnt>=256 || !dircnt) + return; + fat = flash+fatblk*512; + while(dircnt-- && dirblk<256) { + dir = flash+dirblk*512; + dirblk = (fat[2*dirblk+1]<<8)|fat[2*dirblk]; + for(i=0; i<16; i++) + if(dir[i*32] == 0xcc) { + int sz = (dir[i*32+0x19]<<8)|dir[i*32+0x18]; + if(sz>1 && sz<=200) { + gamesize = sz*512; + return; + } + } + } +} + +int loadflash(char *filename) +{ + int r, fd; + + if((fd = open(filename, O_RDONLY|O_BINARY))>=0) { + if(!(r=initflash(fd))) { + close(fd); + error_msg("%s: can't load FLASH image", filename); + return 0; + } + close(fd); + gamesize = r; + if(r<241*512) + fakeflash(filename, r); + check_gamesize(); + return 1; + } else { + perror(filename); + return 0; + } +} +*/ + +void halt_mode() +{ + waitforevents(NULL); + checkevents(); +} + +void lcdrefresh() +{ + static unsigned char icon[4][7] = { + { 0x2a, 0x23, 0x47, 0xfb, 0x23, 0x23, 0x3f }, + { 0xff, 0x83, 0x93, 0xbb, 0x93, 0xbb, 0xff }, + { 0x7c, 0x82, 0x92, 0x9b, 0x82, 0x82, 0x7c }, + { 0x10, 0x28, 0xef, 0x6e, 0x6c, 0x7e, 0xc3 } + }; + int y, x, i, a, b=0, p=0; + + p = sfr[0x22]; + if(p>=0x83) + p -= 0x83; + b = (p>>6); + p = (p&0x3f)*2; + for(y=0; y<32; y++) { + for(x=0; x<48; ) { + int value = xram[b][p++]; + if(!lcdon) + value = 0; + vmputpixel(x++, y, value>>7); + vmputpixel(x++, y, value>>6); + vmputpixel(x++, y, value>>5); + vmputpixel(x++, y, value>>4); + vmputpixel(x++, y, value>>3); + vmputpixel(x++, y, value>>2); + vmputpixel(x++, y, value>>1); + vmputpixel(x++, y, value); + if((p&0xf)>=12) + p+=4; + if(p>=128) { + b++; + p-=128; + } + if(b==2 && p>=6) { + b = 0; + p -= 6; + } + } + } + p++; + if((p&0xf)>=12) + p+=4; + if(p>=128) { + b++; + p-=128; + } + if(b==2 && p>=6) { + b = 0; + p -= 6; + } + for(i=0; i<4; i++) { + a = xram[b][p++]>>(2*(3-i)); + if(!lcdon) + a = 0; + for(y=0; y<7; y++) { + int value = icon[i][y]; + for(x=0; x<7; x++) + vmputpixel(2+i*12+x, y+33, (value>>(7-x))&a); + } + if((p&0xf)>=12) + p+=4; + if(p>=128) { + b++; + p-=128; + } + if(b==2 && p>=6) { + b = 0; + p -= 6; + } + } + redrawlcd(); + lcd_updated = 0; +} + +void writemem(int addr, int value) +{ + value &= 0xff; + if(addr<0x100) { + ram[(sfr[0x01]&2)>>1][addr] = value; + return; + } + if(addr>=0x180) { + int b = sfr[0x25]; + if(b>2 || (b==2 && addr>=0x186)) + return; + xram[b][addr-0x180]=value; + if(lcdon) + lcd_updated = 1; + } else switch(addr) { + case 0x100: + sfr[0x01] = (sfr[0x01]&0xfe)|parity[value]; + break; + case 0x10d: + if((value&1) != (sfr[0x0d]&1)) { + if(pc>0xfffd || rom[pc]!=0x21) + error_msg("EXT 0 changed without following JMPF. pc = %04x", + pc&0xffff); + else + pc = (rom[pc+1]<<8)|rom[pc+2]; + // if(hasbios) + // rom = ((value&1)? flash : bios); + } + break; + case 0x10e: + switch(value&0xa0) { + case 0x00: spd = 3000; break; + case 0x20: spd = 164; break; + case 0x80: spd = 6000; break; + case 0xa0: spd = 328; break; + } + break; + case 0x110: + if(!(value&0x40)) + t0l = sfr[0x13]; + if(!(value&0x80)) + t0h = sfr[0x15]; + break; + case 0x111: + t0scale = 256-value; + t0base = 0; + break; + case 0x113: + if(!(sfr[0x10]&0x40)) + t0l = value; + break; + case 0x115: + if(!(sfr[0x10]&0x80)) + t0h = value; + break; + case 0x118: + if(!(value&0x40)) + t1l = sfr[0x1b]; + if(!(value&0x80)) + t1h = sfr[0x1d]; + break; + case 0x11b: + if(!(sfr[0x18]&0x40)) + t1l = value; + break; + case 0x11d: + if(!(sfr[0x18]&0x80)) + t1h = value; + break; + case 0x122: + if(lcdon) + lcd_updated = 1; + break; + case 0x127: + if((!!(value&0x80)) != lcdon) { + lcdon = !!(value&0x80); + lcdrefresh(); + } + break; + case 0x166: + wram[0x1ff&((sfr[0x65]<<8)|sfr[0x64])] = value; + if(sfr[0x63]&0x10) + if(!++sfr[0x64]) + sfr[0x65]^=1; + return; + } + /* + if(addr>0x10e && addr<0x120 && addr != 0x118) + fprintf(stderr, "%04x: Write to %03x: %02x\n", pc, addr, value); + */ + sfr[addr&0xff] = value; + if(addr == 0x118 || addr == 0x11b) { + /* Check for sound... */ + if(sfr[0x18]&0x40) + sound(32768/((256-sfr[0x1b])*6)); + else + sound(-1); + } +} + +int readmem(int addr) +{ + int r; + if(addr<0x100) + return ram[(sfr[0x01]&2)>>1][addr]; + if(addr>=0x180) { + int b = sfr[0x25]; + if(b>2) + return 0xff; + return xram[b][addr-0x180]; + } else switch(addr) { + case 0x112: + return t0l; + case 0x114: + return t0h; + case 0x11b: + return t1l; + case 0x11d: + return t1h; + case 0x15c: + return 2; + case 0x165: + return 0xfe|(sfr[0x65]&1); + case 0x166: + r = wram[0x1ff&((sfr[0x65]<<8)|sfr[0x64])]; + if(sfr[0x63]&0x10) + if(!++sfr[0x64]) + sfr[0x65]^=1; + return r; + } + /* + if(addr>0x106 && addr<0x180) + fprintf(stderr, "%04x: Read from %03x: %02x\n", pc, addr, sfr[addr&0xff]); + */ + return sfr[addr&0xff]; +} + +int readlatch(int addr) +{ + switch(addr) { + case 0x11b: + case 0x11d: + return 0xff; + default: + return readmem(addr); + } +} + +void push(int n) +{ + writemem(0x106, readmem(0x106)+1); + ram[0][readmem(0x106)]=n; +} + +int pop() +{ + int r = ram[0][readmem(0x106)]; + writemem(0x106, readmem(0x106)-1); + return r; +} + +void resetcpu() +{ + int i; + time_t t = time(NULL); + struct tm *tm = localtime(&t); + memset(ram, 0, sizeof(ram)); + memset(xram, 0, sizeof(xram)); + memset(wram, 0, sizeof(wram)); + memset(sfr, 0, sizeof(sfr)); + parity[0] = 0; + parity[1] = 1; + parity[2] = 1; + parity[3] = 0; + for(i=4; i<16; i++) + parity[i] = parity[i&3]^parity[i>>2]; + for(i=16; i<255; i++) + parity[i] = parity[i&15]^parity[i>>4]; + sfr[0x06] = 0x7f; + sfr[0x4c] = 0xff; + sfr[0x01] = 0x02; + t0h = t0l = 0; + t1h = t1l = 0; + t0base = 0; + t0scale = 256; + ram[0][0x10] = tobcd(tm->tm_year/100+19); + ram[0][0x11] = tobcd(tm->tm_year%100); + ram[0][0x12] = tobcd(tm->tm_mon+1); + ram[0][0x13] = tobcd(tm->tm_mday); + ram[0][0x14] = tobcd(tm->tm_hour); + ram[0][0x15] = tobcd(tm->tm_min); + ram[0][0x17] = (tm->tm_year+1900)>>8; + ram[0][0x18] = (tm->tm_year+1900)&0xff; + ram[0][0x19] = tm->tm_mon+1; + ram[0][0x1a] = tm->tm_mday; + ram[0][0x1b] = tm->tm_hour; + ram[0][0x1c] = tm->tm_min; + ram[0][0x1d] = tm->tm_sec; + ram[0][0x31] = 0xff; + sfr[0x08] = 0x80; + writemem(0x10e, 0x81); + lcd_updated = 0; + lcdon = 0; + imask = 0; + intreq = 0; + if(hasbios) { + sfr[0x0d] = 0; + rom = bios; + pc = 0x1f0; + } else { + sfr[0x0d] = 1; + rom = flash; + pc = 0; + writemem(0x125, 2); + writemem(0x182, 0x10); + writemem(0x125, 0); + writemem(0x127, 0x80); + } + sound(-1); +} + +int month_days() +{ + int m = ram[0][0x19]; + if(m==2) { + int y = ram[0][0x18] | (ram[0][0x17] << 8); + if(y&3) + return 28; + if(!(y%4000)) + return 29; + if(!(y%1000)) + return 28; + if(!(y%400)) + return 29; + if(!(y%100)) + return 28; + return 29; + } else return (m>7? ((m&1)? 30:31) : ((m&1)? 31:30)); +} + +int handle_fwcall(int pc) +{ + switch(pc) { + case 0x100: + { +// int i, a = ((ram[1][0x7d]<<16)|(ram[1][0x7e]<<8)|ram[1][0x7f])&0x1ffff; +// if(a>=gamesize) +// writemem(0x100, 0xff); +// else { +// writemem(0x100, 0x00); + //for(i=0; i<0x80; i++) + // flash[(a&~0xff)|((a+i)&0xff)] = ram[1][i+0x80]; +//#ifdef __DC__ + //if(!flash_written(a)) + writemem(0x100, 0xff); +//#endif +// } + /* + fprintf(stderr, "ROM write @ %05x:\n", a); + for(i=0; i<0x80; i++) + fprintf(stderr, " %02x", ram[1][i+0x80]); + fprintf(stderr, "\n"); + */ + } + return 0x105; + case 0x110: + { + int i, a = ((ram[1][0x7d]<<16)|(ram[1][0x7e]<<8)|ram[1][0x7f])&0x1ffff; + int r = 0; + for(i=0; i<0x80; i++) + if((r = (flash[(a&~0xff)|((a+i)&0xff)] ^ ram[1][i+0x80])) != 0) + break; + writemem(0x100, r); + } + return 0x115; + case 0x120: + { + int i, a = ((ram[1][0x7d]<<16)|(ram[1][0x7e]<<8)|ram[1][0x7f])&0x1ffff; + for(i=0; i<0x80; i++) + ram[1][i+0x80] = flash[(a&~0xff)|((a+i)&0xff)]; + /* + fprintf(stderr, "ROM read @ %05x\n", a); + */ + } + return 0x125; + case 0x130: + if(!((ram[0][0x1e]^=1)&1)) + if(++ram[0][0x1d]>=60) { + ram[0][0x1d] = 0; + if(++ram[0][0x1c]>=60) { + ram[0][0x1c] = 0; + if(++ram[0][0x1b]>=24) { + ram[0][0x1b] = 0; + if(++ram[0][0x1a]>month_days()) { + ram[0][0x1a] = 1; + if(++ram[0][0x19]>=13) { + ram[0][0x19] = 1; + if(ram[0][0x18]==0xff) { + ram[0][0x18]=0; + ram[0][0x17]++; + } else + ram[0][0x18]++; + } + } + } + } + } + return 0x139; + case 0x1f0: + return 0; + default: + error_msg("Firmware entered at unknown vector %04x!", pc); + return 0; + } +} + +void run_cpu( void ) +{ + struct timeval epoch; + int mcy = 0, tick = 0; + + GETTIMEOFDAY(&epoch); + for(;;) { + int r, s, c, cy = 1, i = rom[pc]; +#ifdef TRACE + printf("%04x\n", pc); +#endif + pc++; + pc &= 0xffff; + switch(i&0xf) { + case 0: + switch(i>>4) { + case 0: + break; + case 1: + cy = 4; + push((pc+2)&0xff); + push(((pc+2)&0xff00)>>8); + pc = 0xffff&(pc+1+rom[pc]+((rom[(pc+1)&0xffff])<<8)); + break; + case 2: + cy = 2; + push((pc+2)&0xff); + push(((pc+2)&0xff00)>>8); + pc = (rom[pc]<<8)|rom[(pc+1)&0xffff]; + break; + case 3: + cy = 7; + r = readmem(0x102)*((readmem(0x100)<<8)|readmem(0x103)); + writemem(0x101, (readmem(0x101)&0x7b)|(r>65535? 4:0)); + writemem(0x103, r&0xff); + writemem(0x100, (r&0xff00)>>8); + writemem(0x102, (r&0xff0000)>>16); + break; + case 4: + cy = 7; + r = readmem(0x102); + if(r) { + int v = (readmem(0x100)<<8)|readmem(0x103); + s = v%r; + r = v/r; + } else { + r = 0xff00|readmem(0x103); + s = 0; + } + writemem(0x101, (readmem(0x101)&0x7b)|(s? 0:4)); + writemem(0x103, r&0xff); + writemem(0x100, (r&0xff00)>>8); + writemem(0x102, s); + break; + case 5: + cy = 2; /* ? */ + writemem(0x100, flash[0x1ffff&(readmem(0x104)+(readmem(0x105)<<8)+ + (readmem(0x154)<<16))]); + break; + case 6: + cy = 2; + push(readmem(rom[pc++])); + pc &= 0xffff; + break; + case 7: + cy = 2; + writemem(rom[pc++], pop()); + pc &= 0xffff; + break; + case 8: + cy = 2; + if(readmem(0x100)==0) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 9: + cy = 2; + if(readmem(0x100)!=0) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 0xa: + cy = 2; + r = pop()<<8; + r |= pop(); + pc = r; + break; + case 0xb: + cy = 2; + r = pop()<<8; + r |= pop(); + pc = r; + --imask; + break; + case 0xc: + r = readmem(0x100); + writemem(0x100, (r>>1)|((r&1)<<7)); + break; + case 0xd: + r = readmem(0x100); + s = readmem(0x101); + writemem(0x101, (s&0x7f)|((r&1)<<7)); + writemem(0x100, (r>>1)|(s&0x80)); + break; + case 0xe: + r = readmem(0x100); + writemem(0x100, (r<<1)|((r&0x80)>>7)); + break; + case 0xf: + r = readmem(0x100); + s = readmem(0x101); + writemem(0x101, (s&0x7f)|(r&0x80)); + writemem(0x100, (r<<1)|((s&0x80)>>7)); + break; + } + break; + case 1: + switch(i>>4) { + case 0: + cy = 2; + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + break; + case 1: + cy = 4; + pc = 0xffff&(pc+1+rom[pc]+((rom[(pc+1)&0xffff])<<8)); + break; + case 2: + cy = 2; + pc = (rom[pc]<<8)|rom[(pc+1)&0xffff]; + break; + case 3: + cy = 2; + r = readmem(0x100); + writemem(0x101, (readmem(0x101)&0x7f)|(r<rom[pc]? 0x80:0)); + s = (r == rom[pc++]); + pc &= 0xffff; + if(s) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 4: + cy = 2; + r = readmem(0x100); + writemem(0x101, (readmem(0x101)&0x7f)|(r<rom[pc]? 0x80:0)); + s = (r != rom[pc++]); + pc &= 0xffff; + if(s) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 5: + cy = 2; /* ? * / + if(!(readmem(0x154)&2)) + flash[0x1ffff&(readmem(0x104)+(readmem(0x105)<<8)+ + (readmem(0x154)<<16))] = readmem(0x100); + /* */ + break; + case 6: + cy = 2; + push(readmem(0x100|rom[pc++])); + pc &= 0xffff; + break; + case 7: + cy = 2; + writemem(0x100|rom[pc++], pop()); + pc &= 0xffff; + break; + case 8: + r = readmem(0x100); + s = rom[pc++]; + pc &= 0xffff; + writemem(0x100, r+s); + writemem(0x101, (readmem(0x101)&0x3b)|(r+s>255? 0x80:0)| + ((r&15)+(s&15)>15? 0x40:0)|((0x80&(~r^s)&(s^(r+s)))? 4:0)); + break; + case 9: + r = readmem(0x100); + s = rom[pc++]; + pc &= 0xffff; + c = (readmem(0x101)&0x80)>>7; + writemem(0x100, r+s+c); + writemem(0x101, (readmem(0x101)&0x3b)|(r+s+c>255? 0x80:0)| + ((r&15)+(s&15)+c>15? 0x40:0)| + ((0x80&(~r^s)&(s^(r+s+c)))? 4:0)); + break; + case 0xa: + /* FIXME: OV */ + r = readmem(0x100); + s = rom[pc++]; + pc &= 0xffff; + writemem(0x100, r-s); + writemem(0x101, (readmem(0x101)&0x3b)|(r-s<0? 0x80:0)| + ((r&15)-(s&15)<0? 0x40:0)|(0? 4:0)); + break; + case 0xb: + /* FIXME: OV */ + r = readmem(0x100); + s = rom[pc++]; + pc &= 0xffff; + c = (readmem(0x101)&0x80)>>7; + writemem(0x100, r-s-c); + writemem(0x101, (readmem(0x101)&0x3b)|(r-s-c<0? 0x80:0)| + ((r&15)-(s&15)-c<0? 0x40:0)|(0? 4:0)); + break; + case 0xc: + cy = 2; + writemem(0x100, rom[0xffff&(readmem(0x100)+readmem(0x104)+ + (readmem(0x105)<<8))]); + break; + case 0xd: + writemem(0x100, readmem(0x100)|rom[pc++]); + pc &= 0xffff; + break; + case 0xe: + writemem(0x100, readmem(0x100)&rom[pc++]); + pc &= 0xffff; + break; + case 0xf: + writemem(0x100, readmem(0x100)^rom[pc++]); + pc &= 0xffff; + break; + } + break; + case 2: + case 3: + r = ((i&1)<<8)|rom[pc++]; + pc &= 0xffff; + switch(i>>4) { + case 0: + writemem(0x100, readmem(r)); + break; + case 1: + writemem(r, readmem(0x100)); + break; + case 2: + cy = 2; + writemem(r, rom[pc++]); + pc &= 0xffff; + break; + case 3: + cy = 2; + s = readmem(r); + r = readmem(0x100); + writemem(0x101, (readmem(0x101)&0x7f)|(r<s? 0x80:0)); + if(r == s) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 4: + cy = 2; + s = readmem(r); + r = readmem(0x100); + writemem(0x101, (readmem(0x101)&0x7f)|(r<s? 0x80:0)); + if(r != s) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 5: + cy = 2; + s = (readlatch(r)-1)&0xff; + writemem(r, s); + if(s != 0) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 6: + writemem(r, readlatch(r)+1); + break; + case 7: + writemem(r, readlatch(r)-1); + break; + case 8: + s = readmem(r); + r = readmem(0x100); + writemem(0x100, r+s); + writemem(0x101, (readmem(0x101)&0x3b)|(r+s>255? 0x80:0)| + ((r&15)+(s&15)>15? 0x40:0)|((0x80&(~r^s)&(s^(r+s)))? 4:0)); + break; + case 9: + s = readmem(r); + r = readmem(0x100); + c = (readmem(0x101)&0x80)>>7; + writemem(0x100, r+s+c); + writemem(0x101, (readmem(0x101)&0x3b)|(r+s+c>255? 0x80:0)| + ((r&15)+(s&15)+c>15? 0x40:0)| + ((0x80&(~r^s)&(s^(r+s+c)))? 4:0)); + break; + case 0xa: + /* FIXME: OV */ + s = readmem(r); + r = readmem(0x100); + writemem(0x100, r-s); + writemem(0x101, (readmem(0x101)&0x3b)|(r-s<0? 0x80:0)| + ((r&15)-(s&15)<0? 0x40:0)|(0? 4:0)); + break; + case 0xb: + /* FIXME: OV */ + s = readmem(r); + r = readmem(0x100); + c = (readmem(0x101)&0x80)>>7; + writemem(0x100, r-s-c); + writemem(0x101, (readmem(0x101)&0x3b)|(r-s-c<0? 0x80:0)| + ((r&15)-(s&15)-c<0? 0x40:0)|(0? 4:0)); + break; + case 0xc: + s = readmem(r); + writemem(r, readmem(0x100)); + writemem(0x100, s); + break; + case 0xd: + writemem(0x100, readmem(0x100)|readmem(r)); + break; + case 0xe: + writemem(0x100, readmem(0x100)&readmem(r)); + break; + case 0xf: + writemem(0x100, readmem(0x100)^readmem(r)); + break; + } + break; + case 4: + case 5: + case 6: + case 7: + r = readmem((i&3)|((readmem(0x101)>>1)&0xc))|((i&2)? 0x100 : 0); + switch(i>>4) { + case 0: + writemem(0x100, readmem(r)); + break; + case 1: + writemem(r, readmem(0x100)); + break; + case 2: + writemem(r, rom[pc++]); + pc &= 0xffff; + break; + case 3: + cy = 2; + s = readmem(r); + r = rom[pc++]; + pc &= 0xffff; + writemem(0x101, (readmem(0x101)&0x7f)|(s<r? 0x80:0)); + if(r == s) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 4: + cy = 2; + s = readmem(r); + r = rom[pc++]; + pc &= 0xffff; + writemem(0x101, (readmem(0x101)&0x7f)|(s<r? 0x80:0)); + if(r != s) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 5: + cy = 2; + s = (readlatch(r)-1)&0xff; + writemem(r, s); + if(s != 0) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 6: + writemem(r, readlatch(r)+1); + break; + case 7: + writemem(r, readlatch(r)-1); + break; + case 8: + s = readmem(r); + r = readmem(0x100); + writemem(0x100, r+s); + writemem(0x101, (readmem(0x101)&0x3b)|(r+s>255? 0x80:0)| + ((r&15)+(s&15)>15? 0x40:0)|((0x80&(~r^s)&(s^(r+s)))? 4:0)); + break; + case 9: + s = readmem(r); + r = readmem(0x100); + c = (readmem(0x101)&0x80)>>7; + writemem(0x100, r+s+c); + writemem(0x101, (readmem(0x101)&0x3b)|(r+s+c>255? 0x80:0)| + ((r&15)+(s&15)+c>15? 0x40:0)| + ((0x80&(~r^s)&(s^(r+s+c)))? 4:0)); + break; + case 0xa: + /* FIXME: OV */ + s = readmem(r); + r = readmem(0x100); + writemem(0x100, r-s); + writemem(0x101, (readmem(0x101)&0x3b)|(r-s<0? 0x80:0)| + ((r&15)-(s&15)<0? 0x40:0)|(0? 4:0)); + break; + case 0xb: + /* FIXME: OV */ + s = readmem(r); + r = readmem(0x100); + c = (readmem(0x101)&0x80)>>7; + writemem(0x100, r-s-c); + writemem(0x101, (readmem(0x101)&0x3b)|(r-s-c<0? 0x80:0)| + ((r&15)-(s&15)-c<0? 0x40:0)|(0? 4:0)); + break; + case 0xc: + s = readmem(r); + writemem(r, readmem(0x100)); + writemem(0x100, s); + break; + case 0xd: + writemem(0x100, readmem(0x100)|readmem(r)); + break; + case 0xe: + writemem(0x100, readmem(0x100)&readmem(r)); + break; + case 0xf: + writemem(0x100, readmem(0x100)^readmem(r)); + break; + } + break; + default: + switch(i&0xe0) { + case 0x00: + cy = 2; + r = ((i&7)<<8)|((i&0x10)<<7)|rom[pc++]; + push(pc&0xff); + push((pc&0xff00)>>8); + pc = (pc&0xf000)|r; + break; + case 0x20: + cy = 2; + r = ((i&7)<<8)|((i&0x10)<<7)|rom[pc++]; + pc = (pc&0xf000)|r; + break; + case 0x40: + cy = 2; + r = ((i&0x10)<<4)|rom[pc++]; + pc &= 0xffff; + if((s=readmem(r))&(1<<(i&7))) { + writemem(r, s & ~(1<<(i&7))); + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + } else { + pc++; + pc &= 0xffff; + } + break; + case 0x60: + cy = 2; + r = ((i&0x10)<<4)|rom[pc++]; + pc &= 0xffff; + if(readmem(r)&(1<<(i&7))) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 0x80: + cy = 2; + r = ((i&0x10)<<4)|rom[pc++]; + pc &= 0xffff; + if(!(readmem(r)&(1<<(i&7)))) + pc = 0xffff&(pc+1+SGNEXT(rom[pc])); + else { + pc++; + pc &= 0xffff; + } + break; + case 0xa0: + r = ((i&0x10)<<4)|rom[pc++]; + pc &= 0xffff; + writemem(r, readlatch(r) ^ (1<<(i&7))); + break; + case 0xc0: + r = ((i&0x10)<<4)|rom[pc++]; + pc &= 0xffff; + writemem(r, readlatch(r) & ~(1<<(i&7))); + break; + case 0xe0: + r = ((i&0x10)<<4)|rom[pc++]; + pc &= 0xffff; + writemem(r, readlatch(r) | (1<<(i&7))); + break; + } + break; + } + mcy += cy; + if(mcy>=spd) { + struct timeval now, t; + if(lcd_updated) + lcdrefresh(); + GETTIMEOFDAY(&now); + if((epoch.tv_usec += 10000)>=1000000) { + epoch.tv_usec -= 1000000; + epoch.tv_sec++; + } + if(now.tv_sec>epoch.tv_sec || + (now.tv_sec == epoch.tv_sec && now.tv_usec >= epoch.tv_usec)) { + t.tv_usec = 0; + t.tv_sec = 0; + } else if(epoch.tv_usec<now.tv_usec) { + t.tv_usec = 1000000 + epoch.tv_usec - now.tv_usec; + t.tv_sec = epoch.tv_sec - now.tv_sec - 1; + } else { + t.tv_usec = epoch.tv_usec - now.tv_usec; + t.tv_sec = epoch.tv_sec - now.tv_sec; + } + waitforevents(&t); + checkevents(); + mcy -= spd; + ++tick; + if(tick>=50) { + intreq |= 1<<3; + tick -= 50; + } + } + /* Timer 0 */ + if(sfr[0x10] & 0xc0) { + int c0=0; + if((t0base+=cy) >= t0scale) + do + c0++; + while((t0base-=t0scale) >= t0scale); + if(c0) + if((sfr[0x10] & 0xe0) == 0xe0) { + t0l += c0; + if(t0l>=256) { + t0l -= 256; + if(++t0h >= 256) { + t0h -= 256; + if((t0l += sfr[0x13])>=256) { + t0l -= 256; + if((t0h += sfr[0x15])>=256) { + t0l = sfr[0x13]; + t0h = sfr[0x15]; + } + } + sfr[0x10] |= 10; + if(sfr[0x10]&4) + intreq |= 1<<4; + } + } + } else { + if(sfr[0x10] & 0x40) { + t0l += c0; + if(t0l>=256) { + t0l -= 256; + if((t0l += sfr[0x13])>=256) + t0l = sfr[0x13]; + sfr[0x10] |= 2; + if(sfr[0x10]&1) + intreq |= 1<<2; + } + } + if(sfr[0x10] & 0x80) { + t0h += c0; + if(t0h>=256) { + t0h -= 256; + if((t0h += sfr[0x15])>=256) + t0h = sfr[0x15]; + sfr[0x10] |= 8; + if(sfr[0x10]&4) + intreq |= 1<<4; + } + } + } + } + /* Timer 1 */ + if(sfr[0x18] & 0xc0) { + if((sfr[0x18] & 0xe0) == 0xe0) { + t1l += cy; + if(t1l>=256) { + t1l -= 256; + if(++t1h >= 256) { + t1h -= 256; + if((t1l += sfr[0x1b])>=256) { + t1l -= 256; + if((t1h += sfr[0x1d])>=256) { + t1l = sfr[0x1b]; + t1h = sfr[0x1d]; + } + } + sfr[0x18] |= 10; + if(sfr[0x18]&4) + intreq |= 1<<5; + } + } + } else { + if(sfr[0x18] & 0x40) { + t1l += cy; + if(t1l>=256) { + t1l -= 256; + if((t1l += sfr[0x1b])>=256) + t1l = sfr[0x1b]; + sfr[0x18] |= 2; + if(sfr[0x18]&1) + intreq |= 1<<5; + } + } + if(sfr[0x18] & 0x80) { + t1h += cy; + if(t1h>=256) { + t1h -= 256; + if((t1h += sfr[0x1d])>=256) + t1h = sfr[0x1d]; + sfr[0x18] |= 8; + if(sfr[0x18]&4) + intreq |= 1<<5; + } + } + } + } + if(!(sfr[0x0d]&1) && !hasbios) + if(!(pc=handle_fwcall(pc))) + break; + else + sfr[0x0d]|=1; + + if((sfr[0x4e]&3)==3 && !imask) + intreq |= 1<<9; + + if(!intreq || imask || !(sfr[0x08]&0x80)) + continue; + for(r=0; r<10; r++) + if(intreq & (1<<r)) + break; + intreq &= ~(1<<r); + push(pc&0xff); + push((pc&0xff00)>>8); + imask++; + pc = ((r&~1)<<3)+((r&1)?0xb:0x3); + } +} + +/* +int do_vmsgame(char *filename, char *biosname) +{ + if(filename == NULL && biosname == NULL) + return 0; + if(biosname != NULL) + if(!loadbios(biosname)) + return 0; + if(filename != NULL) + if(!loadflash(filename)) + return 0; + resetcpu(); + run_cpu(); + return 1; +} +*/