Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
osecpu-driver-linux-fbdev-x86-32bit.c
Version 2014-03-31
osecpu-driver-linux-fbdev-x86-32bit.c は、osecpu の linux ドライバーです。
これは X11 を用いずに(GUI環境を用いずに)、起動直後のターミナル環境(昔のDOSのような環境)のみで osecpu を動作させるためのドライバーとなります。
(このドライバーを、実際に osecpu078d/osecpu.c へ組み込んだ、サンプルコードは osecpu078d-linux-fbdev.c です。
また、Ubuntu13.10 など GCC4.8.x でビルドした場合に動作しなかったバグの修正も行ってあります。
なお、現状のOsecpuが対応してるCPUは x86-32bit のみです。64bit環境では動作しないはずです。
(32bit/64bit のマルチライブラリー環境の場合ならば GCC へのビルドオプションとして -m32 を追加することで
動作するかもしれませんし、しないかもしれません。
(私はそのようなマルチライブラリー環境が手元に無いので試せていません)
・グラフィック描画は、linuxカーネルのフレームバッファー(/dev/fb0)へ直接描画することで行っています。
(現状は、32bitカラー(リトルエンディアン) のグラフィックボードのみに対応してます。
Intel G31 オンボードグラフィックでテストしてます。これは i915, i965 系のグラフィックボードです。
最近の nvidia や ati のグラフィックボードも 32bit カラーに対応してるはずですが、エンディアンがリトルかはわかりません。
古いグラフィックボードだと 24bit や 16bit カラー等かもしれません。この場合はには正常動作しません。
・キーボード情報の取得は、linuxカーネルのインプットデバイス(/dev/input)から生のキーボードのスイッチ状態を取得し、
そのスイッチの値を、libxkbcommon によって X11 と同様の値(日本語キーボードへ対応した値)へと変換し、
それを osecpu のキーコードへ変換して osecpu へ渡しています。
http://xkbcommon.org/
また、キーボードデバイスの検索は、/dev/input/by-id/ に依存しています。
この by-id 以下の内容は、linux のシステムブート時に udev によって生成されます。
そのため udev が動作してる必要があります。(最近のディストリビューションならば udev はデフォルトでほぼ必ず動作してるはずです)
・スリープは、CPUクロックに基づいたnanosleep を使用しているので、linux 2.6.28 未満のカーネルでは動作しません。
osecpu ソースへの具体的な追加方法:
osecpu-driver-linux-fbdev-x86-32bit.c を、osecpu.c の最後にコピペして、
マクロが有効な場合に、ここへ分岐するように osecpu.c のドライバー選択マクロに項目を追加することで行えます。
(他のドライバーの場合と同様)
例として osecpu078d/osecpu.c へ追加した場合の例を、完全に動作するコード osecpu078d-linux-fbdev.c として以下に添付してあります。
また、その場合の Makefile も添付してあります。
Makefile の使い方は forMac/Makefile と同様です:
(オリジナルの osecpu078d のソースファイル群の中に、これらを修正ソースを追加して置いた場合を前提とした説明です)
make osecpu-fbdev で /dev/fb0 用の osecpu をビルドできます。(osecpu-fbdev)
make osecpu-blike で blike 用の osecpu をビルドできます。(osecpu-blike)
(ただし、これには c_blike_01f_linux の今日の最新版が別途必要です)
make で osectols をビルドできます。
make app0019.ose で app0019.ask から app0019.ose をビルドできます。
そして、
ターミナル画面の状態で sudo ./osecpu-fbdev app0019.ose とすることで実行できるはずです。(fbdevによる描画)
また、X11 環境ならば ./osecpu-blike app0019.ose でも実行できるはずです。(blikeによる描画)
現状の未完成部分:
現状は大雑把に動いてるだけなので、オリジナルの動作仕様を正確には真似しきれてません。
(Ctlr, Alt 等の特殊キーのフラグ立て挙動などは、まだウインドウズ版ドライバーの完全な模倣にはなってないかもしれません)
(いくつかのバグ修正は日々行ってます。修正内容の具体的な詳細は git のログに全て残してあります)
セキュリティー的な懸念:
このドライバーを組み込んだ Osecpu バイナリーは、実行時にルート権限が必要となります。
そして実行時にはキーボードデバイスおよびフレームバッファーへのフルアクセスを行える状態となります。
これは linux 側のセキュリティー的には問題となる可能性があります。
そのため、必須ではありませんが、TOMOYO 等の強制アクセス制御による対策を行ってからの使用を強くお薦めします。
#DEFS = -DDEBUG_BLD_FB -DDEBUG_BLD_KBDLIST
DEFS =
#CFLAGS = -O4 -march=native -mtune=native -msse3
CFLAGS = -O0 -g
%.ose : %.ask
gcc -E -o a_0ask.txt -x c $<
./osectols tool:aska in:a_0ask.txt out:a_1oas_$*.txt
gcc -E -P -o a_2cas.txt -x c a_1oas_$*.txt
./osectols tool:lbstk in:a_2cas.txt out:a_3cas.txt lst:a_3lbl.txt
./osectols tool:db2bin in:a_3cas.txt out:a_4ose.ose
./osectols tool:appack in:a_4ose.ose out:$@
osectols: osectols.c
gcc $(CFLAGS) $< -o $@ -Wl,-s
osecpu-fbdev: osecpu078d-linux-fbdev.c
gcc -D__LINUX_FBDEV__ $(DEFS) $(CFLAGS) $< -lxkbcommon -lrt -pthread -o osecpu-fbdev
osecpu-blike: osecpu078d-linux-fbdev.c
gcc -D__LINUX_BLIKE__ $(DEFS) $(CFLAGS) $< `pkg-config blike --libs --cflags` -o osecpu-blike
clean:
rm -f osecpu-fbdev
rm -f osecpu-blike
#if (DRV_OSNUM == 0x0004)
/* osecpu driver: linux-fbdev-x86-32bit
* Copyright(C) 2014 Takeutch Kemeco
* license: KL-01
*/
/* Build Command:
* gcc -D__LINUX_FBDEV__ osecpu.c -lxkbcommon -lrt -pthread -o osecpu
* or
* gcc -D__LINUX_FBDEV__ osecpu.c `pkg-config xkbcommon --libs --cflags` -lrt -pthread -o osecpu
*/
#include <stdio.h> /* printf() */
#include <stdlib.h> /* size_t, posix_memalign(), malloc(), calloc(), free() */
#include <string.h> /* strlen(), strcmp(), strcpy(), strcat() */
#include <stddef.h> /* ptrdiff_t */
#include <stdint.h> /* uint32_t */
#include <stdbool.h> /* bool, true, false */
#include <error.h> /* error() */
#include <errno.h> /* errno */
#include <sys/types.h> /* open(), uid_t, fstat(), caddr_t */
#include <sys/stat.h> /* open(), fstat(), struct stat */
#include <sys/ioctl.h> /* ioctl() */
#include <sys/user.h> /* PAGE_MASK */
/* mprotect(), mmap(), munmap(),
* PROT_READ, PROT_WRITE, PROT_EXEC, MAP_SHARED, MAP_FAILED
*/
#include <sys/mman.h>
#include <fcntl.h> /* open() */
#include <dirent.h> /* scandir(), struct dirent */
/* (required: Linux >= 2.6.28)
* (depend libs: -lrt)
* clock_gettime(), clock_nanosleep(), struct timespec, time_t
*/
#include <time.h>
/* struct input_event, EV_KEY, KEY_LEFTSHIFT */
#include <linux/input.h>
/* struct fb_var_screeninfo, struct fb_fix_screeninfo */
#include <linux/fb.h>
/* (depend libs: -lxkbcommon)
* struct xkb_rule_names, xkb_context_new(), xkb_keymap_from_names(),
* xkb_state_new(), xkb_state_update_key(), xkb_state_key_get_one_sym(),
* xkb_keycode_t xkb_keysym_t
*/
#include <xkbcommon/xkbcommon.h>
/* sysconf(), _SC_PAGESIZE, _exit(), read(), fstat(), close() */
#include <unistd.h>
/* epoll_create1(), epoll_pwait(), epoll_ctl(),
* EPOLL_CLOEXEC, EPOLL_CTL_ADD, EPOLLIN,
* struct epoll_event
*/
#include <sys/epoll.h>
/* (depend libs: -pthread)
* pthread_t, pthread_create(), pthread_join()
*/
#include <pthread.h>
#define BLD_ERRSTR "osecpu driver error: "
/* #include <linux/input> 内で、osecpu の KEY_* と同名のマクロ群が定義されているため、
* そのインクリュード以降で、osecpu の KEY_* マクロ群が上書きされてしまうため、
* 元々 osecpu で定義されていたマクロは、以下で別名で再定義してます。
* オリジナルの KEY_* に、接頭辞 OSECPU_ を付加したマクロ名として再定義してます。
*/
#define OSECPU_KEY_ENTER '\n'
#define OSECPU_KEY_ESC 27
#define OSECPU_KEY_BACKSPACE 8
#define OSECPU_KEY_TAB 9
#define OSECPU_KEY_PAGEUP 0x1020
#define OSECPU_KEY_PAGEDOWN 0x1021
#define OSECPU_KEY_END 0x1022
#define OSECPU_KEY_HOME 0x1023
#define OSECPU_KEY_LEFT 0x1024
#define OSECPU_KEY_UP 0x1025
#define OSECPU_KEY_RIGHT 0x1026
#define OSECPU_KEY_DOWN 0x1027
#define OSECPU_KEY_INS 0x1028
#define OSECPU_KEY_DEL 0x1029
struct BLD_KBDLIST {
int *fdlist;
size_t fdlist_len;
int epollfd;
struct xkb_context *xkb_context;
struct xkb_keymap *xkb_keymap;
struct xkb_state *xkb_state;
int modkey_state;
};
struct BLD_RAWIMG {
int width;
int height;
uint32_t *img;
};
struct BLD_FB {
int fd;
int width;
int height;
uint32_t bytePerLine;
uint32_t soff;
uint32_t slen;
void *smem;
};
struct BLD_OSECPUMAIN {
int argc;
char **argv;
int ret;
};
struct BLD_WORK {
struct BLD_KBDLIST *kbdlist;
struct BLD_FB *fb;
struct BLD_RAWIMG *rawimg;
struct BLD_OSECPUMAIN *osecpumain;
};
static struct BLD_WORK *bld_work;
static struct BLD_KBDLIST *bld_kbdlist_new(void)
{
int is_kbd(const struct dirent *dirent)
{
const char magic_suffix[] = "-kbd";
const size_t magic_suffix_len = strlen(magic_suffix);
const size_t dname_len = strlen(dirent->d_name);
const size_t dname_suffix_offset = dname_len - magic_suffix_len;
if (dname_suffix_offset <= 0)
return 0;
if (!strcmp(&dirent->d_name[dname_suffix_offset], magic_suffix))
return 1;
return 0;
}
void dev_init(struct BLD_KBDLIST *kbdlist)
{
const char base_path[] = "/dev/input/by-id/";
struct dirent **dirent;
kbdlist->fdlist_len = scandir(base_path, &dirent, is_kbd, NULL);
if (kbdlist->fdlist_len == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_init_kbdlist() -> scandir()");
kbdlist->fdlist = malloc(sizeof(*(kbdlist->fdlist)) * kbdlist->fdlist_len);
if (kbdlist->fdlist == NULL)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_init_kbdlist() -> kbdlist->fdlist = malloc()");
char *path = calloc(0x1000, sizeof(*path));
if (path == NULL)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_init_kbdlist() -> path = calloc()");
int i;
for (i = 0; i < kbdlist->fdlist_len; i++) {
strcpy(path, base_path);
strcat(path, dirent[i]->d_name);
kbdlist->fdlist[i] = open(path, O_NONBLOCK | O_CLOEXEC | O_RDONLY);
if (kbdlist->fdlist[i] == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_init_kbdlist() -> open()");
}
free(dirent);
free(path);
}
void xkb_init(struct BLD_KBDLIST *kbdlist)
{
kbdlist->xkb_context = xkb_context_new(0);
if (kbdlist->xkb_context == NULL)
error(EXIT_FAILURE, 0, BLD_ERRSTR "bld_init_kbdlist() -> xkb_context_new()");
struct xkb_rule_names rule_names = {
.rules = "evdev",
.model = "evdev",
.layout = "jp",
.variant = "",
.options = ""
};
kbdlist->xkb_keymap = xkb_keymap_new_from_names(kbdlist->xkb_context, &rule_names, 0);
if (kbdlist->xkb_keymap == NULL)
error(EXIT_FAILURE, 0, BLD_ERRSTR "bld_init_kbdlist() -> xkb_keymap_new_from_names()");
kbdlist->xkb_state = xkb_state_new(kbdlist->xkb_keymap);
if (kbdlist->xkb_state == NULL)
error(EXIT_FAILURE, 0, BLD_ERRSTR "bld_init_kbdlist() -> xkb_state_new()");
}
void epoll_init(struct BLD_KBDLIST *kbdlist)
{
kbdlist->epollfd = epoll_create1(EPOLL_CLOEXEC);
if (kbdlist->epollfd == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_init_kbdlist() -> epoll_create1()");
int i;
for (i = 0; i < kbdlist->fdlist_len; i++) {
struct epoll_event ev = {
.events = EPOLLIN,
.data.fd = kbdlist->fdlist[i]
};
if (epoll_ctl(kbdlist->epollfd, EPOLL_CTL_ADD, kbdlist->fdlist[i], &ev) == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_init_kbdlist() -> epoll_ctl()");
}
}
struct BLD_KBDLIST *kbdlist = malloc(sizeof(*kbdlist));
if (kbdlist == NULL)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_init_kbdlist() -> kbdlist = malloc()");
kbdlist->modkey_state = 0;
dev_init(kbdlist);
xkb_init(kbdlist);
epoll_init(kbdlist);
return kbdlist;
}
static void bld_kbdlist_read(struct BLD_KBDLIST *kbdlist)
{
void modkey_update(struct BLD_KBDLIST *kbdlist, struct input_event *ev)
{
int tmp;
if (ev->code == KEY_LEFTCTRL)
tmp = 1 << 17;
else if (ev->code == KEY_RIGHTCTRL)
tmp = 1 << 25;
else if (ev->code == KEY_LEFTALT)
tmp = 1 << 18;
else if (ev->code == KEY_RIGHTALT)
tmp = 1 << 26;
else if (ev->code == KEY_LEFTSHIFT)
tmp = 1 << 16;
else if (ev->code == KEY_RIGHTSHIFT)
tmp = 1 << 24;
else
tmp = 0;
if (ev->code == KEY_NUMLOCK) {
if (kbdlist->modkey_state & (1 << 22))
kbdlist->modkey_state &= ~(1 << 22);
else
kbdlist->modkey_state |= 1 << 22;
} else if (ev->code == KEY_CAPSLOCK) {
if (kbdlist->modkey_state & (1 << 23))
kbdlist->modkey_state &= ~(1 << 23);
else
kbdlist->modkey_state |= 1 << 23;
}
if (ev->value)
kbdlist->modkey_state |= tmp;
else
kbdlist->modkey_state &= ~tmp;
}
xkb_keysym_t xkb_update(struct BLD_KBDLIST *kbdlist, struct input_event *ev)
{
const xkb_keycode_t magic_key = 8;
const xkb_keycode_t key = magic_key + ev->code;
if (ev->value == 0)
xkb_state_update_key(kbdlist->xkb_state, key, XKB_KEY_UP);
else if (ev->value == 1)
xkb_state_update_key(kbdlist->xkb_state, key, XKB_KEY_DOWN);
return xkb_state_key_get_one_sym(kbdlist->xkb_state, key);
}
int to_osecpu_keysym(struct BLD_KBDLIST *kbdlist, const xkb_keysym_t sym)
{
int tmp = 0;
if (sym == XKB_KEY_KP_Enter || sym == XKB_KEY_ISO_Enter)
tmp = OSECPU_KEY_ENTER;
else if (sym == XKB_KEY_Escape)
tmp = OSECPU_KEY_ESC;
else if (sym == XKB_KEY_BackSpace)
tmp = OSECPU_KEY_BACKSPACE;
else if (sym == XKB_KEY_Tab)
tmp = OSECPU_KEY_TAB;
else if (sym == XKB_KEY_SunPageUp)
tmp = OSECPU_KEY_PAGEUP;
else if (sym == XKB_KEY_SunPageDown)
tmp = OSECPU_KEY_PAGEDOWN;
else if (sym == XKB_KEY_KP_End || sym == XKB_KEY_End)
tmp = OSECPU_KEY_END;
else if (sym == XKB_KEY_KP_Home || sym == XKB_KEY_Home)
tmp = OSECPU_KEY_HOME;
else if (sym == XKB_KEY_Left)
tmp = OSECPU_KEY_LEFT;
else if (sym == XKB_KEY_Right)
tmp = OSECPU_KEY_RIGHT;
else if (sym == XKB_KEY_Up)
tmp = OSECPU_KEY_UP;
else if (sym == XKB_KEY_Down)
tmp = OSECPU_KEY_DOWN;
else if (sym == XKB_KEY_KP_Insert || sym == XKB_KEY_Insert)
tmp = OSECPU_KEY_INS;
else if (sym == XKB_KEY_KP_Delete || sym == XKB_KEY_Delete)
tmp = OSECPU_KEY_DEL;
else
tmp = sym;
return tmp | kbdlist->modkey_state;
}
struct epoll_event epoll_event;
const int epoll_event_len = epoll_pwait(kbdlist->epollfd, &epoll_event, 1, -1, NULL);
if (epoll_event_len == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_kbdlist_read() -> epoll_wait()");
if (epoll_event_len != 1)
return;
struct input_event input_event;
const int input_event_len = read(epoll_event.data.fd, &input_event, sizeof(input_event));
if (input_event_len == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_kbdlist_read() -> read()");
if (input_event_len == 0)
return;
if (input_event.type != EV_KEY)
return;
modkey_update(kbdlist, &input_event);
const xkb_keysym_t xkb_keysym = xkb_update(kbdlist, &input_event);
if (input_event.value == 0) {
putKeybuf(0x0fff);
return;
}
const int osecpu_keysym = to_osecpu_keysym(kbdlist, xkb_keysym);
putKeybuf(osecpu_keysym);
#ifdef DEBUG_BLD_KBDLIST
printf("input_event {type:[%#x], code:[%#x], value[%#x], xkb_keysym:[%d, %c], osecpu_keysym[%d, %c]}\n",
input_event.type, input_event.code, input_event.value,
xkb_keysym, xkb_keysym, osecpu_keysym, osecpu_keysym);
#endif /* DEBUG_BLD_KBDLIST */
}
static pthread_t bld_kbdlist_thread_create(struct BLD_KBDLIST *kbdlist)
{
void *bld_kbdlist_thread_routine(void *a)
{
struct BLD_KBDLIST *kbdlist = a;
while (1)
bld_kbdlist_read(kbdlist);
return NULL;
}
pthread_t threadid;
const int err = pthread_create(&threadid, NULL, bld_kbdlist_thread_routine, (void*)kbdlist);
if (err)
error(EXIT_FAILURE, err, BLD_ERRSTR "bld_kbdlist_thread_create() -> pthread_create()");
return threadid;
}
static inline void
bld_fb_screeninfo_show(struct fb_var_screeninfo *fbvs, struct fb_fix_screeninfo *fbfs)
{
#ifdef DEBUG_BLD_FB
int c;
c = fbfs->type;
const char* type =
c == FB_TYPE_PACKED_PIXELS ? "Packed Pixels" :
c == FB_TYPE_PLANES ? "Non interleaved planes" :
c == FB_TYPE_INTERLEAVED_PLANES ? "Interleaved planes" :
c == FB_TYPE_TEXT ? "Text/attributes" :
"Unknown planes";
c = fbfs->visual;
const char* visual =
c == FB_VISUAL_MONO01 ? "Monochr. 1=Black 0=White" :
c == FB_VISUAL_MONO10 ? "Monochr. 1=White 0=Black" :
c == FB_VISUAL_TRUECOLOR ? "True color" :
c == FB_VISUAL_PSEUDOCOLOR ? "Pseudo color (like atari)" :
c == FB_VISUAL_DIRECTCOLOR ? "Direct colo" :
c == FB_VISUAL_STATIC_PSEUDOCOLOR ? "Pseudo color readonly" :
"Unknown Visual";
c = fbvs->rotate;
const char* rotate =
c == FB_ROTATE_UR ? "ur" :
c == FB_ROTATE_CW ? "cw" :
c == FB_ROTATE_UD ? "ud" :
c == FB_ROTATE_CCW ? "ccw" :
"Unknown Rotate";
printf("===== Frame Buffer ===============================\n");
printf("NAME : [%s]\n", fbfs->id);
printf("TYPE : %s\n", type);
printf("VISUAL : %s\n", visual);
printf("SMEM : %p L=%u\n", (void*)fbfs->smem_start, fbfs->smem_len);
printf("MMIO : %p L=%u\n", (void*)fbfs->mmio_start, fbfs->mmio_len);
printf("LLEN : %u\n", fbfs->line_length);
printf("RESO : %ux%u+%u+%u / %ux%u @ %u\n",
fbvs->xres, fbvs->yres, fbvs->xoffset, fbvs->yoffset,
fbvs->xres_virtual, fbvs->yres_virtual,
fbvs->bits_per_pixel);
printf("RED : %u @ %u %c\n",
fbvs->red.offset, fbvs->red.length,
fbvs->red.msb_right ? '-' : '+');
printf("GREEN : %u @ %u %c\n",
fbvs->green.offset, fbvs->green.length,
fbvs->green.msb_right ? '-' : '+');
printf("BLUE : %u @ %u %c\n",
fbvs->blue.offset, fbvs->blue.length,
fbvs->blue.msb_right ? '-' : '+');
printf("ROTATE : %s\n", rotate);
printf("==================================================\n");
#endif /* DEBUG_BLD_FB */
}
static struct BLD_FB *bld_fb_new(void)
{
char fbdev_name[] = "/dev/fb0";
struct BLD_FB *fb = malloc(sizeof(*fb));
fb->fd = open(fbdev_name, O_RDWR);
if (fb->fd == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_fb_new() -> open()"
", フレームバッファー %s がシステムに存在しません", fbdev_name);
struct stat st;
if (fstat(fb->fd, &st) == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_fb_new() -> fstat()"
", %s の情報を取得できません", fbdev_name);
if (!S_ISCHR(st.st_mode) || major(st.st_rdev) != 29 /* FB_MAJOR */)
error(EXIT_FAILURE, 0, BLD_ERRSTR "bld_fb_new() -> stat"
", %s はフレームバッファーデバイスではありません", fbdev_name);
struct fb_var_screeninfo fb_var;
if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb_var) == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_fb_new() -> ioctl(FBIOGET_VSCREENINFO)"
", フレームバッファーの var_screeninfo の取得に失敗しました");
struct fb_fix_screeninfo fb_fix;
if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb_fix) == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_fb_new() -> ioctl(FBIOGET_FSCREENINFO)"
", フレームバッファーの fix_screeninfo の取得に失敗しました");
bld_fb_screeninfo_show(&fb_var, &fb_fix);
fb->width = fb_var.xres;
fb->height = fb_var.yres;
fb->bytePerLine = fb_fix.line_length;
fb->soff = (uint32_t)(fb_fix.smem_start) & (~PAGE_MASK);
fb->slen = (fb_fix.smem_len + fb->soff + ~PAGE_MASK) & PAGE_MASK;
fb->smem = mmap(NULL, fb->slen, PROT_READ | PROT_WRITE, MAP_SHARED, fb->fd, (off_t)0);
if (fb->smem == MAP_FAILED)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_fb_new() -> mmap()"
", %s の mmap に失敗しました", fbdev_name);
fb->smem = (void*)fb->smem + fb->soff;
return fb;
}
static void bld_fb_close(struct BLD_FB *fb)
{
if (fb->smem != MAP_FAILED)
if (munmap((caddr_t)((ptrdiff_t)fb->smem & PAGE_MASK), fb->slen) == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_fb_close() -> munmap()");
if (close(fb->fd) == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "bld_fb_close() -> close()");
}
static void bld_fb_raw_image_draw(struct BLD_FB *fb, struct BLD_RAWIMG *rawimg,
const int offx, const int offy)
{
uint32_t *bld_fb_pix_adrs_seek(struct BLD_FB *fb,
const int x, const int y)
{
return fb->smem + (y * fb->bytePerLine) + (x * 4);
}
void bld_fb_pixel_set(struct BLD_FB *fb, const int x, const int y, const uint32_t col)
{
if ((x >= 0 && x < fb->width) && (y >= 0 && y < fb->height)) {
uint32_t *p = bld_fb_pix_adrs_seek(fb, x, y);
*p = col;
}
}
uint32_t *p = rawimg->img;
int j = 0;
for (j = 0; j < rawimg->height; j++) {
int i = 0;
for (i = 0; i < rawimg->width; i++) {
bld_fb_pixel_set(fb, offx + i, offy + j, *p);
p++;
}
}
}
static struct BLD_OSECPUMAIN *bld_osecpumain_new(int argc, char **argv)
{
struct BLD_OSECPUMAIN *osecpumain = malloc(sizeof(*osecpumain));
osecpumain->argc = argc;
osecpumain->argv = argv;
return osecpumain;
}
static pthread_t bld_osecpumain_thread_create(struct BLD_OSECPUMAIN *osecpumain)
{
void *bld_osecpu_main_thread_routine(void *a)
{
struct BLD_OSECPUMAIN *osecpumain = a;
osecpumain->ret = OsecpuMain(osecpumain->argc, (const UCHAR**)osecpumain->argv);
return NULL;
}
pthread_t threadid;
const int err = pthread_create(&threadid, NULL, bld_osecpu_main_thread_routine, (void*)osecpumain);
if (err)
error(EXIT_FAILURE, err, BLD_ERRSTR "bld_osecpumain_thread_create() -> pthread_create()");
return threadid;
}
void *mallocRWE(int bytes)
{
const size_t pagesize = sysconf(_SC_PAGESIZE);
if (pagesize == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "mallocRWE() -> sysconf()");
void *tmp;
if (posix_memalign(&tmp, pagesize, (size_t)bytes))
error(EXIT_FAILURE, errno, BLD_ERRSTR "mallocRWE() -> posix_memalign()");
if (mprotect(tmp, (size_t)bytes, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
error(EXIT_FAILURE, errno, BLD_ERRSTR "mallocRWE() -> mprotect()");
return tmp;
}
void drv_openWin(int sx, int sy, unsigned char *buf, char *winClosed)
{
bld_work->rawimg->img = (uint32_t*)buf;
bld_work->rawimg->width = sx;
bld_work->rawimg->height = sy;
}
void drv_flshWin(int sx, int sy, int x0, int y0)
{
bld_fb_raw_image_draw(bld_work->fb, bld_work->rawimg, 0, 0);
}
void drv_sleep(int msec)
{
void abs_clock_nanosleep(struct timespec *ts)
{
struct timespec remain;
int err = clock_nanosleep(CLOCK_MONOTONIC, 0, ts, &remain);
if (err != 0) {
if (err == EINTR)
abs_clock_nanosleep(&remain);
else
error(EXIT_FAILURE, errno, BLD_ERRSTR "drv_sleep() -> clock_nanosleep()");
}
}
void drv_sleep_process_sleep(const int msec)
{
struct timespec ts = {
.tv_sec = msec / 1000,
.tv_nsec = (msec % 1000) * (1000 * 1000)
};
abs_clock_nanosleep(&ts);
}
if (msec < 0)
error(EXIT_FAILURE, 0, BLD_ERRSTR "drv_sleep() -> msec < 0");
else
drv_sleep_process_sleep(msec);
}
int main(int argc, char **argv)
{
bld_work = malloc(sizeof(*bld_work));
bld_work->rawimg = malloc(sizeof(*bld_work->rawimg));
bld_work->osecpumain = bld_osecpumain_new(argc, argv);
bld_work->kbdlist = bld_kbdlist_new();
bld_work->fb = bld_fb_new();
const pthread_t kbdlist_threadid = bld_kbdlist_thread_create(bld_work->kbdlist);
const pthread_t osecpumain_threadid = bld_osecpumain_thread_create(bld_work->osecpumain);
pthread_join(kbdlist_threadid, NULL);
pthread_join(osecpumain_threadid, NULL);
bld_fb_close(bld_work->fb);
return EXIT_SUCCESS;
}
#endif /* (DRV_OSNUM == 0x0004) */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <setjmp.h>
#if (!defined(JITC_OSNUM))
#if (defined(_WIN32))
#define JITC_OSNUM 0x0001
#endif
#if (defined(__APPLE__))
#define JITC_OSNUM 0x0002
#endif
#if (defined(__LINUX_BLIKE__))
#define JITC_OSNUM 0x0003
#endif
#if (defined(__LINUX_FBDEV__))
#define JITC_OSNUM 0x0004
#endif
/* 0001: win32-x86-32bit */
/* 0002: MacOS-x86-32bit */
/* 0003: linux-blike-x86-32bit */
/* 0004: linux-fbdev-x86-32bit */
#endif
#if (!defined(REVISION))
#define REVISION 1
#endif
#if (REVISION == 1)
#define SYSLIB_OSE "syslib.ose"
#define SIGN1 0xe1
#elif (REVISION == 2)
#define SYSLIB_OSE "syslib2.ose"
#define SIGN1 0xe2
#endif
#define USE_DEBUGGER 1
#define USE_TEK5 1
#if (USE_TEK5 != 0)
#include "tek.c"
int tek5Decomp(UCHAR *buf, UCHAR *buf1, UCHAR *tmp);
#else
typedef unsigned char UCHAR;
#endif
#define APPSIZ1 1 * 1024 * 1024 /* とりあえず1MBで */
#define JITSIZ1 1 * 1024 * 1024 /* とりあえず1MBで */
#define SJITSIZ1 1 * 1024 * 1024 /* とりあえず1MBで */
#define SYSLIBSIZ1 1 * 1024 * 1024 /* とりあえず1MBで */
#define SYSTMP0SIZ 1 * 1024 * 1024 /* とりあえず1MBで */
#define SYSTMP1SIZ 2 * 1024 * 1024 /* とりあえず2MBで */
struct PtrCtrl {
int liveSign;
int size, typ;
UCHAR *p0;
};
struct Ptr { /* 32バイト(=256bit!) */
UCHAR *p;
int typ;
UCHAR *p0, *p1;
int liveSign;
struct PtrCtrl *pls;
int flags, dummy; /* read/writeなど */
};
struct LabelTable {
UCHAR *p, *p1;
int opt, typ;
};
struct Regs {
int ireg[64]; /* 32bit整数レジスタ */
struct Ptr preg[64]; /* ポインタレジスタ */
int debugInfo0, debugInfo1, dmy[2]; /* 2304 */
struct PtrCtrl *ptrCtrl; /* 2320 */
char winClosed, autoSleep;
jmp_buf *setjmpEnv;
/* for-junkApi */
int argc;
const UCHAR **argv;
UCHAR *buf0, *buf1, *junkStack, lastConsoleChar, *junkStack1;
struct LabelTable *label;
int maxLabels;
UCHAR *jitbuf, *jitbuf1;
void (*errHndl)(struct Regs *);
char dbgr;
int mapDi1s[16][16];
};
/* JITCのフラグ群 */
#define JITC_LV_SLOWEST 0 /* デバッグ支援は何でもやる */
#define JITC_LV_SLOWER 1 /* エラーモジュールはレポートできるが、行番号は分からない、テストは過剰 */
#define JITC_LV_SAFE 2 /* とにかく止まる、場所は不明、テストは必要最小限 */
#define JITC_LV_FASTER 4 /* 情報は生成するがチェックをしない */
#define JITC_LV_FASTEST 5 /* 情報すら生成しない */
#define JITC_PHASE1 0x0001
#define JITC_SKIPCHECK 0x0002 /* セキュリティチェックを省略する(高速危険モード) */
#define JITC_NOSTARTUP 0x0004
#define JITC_MAXLABELS 4096
#define PTRCTRLSIZ 4096
/* JITC_ARCNOについて */
/* 0001: x86-32bitモード */
#if (JITC_OSNUM == 0x0001) /* win32-x86-32bit */
#define JITC_ARCNUM 0x0001 /* x86-32bit */
#define DRV_OSNUM 0x0001 /* win32 */
#endif
#if (JITC_OSNUM == 0x0002) /* MacOS-x86-32bit */
#define JITC_ARCNUM 0x0001 /* x86-32bit */
#define DRV_OSNUM 0x0002 /* MacOS */
#endif
#if (JITC_OSNUM == 0x0003) /* linux-x86-32bit */
#define JITC_ARCNUM 0x0001 /* x86-32bit */
#define DRV_OSNUM 0x0003 /* blike for Linux */
#endif
#if (JITC_OSNUM == 0x0004) /* linux-x86-32bit */
#define JITC_ARCNUM 0x0001 /* x86-32bit */
#define DRV_OSNUM 0x0004 /* Linux /dev/fb0 */
#endif
#define KEYBUFSIZ 4096
static int *keybuf, keybuf_r, keybuf_w, keybuf_c;
static int *vram = NULL, v_xsiz, v_ysiz;
static int di1_serial = 0;
#define KEY_ENTER '\n'
#define KEY_ESC 27
#define KEY_BACKSPACE 8
#define KEY_TAB 9
#define KEY_PAGEUP 0x1020
#define KEY_PAGEDWN 0x1021
#define KEY_END 0x1022
#define KEY_HOME 0x1023
#define KEY_LEFT 0x1024
#define KEY_UP 0x1025
#define KEY_RIGHT 0x1026
#define KEY_DOWN 0x1027
#define KEY_INS 0x1028
#define KEY_DEL 0x1029
/* 雑関数 */
void dbgrMain(struct Regs *r);
const UCHAR *searchArg(int argc, const UCHAR **argv, const UCHAR *tag, int i); // コマンドライン引数処理.
void randStatInit(UINT32 seed);
void devFunc(struct Regs *r); // junkApiを処理する関数
/* ComLib関係 */
UCHAR *ComLib_main(const UCHAR *p, UCHAR *q);
/* JITコンパイラ関係 */
int jitc0(UCHAR **qq, UCHAR *q1, const UCHAR *p0, const UCHAR *p1, int level, struct LabelTable *label);
int jitCompiler(UCHAR *dst, UCHAR *dst1, const UCHAR *src, const UCHAR *src1, const UCHAR *src0, struct LabelTable *label, int maxLabels, int level, int debugInfo1, int flags);
UCHAR *jitCompCallFunc(UCHAR *dst, void *func);
UCHAR *jitCompInit(UCHAR *dst);
void errorHandler(struct Regs *r);
/* OS依存関数 */
void *mallocRWE(int bytes); // 実行権付きメモリのmalloc.
void drv_openWin(int x, int y, UCHAR *buf, char *winClosed);
void drv_flshWin(int sx, int sy, int x0, int y0);
void drv_sleep(int msec);
int OsecpuMain(int argc, const UCHAR **argv)
{
UCHAR *appbin = malloc(APPSIZ1), *up;
UCHAR *jitbuf = mallocRWE(1024 * 1024); /* とりあえず1MBで */
UCHAR *sysjit0 = mallocRWE(SJITSIZ1), *sysjit1 = sysjit0, *sysjit00 = sysjit0;
UCHAR *systmp0 = malloc(SYSTMP0SIZ);
UCHAR *systmp1 = malloc(SYSTMP1SIZ);
UCHAR *systmp2 = malloc(1024 * 1024), *opTbl = malloc(256);
struct LabelTable *label = malloc(JITC_MAXLABELS * sizeof (struct LabelTable));
int level = JITC_LV_SLOWEST, tmpsiz, i;
keybuf = malloc(KEYBUFSIZ * sizeof (int));
keybuf_r = keybuf_w = keybuf_c = 0;
jmp_buf setjmpEnv;
double tm0, tm1, tm2;
struct PtrCtrl *ptrCtrl = malloc(PTRCTRLSIZ * sizeof (struct PtrCtrl));
randStatInit((unsigned int) time(NULL));
for (i = 0; i < PTRCTRLSIZ; i++) {
ptrCtrl[i].liveSign = 0;
ptrCtrl[i].size = -1;
}
ptrCtrl[0].size = -2;
/* syslibの読み込み */
UCHAR *syslib = malloc(SYSLIBSIZ1);
int appsiz0, appsiz1;
FILE *fp = fopen(SYSLIB_OSE, "rb");
if (fp == NULL) {
syslib[0] = '/';
strcpy(syslib + 1, argv[0]);
up = syslib + 1;
while (*up != '\0') up++;
while (*up != '/' && *up != 0x5c) up--;
up++;
strcpy(up, SYSLIB_OSE);
fp = fopen(syslib + 1, "rb");
}
if (fp == NULL) {
fputs("syslib-file fopen error.\n", stderr);
return 1;
}
appsiz0 = fread(syslib, 1, SYSLIBSIZ1 - 4, fp);
fclose(fp);
if (appsiz0 >= SYSLIBSIZ1 - 4) {
fputs("syslib-file too large.\n", stderr);
return 1;
}
if (syslib[0] == 0x05 && syslib[1] == 0xc1) {
memcpy(systmp0, syslib, appsiz0);
ComLib_main(systmp0 + 2, syslib + 2);
syslib[0] = 0x05;
syslib[1] = 0x1b;
}
sysjit1 = jitCompInit(sysjit1);
sysjit0 = sysjit1;
i = jitc0(&sysjit1, sysjit00 + SJITSIZ1, syslib + 32, syslib + SYSLIBSIZ1, JITC_LV_SLOWEST+9, label);
if (i != 0) {
fputs("syslib-file JITC error.\n", stderr);
return 1;
}
di1_serial++;
/* アプリバイナリの読み込み */
if (argc <= 1)
return 0;
const UCHAR *argv1 = argv[1];
if (argv1[0] == ':' && argv1[2] == ':') {
level = argv1[1] - '0';
if (level < 0 || level > 9)
level = JITC_LV_SLOWEST;
argv1 += 3;
}
fp = fopen(argv1, "rb");
if (fp == NULL) {
fputs("app-file load error.\n", stderr);
return 1;
}
appsiz1 = appsiz0 = fread(appbin, 1, APPSIZ1 - 4, fp);
fclose(fp);
if (appsiz0 >= APPSIZ1 - 4) {
fputs("app-file too large.\n", stderr);
return 1;
}
if (appsiz0 < 3) {
header_error:
fputs("app-file header error.\n", stderr);
return 1;
}
tm0 = clock() / (double) CLOCKS_PER_SEC;
if (appbin[2] == 0xf0) {
#if (USE_TEK5 != 0)
appsiz1 = tek5Decomp(appbin + 2, appbin + appsiz0, systmp0) + 2;
#else
appsiz1 = -9;
#endif
if (appsiz1 < 0) {
fputs("unsupported-format(tek5)\n", stderr);
return 1;
}
}
int argDebug = 0, stacksiz = 1;
const UCHAR *cp = searchArg(argc, argv, "debug:", 0);
if (cp != NULL) argDebug = *cp - '0';
cp = searchArg(argc, argv, "stack:", 0);
if (cp != NULL) stacksiz = strtol(cp, NULL, 0);
struct Regs regs;
void (*jitfunc)(char *);
UCHAR *jp = jitbuf; /* JIT-pointer */
/* フロントエンドコードをバックエンドコードに変換する */
if ((appbin[2] & 0xf0) != 0) {
systmp0[0] = appbin[0];
systmp0[1] = appbin[1];
regs.preg[2].p = systmp0 + 2;
regs.preg[3].p = systmp0 + SYSTMP0SIZ;
regs.preg[4].p = appbin + 2;
regs.preg[5].p = appbin + appsiz1;
regs.preg[6].p = systmp1;
regs.preg[7].p = systmp1 + SYSTMP1SIZ;
regs.preg[10].p = systmp2;
int pxxFlag[64], typLabel[4096];
regs.preg[0x0b].p = (void *) pxxFlag;
regs.preg[0x0c].p = (void *) typLabel;
regs.preg[0x0d].p = opTbl;
jitfunc = (void *) sysjit0;
(*jitfunc)(((char *) &regs) + 128); /* サイズを節約するためにEBPを128バイトずらす */
if (regs.ireg[0] != 0) {
jp = regs.preg[2].p - 1;
fprintf(stderr, "unpack error: %02X (at %06X) (R00=%d)\n", *jp, jp - systmp0, regs.ireg[0]);
if ((argDebug & 2) != 0) {
fp = fopen("debug2.bin", "wb");
fwrite(systmp0, 1, jp - systmp0 + 16, fp);
fclose(fp);
}
exit(1);
}
tmpsiz = regs.preg[2].p - systmp0;
} else {
memcpy(systmp0, appbin, appsiz1);
tmpsiz = appsiz1;
}
if ((argDebug & 2) != 0) {
fp = fopen("debug2.bin", "wb");
fwrite(systmp0, 1, tmpsiz, fp);
fclose(fp);
}
i = jitc0(&jp, jitbuf + 1024 * 1024, systmp0, systmp0 + tmpsiz, level, label);
if (i == 1) goto header_error;
if (i != 0) return 1;
di1_serial++;
int appsiz2 = jp - jitbuf;
UCHAR *p28 = jp;
jp = jitCompCallFunc(jp, &devFunc);
tm1 = clock() / (double) CLOCKS_PER_SEC;
/* レジスタ初期化 */
for (i = 0; i < 64; i++)
regs.ireg[i] = 0;
for (i = 0; i < 64; i++) {
regs.preg[i].p = NULL;
regs.preg[i].typ = -1;
regs.preg[i].p0 = NULL;
regs.preg[i].p1 = NULL;
}
regs.argc = argc;
regs.argv = argv;
regs.buf0 = regs.buf1 = NULL;
regs.preg[0x28].p = p28;
regs.preg[0x28].typ = 0; // TYP_CODE
regs.preg[0x28].p0 = p28;
regs.preg[0x28].p1 = p28 + 1;
// regs.preg[0x00].p = malloc(1024 * 1024) + (1024 * 1024 - 32);
regs.junkStack = malloc(stacksiz << 20);
regs.junkStack1 = regs.junkStack + (stacksiz << 20);
regs.winClosed = 0;
regs.autoSleep = 0;
regs.setjmpEnv = &setjmpEnv;
regs.lastConsoleChar = '\n';
regs.label = label;
regs.maxLabels = JITC_MAXLABELS;
regs.jitbuf = jp;
regs.jitbuf1 = jitbuf + 1024 * 1024;
regs.errHndl = &errorHandler;
regs.dbgr = 0;
if (searchArg(argc, argv, "dbgr:1", 0) != NULL) regs.dbgr = 1;
if ((argDebug & 1) != 0) {
fp = fopen("debug1.bin", "wb");
fwrite(jitbuf, 1, jp - jitbuf, fp);
fclose(fp);
}
/* JITコード実行 */
jitfunc = (void *) jitbuf;
if (setjmp(setjmpEnv) == 0)
(*jitfunc)(((char *) &regs) + 128); /* サイズを節約するためにEBPを128バイトずらす */
if (regs.autoSleep != 0) {
if (vram != NULL)
drv_flshWin(v_xsiz, v_ysiz, 0, 0);
while (regs.winClosed == 0)
drv_sleep(100);
}
if (regs.lastConsoleChar != '\n')
putchar('\n');
tm2 = clock() / (double) CLOCKS_PER_SEC;
/* 実行結果確認のためのレジスタダンプ */
if (searchArg(argc, argv, "verbose:1", 0) != NULL) {
printf("time: JITC=%.3f[sec], exec=%.3f[sec]\n", tm1 - tm0, tm2 - tm1);
printf("size: OSECPU=%d, decomp=%d, tmp=%d, native=%d\n", appsiz0, appsiz1, tmpsiz, appsiz2);
printf("result:\n");
printf("R00:0x%08X R01:0x%08X R02:0x%08X R03:0x%08X\n", regs.ireg[0], regs.ireg[1], regs.ireg[2], regs.ireg[3]);
}
#if (USE_DEBUGGER != 0)
dbgrMain(&regs);
#endif
return 0;
}
void errorHandler(struct Regs *r)
{
puts("security error! abort...");
printf("debugInfo0=%d, debugInfo1=%d\n", r->debugInfo0, r->debugInfo1);
#if (USE_DEBUGGER != 0)
dbgrMain(r);
#endif
exit(1);
}
const UCHAR *searchArg(int argc, const UCHAR **argv, const UCHAR *tag, int i)
{
int j, l;
const UCHAR *r = NULL;
if (tag != NULL) {
l = strlen(tag);
for (j = 1; j < argc; j++) {
if (strncmp(argv[j], tag, l) == 0) {
r = argv[j] + l;
if (i == 0) break;
i--;
}
}
} else {
for (j = 1; j < argc; j++) {
if (strchr(argv[j], ':') == NULL) {
r = argv[j];
if (i == 0) break;
i--;
}
}
}
if (i != 0) r = NULL;
return r;
}
static int iColor1[] = {
0x000000, 0xff0000, 0x00ff00, 0xffff00,
0x0000ff, 0xff00ff, 0x00ffff, 0xffffff
};
void putOsaskChar(int c, struct Regs *r)
{
if (0x10 <= c && c <= 0x1f)
c = "0123456789ABCDEF"[c & 0x0f];
putchar(r->lastConsoleChar = c);
return;
}
static unsigned char fontdata[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,
0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x44, 0x44, 0x44, 0xfe, 0x44, 0x44, 0x44, 0x44, 0x44, 0xfe, 0x44, 0x44, 0x44, 0x00, 0x00,
0x10, 0x3a, 0x56, 0x92, 0x92, 0x90, 0x50, 0x38, 0x14, 0x12, 0x92, 0x92, 0xd4, 0xb8, 0x10, 0x10,
0x62, 0x92, 0x94, 0x94, 0x68, 0x08, 0x10, 0x10, 0x20, 0x2c, 0x52, 0x52, 0x92, 0x8c, 0x00, 0x00,
0x00, 0x70, 0x88, 0x88, 0x88, 0x90, 0x60, 0x47, 0xa2, 0x92, 0x8a, 0x84, 0x46, 0x39, 0x00, 0x00,
0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x02, 0x00,
0x80, 0x40, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x40, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x92, 0x54, 0x38, 0x54, 0x92, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x40, 0x80, 0x80,
0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18, 0x00, 0x00,
0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00,
0x00, 0x18, 0x24, 0x42, 0x42, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00,
0x00, 0x18, 0x24, 0x42, 0x02, 0x02, 0x04, 0x18, 0x04, 0x02, 0x02, 0x42, 0x24, 0x18, 0x00, 0x00,
0x00, 0x0c, 0x0c, 0x0c, 0x14, 0x14, 0x14, 0x24, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x1e, 0x00, 0x00,
0x00, 0x7c, 0x40, 0x40, 0x40, 0x58, 0x64, 0x02, 0x02, 0x02, 0x02, 0x42, 0x24, 0x18, 0x00, 0x00,
0x00, 0x18, 0x24, 0x42, 0x40, 0x58, 0x64, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00,
0x00, 0x7e, 0x42, 0x42, 0x04, 0x04, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00,
0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00,
0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x26, 0x1a, 0x02, 0x42, 0x24, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10,
0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00,
0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x04, 0x08, 0x10, 0x10, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
0x00, 0x38, 0x44, 0x82, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x9c, 0x80, 0x46, 0x38, 0x00, 0x00,
0x00, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00,
0x00, 0xf0, 0x48, 0x44, 0x44, 0x44, 0x48, 0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0xf8, 0x00, 0x00,
0x00, 0x3a, 0x46, 0x42, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x82, 0x42, 0x44, 0x38, 0x00, 0x00,
0x00, 0xf8, 0x44, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44, 0x44, 0xf8, 0x00, 0x00,
0x00, 0xfe, 0x42, 0x42, 0x40, 0x40, 0x44, 0x7c, 0x44, 0x40, 0x40, 0x42, 0x42, 0xfe, 0x00, 0x00,
0x00, 0xfe, 0x42, 0x42, 0x40, 0x40, 0x44, 0x7c, 0x44, 0x44, 0x40, 0x40, 0x40, 0xf0, 0x00, 0x00,
0x00, 0x3a, 0x46, 0x42, 0x82, 0x80, 0x80, 0x9e, 0x82, 0x82, 0x82, 0x42, 0x46, 0x38, 0x00, 0x00,
0x00, 0xe7, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00,
0x00, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00,
0x00, 0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x84, 0x48, 0x30, 0x00,
0x00, 0xe7, 0x42, 0x44, 0x48, 0x50, 0x50, 0x60, 0x50, 0x50, 0x48, 0x44, 0x42, 0xe7, 0x00, 0x00,
0x00, 0xf0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0xfe, 0x00, 0x00,
0x00, 0xc3, 0x42, 0x66, 0x66, 0x66, 0x5a, 0x5a, 0x5a, 0x42, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00,
0x00, 0xc7, 0x42, 0x62, 0x62, 0x52, 0x52, 0x52, 0x4a, 0x4a, 0x4a, 0x46, 0x46, 0xe2, 0x00, 0x00,
0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, 0x00,
0x00, 0xf8, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x40, 0x40, 0x40, 0x40, 0x40, 0xf0, 0x00, 0x00,
0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x92, 0x8a, 0x44, 0x3a, 0x00, 0x00,
0x00, 0xfc, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00,
0x00, 0x3a, 0x46, 0x82, 0x82, 0x80, 0x40, 0x38, 0x04, 0x02, 0x82, 0x82, 0xc4, 0xb8, 0x00, 0x00,
0x00, 0xfe, 0x92, 0x92, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00,
0x00, 0xe7, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x3c, 0x00, 0x00,
0x00, 0xe7, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24, 0x24, 0x24, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
0x00, 0xe7, 0x42, 0x42, 0x42, 0x5a, 0x5a, 0x5a, 0x5a, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00,
0x00, 0xe7, 0x42, 0x42, 0x24, 0x24, 0x24, 0x18, 0x24, 0x24, 0x24, 0x42, 0x42, 0xe7, 0x00, 0x00,
0x00, 0xee, 0x44, 0x44, 0x44, 0x28, 0x28, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00,
0x00, 0xfe, 0x84, 0x84, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x42, 0x82, 0xfe, 0x00, 0x00,
0x00, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3e, 0x00,
0x80, 0x80, 0x40, 0x40, 0x20, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x04, 0x02, 0x02,
0x00, 0x7c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x7c, 0x00,
0x00, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00,
0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x08, 0x04, 0x3c, 0x44, 0x84, 0x84, 0x8c, 0x76, 0x00, 0x00,
0xc0, 0x40, 0x40, 0x40, 0x40, 0x58, 0x64, 0x42, 0x42, 0x42, 0x42, 0x42, 0x64, 0x58, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x4c, 0x84, 0x84, 0x80, 0x80, 0x82, 0x44, 0x38, 0x00, 0x00,
0x0c, 0x04, 0x04, 0x04, 0x04, 0x34, 0x4c, 0x84, 0x84, 0x84, 0x84, 0x84, 0x4c, 0x36, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x82, 0xfc, 0x80, 0x82, 0x42, 0x3c, 0x00, 0x00,
0x0e, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x4c, 0x84, 0x84, 0x84, 0x84, 0x4c, 0x34, 0x04, 0x04, 0x78,
0xc0, 0x40, 0x40, 0x40, 0x40, 0x58, 0x64, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0xe3, 0x00, 0x00,
0x00, 0x10, 0x10, 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00,
0x00, 0x04, 0x04, 0x00, 0x00, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x30,
0xc0, 0x40, 0x40, 0x40, 0x40, 0x4e, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0xe6, 0x00, 0x00,
0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0xdb, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x64, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0xe3, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x64, 0x42, 0x42, 0x42, 0x42, 0x42, 0x64, 0x58, 0x40, 0xe0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x4c, 0x84, 0x84, 0x84, 0x84, 0x84, 0x4c, 0x34, 0x04, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x62, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x86, 0x82, 0xc0, 0x38, 0x06, 0x82, 0xc2, 0xbc, 0x00, 0x00,
0x00, 0x00, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x42, 0x42, 0x42, 0x24, 0x24, 0x24, 0x18, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x42, 0x42, 0x5a, 0x5a, 0x5a, 0x24, 0x24, 0x24, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x44, 0x28, 0x28, 0x10, 0x28, 0x28, 0x44, 0xc6, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x42, 0x42, 0x24, 0x24, 0x24, 0x18, 0x18, 0x10, 0x10, 0x60,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x82, 0x84, 0x08, 0x10, 0x20, 0x42, 0x82, 0xfe, 0x00, 0x00,
0x00, 0x06, 0x08, 0x10, 0x10, 0x10, 0x10, 0x60, 0x10, 0x10, 0x10, 0x10, 0x08, 0x06, 0x00, 0x00,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x00, 0x60, 0x10, 0x08, 0x08, 0x08, 0x08, 0x06, 0x08, 0x08, 0x08, 0x08, 0x10, 0x60, 0x00, 0x00,
0x00, 0x72, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x44, 0x82, 0xfe, 0x82, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00
};
//typedef unsigned int UINT32;
typedef signed int SINT32;
/* tinyMTの32bit版のアルゴリズムを使っています */
/* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index-jp.html */
static struct {
UINT32 stat[4], mat1, mat2, tmat;
} randStat;
void randStatNext()
{
UINT32 x, y;
x = (randStat.stat[0] & 0x7fffffff) ^ randStat.stat[1] ^ randStat.stat[2];
y = randStat.stat[3];
x ^= x << 1;
y ^= (y >> 1) ^ x;
randStat.stat[1] = randStat.stat[2] ^ (-((SINT32)(y & 1)) & randStat.mat1);
randStat.stat[2] = x ^ (y << 10) ^ (-((SINT32)(y & 1)) & randStat.mat2);
randStat.stat[3] = y;
return;
}
void randStatInit(UINT32 seed)
{
int i;
randStat.stat[0] = seed;
randStat.stat[1] = randStat.mat1 = 0x8f7011ee;
randStat.stat[2] = randStat.mat2 = 0xfc78ff1f;
randStat.stat[3] = randStat.tmat = 0x3793fdff;
for (i = 1; i < 8; i++)
randStat.stat[i & 3] ^= i + ((UINT32)1812433253) * (randStat.stat[(i - 1) & 3] ^ (randStat.stat[(i - 1) & 3] >> 30));
for (i = 0; i < 8; i++)
randStatNext();
return;
}
void checkString(struct Regs *r, int rxx, int pxx)
{
char c = 0;
if (r->preg[pxx].typ != 0x03) c = 1;
if (r->preg[pxx].p < r->preg[pxx].p0) c = 1;
if (r->ireg[rxx] < 0) c = 1;
if (r->preg[pxx].p + r->ireg[rxx] > r->preg[pxx].p1) c = 1;
if (c != 0)
(*(r->errHndl))(r);
return;
}
int loadColor(struct Regs *r, int rxx)
{
int c = r->ireg[rxx], m = r->ireg[0x31] & 0x0c, rr, gg, bb;
if (m == 0x04) {
if (c < -1 || c > 7)
(*(r->errHndl))(r);
c = iColor1[c & 0x07];
}
if (m == 0x08) {
// 00, 24, 48, 6d, 91, b6, da, ff
if (c < 0 || c >= (1 << 9))
(*(r->errHndl))(r);
rr = (c >> 6) & 0x07;
gg = (c >> 3) & 0x07;
bb = c & 0x07;
rr = (rr * 255) / 7;
gg = (gg * 255) / 7;
bb = (bb * 255) / 7;
c = rr << 16 | gg << 8 | bb;
}
if (m == 0x0c) {
// 00, 08, 10, 18, 20, 29, 31, 39,
// 41, 4a, 52, 5a, 62, 6a, 73, 7b,
// 83, 8b, 94, 9c, a4, ac, b4, bd,
// c5, cd, d5, de, e6, ee, f6, ff
if (c < 0 || c >= (1 << 15))
(*(r->errHndl))(r);
rr = (c >> 10) & 0x1f;
gg = (c >> 5) & 0x1f;
bb = c & 0x1f;
rr = (rr * 255) / 31;
gg = (gg * 255) / 31;
bb = (bb * 255) / 31;
c = rr << 16 | gg << 8 | bb;
}
return c;
}
void checkRect(struct Regs *r, int rxx)
{
char c = 0;
int i;
if (r->ireg[rxx + 0] <= 0 || r->ireg[rxx + 0] > v_xsiz) c = 1;
if (r->ireg[rxx + 1] <= 0 || r->ireg[rxx + 1] > v_ysiz) c = 1;
if (r->ireg[rxx + 2] < 0 || r->ireg[rxx + 2] >= v_xsiz) c = 1;
if (r->ireg[rxx + 3] < 0 || r->ireg[rxx + 3] >= v_ysiz) c = 1;
i = r->ireg[rxx + 2] + r->ireg[rxx + 0]; if (i <= 0 || i > v_xsiz) c = 1;
i = r->ireg[rxx + 1] + r->ireg[rxx + 3]; if (i <= 0 || i > v_ysiz) c = 1;
if (c != 0)
(*(r->errHndl))(r);
return;
}
void devFunc0001(int len, UCHAR *puc, struct Regs *r)
{
while (len > 0) {
putOsaskChar(*puc++, r);
len--;
}
return;
}
void devFunc0006(int mod, int sx, int sy, int x, int y, int c, int len, UCHAR *puc, struct Regs *r)
{
if (sy == 0) sy = sx;
int xx = x + sx * 8;
int yy = y + sy * 16;
if (xx <= 0 || xx > v_xsiz || yy <= 0 || yy > v_ysiz)
(*(r->errHndl))(r);
if (x < 0 || x >= v_xsiz || y < 0 || y >= v_ysiz)
(*(r->errHndl))(r);
int i, ddx, ddy, j, ch, dx, dy;
if ((mod & 3) == 0 && sx == 1 && sy == 1) {
// メジャーケースを高速化.
for (i = 0; i < len; i++) {
ch = puc[i];
if (0x10 <= ch && ch <= 0x1f)
ch = "0123456789ABCDEF"[ch & 0x0f];
for (dy = 0; dy < 16; dy++) {
j = fontdata[(ch - ' ') * 16 + dy];
for (dx = 0; dx < 8; dx++) {
if ((j & (0x80 >> dx)) != 0) vram[(x + dx) + (y + dy) * v_xsiz] = c;
}
}
x += 8;
}
return;
}
for (i = 0; i < len; i++) {
ch = puc[i];
if (0x10 <= ch && ch <= 0x1f)
ch = "0123456789ABCDEF"[ch & 0x0f];
for (dy = 0; dy < 16; dy++) {
j = fontdata[(ch - ' ') * 16 + dy];
for (ddy = 0; ddy < sy; ddy++) {
for (dx = 0; dx < 8; dx++) {
if ((j & (0x80 >> dx)) != 0) {
for (ddx = 0; ddx < sx; ddx++) {
if ((mod & 3) == 0) vram[x + y * v_xsiz] = c;
if ((mod & 3) == 1) vram[x + y * v_xsiz] |= c;
if ((mod & 3) == 2) vram[x + y * v_xsiz] ^= c;
if ((mod & 3) == 3) vram[x + y * v_xsiz] &= c;
x++;
}
} else
x += sx;
}
x -= sx * 8;
y++;
}
}
x += sx * 8;
y -= sy * 16;
}
return;
}
int devFunc0016(int buflen, UCHAR *buf, int plen, UCHAR *p, int qlen, int *q, struct Regs *r)
{
int i = 0, base, j, k;
char sign;
while (plen > 0) {
if (i >= buflen)
(*(r->errHndl))(r);
if (*p != 0x01) {
buf[i++] = *p++;
plen--;
continue;
}
p++;
plen--;
if (qlen < 4)
(*(r->errHndl))(r);
base = q[0];
sign = 0;
if (base == 0) base = 16;
#if (REVISION == 1)
if (base == -3) base = 10;
#endif
if (base == -1) base = 10;
if (base < 0 || base > 16)
(*(r->errHndl))(r);
if (q[1] + i > buflen)
(*(r->errHndl))(r);
j = q[3];
if ((q[2] & 4) == 0) {
// jは符号付き整数.
if ((q[2] & 8) != 0 && j > 0) sign = '+';
if (j < 0) { sign = '-'; j *= -1; }
} else {
// jは符号無し整数.
if ((q[2] & 8) != 0 && j != 0) sign = '+';
}
for (k = q[1] - 1; k >= 0; k--) {
buf[i + k] = (j % base) + 0x10;
j = ((unsigned) j) / base;
}
k = 0;
if ((q[2] & 2) == 0 && j == 0) {
for (k = 0; k < q[1] - 1; k++) {
if (buf[i + k] != 0x10) break;
buf[i + k] = ' ';
}
}
if (sign != 0) {
if (k > 0) k--;
buf[i + k] = sign;
}
if ((q[2] & 1) != 0 && buf[i] == ' ') {
for (j = 0; k < q[1]; k++, j++)
buf[i + j] = buf[i + k];
i += j;
} else
i += q[1];
qlen -= 4;
q += 4;
}
return i;
}
void devFunc0004(int mod, int x0, int y0, int x1, int y1, int c)
{
int x, y;
if (mod == 0) {
for (y = y0; y <= y1; y++) {
for (x = x0; x <= x1; x++) {
vram[x + y * v_xsiz] = c;
}
}
} else {
for (y = y0; y <= y1; y++) {
for (x = x0; x <= x1; x++) {
if (mod == 1) vram[x + y * v_xsiz] |= c;
if (mod == 2) vram[x + y * v_xsiz] ^= c;
if (mod == 3) vram[x + y * v_xsiz] &= c;
}
}
}
return;
}
void devFunc(struct Regs *r)
{
FILE *fp;
r = (struct Regs *) (((char *) r) - 128); /* サイズを節約するためにEBPを128バイトずらしているのを元に戻す */
int i, c;
int x, y, len, dx, dy;
UCHAR *puc;
UCHAR pucbuf[256];
if (r->winClosed != 0)
longjmp(*(r->setjmpEnv), 1);
if (0xff44 <= r->ireg[0x30] && r->ireg[0x30] <= 0xff48) {
if (vram == NULL) {
v_xsiz = 640;
v_ysiz = 480;
vram = malloc(640 * 480 * 4);
drv_openWin(640, 480, (void *) vram, &r->winClosed);
r->autoSleep = 1;
for (i = 640 * 480 - 1; i >= 0; i--)
vram[i] = 0;
}
}
switch (r->ireg[0x30]) {
case 0xff00:
printf("R31=%d(dec)\n", r->ireg[0x31]);
break;
case 0xff01:
/* return: R30, P31 */
if (r->buf0 == NULL)
r->buf0 = malloc(1024 * 1024);
if (r->argc <= r->ireg[0x31]) {
fprintf(stderr, "devFunc: error: R30=ff01: argc error: R31=%08X\n", r->ireg[0x31]);
exit(1);
}
fp = fopen(r->argv[r->ireg[0x31]], "rb");
if (fp == NULL) {
fprintf(stderr, "devFunc: error: R30=ff01: fopen error: '%s'\n", r->argv[r->ireg[0x31]]);
exit(1);
}
i = fread(r->buf0, 1, 1024 * 1024 - 4, fp);
if (i >= 1024 * 1024 - 4 || i < 0) {
fprintf(stderr, "devFunc: error: R30=ff01: fread error: '%s'\n", r->argv[r->ireg[0x31]]);
exit(1);
}
fclose(fp);
r->preg[0x31].p = r->buf0;
r->preg[0x31].p0 = r->buf0;
r->preg[0x31].p1 = r->buf0 + i;
r->preg[0x31].typ = 3; // T_UINT8
r->ireg[0x30] = i;
break;
case 0xff02:
/* return: none */
if (r->argc <= r->ireg[0x31]) {
fprintf(stderr, "devFunc: error: R30=ff02: argc error: R31=%08X\n", r->ireg[0x31]);
exit(1);
}
fp = fopen(r->argv[r->ireg[0x31]], "wb");
if (fp == NULL) {
fprintf(stderr, "devFunc: error: R30=ff02: fopen error: '%s'\n", r->argv[r->ireg[0x31]]);
exit(1);
}
if (r->ireg[0x32] >= 1024 * 1024 || r->ireg[0x32] < 0){
fprintf(stderr, "devFunc: error: R30=ff02: fwrite error: R02=%08X\n", r->ireg[0x32]);
exit(1);
}
fwrite(r->preg[0x31].p, 1, r->ireg[0x32], fp);
fclose(fp);
break;
case 0xff03:
/* return: P31 */
if (r->buf1 == NULL)
r->buf1 = malloc(1024 * 1024);
r->preg[0x31].p = r->buf1;
r->preg[0x31].p0 = r->buf1;
r->preg[0x31].p1 = r->buf1 + 1024 * 1024;
break;
case 0xff04:
printf("P31.(p-p0)=%d(dec)\n", r->preg[0x31].p - r->preg[0x31].p0);
break;
case 0xff05:
fwrite(r->preg[0x31].p, 1, r->ireg[0x31], stdout);
break;
case 0xff06:
// R31はリターンコード.
// これを反映すべきだが、現状は手抜きでいつも正常終了.
longjmp(*(r->setjmpEnv), 1);
break;
case 0xff07:
// マシになった文字列表示.OSASK文字列に対応.offにすれば通常の文字列処理もできる.現状はonのみサポート.
checkString(r, 0x31, 0x31);
devFunc0001(r->ireg[0x31], r->preg[0x31].p, r);
break;
case 0xff08:
// JITC on JITC
// R31: 言語(back-end, front-end, ...
// R32: level
// R33: debugInfo1
checkString(r, 0x34, 0x31);
if (r->ireg[0x33] < 0 || r->ireg[0x33] > 15 || r->debugInfo1 > 15)
(*(r->errHndl))(r);
for (i = 0; i < r->maxLabels; i++)
r->label[i].opt = 0;
puc = r->preg[0x31].p;
i = jitCompiler(r->jitbuf, r->jitbuf1, puc, puc + r->ireg[0x34], puc, r->label, r->maxLabels, r->ireg[0x32], di1_serial, JITC_NOSTARTUP+0);
if (i == 0) {
i = jitCompiler(r->jitbuf, r->jitbuf1, puc, puc + r->ireg[0x34], puc, r->label, r->maxLabels, r->ireg[0x32], di1_serial, JITC_NOSTARTUP+JITC_PHASE1+0);
if (i >= 0) {
r->mapDi1s[r->debugInfo1][r->ireg[0x33]] = di1_serial;
di1_serial++;
r->ireg[0x30] = 0;
r->preg[0x31].p = r->jitbuf;
r->preg[0x31].typ = 0; // TYP_CODE
r->preg[0x31].p0 = r->jitbuf;
r->preg[0x31].p1 = r->jitbuf + 1;
//int j; for (j = 0; j < i; j++) printf("%02X ", r->jitbuf[j]); putchar('\n');
r->jitbuf += i;
static UCHAR ff08_ret[3] = { 0x1e, 0x3f, 0x30 };
i = jitCompiler(r->jitbuf, r->jitbuf1, ff08_ret, ff08_ret + 3, puc, r->label, r->maxLabels, r->ireg[0x32], -1, JITC_NOSTARTUP+JITC_PHASE1+0);
r->jitbuf += i;
break;
}
}
r->ireg[0x30] = -1;
break;
case 0xff09:
// たぶんbit7を使ったテキストはうまく処理できない(これはもはや仕様にしても問題ないかも).
checkString(r, 0x31, 0x31);
len = devFunc0016(sizeof pucbuf, pucbuf, r->ireg[0x31], r->preg[0x31].p, r->ireg[0x32], (int *) r->preg[0x32].p, r);
devFunc0001(len, pucbuf, r);
break;
case 0xff40:
/* R31とR32でサイズを指定 */
v_xsiz = r->ireg[0x31];
v_ysiz = r->ireg[0x32];
if (v_xsiz <= 0 || v_ysiz <= 0)
(*(r->errHndl))(r);
r->preg[0x31].p = (void *) (vram = malloc(v_xsiz * v_ysiz * 4));
r->preg[0x31].p0 = r->preg[0x31].p;
r->preg[0x31].p1 = r->preg[0x31].p + v_xsiz * v_ysiz * 4;
drv_openWin(r->ireg[0x31], r->ireg[0x32], r->preg[0x31].p, &r->winClosed);
// drv_flshWin(r->ireg[1], r->ireg[2], 0, 0);
r->autoSleep = 1;
for (i = v_xsiz * v_ysiz - 1; i >= 0; i--)
vram[i] = 0;
break;
case 0xff41:
/* R31とR32でサイズを指定、R33とR34でx0,y0指定 */
if (r->ireg[0x31] == -1) { r->ireg[0x31] = v_xsiz; r->ireg[0x33] &= 0; }
if (r->ireg[0x32] == -1) { r->ireg[0x32] = v_ysiz; r->ireg[0x34] &= 0; }
checkRect(r, 0x31);
drv_flshWin(r->ireg[0x31], r->ireg[0x32], r->ireg[0x33], r->ireg[0x34]);
break;
case 0xff42:
if (r->ireg[0x32] == -1) {
r->autoSleep = 1;
longjmp(*(r->setjmpEnv), 1);
}
if (r->ireg[0x32] < 0)
(*(r->errHndl))(r);
r->autoSleep = 0;
if ((r->ireg[0x31] & 1) == 0 && vram != NULL)
drv_flshWin(v_xsiz, v_ysiz, 0, 0);
for (;;) {
if (r->winClosed != 0)
longjmp(*(r->setjmpEnv), 1);
drv_sleep(r->ireg[0x32]);
if ((r->ireg[0x31] & 2) != 0 && keybuf_c <= 0) continue;
break;
}
break;
case 0xff43:
// 1:peek
// 2:stdin
// 4,8: ソース指定.
// 16: shift, lock系を有効化.
// 32: 左右のshift系を区別する.
if (r->ireg[0x31] == 2) { // なぜ3にしなかったのか...
r->ireg[0x30] = fgetc(stdin);
if (r->ireg[0x30] == EOF)
r->ireg[0x30] = -1;
break;
}
r->ireg[0x30] |= -1;
if (keybuf_c > 0) {
r->ireg[0x30] = keybuf[keybuf_r];
if ((r->ireg[0x31] & 16) == 0) r->ireg[0x30] &= 0x3e3effff;
if ((r->ireg[0x31] & 32) == 0) r->ireg[0x30] |= (r->ireg[0x30] >> 8) & 0xff0000;
if ((r->ireg[0x31] & 1) != 0) {
keybuf_c--;
keybuf_r = (keybuf_r + 1) & (KEYBUFSIZ - 1);
}
}
r->ireg[0x32] = r->ireg[0x33] = 0;
if (r->ireg[0x30] == 4132) r->ireg[0x32]--;
if (r->ireg[0x30] == 4133) r->ireg[0x33]--;
if (r->ireg[0x30] == 4134) r->ireg[0x32]++;
if (r->ireg[0x30] == 4135) r->ireg[0x33]++;
break;
case 0xff44:
c = loadColor(r, 0x34);
if (r->ireg[0x32] < 0 || r->ireg[0x32] >= v_xsiz || r->ireg[0x33] < 0 || r->ireg[0x33] >= v_ysiz)
(*(r->errHndl))(r);
if ((r->ireg[0x31] & 3) == 0) vram[r->ireg[0x32] + r->ireg[0x33] * v_xsiz] = c;
if ((r->ireg[0x31] & 3) == 1) vram[r->ireg[0x32] + r->ireg[0x33] * v_xsiz] |= c;
if ((r->ireg[0x31] & 3) == 2) vram[r->ireg[0x32] + r->ireg[0x33] * v_xsiz] ^= c;
if ((r->ireg[0x31] & 3) == 3) vram[r->ireg[0x32] + r->ireg[0x33] * v_xsiz] &= c;
break;
case 0xff45:
c = loadColor(r, 0x36);
if (r->ireg[0x32] < 0 || r->ireg[0x32] >= v_xsiz || r->ireg[0x33] < 0 || r->ireg[0x33] >= v_ysiz)
(*(r->errHndl))(r);
if (r->ireg[0x34] < 0 || r->ireg[0x34] >= v_xsiz || r->ireg[0x35] < 0 || r->ireg[0x35] >= v_ysiz)
(*(r->errHndl))(r);
dx = r->ireg[0x34] - r->ireg[0x32];
dy = r->ireg[0x35] - r->ireg[0x33];
x = r->ireg[0x32] << 10;
y = r->ireg[0x33] << 10;
if (dx < 0) dx = - dx;
if (dy < 0) dy = - dy;
if (dx >= dy) {
len = dx + 1; dx = 1024;
if (r->ireg[0x32] > r->ireg[0x34]) dx *= -1;
if (r->ireg[0x33] > r->ireg[0x35]) dy *= -1;
dy = (dy << 10) / len;
} else {
len = dy + 1; dy = 1024;
if (r->ireg[0x33] > r->ireg[0x35]) dy *= -1;
if (r->ireg[0x32] > r->ireg[0x34]) dx *= -1;
dx = (dx << 10) / len;
}
if ((r->ireg[0x31] & 3) == 0) {
for (i = 0; i < len; i++) {
vram[(x >> 10) + (y >> 10) * v_xsiz] = c;
x += dx;
y += dy;
}
break;
}
for (i = 0; i < len; i++) {
// if ((r->ireg[0x31] & 3) == 0) vram[(x >> 10) + (y >> 10) * v_xsiz] = c;
if ((r->ireg[0x31] & 3) == 1) vram[(x >> 10) + (y >> 10) * v_xsiz] |= c;
if ((r->ireg[0x31] & 3) == 2) vram[(x >> 10) + (y >> 10) * v_xsiz] ^= c;
if ((r->ireg[0x31] & 3) == 3) vram[(x >> 10) + (y >> 10) * v_xsiz] &= c;
x += dx;
y += dy;
}
break;
case 0xff46: // fillRect(opt:R31, xsiz:R32, ysiz:R33, x0:R34, y0:R35, c:R36)
c = loadColor(r, 0x36);
if (r->ireg[0x32] == -1) { r->ireg[0x32] = v_xsiz; r->ireg[0x34] &= 0; }
if (r->ireg[0x33] == -1) { r->ireg[0x33] = v_ysiz; r->ireg[0x35] &= 0; }
checkRect(r, 0x32);
int mod3 = r->ireg[0x31] & 3, x0 = r->ireg[0x34], y0 = r->ireg[0x35], x1 = r->ireg[0x34] + r->ireg[0x32] - 1, y1 = r->ireg[0x35] + r->ireg[0x33] - 1;
if ((r->ireg[0x31] & 0x20) == 0) {
devFunc0004(mod3, x0, y0, x1, y1, c);
} else { // drawRect
devFunc0004(mod3, x0, y0, x1, y0, c);
devFunc0004(mod3, x0, y1, x1, y1, c);
devFunc0004(mod3, x0, y0, x0, y1, c);
devFunc0004(mod3, x1, y0, x1, y1, c);
}
break;
case 0xff47: // fillOval(opt:R31, xsiz:R32, ysiz:R33, x0:R34, y0:R35, c:R36)
// これの計算精度はアーキテクチャに依存する.
c = loadColor(r, 0x36);
if (r->ireg[0x32] == -1) { r->ireg[0x32] = v_xsiz; r->ireg[0x34] &= 0; }
if (r->ireg[0x33] == -1) { r->ireg[0x33] = v_ysiz; r->ireg[0x35] &= 0; }
checkRect(r, 0x32);
double dcx = 0.5 * (r->ireg[0x32] - 1), dcy = 0.5 * (r->ireg[0x33] - 1), dcxy = (dcx + 0.5) * (dcy + 0.5) - 0.1;
dcxy *= dcxy;
mod3 = r->ireg[0x31] & 3;
x1 = r->ireg[0x32];
y1 = r->ireg[0x33];
if (mod3 == 0 && (r->ireg[0x31] & 0x20) == 0) {
for (y = 0; y < y1; y++) {
double dty = (y - dcy) * dcx;
for (x = 0; x < x1; x++) {
double dtx = (x - dcx) * dcy;
if (dtx * dtx + dty * dty > dcxy) continue;
vram[(x + r->ireg[0x34]) + (y + r->ireg[0x35]) * v_xsiz] = c;
}
}
} else {
#define DRAWOVALPARAM 1
double dcx1 = 0.5 * (r->ireg[0x32] - (1 + DRAWOVALPARAM * 2)), dcy1 = 0.5 * (r->ireg[0x33] - (1 + DRAWOVALPARAM * 2)), dcxy1 = (dcx1 + 0.5) * (dcy1 + 0.5) - 0.1;
dcxy1 *= dcxy1;
for (y = 0; y < y1; y++) {
double dty = (y - dcy) * dcx;
double dty1 = (y - dcy) * dcx1;
for (x = 0; x < x1; x++) {
double dtx = (x - dcx) * dcy;
double dtx1 = (x - dcx) * dcy1;
if (dtx * dtx + dty * dty > dcxy) continue;
if (DRAWOVALPARAM <= x && x < x1 - DRAWOVALPARAM && DRAWOVALPARAM <= y && y < y1 - DRAWOVALPARAM) {
if (dtx1 * dtx1 + dty1 * dty1 < dcxy1) continue;
}
if (mod3 == 0) vram[(x + r->ireg[0x34]) + (y + r->ireg[0x35]) * v_xsiz] = c;
if (mod3 == 1) vram[(x + r->ireg[0x34]) + (y + r->ireg[0x35]) * v_xsiz] |= c;
if (mod3 == 2) vram[(x + r->ireg[0x34]) + (y + r->ireg[0x35]) * v_xsiz] ^= c;
if (mod3 == 3) vram[(x + r->ireg[0x34]) + (y + r->ireg[0x35]) * v_xsiz] &= c;
}
}
}
break;
case 0xff48: // drawString(opt:R31, xsiz:R32, ysiz:R33, x0:R34, y0:R35, c:R36, s.len:R37, s.p:P31)
checkString(r, 0x37, 0x31);
devFunc0006(r->ireg[0x31], r->ireg[0x32], r->ireg[0x33], r->ireg[0x34], r->ireg[0x35], loadColor(r, 0x36), r->ireg[0x37], r->preg[0x31].p, r);
break;
case 0xff49: /* 適当な乱数を返す */
randStatNext();
UINT32 u32t;
u32t = randStat.stat[0] + (randStat.stat[2] >> 8);
r->ireg[0x30] = randStat.stat[3] ^ u32t ^ (-((SINT32)(u32t & 1)) & randStat.tmat);
if (r->ireg[0x31] > 0)
r->ireg[0x30] = (r->ireg[0x30] & 0x7fffffff) % (r->ireg[0x31] + 1);
break;
case 0xff4a: /* seedの指定 */
randStatInit(r->ireg[0x31]);
break;
case 0xff4b: /* 適当なseedを提供 */
r->ireg[0x30] = time(NULL) ^ 0x55555555;
break;
case 0xff4c:
checkString(r, 0x37, 0x31);
len = devFunc0016(sizeof pucbuf, pucbuf, r->ireg[0x37], r->preg[0x31].p, r->ireg[0x38], (int *) r->preg[0x32].p, r);
devFunc0006(r->ireg[0x31], r->ireg[0x32], r->ireg[0x33], r->ireg[0x34], r->ireg[0x35], loadColor(r, 0x36), len, pucbuf, r);
break;
case 0xff4d:
// bitblt(mod, xsiz, ysiz, xscale, yscale, x0, y0, lineskip, inv, p_buf, typ0, p_table, typ1);
// mod: 0x20:use_table, 0x40:inv_is_visible & typ1_is_color
puc = r->preg[0x31].p;
mod3 = r->ireg[0x31] & 3;
dx = r->ireg[0x34];
dy = r->ireg[0x35];
if (dy == 0) dy = dx;
if (r->ireg[0x32] == -1) { r->ireg[0x32] = v_xsiz / dx; r->ireg[0x36] &= 0; }
if (r->ireg[0x33] == -1) { r->ireg[0x33] = v_ysiz / dy; r->ireg[0x37] &= 0; }
for (y = 0; y < r->ireg[0x33]; y++) {
y0 = y * dy + r->ireg[0x37];
for (x = 0; x < r->ireg[0x32]; x++) {
x0 = x * dx + r->ireg[0x36];
c = iColor1[*puc++];
devFunc0004(mod3, x0, y0, x0 + dx, y0 + dy, c);
}
puc += r->ireg[0x38];
}
break;
default:
printf("devFunc: error: R30=%08X\n", r->ireg[0x30]);
exit(1);
}
return;
}
void putKeybuf(int i)
{
if (keybuf_c < KEYBUFSIZ) {
keybuf[keybuf_w] = i;
keybuf_c++;
keybuf_w = (keybuf_w + 1) & (KEYBUFSIZ - 1);
}
return;
}
/* tek5圧縮関係 */
#if (USE_TEK5 != 0)
int appackSub2(const UCHAR **pp, char *pif)
{
int r = 0;
const UCHAR *p = *pp;
if (*pif == 0) {
r = *p >> 4;
} else {
r = *p & 0x0f;
p++;
*pp = p;
}
*pif ^= 1;
return r;
}
int appackSub3u(const UCHAR **pp, char *pif)
{
int r = 0, i, j;
r = appackSub2(pp, pif);
if (0x8 <= r && r <= 0xb) {
r = r << 4 | appackSub2(pp, pif);
r &= 0x3f;
} else if (0xc <= r && r <= 0xd) {
r = r << 4 | appackSub2(pp, pif);
r = r << 4 | appackSub2(pp, pif);
r &= 0x1ff;
} else if (r == 0xe) {
r = appackSub2(pp, pif);
r = r << 4 | appackSub2(pp, pif);
r = r << 4 | appackSub2(pp, pif);
} else if (r == 0x7) {
i = appackSub3u(pp, pif);
r = 0;
while (i > 0) {
r = r << 4 | appackSub2(pp, pif);
i--;
}
}
return r;
}
int tek5Decomp(UCHAR *buf, UCHAR *buf1, UCHAR *tmp)
{
static char tek5head[16] = {
0x89, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
0x4f, 0x53, 0x41, 0x53, 0x4b, 0x43, 0x4d, 0x50
};
memcpy(tmp, tek5head, 16);
UCHAR *q = tmp + 16;
char iif = 0;
int i, tmpsiz;
const UCHAR *p = &buf[1];
i = appackSub3u(&p, &iif);
tmpsiz = appackSub3u(&p, &iif);
tmpsiz = tmpsiz << 8 | *p++;
*q++ = (tmpsiz >> 27) & 0xfe;
*q++ = (tmpsiz >> 20) & 0xfe;
*q++ = (tmpsiz >> 13) & 0xfe;
*q++ = (tmpsiz >> 6) & 0xfe;
*q++ = (tmpsiz << 1 | 1) & 0xff;
if (i == 1) *q++ = 0x15;
if (i == 2) *q++ = 0x19;
if (i == 3) *q++ = 0x21;
if (i >= 4) return -9;
while (p < buf1)
*q++ = *p++;
tek_decomp(tmp, buf, tmpsiz);
return tmpsiz;
}
#endif
/* ComLib関係 */
struct ComLib_Str {
const UCHAR *p;
int bitBuf, bitBufLen;
int tmp;
};
int ComLib_getBit(struct ComLib_Str *s)
{
if (s->bitBufLen == 0) {
s->bitBuf = s->p[0] | s->p[1] << 8;
s->p += 2;
s->bitBufLen |= 16;
}
s->bitBufLen--;
return (s->bitBuf >> s->bitBufLen) & 1;
}
int ComLib_getTmpBit(struct ComLib_Str *s)
{
s->tmp = (s->tmp << 1 | ComLib_getBit(s)) & 0xffff;
return ComLib_getBit(s);
}
UCHAR *ComLib_main(const UCHAR *p, UCHAR *q)
{
struct ComLib_Str s;
int i, dis;
dis |= -1;
s.p = p;
s.bitBufLen &= 0;
goto l1;
l0:
*q++ = *s.p++;
l1:
i = ComLib_getBit(&s);
if (i != 0) goto l0;
s.tmp = 1;
do {
i = ComLib_getTmpBit(&s);
if (s.tmp == 0) goto fin;
} while (i == 0);
if (s.tmp >= 3)
dis = ~((s.tmp - 3) << 8 | *s.p++);
s.tmp &= 0;
i = ComLib_getTmpBit(&s);
s.tmp = s.tmp << 1 | i;
if (s.tmp == 0) {
s.tmp |= 1;
do {
i = ComLib_getTmpBit(&s);
} while (i == 0);
s.tmp += 2;
}
s.tmp++;
if (dis < -0xd00) s.tmp++;
for (i = 0; i < s.tmp; i++)
q[i] = q[i + dis];
q += s.tmp;
goto l1;
fin:
return q;
}
/* JITC関係 */
#define JITC_ERR_MASK 255
#define JITC_ERR_PHASE0ONLY 256
#define JITC_ERR_REGNUM (1 | JITC_ERR_PHASE0ONLY)
#define JITC_ERR_DST1 (2 | JITC_ERR_PHASE0ONLY)
#define JITC_ERR_OPECODE (3 | JITC_ERR_PHASE0ONLY)
#define JITC_ERR_LABELNUM (4 | JITC_ERR_PHASE0ONLY)
#define JITC_ERR_LABELREDEF (5 | JITC_ERR_PHASE0ONLY)
#define JITC_ERR_PREFIX (6 | JITC_ERR_PHASE0ONLY)
#define JITC_ERR_LABELNODEF 7
#define JITC_ERR_LABELTYP 8
#define JITC_ERR_IDIOM 9
#define JITC_ERR_PREGNUM (10 | JITC_ERR_PHASE0ONLY)
#define JITC_ERR_SRC1 (11 | JITC_ERR_PHASE0ONLY)
#define JITC_ERR_BADTYPE (12 | JITC_ERR_PHASE0ONLY)
#define JITC_ERR_PREFIXFAR (13 | JITC_ERR_PHASE0ONLY)
#define JITC_ERR_INTERNAL 99
int jitCompCmdLen(const UCHAR *src)
{
int i = 1;
if (0x01 <= *src && *src < 0x04) i = 6;
if (*src == 0x04) i = 2;
if (0x08 <= *src && *src < 0x0d) i = 8 + src[7] * 4;
if (0x0e <= *src && *src < 0x10) i = 8;
if (0x10 <= *src && *src < 0x2e) i = 4;
if (0x1c <= *src && *src < 0x1f) i = 3;
if (*src == 0x1f) i = 11;
if (*src == 0x2f) i = 4 + src[1];
if (0x30 <= *src && *src <= 0x33) i = 4;
if (0x3c <= *src && *src <= 0x3d) i = 7;
if (*src == 0xfe) i = 2 + src[1];
return i;
}
#if (JITC_ARCNUM == 0x0001) /* x86-32bit */
/* 他のCPUへ移植する人へ:
以下は最適化のためのものなので、すべて0として簡単に移植しても問題ありません */
#define jitCompA0001_USE_R3F_CMPJMP 1*1
#define jitCompA0001_USE_R3F_IMM32 1*1
#define jitCompA0001_USE_R3F_IMM8 1*1
#define jitCompA0001_USE_R3F_INCDEC 1*1
#define jitCompA0001_OPTIMIZE_JMP 1*1
#define jitCompA0001_OPTIMIZE_MOV 1*1 /* 1にすると速度低下する? */
#define jitCompA0001_OPTIMIZE_CMP 1*1
#define jitCompA0001_OPTIMIZE_ALIGN 4*1 /* 0-8を想定 */
#define jitCompA0001_EBP128 128*1
struct JitCompWork {
UCHAR *dst, *dst0;
int err, maxLabels;
#if (jitCompA0001_USE_R3F_IMM32 != 0)
int r3f;
#endif
char prefix;
};
#define jitCompPutByte1(p, c0) *p++ = c0
#define jitCompPutByte2(p, c0, c1) *p++ = c0; *p++ = c1
#define jitCompPutByte3(p, c0, c1, c2) *p++ = c0; *p++ = c1; *p++ = c2
#define jitCompPutByte4(p, c0, c1, c2, c3) *p++ = c0; *p++ = c1; *p++ = c2; *p++ = c3
static inline void jitCompPutImm32(struct JitCompWork *w, int i)
{
jitCompPutByte1(w->dst, i & 0xff);
jitCompPutByte1(w->dst, (i >> 8) & 0xff);
jitCompPutByte1(w->dst, (i >> 16) & 0xff);
jitCompPutByte1(w->dst, (i >> 24) & 0xff);
return;
}
int jitCompGetImm32(const UCHAR *src)
{
return (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
}
int jitCompGetLabelNum(struct JitCompWork *w, const UCHAR *src)
{
int i = jitCompGetImm32(src);
if (i < 0 || i >= w->maxLabels) {
w->err = JITC_ERR_LABELNUM;
i = 0;
}
return i;
}
void jitCompA0001_85DispN(struct JitCompWork *w, int disp, int n)
{
disp -= jitCompA0001_EBP128;
if (-128 <= disp && disp <= 127) {
jitCompPutByte2(w->dst, 0x45 | (n << 3), disp & 0xff);
} else {
jitCompPutByte1(w->dst, 0x85 | (n << 3));
jitCompPutImm32(w, disp);
}
return;
}
void jitCompA0001_movEbpDispReg32(struct JitCompWork *w, int disp, int reg32)
{
jitCompPutByte1(w->dst, 0x89); /* MOV(mem, reg32); */
jitCompA0001_85DispN(w, disp, reg32);
return;
}
void jitCompA0001_movReg32EbpDisp(struct JitCompWork *w, int reg32, int disp)
{
jitCompPutByte1(w->dst, 0x8b); /* MOV(reg32, mem); */
jitCompA0001_85DispN(w, disp, reg32);
return;
}
void jitCompA0001_movEaxRxx(struct JitCompWork *w, int rxx)
{
#if (jitCompA0001_USE_R3F_IMM32 != 0)
if (rxx == 0x3f) {
jitCompPutByte1(w->dst, 0xb8); /* MOV(EAX, ?); */
jitCompPutImm32(w, w->r3f);
return;
}
#endif
if (rxx >= 0x40 || rxx < 0) w->err = JITC_ERR_REGNUM;
jitCompA0001_movReg32EbpDisp(w, 0 /* EAX */, rxx * 4); /* MOV(EAX, [EBP+?]); */
return;
}
void jitCompA0001_movRxxEax(struct JitCompWork *w, int rxx)
{
if (rxx >= 0x40 || rxx < 0) w->err = JITC_ERR_REGNUM;
jitCompA0001_movEbpDispReg32(w, rxx * 4, 0 /* EAX */); /* MOV([EBP+?], EAX); */
return;
}
void jitCompA0001_fixPrefix(struct JitCompWork *w)
{
if (w->prefix != 0) {
if (w->dst - w->dst0 > 127) w->err = JITC_ERR_REGNUM;
w->dst0[-1] = (UCHAR) ((w->dst - w->dst0) & 0xff);
}
return;
}
void jitCompA0001_checkCompPtr(struct JitCompWork *w, int p0, int p1)
{
if (p0 >= 0x3f || p0 < 0) w->err = JITC_ERR_PREGNUM;
if (p1 >= 0x3f || p1 < 0) w->err = JITC_ERR_PREGNUM;
/* 比較可能可能なのかのチェックのコードを出力 */ /* 未完成 */
return;
}
void jitCompA000_loadRegCacheAll(struct JitCompWork *w)
{
jitCompA0001_movReg32EbpDisp(w, 3 /* EBX */, 0 * 4); /* EBX = R00; */
jitCompA0001_movReg32EbpDisp(w, 1 /* ECX */, 1 * 4); /* ECX = R01; */
jitCompA0001_movReg32EbpDisp(w, 2 /* EDX */, 2 * 4); /* EDX = R02; */
return;
}
void jitCompA000_storeRegCacheAll(struct JitCompWork *w)
{
jitCompA0001_movEbpDispReg32(w, 0 * 4, 3 /* EBX */); /* R00 = EBX; */
jitCompA0001_movEbpDispReg32(w, 1 * 4, 1 /* ECX */); /* R01 = ECX; */
jitCompA0001_movEbpDispReg32(w, 2 * 4, 2 /* EDX */); /* R02 = EDX; */
return;
}
void jitCompA000_loadRegCacheEcx(struct JitCompWork *w)
{
jitCompA0001_movReg32EbpDisp(w, 1 /* ECX */, 1 * 4); /* ECX = R01; */
return;
}
void jitCompA000_storeRegCacheEcx(struct JitCompWork *w)
{
jitCompA0001_movEbpDispReg32(w, 1 * 4, 1 /* ECX */); /* R01 = ECX; */
return;
}
void jitCompA000_loadRegCacheEdx(struct JitCompWork *w)
{
jitCompA0001_movReg32EbpDisp(w, 2 /* EDX */, 2 * 4); /* EDX = R02; */
return;
}
void jitCompA000_storeRegCacheEdx(struct JitCompWork *w)
{
jitCompA0001_movEbpDispReg32(w, 2 * 4, 2 /* EDX */); /* R02 = EDX; */
return;
}
int jitCompA000_selectRegCache(int rxx, int reg)
{
if (rxx == 0) reg = 3; /* EBX */
if (rxx == 1) reg = 1; /* ECX */
if (rxx == 2) reg = 2; /* EDX */
return reg;
}
void jitCompA000_loadPRegCacheAll(struct JitCompWork *w)
{
// jitCompA0001_movReg32EbpDisp(w, 5 /* EBP */, 256 + 0 * 32 + 0); /* EBP = P00; */
jitCompA0001_movReg32EbpDisp(w, 6 /* ESI */, 256 + 1 * 32 + 0); /* ESI = P01; */
jitCompA0001_movReg32EbpDisp(w, 7 /* EDI */, 256 + 2 * 32 + 0); /* EDI = P02; */
return;
}
void jitCompA000_storePRegCacheAll(struct JitCompWork *w)
{
// jitCompA0001_movEbpDispReg32(w, 256 + 0 * 32 + 0, 5 /* EBP */); /* P00 = EBP; */
jitCompA0001_movEbpDispReg32(w, 256 + 1 * 32 + 0, 6 /* ESI */); /* P01 = ESI; */
jitCompA0001_movEbpDispReg32(w, 256 + 2 * 32 + 0, 7 /* EDI */); /* P02 = EDI; */
return;
}
int jitCompA000_selectPRegCache(int pxx, int reg)
{
// if (pxx == 0) reg = 5; /* EBP */
if (pxx == 1) reg = 6; /* ESI */
if (pxx == 2) reg = 7; /* EDI */
return reg;
}
int jitCompA000_convTyp(int t)
{
int r = -1;
if (1 <= t && t <= 7) r = t;
if (8 <= t && t <= 13) r = 2 | (t & 1);
if (14 <= t && t <= 15) r = 4 | (t & 1);
if (16 <= t && t <= 21) r = 6 | (t & 1);
return r;
}
int jitCompA000_dataWidth(int t)
{
int r = -1;
if (t == 0x0001) r = 256;
t >>= 1;
if (t == 0x0002 / 2) r = 8;
if (t == 0x0004 / 2) r = 16;
if (t == 0x0006 / 2) r = 32;
if (t == 0x0008 / 2) r = 4;
if (t == 0x000a / 2) r = 2;
if (t == 0x000c / 2) r = 1;
if (t == 0x000e / 2) r = 12;
if (t == 0x0010 / 2) r = 20;
if (t == 0x0012 / 2) r = 24;
if (t == 0x0014 / 2) r = 28;
return r;
}
static UCHAR *errfnc;
void jitCompA0001_checkType0(struct JitCompWork *w, int pxx, int typ, int ac)
{
if (typ <= 0) { w->err = JITC_ERR_BADTYPE; }
if (typ > 0x7f) { w->err = JITC_ERR_INTERNAL; }
jitCompA0001_movReg32EbpDisp(w, 0 /* EAX */, 256 + pxx * 32 + 4); /* MOV(EAX, [EBP+?]); */ /* typ */
jitCompPutByte3(w->dst, 0x83, 0xf8, typ & 0x7f); /* CMP(EAX, ?); */
jitCompPutByte2(w->dst, 0x0f, 0x85); /* JNE */
jitCompPutImm32(w, errfnc - (w->dst + 4));
return;
}
void jitCompA0001_checkType(struct JitCompWork *w, int pxx, int typ, int ac)
// data用.
// 将来的にはaliveやアクセス権チェックも入れる
{
jitCompA0001_checkType0(w, pxx, typ, ac);
return;
}
void jitCompA0001_checkLimit(struct JitCompWork *w, int reg, int pxx)
{
jitCompPutByte1(w->dst, 0x3b); /* CMP(reg, [EBP+?]); */
jitCompA0001_85DispN(w, 256 + pxx * 32 + 8, reg); /* p0 */
jitCompPutByte2(w->dst, 0x0f, 0x82); /* JB */
jitCompPutImm32(w, errfnc - (w->dst + 4));
jitCompPutByte1(w->dst, 0x3b); /* CMP(reg, [EBP+?]); */
jitCompA0001_85DispN(w, 256 + pxx * 32 + 12, reg); /* p1 */
jitCompPutByte2(w->dst, 0x0f, 0x83); /* JAE */
jitCompPutImm32(w, errfnc - (w->dst + 4));
return;
}
void func3c(char *ebp, int opt, int r1, int p1, int lenR, int lenP, int r0, int p0);
void func3d(char *ebp, int opt, int r1, int p1, int lenR, int lenP, int r0, int p0);
void funcf4(char *ebp, int pxx, int typ, int len);
void funcf5(char *ebp, int pxx, int typ, int len); // pxxはダミーで参照されない.
void funcf6(char *ebp, int pxx, int typ, int len);
void funcf7(char *ebp, int pxx, int typ, int len); // typとlenはダミーで参照されない.
// F5の場合、decoderが対応するalloc-freeを結びつけるのが簡単で、typやlenを指定必須にしてもフロントエンドコードに影響はない.
void errHndl(struct Regs *r);
int jitCompiler(UCHAR *dst, UCHAR *dst1, const UCHAR *src, const UCHAR *src1, const UCHAR *src0, struct LabelTable *label, int maxLabels, int level, int debugInfo1, int flags)
/* IA-32用 */
/* 本来ならこのレイヤでは文法チェックしない */
{
struct JitCompWork w;
UCHAR *dst00 = dst, *errmsg = "", *enter0 = NULL, *tmp_ucp;
const UCHAR *oldsrc;
int timecount = 0, i, j, lastlabel = -1, debugInfo0 = -1;
int reg0, reg1, reg2, cmp0reg = -1, cmp0lev = 0;
w.dst = w.dst0 = dst;
w.err = 0;
w.maxLabels = maxLabels;
if ((flags & JITC_NOSTARTUP) == 0) {
jitCompPutByte1(w.dst, 0x60); /* PUSHAD(); */
jitCompA000_loadRegCacheAll(&w); /* start-up */
jitCompA000_loadPRegCacheAll(&w);
}
if (level <= JITC_LV_SLOWER) {
jitCompPutByte2(w.dst, 0x31, 0xc0); /* XOR(EAX, EAX); */
jitCompA0001_movEbpDispReg32(&w, 2304 + 0, 0 /* EAX */); /* MOV(debugInfo0, EAX); */
jitCompPutByte1(w.dst, 0xb8); /* MOV(EAX, ?); */
jitCompPutImm32(&w, debugInfo1);
jitCompA0001_movEbpDispReg32(&w, 2304 + 4, 0 /* EAX */); /* MOV(debugInfo1, EAX); */
}
while (src < src1) {
w.prefix = 0;
if (w.dst + 256 > dst1) { w.err = JITC_ERR_DST1; goto err_w; }
timecount++;
if (timecount >= 64) {
timecount -= 64;
/* 未完成(timeoutチェックコードを入れる) */
}
prefix_continue:
switch (*src) {
case 0x00: /* NOP */
if (w.prefix != 0) { w.err = JITC_ERR_PREFIX; goto err_w; }
break;
case 0x01: /* LB */
if (enter0 == NULL && (src[6] == 0x3c || (src[6] == 0xfe && src[7] == 0x01 && src[9] == 0x3c))) {
jitCompPutByte1(w.dst, 0xe9);
enter0 = w.dst;
jitCompPutImm32(&w, 0);
}
if (src[6] == 0x34) {
tmp_ucp = w.dst;
jitCompPutByte1(w.dst, 0xe9);
i = jitCompGetImm32(&src[7]);
j = 32;
if (i != 1) {
i = jitCompA000_convTyp(i);
j = 0;
if (i == 2 || i == 3) { j = 1; }
if (i == 4 || i == 5) { j = 2; }
if (i == 6 || i == 7) { j = 4; }
}
j *= jitCompGetImm32(&src[11]);
if (j <= 0) w.err = JITC_ERR_BADTYPE;
jitCompPutImm32(&w, j);
#if (jitCompA0001_OPTIMIZE_JMP != 0)
if (j <= 127 - jitCompA0001_OPTIMIZE_ALIGN) {
w.dst -= 5;
jitCompPutByte2(w.dst, 0xeb, j);
}
#endif
}
#if (jitCompA0001_OPTIMIZE_ALIGN != 0)
for (;;) {
i = ((int) w.dst) & (jitCompA0001_O