Files
miraclemage/mmvm/mmvm.cpp
2018-05-21 08:48:53 +01:00

575 lines
17 KiB
C++

#include "../mmage/mmage.h"
#include "../mmage/preference.h"
#include "../resource/resource.h"
#include "wwstruct.h"
#include "mmvm.h"
#include "filesys.h"
#include "kanjifont.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <process.h>
#include <tchar.h>
#ifdef __GNUC__
#if defined(_MBCS)
#define _tmakepath _makepath
#define _tsplitpath _splitpath
#elif defined(_UNICODE)
#define _tmakepath _wmakepath
#define _tsplitpath _wplitpath
#else
#define _tmakepath _makepath
#define _tsplitpath _splitpath
#endif
#endif
/*
IL は CS:ip が特定アドレスになったところでトラップすることで実現する
IlibIL は 0100:0000 に配置。
IlibIL の関数は 0100:0000 から 1byte ずつ順に配置されているように見せる。
_get_info() は 0100:0000
_open() は 0100:0001
_open_system() は 0100:0002
という具合に。
Ilib の ILInfo は 0100:0100 に配置。
Ilib の ILInfo が指す文字列は 0100:(0100 + ILInfo のサイズ) に配置。
なので IL の関数の数は(_get_info() を含めて) 0x0100 個まで。
ProcIL は 0200:0000 から、FsIL は 0300:0000 から同じように配置。
こんなんでええんか?
*/
#define MMVM_ILIBILADDR 0x01000000
#define MMVM_PROCILADDR 0x02000000
#define MMVM_FSILADDR 0x03000000
static MMVM_IL mmvmil_struct;
static MMVM mmvm_struct;
static MMVM_APPINFO appinfo_struct;
LPMMVM mmvm;
BYTE *memory;
static void HandleIlibIL();
static void HandleProcIL();
static LRESULT CALLBACK GetArgument(HWND, UINT, WPARAM, LPARAM);
static void StartThread(LPVOID arg);
BOOL CreateVM() {
LPBYTE rom0;
TCHAR fontfile[MAX_PATH + 1];
char drive[_MAX_DRIVE + 1];
char dir[_MAX_DIR + 1];
mmvm = &mmvm_struct;
mmvm->memory = memory = (BYTE *)malloc(MEMORYSIZE);
if(!memory) {
return FALSE;
}
memset(memory, 0, MEMORYSIZE);
mmvm->il = &mmvmil_struct;
mmvm->appinfo = &appinfo_struct;
mmvm->il->il.farptr = MMVM_ILIBILADDR;
strcpy(mmvm->il->ilinfo.className, "ILibIL");
strcpy(mmvm->il->ilinfo.name, "ILibIL");
strcpy(mmvm->il->ilinfo.version, "1.0");
strcpy(mmvm->il->ilinfo.description, "MMVM default ILibIL");
mmvm->il->ilinfo.depends = NULL;
mmvm->il->proc.farptr = MMVM_PROCILADDR;
strcpy(mmvm->il->procinfo.className, "ProcIL");
strcpy(mmvm->il->procinfo.name, "ProcIL");
strcpy(mmvm->il->procinfo.version, "1.0");
strcpy(mmvm->il->procinfo.description, "MMVM default ProcIL");
mmvm->il->procinfo.depends = NULL;
mmvm->il->fs.farptr = MMVM_FSILADDR;
strcpy(mmvm->il->fsinfo.className, "FsIL");
strcpy(mmvm->il->fsinfo.name, "FsIL");
strcpy(mmvm->il->fsinfo.version, "1.0");
strcpy(mmvm->il->fsinfo.description, "MMVM default FsIL");
mmvm->il->fsinfo.depends = NULL;
mmvm->swork = (LPWW_SRAMWork)&memory[SRAMWORK_SEG << 4];
rom0 = (LPBYTE)&(mmvm->swork->_root_fs_entries[DIRENT_ROM0]);
mmvm->cwfs.segoff.seg = SRAMWORK_SEG;
mmvm->cwfs.segoff.off = rom0 - (LPBYTE)(mmvm->swork);
mmvm->lcdseg = 0;
GetModuleFileName(NULL, fontfile, MAX_PATH);
_tsplitpath(fontfile, drive, dir, NULL, NULL);
_tmakepath(fontfile, drive, dir, ELISA_FONTFILE, NULL);
InitKanjiFont(fontfile);
return TRUE;
}
void InitVM() {
LPWW_IlibIL ilil;
LPWW_ProcIL procil;
LPWW_FsIL fsil;
LPWW_ILInfo ilinfo, procinfo, fsinfo;
unsigned int tmp1;
init_cpu();
sregs[CS] = APP_CSEG;
sregs[DS] = APP_CSEG; // ここでは何に設定しても同じ
sregs[ES] = APP_CSEG; // ここでは何に設定しても同じ
sregs[SS] = STACK_SEG;
ip = 0;
c_cs = SegToMemPtr(CS);
c_ds = SegToMemPtr(DS);
c_es = SegToMemPtr(ES);
c_stack = c_ss = SegToMemPtr(SS);
// set return address
tmp1 = (WORD)(ReadWord(&wregs[SP]) - 2);
PutMemW(c_stack, tmp1, 0x0010);
tmp1 = (WORD)(tmp1 - 2);
PutMemW(c_stack, tmp1, 0x0000);
WriteWord(&wregs[SP], tmp1);
ilil = (LPWW_IlibIL)&memory[FARPTR2ADDR(mmvm->il->il)];
ilil->super.n_methods = 2;
ilil->super.link_pos.farptr = GETFARPTR(mmvm->il->il);
ilil->super._get_info.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->il), 0);
ilil->_open.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->il), 1);
ilil->_open_system.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->il), 2);
ilinfo = (LPWW_ILInfo)&memory[GETSEG(mmvm->il->il) << 4 | 0x0100];
memcpy((LPBYTE)ilinfo + sizeof(WW_ILInfo), &mmvm->il->ilinfo, sizeof(mmvm->il->ilinfo));
ilinfo->className.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->il), 0x0100 + sizeof(WW_ILInfo) );
ilinfo->name.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->il), 0x0100 + sizeof(WW_ILInfo) + 32);
ilinfo->version.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->il), 0x0100 + sizeof(WW_ILInfo) + 64);
ilinfo->description.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->il), 0x0100 + sizeof(WW_ILInfo) + 96);
ilinfo->depends.farptr = SEGOFF2FARPTR(0, 0);
procil = (LPWW_ProcIL)&memory[FARPTR2ADDR(mmvm->il->proc)];
procil->super.n_methods = 8;
procil->super.link_pos.farptr = GETFARPTR(mmvm->il->proc);
procil->super._get_info.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 0);
procil->_load.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 1);
procil->_run.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 2);
procil->_exec.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 3);
procil->_exit.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 4);
procil->_yield.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 5);
procil->_suspend.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 6);
procil->_resume.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 7);
procil->_swap.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 8);
procinfo = (LPWW_ILInfo)&memory[GETSEG(mmvm->il->proc) << 4 | 0x0100];
memcpy((LPBYTE)procinfo + sizeof(WW_ILInfo), &mmvm->il->procinfo, sizeof(mmvm->il->procinfo));
procinfo->className.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 0x0100 + sizeof(WW_ILInfo) );
procinfo->name.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 0x0100 + sizeof(WW_ILInfo) + 32);
procinfo->version.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 0x0100 + sizeof(WW_ILInfo) + 64);
procinfo->description.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->proc), 0x0100 + sizeof(WW_ILInfo) + 96);
procinfo->depends.farptr = SEGOFF2FARPTR(0, 0);
fsil = (LPWW_FsIL)&memory[FARPTR2ADDR(mmvm->il->fs)];
fsil->super.link_pos.farptr = GETFARPTR(mmvm->il->il);
fsil->super.n_methods = 18;
fsil->super._get_info.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 0);
fsil->_entries.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 1);
fsil->_n_entries.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 2);
fsil->_getent.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 3);
fsil->_findent.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 4);
fsil->_mmap.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 5);
fsil->_open.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 6);
fsil->_close.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 7);
fsil->_read.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 8);
fsil->_write.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 9);
fsil->_lseek.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 10);
fsil->_chmod.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 11);
fsil->_freeze.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 12);
fsil->_melt.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 13);
fsil->_creat.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 14);
fsil->_unlink.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 15);
fsil->_newfs.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 16);
fsil->_defrag.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 17);
fsil->_space.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 18);
fsinfo = (LPWW_ILInfo)&memory[GETSEG(mmvm->il->fs) << 4 | 0x0100];
memcpy((LPBYTE)fsinfo + sizeof(WW_ILInfo), &mmvm->il->fsinfo, sizeof(mmvm->il->fsinfo));
fsinfo->className.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 0x0100 + sizeof(WW_ILInfo) );
fsinfo->name.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 0x0100 + sizeof(WW_ILInfo) + 32);
fsinfo->version.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 0x0100 + sizeof(WW_ILInfo) + 64);
fsinfo->description.farptr = SEGOFF2FARPTR(GETSEG(mmvm->il->fs), 0x0100 + sizeof(WW_ILInfo) + 96);
fsinfo->depends.farptr = SEGOFF2FARPTR(0, 0);
mmvm->lcdseg = 0;
mmvm->appinfo->loadended = FALSE;
mmvm->appinfo->maincalled = FALSE;
}
void UpdateVM() {
LPWW_PCB pcb;
unsigned int tmp1;
WORD argptr;
WORD argc;
WORD args[256];
int i;
BOOL quote;
if(sregs[CS] == GETSEG(mmvm->il->il)) {
HandleIlibIL();
return;
}
if(sregs[CS] == GETSEG(mmvm->il->proc)) {
HandleProcIL();
return;
}
if(sregs[CS] == GETSEG(mmvm->il->fs)) {
HandleFsIL(mmvm);
return;
}
if(sregs[CS] == 0x0010 && ip == 0x0000) { // if load routine returned
mmvm->appinfo->loadended = TRUE;
ip = wregs[AX];
sregs[CS] = wregs[DX];
c_cs = SegToMemPtr(CS);
c_ds = SegToMemPtr(DS);
c_es = SegToMemPtr(ES);
c_stack = c_ss = SegToMemPtr(SS);
pcb = (LPWW_PCB)SegToMemPtr(ES);
// init dseg_start
pcb->pid = 1;
pcb->ppid = 0;
pcb->pcbid = 1;
pcb->ppcbid = 0;
pcb->cwfs.farptr = GETFARPTR(mmvm->cwfs);
pcb->ilib.farptr = GETFARPTR(mmvm->il->il);
pcb->proc.farptr = GETFARPTR(mmvm->il->proc);
pcb->resource.farptr = (sregs[CS] << 16) | mmvm->appinfo->fent.resource;
strcpy(pcb->currentdir, "/rom0");
argptr = pcb->argv;
argc = 0;
args[0] = argptr;
quote = FALSE;
for(i = 0; i < (int)strlen(mmvm->appinfo->commandline) + 1; i++) {
if(mmvm->appinfo->commandline[i] == TEXT('\\')) {
if(i < (int)strlen(mmvm->appinfo->commandline)) {
i++;
memory[(FIRST_DSEG << 4) + argptr++] = mmvm->appinfo->commandline[i];
}
} else if(_istspace(mmvm->appinfo->commandline[i]) && !quote) {
argc++;
memory[(FIRST_DSEG << 4) + argptr++] = TEXT('\0');
args[argc] = argptr;
while(isspace(mmvm->appinfo->commandline[i]))
i++;
if(!mmvm->appinfo->commandline[i])
argc--;
i--;
} else if(quote && (mmvm->appinfo->commandline[i] == TEXT('\"') || mmvm->appinfo->commandline[i] == TEXT('\''))) {
quote = FALSE;
} else if(!quote && (mmvm->appinfo->commandline[i] == TEXT('\"') || mmvm->appinfo->commandline[i] == TEXT('\''))) {
quote = TRUE;
} else {
memory[(FIRST_DSEG << 4) + argptr++] = mmvm->appinfo->commandline[i];
}
}
argc++;
// push argv
tmp1 = (WORD)(ReadWord(&wregs[SP]) - 2);
PutMemW(c_stack, tmp1, argptr);
pcb->argv = argptr;
// set argv
for(i = 0; i < argc; i++) {
memory[(FIRST_DSEG << 4) + argptr++] = args[i] & 0xff;
memory[(FIRST_DSEG << 4) + argptr++] = (args[i] >> 8) & 0xff;
}
// push argc
tmp1 = (WORD)(tmp1 - 2);
PutMemW(c_stack, tmp1, argc);
// set _heap address
pcb->heap = argptr;
// push return address
tmp1 = (WORD)(tmp1 - 2);
PutMemW(c_stack, tmp1, 0x0010);
tmp1 = (WORD)(tmp1 - 2);
PutMemW(c_stack, tmp1, 0x0000);
WriteWord(&wregs[SP], tmp1);
memcpy(&memory[FINAL_DSEG << 4], &memory[FIRST_DSEG << 4], 0x10000);
sregs[DS] = FINAL_DSEG; // どうせ run ルーチンで変更されるけど
sregs[ES] = FINAL_DSEG; // どうせ run ルーチンで変更されるけど
c_ds = SegToMemPtr(DS);
c_es = SegToMemPtr(ES);
InitFilesys(mmvm);
}
// main が呼ばれる直前に無理矢理 DS、ES を 0x2000 にする
if(mmvm->appinfo->loadended && !mmvm->appinfo->maincalled && *(c_cs + ip) == 0xe8) {
sregs[DS] = FINAL_DSEG;
sregs[ES] = FINAL_DSEG;
c_ds = SegToMemPtr(DS);
c_es = SegToMemPtr(ES);
mmvm->appinfo->maincalled = TRUE;
}
}
void OpenDlgAndRun() {
OPENFILENAME ofn;
TCHAR filename[MAX_PATH + 1];
TCHAR wndName[1024];
filename[0] = TEXT('\0');
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = wonw32ctx->hWnd;
ofn.lpstrFilter = TEXT("WonderWitch 転送形式ファイル (*.fx)\0*.fx\0すべてのファイル (*.*)\0*.*\0\0");
ofn.lpstrFile = filename;
ofn.nMaxFile = sizeof(filename);
ofn.Flags = OFN_FILEMUSTEXIST;
if(GetOpenFileName(&ofn)) {
if(wonw32ctx->running) {
StopExecution(5000);
}
wonw32ctx->loaded = LoadFXFile(filename, APP_CSEG, &(mmvm->appinfo->fent));
if(!wonw32ctx->loaded) {
SetWindowText(wonw32ctx->hWnd, THIS_APP_TITLE);
MessageBox(wonw32ctx->hWnd, "ファイルの読み込みに失敗しました", NULL, MB_OK);
wonw32ctx->loaded = FALSE;
return;
}
wsprintf(wndName, "%s - %s", (LPCTSTR)mmvm->appinfo->fent.info, THIS_APP_TITLE);
SetWindowText(wonw32ctx->hWnd, wndName);
sprintf(mmvm->appinfo->commandline, "%s ", mmvm->appinfo->fent.name);
if(mmconfig->queryarg) {
DialogBoxParam(wonw32ctx->hInst, MAKEINTRESOURCE(IDD_ARGUMENT), wonw32ctx->hWnd,
(DLGPROC)GetArgument, (LPARAM)mmvm->appinfo->commandline);
} else {
sprintf(mmvm->appinfo->commandline, "%s %s", mmvm->appinfo->fent.name, mmconfig->argument);
}
RunWWApp();
}
return;
}
void OpenAndRun(LPCTSTR filename, LPCTSTR cmdline) {
TCHAR wndName[1024];
if(wonw32ctx->running) {
StopExecution(5000);
}
wonw32ctx->loaded = LoadFXFile(filename, APP_CSEG, &(mmvm->appinfo->fent));
if(!wonw32ctx->loaded) {
SetWindowText(wonw32ctx->hWnd, THIS_APP_TITLE);
MessageBox(wonw32ctx->hWnd, "ファイルの読み込みに失敗しました", NULL, MB_OK);
wonw32ctx->loaded = FALSE;
return;
}
wsprintf(wndName, "%s - %s", (LPCTSTR)mmvm->appinfo->fent.info, THIS_APP_TITLE);
SetWindowText(wonw32ctx->hWnd, wndName);
sprintf(mmvm->appinfo->commandline, "%s %s", mmvm->appinfo->fent.name, cmdline);
RunWWApp();
return;
}
void RunWWApp() {
wonw32ctx->cputhread = (HANDLE)_beginthread(StartThread, 0, NULL);
}
BOOL LoadFXFile(LPCTSTR filename, WORD seg, WW_FENT_T *fentp) {
LPBYTE b;
int c;
FILE *fp;
int i;
b = (LPBYTE)fentp;
fp = fopen(filename, "rb");
if(!fp)
goto error;
for(i = 0; i < 64; i++) {
if((c = fgetc(fp)) == EOF)
goto error;
b[i] = (BYTE)(c & 0xff);
if((i == 0) && (b[i] != 0x23)) goto error;
if((i == 1) && (b[i] != 0x21)) goto error;
if((i == 2) && (b[i] != 0x77)) goto error;
if((i == 3) && (b[i] != 0x73)) goto error;
}
for(i = 0; i < 64; i++) {
if((c = fgetc(fp)) == EOF)
goto error;
b[i] = (BYTE)(c & 0xff);
}
i = seg << 4;
while((c = fgetc(fp)) != EOF)
memory[i++] = (BYTE)(c & 0xff);
return TRUE;
error:
if(fp)
fclose(fp);
return FALSE;
}
static LRESULT CALLBACK GetArgument( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
static LPTSTR arg;
HWND argwnd;
HWND ok;
switch( message )
{
case WM_INITDIALOG:
arg = (LPTSTR)lParam;
argwnd = GetDlgItem(hDlg, IDC_ARGUMENT);
SetWindowText(argwnd, arg);
SendMessage(argwnd, EM_SETSEL, -1, 0);
return TRUE;
case WM_COMMAND:
argwnd = GetDlgItem(hDlg, IDC_ARGUMENT);
GetWindowText(argwnd, arg, 1024);
if( LOWORD(wParam) == IDOK) {
if(lstrlen(arg) > 0)
{
EndDialog(hDlg, 0);
return TRUE;
}
} else if(LOWORD(wParam) == IDC_ARGUMENT && HIWORD(wParam) == EN_UPDATE) {
ok = GetDlgItem(hDlg, IDOK);
if(lstrlen(arg) > 0) {
EnableWindow(ok, TRUE);
} else {
EnableWindow(ok, FALSE);
}
return TRUE;
}
break;
}
return FALSE;
}
void Restart() {
if(wonw32ctx->running) {
StopExecution(5000);
}
RunWWApp();
}
void StopExecution(DWORD wait) {
wonw32ctx->running = FALSE;
PulseEvent(wonw32ctx->syncevent);
TerminateThread(wonw32ctx->cputhread, 0);
if(WaitForSingleObject(wonw32ctx->cputhread, wait) != WAIT_OBJECT_0) {
MessageBox(wonw32ctx->hWnd, TEXT("MiracleMage 内部エラーです\nMiracleMage を再起動してください"), NULL, MB_OK);
}
}
void StartThread(LPVOID arg) {
wonw32ctx->running = TRUE;
InitVM();
InvalidateRect(wonw32ctx->hWnd, NULL, FALSE);
UpdateWindow(wonw32ctx->hWnd);
while(wonw32ctx->running) {
execute();
UpdateVM();
}
CloseFilesys();
mmvm->lcdseg = 0;
InvalidateRect(wonw32ctx->hWnd, NULL, FALSE);
UpdateWindow(wonw32ctx->hWnd);
_endthread();
}
static void HandleIlibIL() {
WW_FARPTR ilname;
WW_FARPTR ilbuf;
switch(ip) {
case 0: // ILInfo far *super._get_info();
wregs[DX] = GETSEG(mmvm->il->il);
wregs[AX] = 0x0100;
break;
case 1: // int _open(char far *ilname, IL far *ilbuf);
case 2: // int _open_system(char far *ilname, IL far *ilbuf);
ilname = *((WW_FARPTR *)GetArgAddr(0));
ilbuf = *((WW_FARPTR *)GetArgAddr(4));
memory[FARPTR2ADDR(ilbuf) ] = 0;
memory[FARPTR2ADDR(ilbuf) + 1] = 0;
memory[FARPTR2ADDR(ilbuf) + 2] = 0;
memory[FARPTR2ADDR(ilbuf) + 3] = 0;
wregs[AX] = 0xffff;
break;
default:
wregs[AX] = 0xffff;
break;
}
ILReturn();
}
static void HandleProcIL() {
switch(ip) {
case 0: // ILInfo far *super._get_info();
wregs[DX] = GETSEG(mmvm->il->proc);
wregs[AX] = 0x0100;
break;
default:
wregs[AX] = 0xffff;
break;
}
ILReturn();
}
void ILReturn() {
unsigned tmp = ReadWord(&wregs[SP]);
ip = GetMemW(c_stack,tmp);
tmp = (WORD)(tmp+2);
sregs[CS] = GetMemW(c_stack,tmp);
c_cs = SegToMemPtr(CS);
tmp += 2;
WriteWord(&wregs[SP],tmp);
}
LPBYTE GetArgAddr(int pos) {
return c_stack + ReadWord(&wregs[SP]) + 4 + pos;
}