Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takeutch-kemeco/9703915 to your computer and use it in GitHub Desktop.
Save takeutch-kemeco/9703915 to your computer and use it in GitHub Desktop.
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_OPTIMIZE_ALIGN - 1); /* ALIGNで割ったあまりを計算 */
if (i == 0) break;
i = jitCompA0001_OPTIMIZE_ALIGN - i;
if (i == 1) { jitCompPutByte1(w.dst, 0x90); j += i; } /* NOP(); */
if (i == 2) { jitCompPutByte2(w.dst, 0x89, 0xc0); j += i; } /* MOV(EAX, EAX); */
if (i == 3) { jitCompPutByte3(w.dst, 0x8d, 0x76, 0x00); j += i; } /* LEA(ESI, [ESI+0]); */
if (i == 4) { jitCompPutByte4(w.dst, 0x8d, 0x74, 0x26, 0x00); j += i; } /* LEA(ESI, [ESI*1+0]); */
if (i == 5) { jitCompPutByte1(w.dst, 0x0d); jitCompPutImm32(&w, 0); j += i; } /* OR(EAX, 0); */
if (i == 6) { jitCompPutByte2(w.dst, 0x8d, 0xb6); jitCompPutImm32(&w, 0); j += i; } /* LEA(ESI, [ESI+0]); */
if (i >= 7) { jitCompPutByte3(w.dst, 0x8d, 0xb4, 0x26); jitCompPutImm32(&w, 0); j += 7; } /* LEA(ESI, [ESI*1+0]); */
}
#endif
if (src[6] == 0x34) {
tmp_ucp[1] = j & 0xff;
if (*tmp_ucp == 0xe9) {
tmp_ucp[2] = (j >> 8) & 0xff;
tmp_ucp[3] = (j >> 16) & 0xff;
tmp_ucp[4] = (j >> 24) & 0xff;
}
}
if ((flags & JITC_PHASE1) == 0) {
i = jitCompGetLabelNum(&w, src + 2);
//printf("i=%06X %06X\n", i, src-src0);
if (label[i].opt != 0 && w.err == 0) { w.err = JITC_ERR_LABELREDEF; goto err_w; }
if (w.prefix != 0) { w.err = JITC_ERR_PREFIX; goto err_w; }
label[i].opt = src[1] + 1;
label[i].typ = 0; /* TYP_CODE */
label[i].p = w.dst;
label[i].p1 = w.dst + 1;
lastlabel = i;
}
cmp0reg = -1;
timecount = 0;
/* 未完成(timeoutチェックコードを入れる) */
break;
case 0x02: /* LIMM */
if (src[1] == 0x3f && w.prefix != 0) w.err = JITC_ERR_PREFIX;
#if (jitCompA0001_USE_R3F_IMM32 != 0)
if (src[1] == 0x3f) {
w.r3f = jitCompGetImm32(src + 2);
break;
}
#endif
i = jitCompGetImm32(src + 2);
reg0 = jitCompA000_selectRegCache(src[1], 0 /* EAX */);
#if (jitCompA0001_OPTIMIZE_MOV != 0)
if (i == 0) {
jitCompPutByte2(w.dst, 0x31, 0xc0 | reg0 << 3 | reg0); /* XOR(reg0, reg0); */
jitCompA0001_movRxxEax(&w, src[1]);
break;
}
#endif
jitCompPutByte1(w.dst, 0xb8 | reg0); /* MOV(reg0, ?); */
jitCompPutImm32(&w, i);
if (reg0 == 0)
jitCompA0001_movRxxEax(&w, src[1]);
break;
case 0x03: /* PLIMM */ /* 未完成(plsまで対応) */
i = jitCompGetLabelNum(&w, src + 2);
if ((flags & JITC_PHASE1) != 0 && w.err == 0) {
if (label[i].opt == 0) { w.err = JITC_ERR_LABELNODEF; goto err_w; }
if (src[1] != 0x3f && label[i].opt != 2) { w.err = JITC_ERR_LABELTYP; goto err_w; }
if (src[1] == 0x3f && label[i].typ != 0) { w.err = JITC_ERR_LABELTYP; goto err_w; }
}
if (src[1] == 0x3f) {
if (w.prefix == 0) {
jitCompPutByte1(w.dst, 0xe9); /* JMP(?); */
} else {
w.dst[-1] = w.dst[-2] ^ 0xf1; /* 74->85, 75->84 */
w.dst[-2] = 0x0f;
w.prefix = 0;
}
j = 0;
if ((flags & JITC_PHASE1) != 0 || ((flags & JITC_PHASE1) == 0) && label[i].opt != 0)
j = label[i].p - (w.dst + 4);
jitCompPutImm32(&w, j);
#if (jitCompA0001_OPTIMIZE_JMP != 0)
if (-128 - 3 <= j && j < 0) {
if (w.dst[-5] == 0xe9) {
j += 3;
w.dst -= 5;
jitCompPutByte1(w.dst, 0xeb); /* JMP(?); */
} else {
j += 4;
w.dst -= 6;
w.dst[0] = w.dst[1] ^ 0xf0;
w.dst += 1;
}
jitCompPutByte1(w.dst, j & 0xff);
}
#endif
} else {
reg0 = jitCompA000_selectPRegCache(src[1], 0 /* EAX */);
jitCompPutByte1(w.dst, 0xb8 | reg0); /* MOV(reg0, ?); */
jitCompPutImm32(&w, (int) label[i].p);
if (reg0 == 0)
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32, 0); /* MOV([EBP+?], EAX); */
if (level < JITC_LV_FASTEST) {
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + 8, reg0); /* MOV([EBP+?], reg0); */ /* p0 */
jitCompPutByte1(w.dst, 0xb8); /* MOV(EAX, ?); */
jitCompPutImm32(&w, label[i].typ);
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + 4, 0); /* MOV([EBP+?], EAX); */ /* typ */
jitCompPutByte1(w.dst, 0xb8); /* MOV(EAX, ?); */
jitCompPutImm32(&w, (int) label[i].p1);
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + 12, 0); /* MOV([EBP+?], EAX); */ /* p1 */
jitCompPutByte2(w.dst, 0x31, 0xc0); /* XOR(EAX, EAX); */
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + 16, 0); /* MOV([EBP+?], EAX); */ /* liveSign */
jitCompA0001_movReg32EbpDisp(&w, 0, 2320); /* MOV(EAX, ptrCtrl); */
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + 20, 0); /* MOV([EBP+?], EAX); */ /* pls */
}
}
break;
case 0x04: /* CND (prefix) */
if (src[1] >= 0x40) w.err = JITC_ERR_REGNUM;
reg0 = jitCompA000_selectRegCache(src[1], -1 /* mem */);
if (reg0 < 0) {
jitCompPutByte1(w.dst, 0xf7); /* TEST([EBP+?],1); */
jitCompA0001_85DispN(&w, src[1] * 4, 0);
} else {
jitCompPutByte2(w.dst, 0xf7, 0xc0 | reg0); /* TEST(reg0,1); */
}
jitCompPutImm32(&w, 1);
jitCompPutByte2(w.dst, 0x74, 0x00); /* JZ($+2) */
cmp0reg = -1;
if (w.err != 0) goto err_w;
src += 2;
w.prefix = 1;
w.dst0 = w.dst;
goto prefix_continue;
case 0x08: /* LMEM */ /* 完成 */
i = jitCompGetImm32(src + 2);
if (i == 0x0001) w.err = JITC_ERR_BADTYPE;
if (level < JITC_LV_FASTER) {
jitCompA0001_checkType(&w, src[6], i, 0); // read
cmp0reg = -1;
}
reg0 = jitCompA000_selectRegCache(src[1], 0 /* EAX */);
reg1 = jitCompA000_selectPRegCache(src[6], 2 /* EDX */);
if (reg0 != 0 /* EAX */ && reg1 == 2 /* EDX */)
reg1 = 0; /* EAX */
if (reg1 == 2 /* EDX */)
jitCompA000_storeRegCacheEdx(&w);
if (reg1 <= 3 /* EAX, EDX */)
jitCompA0001_movReg32EbpDisp(&w, reg1, 256 + src[6] * 32 + 0); /* MOV(reg1, [EBP+?]); */
if (level < JITC_LV_FASTER)
jitCompA0001_checkLimit(&w, reg1, src[6]);
i = jitCompA000_convTyp(jitCompGetImm32(src + 2));
switch (i) {
case 0x0002:
jitCompPutByte3(w.dst, 0x0f, 0xbe, reg0 << 3 | reg1); /* MOVSX(reg0,BYTE [reg1]); */
break;
case 0x0003:
jitCompPutByte3(w.dst, 0x0f, 0xb6, reg0 << 3 | reg1); /* MOVZX(reg0,BYTE [reg1]); */
break;
case 0x0004:
jitCompPutByte3(w.dst, 0x0f, 0xbf, reg0 << 3 | reg1); /* MOVSX(reg0,WORD [reg1]); */
break;
case 0x0005:
jitCompPutByte3(w.dst, 0x0f, 0xb7, reg0 << 3 | reg1); /* MOVZX(reg0,WORD [reg1]); */
break;
case 0x0006:
case 0x0007:
jitCompPutByte2(w.dst, 0x8b, reg0 << 3 | reg1); /* MOV(reg0, [reg1]); */
break;
default:
w.err = JITC_ERR_BADTYPE;
}
if (reg0 == 0 /* EAX */)
jitCompA0001_movRxxEax(&w, src[1]);
if (reg1 == 2 /* EDX */)
jitCompA000_loadRegCacheEdx(&w);
break;
case 0x09: /* SMEM */ /* 完成 */
i = jitCompGetImm32(src + 2);
if (i == 0x0001) w.err = JITC_ERR_BADTYPE;
if (level < JITC_LV_FASTER) {
jitCompA0001_checkType(&w, src[6], i, 1); // write
cmp0reg = -1;
}
reg0 = jitCompA000_selectRegCache(src[1], 0 /* EAX */);
reg1 = jitCompA000_selectPRegCache(src[6], 2 /* EDX */);
if (reg0 != 0 /* EAX */ && reg1 == 2 /* EDX */)
reg1 = 0; /* EAX */
if (reg1 == 2 /* EDX */)
jitCompA000_storeRegCacheEdx(&w);
if (reg1 <= 3 /* EAX, EDX */)
jitCompA0001_movReg32EbpDisp(&w, reg1, 256 + src[6] * 32 + 0); /* MOV(reg1, [EBP+?]); */
if (level < JITC_LV_FASTER)
jitCompA0001_checkLimit(&w, reg1, src[6]);
if (reg0 == 0 /* EAX */)
jitCompA0001_movEaxRxx(&w, src[1]);
/* 値の範囲チェック */
i = jitCompA000_convTyp(jitCompGetImm32(src + 2));
switch (i) {
case 0x0002:
case 0x0003:
jitCompPutByte2(w.dst, 0x88, reg0 << 3 | reg1); /* MOV([reg1], BYTE(reg0)); */
break;
case 0x0004:
case 0x0005:
jitCompPutByte3(w.dst, 0x66, 0x89, reg0 << 3 | reg1); /* MOV([reg1], WORD(reg0)); */
break;
case 0x0006:
case 0x0007:
jitCompPutByte2(w.dst, 0x89, reg0 << 3 | reg1); /* MOV([reg1], reg0); */
break;
default:
w.err = JITC_ERR_BADTYPE;
}
if (reg1 == 2 /* EDX */)
jitCompA000_loadRegCacheEdx(&w);
break;
case 0x0a: /* PLMEM */ /* 完成 */
i = jitCompGetImm32(src + 2);
if (i != 0x0001) w.err = JITC_ERR_BADTYPE;
if (level < JITC_LV_FASTER) {
jitCompA0001_checkType(&w, src[6], i, 0); // read
cmp0reg = -1;
}
reg0 = jitCompA000_selectPRegCache(src[1], 0 /* EAX */);
reg1 = jitCompA000_selectPRegCache(src[6], 2 /* EDX */);
// if (reg0 != 0 /* EAX */ && reg1 == 2 /* EDX */) /* これをやってはいけない!(by K, 2013.08.02) */
// reg1 = 0; /* EAX */
if (reg0 == reg1 && reg0 != 0) { // bugfix: hinted by yao, 2013.09.14. thanks!
jitCompA000_storePRegCacheAll(&w);
reg1 = 2; /* EDX */
}
if (reg1 == 2 /* EDX */)
jitCompA000_storeRegCacheEdx(&w);
if (reg1 <= 3 /* EAX, EDX */)
jitCompA0001_movReg32EbpDisp(&w, reg1, 256 + src[6] * 32 + 0); /* MOV(reg1, [EBP+?]); */
if (level < JITC_LV_FASTER)
jitCompA0001_checkLimit(&w, reg1, src[6]);
jitCompPutByte2(w.dst, 0x8b, reg0 << 3 | reg1); /* MOV(reg0, [reg1]); */
if (reg0 == 0 /* EAX */)
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + 0, 0); /* MOV([EBP+?], EAX); */
for (i = 4; i < 32; i += 4) {
jitCompPutByte3(w.dst, 0x8b, 0x40 | reg1, i); /* MOV(EAX, [reg1+?]); */
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + i, 0 /* EAX */); /* MOV([EBP+?], EAX); */
}
if (reg1 == 2 /* EDX */)
jitCompA000_loadRegCacheEdx(&w);
break;
case 0x0b: /* PSMEM */ /* 完成 */
i = jitCompGetImm32(src + 2);
if (i != 0x0001) w.err = JITC_ERR_BADTYPE;
if (level < JITC_LV_FASTER) {
jitCompA0001_checkType(&w, src[6], i, 1); // write
cmp0reg = -1;
}
reg0 = jitCompA000_selectPRegCache(src[1], 0 /* EAX */);
reg1 = jitCompA000_selectPRegCache(src[6], 2 /* EDX */);
// if (reg0 != 0 /* EAX */ && reg1 == 2 /* EDX */) /* これをやってはいけない!(by K, 2013.08.02) */
// reg1 = 0; /* EAX */
if (reg1 == 2 /* EDX */)
jitCompA000_storeRegCacheEdx(&w);
if (reg1 <= 3 /* EAX, EDX */)
jitCompA0001_movReg32EbpDisp(&w, reg1, 256 + src[6] * 32 + 0); /* MOV(reg1, [EBP+?]); */
if (level < JITC_LV_FASTER)
jitCompA0001_checkLimit(&w, reg1, src[6]);
if (reg0 == 0 /* EAX */)
jitCompA0001_movReg32EbpDisp(&w, reg0, 256 + src[1] * 32 + 0); /* MOV(reg0, [EBP+?]); */
jitCompPutByte2(w.dst, 0x89, reg0 << 3 | reg1); /* MOV([reg1], reg0); */
for (i = 4; i < 32; i += 4) {
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, 256 + src[1] * 32 + i); /* MOV(EAX, [EBP+?]); */
jitCompPutByte3(w.dst, 0x89, 0x40 | reg1, i); /* MOV([reg1+?], EAX); */
}
if (reg1 == 2 /* EDX */)
jitCompA000_loadRegCacheEdx(&w);
break;
case 0x0e: /* PADD */ /* 完成 */
if (level < JITC_LV_FASTER) {
jitCompA0001_checkType0(&w, src[6], jitCompGetImm32(src + 2), 2); // other, aliveテストはとりあえずしない.
cmp0reg = -1;
}
reg0 = jitCompA000_selectPRegCache(src[1], 0 /* EAX */);
reg1 = jitCompA000_selectPRegCache(src[6], -1 /* mem */);
if (reg1 < 0 /* mem */)
jitCompA0001_movReg32EbpDisp(&w, reg0, 256 + src[6] * 32 + 0); /* MOV(reg0, [EBP+?]); */
if (reg1 >= 0 && reg0 != reg1) {
jitCompPutByte2(w.dst, 0x89, 0xc0 | reg1 << 3 | reg0); /* MOV(reg0, reg1); */
}
i = jitCompGetImm32(src + 2);
j = -1;
if (i == 1)
j = 5; /* 32 */
else {
i = jitCompA000_convTyp(i);
if (0x0002 <= i && i <= 0x0007)
j = (i - 0x0002) >> 1;
}
if (j < 0) { w.err = JITC_ERR_BADTYPE; goto err_w; }
#if (jitCompA0001_USE_R3F_IMM32 != 0)
if (src[7] == 0x3f) {
j = w.r3f << j;
#if (jitCompA0001_USE_R3F_IMM8 != 0)
if (-0x80 <= j && j <= 0x7f) {
#if (jitCompA0001_USE_R3F_INCDEC != 0)
if (j == 1) { jitCompPutByte1(w.dst, 0x40 | reg0); goto padd1; } /* INC */
if (j == -1) { jitCompPutByte1(w.dst, 0x48 | reg0); goto padd1; } /* DEC */
#endif
jitCompPutByte3(w.dst, 0x83, 0xc0 | reg0, j & 0xff); /* ADD(reg0, im8); */
goto padd1;
}
#endif
if (reg0 == 0) {
jitCompPutByte1(w.dst, 0x05); /* ADD(reg0, ?); */
} else {
jitCompPutByte2(w.dst, 0x81, 0xc0 | reg0); /* ADD(reg0, ?); */
}
jitCompPutImm32(&w, j);
goto padd1;
}
#endif
if (src[7] >= 0x40) w.err = JITC_ERR_REGNUM;
if (j == 0) {
reg1 = jitCompA000_selectRegCache(src[7], -1 /* mem */);
if (reg1 >= 0) {
jitCompPutByte2(w.dst, 0x01, 0xc0 | reg1 << 3 | reg0); /* ADD(reg0, reg1); */
} else {
jitCompPutByte1(w.dst, 0x03); /* ADD(reg0, [EBP+?]); */
jitCompA0001_85DispN(&w, src[7] * 4, reg0);
}
} else {
reg1 = jitCompA000_selectRegCache(src[7], -1 /* mem */);
reg2 = 2; /* EDX */
jitCompA000_storeRegCacheEdx(&w);
if (reg1 < 0)
jitCompA0001_movReg32EbpDisp(&w, reg2, src[7] * 4); /* MOV(reg2, [EBP+?]); */
if (reg1 >= 0 && reg1 != reg2) {
jitCompPutByte2(w.dst, 0x89, 0xc0 | reg1 << 3 | reg2); /* MOV(reg2, reg1); */
}
jitCompPutByte3(w.dst, 0xc1, 0xe0 | reg2, j); /* SHL(reg2, ?); */
jitCompPutByte2(w.dst, 0x01, 0xc0 | reg2 << 3 | reg0); /* ADD(reg0, reg2); */
jitCompA000_loadRegCacheEdx(&w);
}
#if (jitCompA0001_USE_R3F_IMM32 != 0)
padd1:
#endif
if (reg0 == 0 /* EAX */)
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + 0, reg0); /* MOV([EBP+?], reg0); */
if (src[1] != src[6]) {
for (i = 4; i < 32; i += 4) {
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, 256 + src[6] * 32 + i); /* MOV(EAX, [EBP+?]); */
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + i, 0 /* EAX */); /* MOV([EBP+?], EAX); */
}
}
cmp0reg = -1;
break;
case 0x0f: /* PDIF */ /* 未完成 */
reg0 = jitCompA000_selectRegCache(src[1], 0 /* EAX */);
jitCompA000_storePRegCacheAll(&w); // 手抜き.
jitCompA0001_checkCompPtr(&w, src[6], src[7]);
jitCompA0001_movReg32EbpDisp(&w, reg0, 256 + src[6] * 32 + 0); /* MOV(reg0, [EBP+?]); */
jitCompPutByte1(w.dst, 0x2b); /* SUB(EAX, [EBP+?]); */
jitCompA0001_85DispN(&w, 256 + src[7] * 32 + 0, reg0);
i = jitCompA000_convTyp(jitCompGetImm32(src + 2));
j = -1;
if (0x0002 <= i && i <= 0x0007)
j = (i - 0x0002) >> 1;
if (j < 0) { w.err = JITC_ERR_BADTYPE; goto err_w; }
if (j > 0) {
jitCompPutByte3(w.dst, 0xc1, 0xf8 | reg0, j); /* SAR(reg0,?); */
}
if (reg0 == 0 /* EAX */)
jitCompA0001_movRxxEax(&w, src[1]);
cmp0reg = src[1]; cmp0lev = 1;
break;
case 0x10: /* OR */
case 0x11: /* XOR */
case 0x12: /* AND */
case 0x14: /* ADD */
case 0x15: /* SUB */
case 0x16: /* MUL */
if (src[1] >= 0x3f) w.err = JITC_ERR_REGNUM;
reg0 = jitCompA000_selectRegCache(src[1], 0 /* EAX */);
reg1 = jitCompA000_selectRegCache(src[2], -1 /* mem */);
#if (jitCompA0001_USE_R3F_IMM32 != 0)
if (src[2] == 0x3f) { // SUBのみ該当.
if (*src != 0x15) w.err = JITC_ERR_REGNUM;
reg2 = jitCompA000_selectRegCache(src[3], -1 /* mem */);
if (reg2 >= 0)
jitCompA000_storeRegCacheAll(&w);
jitCompPutByte1(w.dst, 0xb8 | reg0); /* MOV(reg0, ?); */
jitCompPutImm32(&w, w.r3f);
jitCompPutByte1(w.dst, 0x2b);
jitCompA0001_85DispN(&w, src[3] * 4, reg0);
if (reg0 == 0)
jitCompA0001_movRxxEax(&w, src[1]);
break;
}
#endif
if (reg1 < 0) {
jitCompA0001_movReg32EbpDisp(&w, reg0, src[2] * 4); /* MOV(reg0, [EBP+?]); */
}
if (reg1 >= 0 && reg0 != reg1) {
jitCompPutByte2(w.dst, 0x89, 0xc0 | reg1 << 3 | reg0); /* MOV(reg0, reg1); */
}
if (!(src[0] == 0x10 && src[3] == 0xff)) { // bugfix: hinted by Iris, 2013.06.26. thanks!
cmp0reg = src[1];
cmp0lev = 1;
if (src[0] < 0x14)
cmp0lev = 2;
if (src[0] == 0x16)
cmp0reg = -1;
}
if (!(src[0] == 0x10 && src[3] == 0xff)) {
#if (jitCompA0001_USE_R3F_IMM32 != 0)
if (src[3] == 0x3f) {
if (*src == 0x16 && w.r3f == -1) {
jitCompPutByte2(w.dst, 0xf7, 0xd8 | reg0); /* NEG(reg0); */
if (reg0 == 0)
jitCompA0001_movRxxEax(&w, src[1]);
break;
}
#if (jitCompA0001_USE_R3F_INCDEC != 0)
if ((*src == 0x14 && w.r3f == 1) || (*src == 0x15 && w.r3f == -1)) {
jitCompPutByte1(w.dst, 0x40 | reg0); /* INC(reg0); */
if (reg0 == 0)
jitCompA0001_movRxxEax(&w, src[1]);
break;
}
if ((*src == 0x15 && w.r3f == 1) || (*src == 0x14 && w.r3f == -1)) {
jitCompPutByte1(w.dst, 0x48 | reg0); /* DEC(reg0); */
if (reg0 == 0)
jitCompA0001_movRxxEax(&w, src[1]);
break;
}
#endif
#if (jitCompA0001_USE_R3F_IMM8 != 0)
if (-0x80 <= w.r3f && w.r3f <= 0x7f) {
if (*src != 0x16) {
static UCHAR basic_op_table_im8[] = { 0xc8, 0xf0, 0xe0, 0, 0xc0, 0xe8 };
jitCompPutByte3(w.dst, 0x83, basic_op_table_im8[*src - 0x10] | reg0, w.r3f & 0xff);
} else {
jitCompPutByte3(w.dst, 0x6b, 0xc0 | reg0 << 3 | reg0, w.r3f & 0xff);
}
if (reg0 == 0)
jitCompA0001_movRxxEax(&w, src[1]);
break;
}
#endif
if (reg0 == 0 /* EAX */) {
static UCHAR basic_op_table_im32_eax[] = { 0x0d, 0x35, 0x25, 0, 0x05, 0x2d, 0xc0 };
if (*src == 0x16) { jitCompPutByte1(w.dst, 0x69); }
jitCompPutByte1(w.dst, basic_op_table_im32_eax[*src - 0x10]);
} else {
if (*src != 0x16) {
static UCHAR basic_op_table_im32_reg[] = { 0xc8, 0xf0, 0xe0, 0, 0xc0, 0xe8 };
jitCompPutByte2(w.dst, 0x81, basic_op_table_im32_reg[*src - 0x10] | reg0);
} else {
jitCompPutByte2(w.dst, 0x69, 0xc0 | reg0 << 3 | reg0);
}
}
jitCompPutImm32(&w, w.r3f);
if (reg0 == 0)
jitCompA0001_movRxxEax(&w, src[1]);
break;
}
#endif
reg1 = jitCompA000_selectRegCache(src[3], -1 /* mem */);
if (src[3] >= 0x40) w.err = JITC_ERR_REGNUM;
if (*src != 0x16) {
if (reg1 >= 0) {
static UCHAR basic_op_table_rr[] = { 0x09, 0x31, 0x21, 0, 0x01, 0x29 }; /* op(reg,reg); */
jitCompPutByte2(w.dst, basic_op_table_rr[*src - 0x10], 0xc0 | reg1 << 3 | reg0);
} else {
static UCHAR basic_op_table_rm[] = { 0x0b, 0x33, 0x23, 0, 0x03, 0x2b, 0xaf }; /* op(reg,mem); */
jitCompPutByte1(w.dst, basic_op_table_rm[*src - 0x10]);
jitCompA0001_85DispN(&w, src[3] * 4, reg0);
}
} else {
if (reg1 >= 0) {
jitCompPutByte3(w.dst, 0x0f, 0xaf, 0xc0 | reg0 << 3 | reg1);
} else {
jitCompPutByte2(w.dst, 0x0f, 0xaf);
jitCompA0001_85DispN(&w, src[3] * 4, reg0);
}
}
}
if (reg0 == 0)
jitCompA0001_movRxxEax(&w, src[1]);
break;
case 0x18: /* SHL */
case 0x19: /* SAR */
if (src[1] >= 0x3f) w.err = JITC_ERR_REGNUM;
if (src[3] >= 0x40) w.err = JITC_ERR_REGNUM;
#if (jitCompA0001_USE_R3F_IMM32 != 0)
if (src[3] == 0x3f) {
reg0 = jitCompA000_selectRegCache(src[1], 0 /* EAX */);
reg1 = jitCompA000_selectRegCache(src[2], -1 /* mem */);
if (src[1] >= 0x3f) w.err = JITC_ERR_REGNUM;
if (reg1 == -1)
jitCompA0001_movReg32EbpDisp(&w, reg0, src[2] * 4); /* MOV(reg1, [EBP+?]); */
else {
if (reg0 != reg1) {
jitCompPutByte2(w.dst, 0x89, 0xc0 | reg1 << 3 | reg0); /* MOV(reg0, reg1); */
}
}
if (*src == 0x18) { jitCompPutByte3(w.dst, 0xc1, 0xe0 | reg0, w.r3f); } /* SHL(reg0, im8); */
if (*src == 0x19) { jitCompPutByte3(w.dst, 0xc1, 0xf8 | reg0, w.r3f); } /* SAR(reg0, im8); */
if (reg0 == 0 /* EAX */)
jitCompA0001_movRxxEax(&w, src[1]);
cmp0reg = src[1];
cmp0lev = 1;
break;
}
#endif
jitCompA000_storeRegCacheAll(&w); // 手抜き.
jitCompA0001_movReg32EbpDisp(&w, 1 /* ECX */, src[3] * 4); /* MOV(ECX, [EBP+?]); */
#if (jitCompA0001_USE_R3F_IMM32 != 0)
if (src[2] == 0x3f) {
jitCompPutByte1(w.dst, 0xb8); /* MOV(EAX, ?); */
jitCompPutImm32(&w, w.r3f);
} else {
jitCompA0001_movEaxRxx(&w, src[2]);
}
#else
jitCompA0001_movEaxRxx(&w, src[2]);
#endif
if (*src == 0x18) { jitCompPutByte2(w.dst, 0xd3, 0xe0); } /* SHL(EAX, CL); */
if (*src == 0x19) { jitCompPutByte2(w.dst, 0xd3, 0xf8); } /* SAR(EAX, CL); */
jitCompA0001_movRxxEax(&w, src[1]);
jitCompA000_loadRegCacheAll(&w); // 手抜き.
cmp0reg = src[1];
cmp0lev = 1;
break;
case 0x1a: /* DIV */
case 0x1b: /* MOD */
if (src[1] >= 0x3f) w.err = JITC_ERR_REGNUM;
if (src[2] >= 0x40) w.err = JITC_ERR_REGNUM;
if (src[3] >= 0x40) w.err = JITC_ERR_REGNUM;
jitCompA000_storeRegCacheAll(&w); // 手抜き.
#if (jitCompA0001_USE_R3F_IMM32 != 0)
if (src[3] == 0x3f) {
jitCompPutByte1(w.dst, 0xb8 | 1); /* MOV(ECX, ?); */
jitCompPutImm32(&w, w.r3f);
} else {
jitCompA0001_movReg32EbpDisp(&w, 1 /* ECX */, src[3] * 4); /* MOV(ECX, [EBP+?]); */
}
if (src[2] == 0x3f) {
jitCompPutByte1(w.dst, 0xb8 | 0); /* MOV(EAX, ?); */
jitCompPutImm32(&w, w.r3f);
} else {
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, src[2] * 4); /* MOV(EAX, [EBP+?]); */
}
#else
jitCompA0001_movReg32EbpDisp(&w, 1 /* ECX */, src[3] * 4); /* MOV(ECX, [EBP+?]); */
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, src[2] * 4); /* MOV(EAX, [EBP+?]); */
#endif
jitCompPutByte1(w.dst, 0x99); /* CDQ(); */
/* ECXがゼロではないことを確認すべき */
jitCompPutByte2(w.dst, 0xf7, 0xf9); /* IDIV(ECX); */
if (*src == 0x1a) { jitCompA0001_movEbpDispReg32(&w, src[1] * 4, 0 /* EAX */); }
if (*src == 0x1b) { jitCompA0001_movEbpDispReg32(&w, src[1] * 4, 2 /* EDX */); }
jitCompA000_loadRegCacheAll(&w); // 手抜き.
cmp0reg = -1;
break;
case 0x1c: /* PLMT0 */
case 0x1d: /* PLMT1 */
if (src[1] >= 0x40 || src[2] >= 0x40) w.err = JITC_ERR_PREGNUM;
if (level < JITC_LV_FASTEST) {
cmp0reg = -1;
if (level < JITC_LV_FASTER) {
// typ が一致していることを確認.
// plsとliveSignが一致していることを確認.
// preg1はp0 <= p <= p1 を満たしているか?.
// 新しいp0/p1は古いp0〜p1に適合しているか?.
}
}
case 0x1e: /* PCP */ /* 未完成(p1まで完成) */
if (src[1] >= 0x40 || src[2] >= 0x40) w.err = JITC_ERR_PREGNUM;
if (src[2] == 0x3f) w.err = JITC_ERR_PREGNUM;
if (src[1] != 0x3f) {
/* src[2] == 0xff の場合に対応できてない */
jitCompA000_storePRegCacheAll(&w); // 手抜き.
for (i = 0; i < 32; i += 4) {
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, 256 + src[2] * 32 + i); /* MOV(EAX, [EBP+?]); */
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + i, 0 /* EAX */); /* MOV([EBP+?], EAX); */
}
jitCompA000_loadPRegCacheAll(&w); // 手抜き.
} else {
if (level < JITC_LV_FASTER) {
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, 256 + src[2] * 32 + 4); /* MOV(EAX, [EBP+?]); */ /* typ */
jitCompPutByte3(w.dst, 0x83, 0xf8, 0); /* CMP(EAX, 0); */
jitCompPutByte2(w.dst, 0x0f, 0x85); /* JNE */
jitCompPutImm32(&w, errfnc - (w.dst + 4));
/* セキュリティチェックが足りてない!(aliveとか) */
}
reg0 = 0; /* EAX */
jitCompA000_storePRegCacheAll(&w); // 手抜き.
jitCompA0001_movReg32EbpDisp(&w, reg0, 256 + src[2] * 32 + 0); /* MOV(EAX, [EBP+?]); */
if (level < JITC_LV_FASTER) {
jitCompPutByte1(w.dst, 0x3b); /* CMP(reg0, [EBP+?]); */
jitCompA0001_85DispN(&w, 256 + src[2] * 32 + 8, reg0); /* p0 */
jitCompPutByte2(w.dst, 0x0f, 0x85); /* JNE */
jitCompPutImm32(&w, errfnc - (w.dst + 4));
}
jitCompPutByte2(w.dst, 0xff, 0xe0); /* JMP(EAX); */
}
break;
case 0x1f: /* PCST */
if (jitCompGetImm32(src + 2) == 0) {
if (level < JITC_LV_FASTER)
jitCompA0001_checkType0(&w, src[6], jitCompGetImm32(src + 7), 2);
jitCompA000_storePRegCacheAll(&w); // 手抜き.
for (i = 0; i < 32 - 4; i += 4) {
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, 256 + src[6] * 32 + i); /* MOV(EAX, [EBP+?]); */
if (i == 4) {
jitCompPutByte1(w.dst, 0x0d); /* OR(EAX, ?); */
jitCompPutImm32(&w, 0x80000000);
}
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + i, 0 /* EAX */); /* MOV([EBP+?], EAX); */
}
jitCompPutByte1(w.dst, 0xb8); /* MOV(EAX, ?); */
jitCompPutImm32(&w, debugInfo1);
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + 28, 0 /* EAX */); /* MOV([EBP+?], EAX); */
jitCompA000_loadPRegCacheAll(&w); // 手抜き.
cmp0reg = -1;
break;
}
if (jitCompGetImm32(src + 7) == 0) {
jitCompA000_storePRegCacheAll(&w); // 手抜き.
for (i = 0; i < 32 - 4; i += 4) {
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, 256 + src[6] * 32 + i); /* MOV(EAX, [EBP+?]); */
if (i == 4) {
jitCompPutByte1(w.dst, 0x25); /* AND(EAX, ?); */
jitCompPutImm32(&w, 0x7fffffff);
}
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + i, 0 /* EAX */); /* MOV([EBP+?], EAX); */
}
if (level < JITC_LV_FASTER) {
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, 256 + src[6] * 32 + 28); /* MOV(EAX, [EBP+?]); */
jitCompPutByte1(w.dst, 0x3d); /* CMP(EAX, ?); */
jitCompPutImm32(&w, debugInfo1);
jitCompPutByte2(w.dst, 0x74, 8); /* JE */
jitCompPutByte2(w.dst, 0x31, 0xc0); /* XOR(EAX, EAX); (2) */
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + 0, 0 /* EAX */); /* MOV([EBP+?], EAX); (1+1+4) */
}
jitCompA000_loadPRegCacheAll(&w); // 手抜き.
cmp0reg = -1;
break;
}
w.err = JITC_ERR_OPECODE;
goto err_w;
case 0x20: /* CMPE */
case 0x21: /* CMPNE */
case 0x22: /* CMPL */
case 0x23: /* CMPGE */
case 0x24: /* CMPLE */
case 0x25: /* CMPG */
case 0x26: /* TSTZ */
case 0x27: /* TSTNZ */
reg0 = jitCompA000_selectRegCache(src[2], 0 /* EAX */);
reg1 = jitCompA000_selectRegCache(src[3], -1 /* mem */);
if (src[1] == 0x3f) {
/* 特殊構文チェック */
if (w.prefix != 0) { w.err = JITC_ERR_PREFIX; goto err_w; }
if (src[4] != 0x04 || src[5] != 0x3f || src[6] != 0x03 || src[7] != 0x3f) {
w.err = JITC_ERR_IDIOM; goto err_w;
}
}
if (reg0 == 0)
jitCompA0001_movEaxRxx(&w, src[2]);
#if (jitCompA0001_USE_R3F_IMM32 != 0)
if (src[3] == 0x3f) {
#if (jitCompA0001_OPTIMIZE_CMP != 0)
if ((*src <= 0x25 && w.r3f == 0) || (*src >= 0x26 && w.r3f == -1)) {
i = 0;
if (cmp0reg == src[2]) {
if (cmp0lev >= 1 && (src[0] == 0x20 || src[0] == 0x21 || src[0] == 0x26 || src[0] == 0x27))
i = 1;
if (cmp0lev >= 2 && (src[0] == 0x22 || src[0] == 0x23 || src[0] == 0x24 || src[0] == 0x25))
i = 1;
}
if (i == 0) {
jitCompPutByte2(w.dst, 0x85, 0xc0 | reg0 << 3 | reg0); /* TEST(reg0, reg0); */
}
cmp0reg = src[2];
cmp0lev = 2;
goto cmpcc1;
}
#endif
#if (jitCompA0001_USE_R3F_IMM8 != 0)
if (-0x80 <= w.r3f && w.r3f <= 0x7f && *src <= 0x25) {
jitCompPutByte3(w.dst, 0x83, 0xf8 | reg0, w.r3f);
goto cmpcc1;
}
#endif
if (reg0 == 0) {
if (*src <= 0x25) { jitCompPutByte1(w.dst, 0x3d); }
if (*src >= 0x26) { jitCompPutByte1(w.dst, 0xa9); }
} else {
if (*src <= 0x25) { jitCompPutByte2(w.dst, 0x81, 0xf8 | reg0); }
if (*src >= 0x26) { jitCompPutByte2(w.dst, 0xf7, 0xc0 | reg0); }
}
jitCompPutImm32(&w, w.r3f);
goto cmpcc1;
}
#endif
if (src[3] >= 0x40) w.err = JITC_ERR_PREGNUM;
if (reg1 >= 0) {
if (*src <= 0x25) { jitCompPutByte2(w.dst, 0x39, 0xc0 | reg1 << 3 | reg0); }
if (*src >= 0x26) { jitCompPutByte2(w.dst, 0x85, 0xc0 | reg1 << 3 | reg0); }
} else {
if (*src <= 0x25) { jitCompPutByte1(w.dst, 0x3b); }
if (*src >= 0x26) { jitCompPutByte1(w.dst, 0x85); }
jitCompA0001_85DispN(&w, src[3] * 4, reg0);
}
cmpcc1:
if (w.err != 0) goto err_w;
static UCHAR cmpcc_table0[] = {
0x04, 0x05, 0x0c, 0x0d, 0x0e, 0x0f, 0x04, 0x05, /* CMPcc, TSTcc */
0x04, 0x05, 0x02, 0x03, 0x06, 0x07 /* PCMPcc */
};
#if (jitCompA0001_USE_R3F_CMPJMP != 0)
if (src[1] == 0x3f) {
/* 特殊構文を利用した最適化 */
jitCompPutByte2(w.dst, 0x0f, 0x80 | cmpcc_table0[*src - 0x20]);
src += 6;
i = jitCompGetLabelNum(&w, src + 2);
if ((flags & JITC_PHASE1) != 0 && w.err != 0) {
if (label[i].opt == 0) { w.err = JITC_ERR_LABELNODEF; goto err_w; }
// if (label[i].typ != 1) { w.err = JITC_ERR_LABELTYP; goto err_w; }
}
j = 0;
if ((flags & JITC_PHASE1) != 0 || ((flags & JITC_PHASE1) == 0) && label[i].opt != 0)
j = label[i].p - (w.dst + 4);
jitCompPutImm32(&w, j);
#if (jitCompA0001_OPTIMIZE_JMP != 0)
if (-128 - 4 <= j && j < 0) {
j += 4;
w.dst -= 6;
w.dst[0] = w.dst[1] ^ 0xf0;
w.dst[1] = j & 0xff;
w.dst += 2;
}
#endif
src += 6;
if (w.err != 0) goto err_w;
continue;
}
#endif
/* 一般的なJITC */
reg0 = jitCompA000_selectRegCache(src[1], 0 /* EAX */);
jitCompPutByte3(w.dst, 0x0f, 0x90 | cmpcc_table0[*src - 0x20], 0xc0 | reg0); /* SETcc(BYTE(reg0)); */
jitCompPutByte3(w.dst, 0x0f, 0xb6, 0xc0 | reg0 << 3 | reg0); /* MOVZX(reg0, BYTE(reg0)); */
jitCompPutByte2(w.dst, 0xf7, 0xd8 | reg0); /* NEG(reg0); */
if (reg0 == 0)
jitCompA0001_movRxxEax(&w, src[1]);
cmp0reg = src[2];
cmp0lev = 1;
break;
case 0x28: /* PCMPE */
case 0x29: /* PCMPNE */
case 0x2a: /* PCMPL */
case 0x2b: /* PCMPGE */
case 0x2c: /* PCMPLE */
case 0x2d: /* PCMPG */
if (src[1] == 0x3f) {
/* 特殊構文チェック */
if (w.prefix != 0) { w.err = JITC_ERR_PREFIX; goto err_w; }
if (src[4] != 0x04 || src[5] != 0x3f || src[6] != 0x03 || src[7] != 0x3f) {
w.err = JITC_ERR_IDIOM; goto err_w;
}
}
if (src[2] >= 0x40) w.err = JITC_ERR_PREGNUM;
jitCompA000_storePRegCacheAll(&w); // 手抜き.
if (src[3] != 0xff)
jitCompA0001_checkCompPtr(&w, src[2], src[3]);
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, 256 + src[2] * 32 + 0); /* MOV(EAX, [EBP+?]); */
if (src[3] != 0xff) {
jitCompPutByte1(w.dst, 0x3b); /* CMP(EAX, [EBP+?]); */
jitCompA0001_85DispN(&w, 256 + src[3] * 32 + 0, 0);
} else {
/* ヌルポインタとの比較はこれでいいのか?たぶんよくない */
jitCompPutByte3(w.dst, 0x83, 0xf8, 0x00); /* CMP(EAX, 0); */
}
cmp0reg = -1;
goto cmpcc1;
case 0x30: /* talloc(old:F4) */
case 0x31: /* tfree(old:F5) */
case 0x32: /* malloc(old:F6) */
case 0x33: /* mfree(old:F7) */
jitCompA000_storeRegCacheAll(&w); // 手抜き.
jitCompA000_storePRegCacheAll(&w); // 手抜き.
jitCompPutByte2(w.dst, 0x6a, src[3]); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[2]); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[1]); /* PUSH(?); */
jitCompPutByte1(w.dst, 0x55); /* PUSH(EBP); */
jitCompPutByte1(w.dst, 0xe8);
if (*src == 0x30) j = ((UCHAR *) &funcf4) - (w.dst + 4);
if (*src == 0x31) j = ((UCHAR *) &funcf5) - (w.dst + 4);
if (*src == 0x32) j = ((UCHAR *) &funcf6) - (w.dst + 4);
if (*src == 0x33) j = ((UCHAR *) &funcf7) - (w.dst + 4);
jitCompPutImm32(&w, j);
jitCompPutByte3(w.dst, 0x83, 0xc4, 0x10); /* ADD(ESP,16); */
jitCompA000_loadRegCacheAll(&w); // 手抜き.
jitCompA000_loadPRegCacheAll(&w); // 手抜き.
cmp0reg = -1;
break;
case 0x34: /* data (暫定) */
cmp0reg = -1;
if (w.prefix != 0) { w.err = JITC_ERR_PREFIX; goto err_w; }
int k = jitCompGetImm32(&src[1]), tmpData, bitCount, dataWidth = jitCompA000_dataWidth(k);
if (lastlabel >= 0 && label[lastlabel].typ == 0)
label[lastlabel].typ = k;
if (k != 1) {
i = jitCompA000_convTyp(k);
if (i < 2 || i > 7) { w.err = JITC_ERR_BADTYPE; goto err_w; }
}
j = jitCompGetImm32(&src[5]);
oldsrc = src;
src += 9;
if (k != 1) {
bitCount = 7;
while (j > 0) {
if (src >= src1) { w.err = JITC_ERR_SRC1; src = oldsrc; goto err_w; }
if (w.dst + 256 > dst1) { w.err = JITC_ERR_DST1; src = oldsrc; goto err_w; }
tmpData = 0;
for (k = 0; k < dataWidth; k++) {
tmpData = tmpData << 1 | ((*src >> bitCount) & 1);
bitCount--;
if (bitCount < 0) {
bitCount = 7;
src++;
}
}
if ((i & 1) == 0 && dataWidth <= 31 && (tmpData >> (dataWidth - 1)) != 0) {
tmpData -= 1 << dataWidth;
}
if (i == 2 || i == 3) { jitCompPutByte1(w.dst, tmpData & 0xff); }
if (i == 4 || i == 5) { jitCompPutByte2(w.dst, tmpData & 0xff, (tmpData >> 8) & 0xff); }
if (i == 6 || i == 7) { jitCompPutByte4(w.dst, tmpData & 0xff, (tmpData >> 8) & 0xff, (tmpData >> 16) & 0xff, (tmpData >> 24) & 0xff); }
j--;
}
} else {
while (j > 0) {
if (src >= src1) { w.err = JITC_ERR_SRC1; src = oldsrc; goto err_w; }
if (w.dst + 256 > dst1) { w.err = JITC_ERR_DST1; src = oldsrc; goto err_w; }
i = jitCompGetImm32(src);
src += 4;
if ((flags & JITC_PHASE1) != 0 && w.err == 0) {
if (label[i].opt == 0) { w.err = JITC_ERR_LABELNODEF; goto err_w; }
}
jitCompPutImm32(&w, (int) label[i].p);
jitCompPutImm32(&w, label[i].typ);
jitCompPutImm32(&w, (int) label[i].p);
jitCompPutImm32(&w, (int) label[i].p1);
jitCompPutImm32(&w, 0); /* liveSign */
jitCompPutImm32(&w, 2320); /* pls */
jitCompPutImm32(&w, 0);
jitCompPutImm32(&w, 0);
j--;
}
}
if (lastlabel >= 0 && label[lastlabel].p1 < w.dst)
label[lastlabel].p1 = w.dst;
continue;
case 0x3c: /* ENTER */
jitCompA000_storeRegCacheAll(&w); // 手抜き.
jitCompA000_storePRegCacheAll(&w); // 手抜き.
jitCompPutByte2(w.dst, 0x6a, src[6]); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[5]); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[4] & 0x0f); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, (src[4] >> 4) & 0x0f); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[3]); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[2]); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[1]); /* PUSH(?); */
jitCompPutByte1(w.dst, 0x55); /* PUSH(EBP); */
jitCompPutByte1(w.dst, 0xe8);
j = ((UCHAR *) &func3c) - (w.dst + 4);
jitCompPutImm32(&w, j);
jitCompPutByte3(w.dst, 0x83, 0xc4, 0x20); /* ADD(ESP,32); */
jitCompA000_loadRegCacheAll(&w); // 手抜き.
jitCompA000_loadPRegCacheAll(&w); // 手抜き.
cmp0reg = -1;
break;
case 0x3d: /* LEAVE */
jitCompA000_storeRegCacheAll(&w); // 手抜き.
jitCompA000_storePRegCacheAll(&w); // 手抜き.
jitCompPutByte2(w.dst, 0x6a, src[6]); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[5]); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[4] & 0x0f); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, (src[4] >> 4) & 0x0f); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[3]); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[2]); /* PUSH(?); */
jitCompPutByte2(w.dst, 0x6a, src[1]); /* PUSH(?); */
jitCompPutByte1(w.dst, 0x55); /* PUSH(EBP); */
jitCompPutByte1(w.dst, 0xe8);
j = ((UCHAR *) &func3d) - (w.dst + 4);
jitCompPutImm32(&w, j);
jitCompPutByte3(w.dst, 0x83, 0xc4, 0x20); /* ADD(ESP,32); */
jitCompA000_loadRegCacheAll(&w); // 手抜き.
jitCompA000_loadPRegCacheAll(&w); // 手抜き.
cmp0reg = -1;
break;
case 0xfe: /* remark */
if (src[1] == 0x01 && src[2] == 0x00) { // DBGINFO1
if (level <= JITC_LV_SLOWER) {
jitCompPutByte1(w.dst, 0xb8); /* MOV(EAX, ?); */
jitCompPutImm32(&w, debugInfo1);
jitCompA0001_movEbpDispReg32(&w, 2304 + 4, 0 /* EAX */); /* MOV(debugInfo1, EAX); */
}
}
if (src[1] == 0x01 && src[2] == 0x03) { // DBGINFO1CLR
if (level <= JITC_LV_SLOWER) {
jitCompPutByte1(w.dst, 0xb8); /* MOV(EAX, ?); */
jitCompPutImm32(&w, -1);
jitCompA0001_movEbpDispReg32(&w, 2304 + 4, 0 /* EAX */); /* MOV(debugInfo1, EAX); */
}
}
if (src[1] == 0x05 && src[2] == 0x00) { // DBGINFO0
if (level <= JITC_LV_SLOWEST) {
debugInfo0 = jitCompGetImm32(src + 3);
// jitCompPutByte1(w.dst, 0xbf); /* MOV(EDI, ?); */
// jitCompPutImm32(&w, debugInfo0);
jitCompPutByte1(w.dst, 0xb8); /* MOV(EAX, ?); */
jitCompPutImm32(&w, debugInfo0);
jitCompA0001_movEbpDispReg32(&w, 2304 + 0, 0 /* EAX */); /* MOV(debugInfo0, EAX); */
}
}
break;
default:
w.err = JITC_ERR_OPECODE;
goto err_w;
}
if (w.err != 0) goto err_w;
jitCompA0001_fixPrefix(&w);
if (w.err != 0) goto err_w;
src += jitCompCmdLen(src);
}
if (enter0 != NULL) {
j = w.dst - (enter0 + 4);
enter0[0] = j & 0xff;
enter0[1] = (j >> 8) & 0xff;
enter0[2] = (j >> 16) & 0xff;
enter0[3] = (j >> 24) & 0xff;
}
if ((flags & JITC_NOSTARTUP) == 0) {
jitCompA000_storeRegCacheAll(&w);
jitCompA000_storePRegCacheAll(&w);
jitCompPutByte1(w.dst, 0x61); /* POPAD(); */
}
if ((flags & JITC_PHASE1) != 0)
return w.dst - dst00;
return 0;
err_w:
if ((w.err & JITC_ERR_PHASE0ONLY) != 0) {
if ((flags & JITC_PHASE1) == 0)
w.err &= ~JITC_ERR_PHASE0ONLY;
}
if (w.err == (JITC_ERR_MASK & JITC_ERR_REGNUM)) errmsg = "reg-number error";
if (w.err == (JITC_ERR_MASK & JITC_ERR_DST1)) errmsg = "dst1 error";
if (w.err == (JITC_ERR_MASK & JITC_ERR_OPECODE)) errmsg = "opecode error";
if (w.err == (JITC_ERR_MASK & JITC_ERR_LABELNUM)) errmsg = "label number too large";
if (w.err == (JITC_ERR_MASK & JITC_ERR_LABELREDEF)) errmsg = "label redefine";
if (w.err == (JITC_ERR_MASK & JITC_ERR_PREFIX)) { errmsg = "prefix redefine"; w.dst -= 2; }
if (w.err == (JITC_ERR_MASK & JITC_ERR_LABELNODEF)) errmsg = "label not defined";
if (w.err == (JITC_ERR_MASK & JITC_ERR_LABELTYP)) errmsg = "label type error";
if (w.err == (JITC_ERR_MASK & JITC_ERR_IDIOM)) errmsg = "idiom error";
if (w.err == (JITC_ERR_MASK & JITC_ERR_PREGNUM)) errmsg = "preg-number error";
if (w.err == (JITC_ERR_MASK & JITC_ERR_SRC1)) errmsg = "src1 error";
if (w.err == (JITC_ERR_MASK & JITC_ERR_BADTYPE)) errmsg = "bad type code";
if (w.err == (JITC_ERR_MASK & JITC_ERR_PREFIXFAR)) errmsg = "prefix internal error";
if (w.err == (JITC_ERR_MASK & JITC_ERR_INTERNAL)) errmsg = "general internal error";
if (*errmsg != '\0') {
fprintf(stderr, "JITC: %s at %06X (debugInfo0=%d)\n ", errmsg, src - src0, debugInfo0);
for (i = 0; i < 16; i++)
fprintf(stderr, "%02X ", src[i]);
static char *table[0x30] = {
"NOP", "LB", "LIMM", "PLIMM", "CND", "??", "??", "??",
"LMEM", "SMEM", "PLMEM", "PSMEM", "LEA", "??", "PADD", "PDIF",
"CP/OR", "XOR", "AND", "??", "ADD", "SUB", "MUL", "??",
"SHL", "SAR", "DIV", "MOD", "PLMT0", "PLMT1", "PCP", "PCST",
"CMPE", "CMPNE", "CMPL", "CMPGE", "CMPLE", "CMPG", "TSTZ", "TSTNZ",
"PCMPE", "PCMPNE", "PCMPL", "PCMPGE", "PCMPLE", "PCMPG", "??", "EXT" };
errmsg = "??";
if (*src < 0x30) errmsg = table[*src];
fprintf(stderr, "(%s)\n", errmsg);
}
return -1;
}
UCHAR *jitCompCallFunc(UCHAR *dst, void *func)
{
struct JitCompWork w;
w.dst = dst;
int i;
jitCompA000_storeRegCacheAll(&w);
jitCompA000_storePRegCacheAll(&w);
jitCompPutByte1(w.dst, 0x60); /* PUSHAD(); */
jitCompPutByte1(w.dst, 0x50); /* PUSH(EAX); */ /* for 16byte-align(win32では不要なのだけど、MacOSには必要らしい) */
jitCompPutByte1(w.dst, 0x55); /* PUSH(EBP); */
jitCompPutByte1(w.dst, 0xe8); /* CALL(func); */
int j = ((UCHAR *) func) - (w.dst + 4);
jitCompPutImm32(&w, j);
jitCompPutByte1(w.dst, 0x58); /* POP(EAX); */ /* (win32では不要なのだけど、MacOSには必要らしい) */
jitCompPutByte1(w.dst, 0x58); /* POP(EAX); */
jitCompPutByte1(w.dst, 0x61); /* POPAD(); */
jitCompA000_loadRegCacheAll(&w);
jitCompA000_loadPRegCacheAll(&w);
jitCompA0001_movReg32EbpDisp(&w, 0 /* EAX */, 256 + 0x30 * 32 + 0); /* MOV(EAX, [EBP+?]); */
jitCompPutByte2(w.dst, 0xff, 0xe0); /* JMP(EAX); */
return w.dst;
}
UCHAR *jitCompInit(UCHAR *dst)
{
errfnc = dst;
return jitCompCallFunc(dst, &errHndl);
}
void func3c(char *ebp, int opt, int r1, int p1, int lenR, int lenP, int r0, int p0)
{
struct Regs *r = (struct Regs *) (ebp - jitCompA0001_EBP128);
int i, *pi;
struct Ptr *pp;
if (r->junkStack + 2048 > r->junkStack1) (*(r->errHndl))(r);
pi = (void *) r->junkStack; r->junkStack += r1 * 4;
for (i = 0; i < r1; i++)
pi[i] = r->ireg[i];
pp = (void *) r->junkStack; r->junkStack += p1 * 32;
for (i = 0; i < p1; i++)
pp[i] = r->preg[i];
pp = (void *) r->junkStack; r->junkStack += 32;
*pp = r->preg[0x30];
pi = (void *) r->junkStack; r->junkStack += 4;
*pi = opt << 16 | r1 << 8 | p1;
for (i = 0; i < lenR; i++)
r->ireg[r0 + i] = r->ireg[0x30 + i];
for (i = 0; i < lenP; i++)
r->preg[p0 + i] = r->preg[0x31 + i];
return;
}
void func3d(char *ebp, int opt, int r1, int p1, int lenR, int lenP, int r0, int p0)
{
struct Regs *r = (struct Regs *) (ebp - jitCompA0001_EBP128);
int i;
r->junkStack -= 4;
r->junkStack -= 32; struct Ptr *pp = (void *) r->junkStack;
r->preg[0x30] = *pp;
r->junkStack -= p1 * 32; pp = (void *) r->junkStack;
for (i = 0; i < p1; i++)
r->preg[i] = pp[i];
r->junkStack -= r1 * 4; int *pi = (void *) r->junkStack;
for (i = 0; i < r1; i++)
r->ireg[i] = pi[i];
return;
}
void funcf4(char *ebp, int pxx, int typ, int len)
{
struct Regs *r = (struct Regs *) (ebp - jitCompA0001_EBP128);
int width = jitCompA000_dataWidth(jitCompA000_convTyp(r->ireg[typ])) >> 3;
if (width < 0 || r->ireg[len] < 0)
(*(r->errHndl))(r);
void *p = r->junkStack;
if (r->junkStack + width * r->ireg[len] + 256 > r->junkStack1) (*(r->errHndl))(r);
r->junkStack += width * r->ireg[len];
r->preg[pxx].p = p;
r->preg[pxx].typ = r->ireg[typ];
r->preg[pxx].p0 = p;
r->preg[pxx].p1 = (void *) r->junkStack;
int *pi = (int *) r->junkStack;
*pi = width * r->ireg[len];
r->junkStack += sizeof (int);
if (r->ireg[typ] == 1) {
int i, i1 = (width * r->ireg[len]) >> 2;
pi = p;
for (i = 0; i < i1; i++)
pi[i] = 0;
}
return;
}
void funcf5(char *ebp, int pxx, int typ, int len)
{
struct Regs *r = (struct Regs *) (ebp - jitCompA0001_EBP128);
r->junkStack -= sizeof (int);
int *pi = (int *) r->junkStack;
r->junkStack -= *pi;
#if 0
int width = jitCompA000_dataWidth(r->ireg[typ]);
void *p = r->junkStack;
r->junkStack -= width * r->ireg[len];
#endif
return;
}
void funcf6(char *ebp, int pxx, int typ, int len)
{
struct Regs *r = (struct Regs *) (ebp - jitCompA0001_EBP128);
int width = jitCompA000_dataWidth(jitCompA000_convTyp(r->ireg[typ])) >> 3;
if (width < 0 || r->ireg[len] < 0)
(*(r->errHndl))(r);
void *p = malloc(width * r->ireg[len]);
r->preg[pxx].p = p;
r->preg[pxx].typ = r->ireg[typ];
r->preg[pxx].p0 = p;
r->preg[pxx].p1 = p + width * r->ireg[len];
if (r->ireg[typ] == 1) {
int i, i1 = (width * r->ireg[len]) >> 2, *pi;
pi = p;
for (i = 0; i < i1; i++)
pi[i] = 0;
for (i = 1; i < i1; i += 8)
pi[i] |= -1;
}
return;
}
void funcf7(char *ebp, int pxx, int typ, int len)
{
struct Regs *r = (struct Regs *) (ebp - jitCompA0001_EBP128);
free(r->preg[pxx].p);
return;
}
void errHndl(struct Regs *r)
{
r = (struct Regs *) (((char *) r) - jitCompA0001_EBP128);
(*(r->errHndl))(r);
// ここに帰ってきてはいけない.
}
int jitc0(UCHAR **qq, UCHAR *q1, const UCHAR *p0, const UCHAR *p1, int level, struct LabelTable *label)
{
UCHAR *q = *qq;
if (p0[0] != 0x05 || p0[1] != SIGN1)
return 1;
*q++ = 0x55; /* PUSH(EBP); */
*q++ = 0x8b; *q++ = 0x6c; *q++ = 0x24; *q++ = 0x08; /* MOV(EBP,[ESP+8]); */
int i;
for (i = 0; i < JITC_MAXLABELS; i++)
label[i].opt = 0;
i = jitCompiler(q, q1, p0 + 2, p1, p0, label, JITC_MAXLABELS, level, di1_serial, 0);
if (i != 0) return 2;
i = jitCompiler(q, q1, p0 + 2, p1, p0, label, JITC_MAXLABELS, level, di1_serial, JITC_PHASE1+0);
if (i < 0) return 2;
q += i;
*q++ = 0x5d; /* POP(EBP); */
*q++ = 0xc3; /* RET(); */
*qq = q;
return 0;
}
#if (USE_DEBUGGER != 0)
int dbgrGetRegNum(const UCHAR *p)
{
int i, j, r = -1;
if (p[2] <= ' ') {
i = p[0] - '0';
j = p[1] - '0';
if (i > 9) i -= 'A' - '0' - 10;
if (j > 9) j -= 'A' - '0' - 10;
if (0 <= i && i <= 15 && 0 <= j && j <= 15)
r = i << 4 | j;
}
return r;
}
void dbgrMain(struct Regs *r)
{
if (r->dbgr == 0) return;
for (;;) {
UCHAR cmd[64], *p;
int i, j, k;
printf("\ndbgr>");
p = fgets(cmd, 64, stdin);
if (p == NULL) break;
if (cmd[0] == '\0') continue;
if (cmd[0] == 'q' && cmd[1] <= ' ') break;
if (cmd[0] == 'p' && cmd[1] <= ' ' && cmd[1] != '\0') {
p = &cmd[2];
while (*p <= ' ' && *p != '\0') p++;
if (*p == 'R') {
i = dbgrGetRegNum(p + 1);
if (0 <= i && i <= 0x3f) {
printf("R%02X = 0x%08X = %d\n", i, r->ireg[i], r->ireg[i]);
} else
puts("register name error");
continue;
}
if (*p == 'P') {
i = dbgrGetRegNum(p + 1);
if (0 <= i && i <= 0x3f) {
p = "invalid";
if (0 <= r->preg[i].typ && r->preg[i].typ <= 0x15) {
static UCHAR *typName[] = {
"T_CODE", "T_VPTR", "T_SINT8", "T_UINT8",
"T_SINT16", "T_UINT16", "T_SINT32", "T_UINT32",
"T_SINT4", "T_UINT4", "T_SINT2", "T_UINT2",
"T_SINT1", "T_UINT1", "T_SINT12", "T_UINT12",
"T_SINT20", "T_UINT20", "T_SINT24", "T_UINT24",
"T_SINT28", "T_UINT28"
};
p = typName[r->preg[i].typ];
}
printf("P%02X:\n type = %s(%04X), (origin-ptr) = 0x%08X\n", i, p, r->preg[i].typ, r->preg[i].p0);
if (r->preg[i].p != NULL && r->preg[i].p0 != NULL) {
j = jitCompA000_dataWidth(jitCompA000_convTyp(r->preg[i].typ)) >> 3;
if (j <= 0) j = 1;
k = (r->preg[i].p1 - r->preg[i].p0) / j;
printf(" size = 0x%08X = %d\n", k, k);
k = (r->preg[i].p - r->preg[i].p0) / j;
printf(" pos = 0x%08X = %d\n", k, k);
} else {
puts(" null pointer");
}
} else
puts("register name error");
continue;
}
}
puts("command error");
}
return;
}
#endif
#endif
/* OS依存部 */
#if (DRV_OSNUM == 0x0001)
#include <windows.h>
#include <setjmp.h>
#define TIMER_ID 1
#define TIMER_INTERVAL 10
struct BLD_WORK {
HINSTANCE hi;
HWND hw;
BITMAPINFO bmi;
int tmcount1, tmcount2, flags, smp; /* bit0: 終了 */
HANDLE mtx;
char *winClosed;
};
struct BLD_WORK bld_work;
struct BL_WIN {
int xsiz, ysiz, *buf;
};
struct BL_WORK {
struct BL_WIN win;
jmp_buf jb;
int csiz_x, csiz_y, cx, cy, col0, col1, tabsiz, slctwin;
int tmcount, tmcount0, mod, rand_seed;
int *cbuf;
unsigned char *ftyp;
unsigned char **fptn;
int *ccol, *cbak;
int *kbuf, kbuf_rp, kbuf_wp, kbuf_c;
};
struct BL_WORK bl_work;
#define BL_SIZ_KBUF 8192
#define BL_WAITKEYF 0x00000001
#define BL_WAITKEYNF 0x00000002
#define BL_WAITKEY 0x00000003
#define BL_GETKEY 0x00000004
#define BL_CLEARREP 0x00000008
#define BL_DELFFF 0x00000010
#define BL_KEYMODE 0x00000000 // 作りかけ, make/remake/breakが見えるかどうか
#define w bl_work
#define dw bld_work
void bld_openWin(int x, int y, char *winClosed);
void bld_flshWin(int sx, int sy, int x0, int y0);
LRESULT CALLBACK WndProc(HWND hw, unsigned int msg, WPARAM wp, LPARAM lp);
void bl_cls();
int bl_iCol(int i);
void bl_readyWin(int n);
static HANDLE threadhandle;
int main(int argc, const UCHAR **argv)
{
return OsecpuMain(argc, argv);
}
void *mallocRWE(int bytes)
{
void *p = malloc(bytes);
DWORD dmy;
VirtualProtect(p, bytes, PAGE_EXECUTE_READWRITE, &dmy);
return p;
}
static int winthread(void *dmy)
{
WNDCLASSEX wc;
RECT r;
unsigned char *p, *p0, *p00;
int i, x, y;
MSG msg;
x = dw.bmi.bmiHeader.biWidth;
y = - dw.bmi.bmiHeader.biHeight;
wc.cbSize = sizeof (WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = dw.hi;
wc.hIcon = (HICON) LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
wc.hIconSm = wc.hIcon;
wc.hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW),
IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
wc.hbrBackground = (HBRUSH) COLOR_APPWORKSPACE;
wc.lpszMenuName = NULL;
wc.lpszClassName = "WinClass";
if (RegisterClassEx(&wc) == 0)
return 1;
r.left = 0;
r.top = 0;
r.right = x;
r.bottom = y;
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE);
x = r.right - r.left;
y = r.bottom - r.top;
#if 0
static unsigned char t[32];
p00 = p0 = p = GetCommandLineA();
if (*p == 0x22) {
p00 = p0 = ++p;
while (*p != '\0' && *p != 0x22) {
if (*p == '\\')
p0 = p + 1;
p++;
}
} else {
while (*p > ' ') {
if (*p == '\\')
p0 = p + 1;
p++;
}
}
if (p - p0 > 4 && p[-4] == '.' && p[-3] == 'e' && p[-2] == 'x' && p[-1] == 'e')
p -= 4;
for (i = 0; i < 32 - 1; i++) {
if (p <= &p0[i])
break;
t[i] = p0[i];
}
t[i] = '\0';
#endif
char *t = "osecpu";
dw.hw = CreateWindowA(wc.lpszClassName, t, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, x, y, NULL, NULL, dw.hi, NULL);
if (dw.hw == NULL)
return 1;
ShowWindow(dw.hw, SW_SHOW);
UpdateWindow(dw.hw);
SetTimer(dw.hw, TIMER_ID, TIMER_INTERVAL, NULL);
SetTimer(dw.hw, TIMER_ID + 1, TIMER_INTERVAL * 10, NULL);
SetTimer(dw.hw, TIMER_ID + 2, TIMER_INTERVAL * 100, NULL);
dw.flags |= 2 | 4;
for (;;) {
i = GetMessage(&msg, NULL, 0, 0);
if (i == 0 || i == -1) /* エラーもしくは終了メッセージ */
break;
/* そのほかはとりあえずデフォルト処理で */
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// PostQuitMessage(0);
dw.flags |= 1; /* 終了, bld_waitNF()が見つける */
if (dw.winClosed != NULL)
*dw.winClosed = 1;
return 0;
}
void bld_openWin(int sx, int sy, char *winClosed)
{
static int i;
dw.bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
dw.bmi.bmiHeader.biWidth = sx;
dw.bmi.bmiHeader.biHeight = - sy;
dw.bmi.bmiHeader.biPlanes = 1;
dw.bmi.bmiHeader.biBitCount = 32;
dw.bmi.bmiHeader.biCompression = BI_RGB;
dw.winClosed = winClosed;
threadhandle = CreateThread(NULL, 0, (void *) &winthread, NULL, 0, (void *) &i);
return;
}
void drv_flshWin(int sx, int sy, int x0, int y0)
{
InvalidateRect(dw.hw, NULL, FALSE);
UpdateWindow(dw.hw);
return;
}
LRESULT CALLBACK WndProc(HWND hw, unsigned int msg, WPARAM wp, LPARAM lp)
{
int i, j;
if (msg == WM_PAINT) {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(dw.hw, &ps);
SetDIBitsToDevice(hdc, 0, 0, w.win.xsiz, w.win.ysiz,
0, 0, 0, w.win.ysiz, w.win.buf, &dw.bmi, DIB_RGB_COLORS);
EndPaint(dw.hw, &ps);
}
if (msg == WM_DESTROY) {
PostQuitMessage(0);
return 0;
}
if (msg == WM_TIMER && wp == TIMER_ID) {
w.tmcount += TIMER_INTERVAL;
return 0;
}
if (msg == WM_TIMER && wp == TIMER_ID + 1) {
dw.tmcount1 += TIMER_INTERVAL * 10;
w.tmcount = dw.tmcount1;
return 0;
}
if (msg == WM_TIMER && wp == TIMER_ID + 2) {
dw.tmcount2 += TIMER_INTERVAL * 100;
w.tmcount = dw.tmcount1 = dw.tmcount2;
return 0;
}
if (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) {
i = -1;
#if 0
int s_sht = GetKeyState(VK_SHIFT);
int s_ctl = GetKeyState(VK_CONTROL);
int s_cap = GetKeyState(VK_CAPITAL);
int s_num = GetKeyState(VK_NUMLOCK);
if ('A' <= wp && wp <= 'Z') {
i = wp;
if (((s_sht < 0) ^ (s_cap & 1)) == 0)
i += 'a' - 'A';
}
if (wp == VK_SPACE) i = ' ';
#endif
if (wp == VK_RETURN) i = KEY_ENTER;
if (wp == VK_ESCAPE) i = KEY_ESC;
if (wp == VK_BACK) i = KEY_BACKSPACE;
if (wp == VK_TAB) i = KEY_TAB;
if (wp == VK_PRIOR) i = KEY_PAGEUP;
if (wp == VK_NEXT) i = KEY_PAGEDWN;
if (wp == VK_END) i = KEY_END;
if (wp == VK_HOME) i = KEY_HOME;
if (wp == VK_LEFT) i = KEY_LEFT;
if (wp == VK_RIGHT) i = KEY_RIGHT;
if (wp == VK_UP) i = KEY_UP;
if (wp == VK_DOWN) i = KEY_DOWN;
if (wp == VK_INSERT) i = KEY_INS;
if (wp == VK_DELETE) i = KEY_DEL;
j &= 0;
if ((GetKeyState(VK_LCONTROL) & (1 << 15)) != 0) j |= 1 << 17;
if ((GetKeyState(VK_LMENU) & (1 << 15)) != 0) j |= 1 << 18;
if ((GetKeyState(VK_RCONTROL) & (1 << 15)) != 0) j |= 1 << 25;
if ((GetKeyState(VK_RMENU) & (1 << 15)) != 0) j |= 1 << 26;
if ((GetKeyState(VK_RSHIFT) & (1 << 15)) != 0) i |= 1 << 24;
if ((GetKeyState(VK_LSHIFT) & (1 << 15)) != 0) i |= 1 << 16;
if ((GetKeyState(VK_NUMLOCK) & (1 << 0)) != 0) i |= 1 << 22;
if ((GetKeyState(VK_CAPITAL) & (1 << 0)) != 0) i |= 1 << 23;
if (j != 0) {
if ('A' <= wp && wp <= 'Z') i = wp;
}
if (i != -1) {
putKeybuf(i | j);
// bl_putKeyB(1, &i);
return 0;
}
}
if (msg == WM_KEYUP) {
i = 0xfff;
// bl_putKeyB(1, &i);
}
if (msg == WM_CHAR) {
i = 0;
if (' ' <= wp && wp <= 0x7e) {
i = wp;
j &= 0;
if ((GetKeyState(VK_LCONTROL) & (1 << 15)) != 0) j |= 1 << 17;
if ((GetKeyState(VK_LMENU) & (1 << 15)) != 0) j |= 1 << 18;
if ((GetKeyState(VK_RCONTROL) & (1 << 15)) != 0) j |= 1 << 25;
if ((GetKeyState(VK_RMENU) & (1 << 15)) != 0) j |= 1 << 26;
if ((GetKeyState(VK_RSHIFT) & (1 << 15)) != 0) i |= 1 << 24;
if ((GetKeyState(VK_LSHIFT) & (1 << 15)) != 0) i |= 1 << 16;
if ((GetKeyState(VK_NUMLOCK) & (1 << 0)) != 0) i |= 1 << 22;
if ((GetKeyState(VK_CAPITAL) & (1 << 0)) != 0) i |= 1 << 23;
if (('A' <= wp && wp <= 'Z') || ('a' <= wp && wp <= 'z')) {
if (j != 0) {
i |= j;
i &= ~0x20;
}
}
putKeybuf(i);
// bl_putKeyB(1, &i);
return 0;
}
}
return DefWindowProc(hw, msg, wp, lp);
}
void drv_openWin(int sx, int sy, UCHAR *buf, char *winClosed)
{
int i, x, y;
// if (sx <= 0 || sy <= 0) return;
// if (sx < 160) return;
w.win.buf = (int *) buf;
w.win.xsiz = sx;
w.win.ysiz = sy;
bld_openWin(sx, sy, winClosed);
return;
}
void drv_sleep(int msec)
{
Sleep(msec);
// MsgWaitForMultipleObjects(1, &threadhandle, FALSE, msec, QS_ALLINPUT);
/* 勉強不足でまだ書き方が分かりません! */
return;
}
#endif
#if (DRV_OSNUM == 0x0002)
// by Liva, 2013.05.29-
#include <mach/mach.h>
#include <Cocoa/Cocoa.h>
void *mallocRWE(int bytes)
{
void *p = malloc(bytes);
vm_protect(mach_task_self(), (vm_address_t) p, bytes, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
return p;
}
NSApplication* app;
@interface OSECPUView : NSView {
UCHAR *_buf;
int _sx;
int _sy;
CGContextRef _context;
}
- (id)initWithFrame:(NSRect)frameRect
buf : (UCHAR *) buf
sx : (int) sx
sy : (int) sy;
- (void)drawRect:(NSRect)rect;
@end
@implementation OSECPUView
- (id)initWithFrame:(NSRect)frameRect
buf : (UCHAR *) buf
sx : (int) sx
sy : (int) sy
{
self = [super initWithFrame:frameRect];
if (self) {
_buf = buf;
_sx = sx;
_sy = sy;
}
return self;
}
- (void)drawRect:(NSRect)rect {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
_context = CGBitmapContextCreate (_buf, _sx, _sy, 8, 4 * _sx, colorSpace, (kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst));
CGImageRef image = CGBitmapContextCreateImage(_context);
CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextDrawImage(currentContext, NSRectToCGRect(rect), image);
}
@end
@interface Main : NSObject<NSWindowDelegate> {
int argc;
const UCHAR **argv;
char *winClosed;
OSECPUView *_view;
}
- (void)runApp;
- (void)createThread : (int)_argc
args : (const UCHAR **)_argv;
- (BOOL)windowShouldClose:(id)sender;
- (void)openWin : (UCHAR *)buf
sx : (int) sx
sy : (int) sy
winClosed : (char *)_winClosed;
- (void)flushWin : (NSRect) rect;
@end
@implementation Main
- (void)runApp
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
OsecpuMain(argc,argv);
[NSApp terminate:self];
[pool release];
}
- (void)createThread : (int)_argc
args : (const UCHAR **)_argv
{
argc = _argc;
argv = _argv;
NSThread *thread = [[[NSThread alloc] initWithTarget:self selector:@selector(runApp) object:nil] autorelease];
[thread start];
}
- (BOOL)windowShouldClose:(id)sender
{
*winClosed = 1;
return YES;
}
- (void)openWin : (UCHAR *)buf
sx : (int) sx
sy : (int) sy
winClosed : (char *)_winClosed
{
NSWindow* window = [[NSWindow alloc] initWithContentRect: NSMakeRect(0, 0, sx, sy) styleMask: NSTitledWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask backing: NSBackingStoreBuffered defer: NO];
[window setTitle: @"osecpu"];
[window center];
[window makeKeyAndOrderFront:nil];
[window setReleasedWhenClosed:YES];
window.delegate = self;
winClosed = _winClosed;
_view = [[OSECPUView alloc] initWithFrame:NSMakeRect(0,0,sx,sy) buf:buf sx:sx sy:sy];
[window.contentView addSubview:_view];
}
- (void)flushWin : (NSRect) rect
{
[_view drawRect:rect];
}
@end
id objc_main;
int main(int argc, const UCHAR **argv)
{
objc_main = [[Main alloc] init];
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
app = [[NSApplication alloc] init];
[objc_main createThread:argc args:argv];
[app run];
[pool release];
return 0;
}
void drv_openWin(int sx, int sy, UCHAR *buf, char *winClosed)
{
[objc_main openWin:buf sx:sx sy:sy winClosed:winClosed];
}
void drv_flshWin(int sx, int sy, int x0, int y0)
{
[objc_main flushWin:NSMakeRect(x0,y0,sx,sy)];
}
void drv_sleep(int msec)
{
[NSThread sleepForTimeInterval:0.001*msec];
return;
}
#endif
#if (DRV_OSNUM == 0x0003)
// by takeutch-kemeco, 2013.07.25-
// gcc -D__LINUX_BLIKE__ osecpu.c `pkg-config blike --cflags --libs` -o osecpu
void __bl_openWin_attach_vram(int, int, int*);
void *__bld_mallocRWE(unsigned int);
void bld_flshWin(int, int, int, int);
void bl_wait(int);
void __bld_set_callback_key_press(void (*f)(void*, const int));
void __bld_set_callback_key_release(void (*f)(void*, const int));
extern int bl_argc;
extern const UCHAR** bl_argv;
static void __drv_bld_callback_key_press(void* a, const int keyval) { if (keyval != -1) putKeybuf(keyval); }
static void __drv_bld_callback_key_release(void* a, const int keyval) { /* putKeybuf(0x0fff); */ }
void *mallocRWE(int bytes) { return __bld_mallocRWE(bytes); }
void drv_openWin(int sx, int sy, UCHAR *buf, char *winClosed) { __bl_openWin_attach_vram(sx, sy, (int*) buf); }
void drv_flshWin(int sx, int sy, int x0, int y0) { bld_flshWin(sx, sy, x0, y0); }
void drv_sleep(int msec) { bl_wait(msec); }
blMain()
{
__bld_set_callback_key_press(__drv_bld_callback_key_press);
__bld_set_callback_key_release(__drv_bld_callback_key_release);
OsecpuMain(bl_argc, bl_argv);
}
#endif /* (DRV_OSNUM == 0x0003) */
#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) */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment