
// HSPOSCmp
// Copyright (c) 2012 mogesystem

#define HSP3_MEMVAL

#include "bootpack.h"
#include "hsp.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

extern CHSP3_TASK __HspTaskFunc[];
extern struct SHEET *sht_back;
extern int *fat;
extern int onmouse;
struct TASK *hsptask;
struct TIMER *hsptimer;

int onclick_jmp	= -1;
int onkey_jmp	= -1;
int rndseed		= 0;
int wparam		= 0;

char strtmp[256];
int hspredraw;
int hspcnt;
int hspstrsize;
PVal hspstat;

struct HSPRGB color;
struct HSPPOS pos;

// 変数バッファ
PVal mem_var[STACKSIZE];

/*
	コメントについてる記号の読み方

	TBD			未定（to be determined）
	TODO		要実装（To do）
	ReqImp		要改良（Require improvement）

*/


unsigned int getseed(void)
{
	unsigned char t[7];
    char err;
    static unsigned char adr[7] = { 0x00, 0x02, 0x04, 0x07, 0x08, 0x09, 0x32 };
    static unsigned char max[7] = { 0x60, 0x59, 0x23, 0x31, 0x12, 0x99, 0x99 };
    int i;
    for (;;) {
        err = 0;
        for (i = 0; i < 7; i++) {
            io_out8(0x70, adr[i]);
            t[i] = io_in8(0x71);
        }
        for (i = 0; i < 7; i++) {
            io_out8(0x70, adr[i]);
            if (t[i] != io_in8(0x71) || (t[i] & 0x0f) > 9 || t[i] > max[i]) {
                err = 1;
            }
        }
        if (err == 0) {
            return t[0]*0x1000 + t[1]*0x10 + t[2];
        }
    }
}

// 文字列出力
void putfonts8_asc_sht(struct SHEET *sht, int x, int y, struct HSPRGB c, int b, char *s, int l)
{
	struct TASK *task = task_now();
	if (task->langmode != 0 && task->langbyte1 != 0) {
		putstringA(sht->buf, sht->bxsize, x, y, c.r, c.g, c.b, s);
		sheet_refresh(sht, x - 8, y, x + l * 8, y + 16);
	} else {
		putstringA(sht->buf, sht->bxsize, x, y, c.r, c.g, c.b, s);
		sheet_refresh(sht, x, y, x + l * 8, y + 16);
	}
	return;
}

#define MAXSTR    120
// テスト用printf
int hsp_printf(const char *format, ...)
{
	va_list arglist;
	char buf[MAXSTR];
	int ret;

	va_start(arglist, format);
	ret = vsprintf(buf, format, arglist);
	mes(buf);
	va_end(arglist);

	return ret;
}

// 画像読み込み(CD-R)
// QEMUだとかなり速度が遅い
int loadimg(char *filename, int x, int y)
{
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	unsigned char *filebuf, r, g, b;
	struct DLL_STRPICENV env;
	struct RGB *picbuf;
	int info[8], fsize, xx, yy;
	FILE *fp;

	fp = fopen(filename, "r");

	if (fp != NULL) {
		fsize   = fp->size;
		filebuf = (unsigned char *) memman_alloc_4k(memman, fsize);
		if (!fread(filebuf, fsize, 1, fp)) {
			fclose(fp);
			return 1;
		}
		fclose(fp);
		if (info_BMP(&env, info, fsize, filebuf) == 0)
			if (info_JPEG(&env, info, fsize, filebuf) == 0)
				return 1;
		picbuf = (struct RGB *) memman_alloc_4k(memman, info[2] * info[3] * sizeof(struct RGB));
		if (info[0] == 1)
			decode0_BMP(&env, fsize, filebuf, 4, (unsigned char *) picbuf, 0);
		else
			decode0_JPEG(&env, fsize, filebuf, 4, (unsigned char *) picbuf, 0);
		for (yy = 0; yy < info[3]; yy++) {
			for (xx = 0; xx < info[2]; xx++) {
				r = picbuf[yy * info[2] + xx].r;
				g = picbuf[yy * info[2] + xx].g;
				b = picbuf[yy * info[2] + xx].b;
				sht_back->buf[(yy + y) * sht_back->bxsize + (xx + x)] = (unsigned short)(((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | (b >> 3));
			}
		}
	} else {
		fclose(fp);
		return 1;
	}

	sheet_refresh(sht_back, 0, 0, sht_back->bxsize, sht_back->bysize);
	return 0;
}


// HSPタスク設定
void init_hsp_task(void)
{
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	hsptask = task_alloc();
	int *hsptask_fifo = (int *) memman_alloc_4k(memman, 128 * 4);
	hsptask->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;
	hsptask->tss.eip = (int) &hsp_task;
	hsptask->tss.es =  8;
	hsptask->tss.cs = 16;
	hsptask->tss.ss =  8;
	hsptask->tss.ds =  8;
	hsptask->tss.fs =  8;
	hsptask->tss.gs =  8;
	hsptask->langmode = 1;
	task_run(hsptask, 1, 2); /* level=1, priority=2 */
	fifo32_init(&hsptask->fifo, 128, hsptask_fifo, hsptask);
}

// キー配列からWin32APIの仮想キーコードを割り出す
int key2vk(int i)
{
	static char keytable[0x80] = {
		  0,0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^',0x08,0x09,
		'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[',0x0d,0x11, 'A', 'S',
		'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':',   0,0x10, ']', 'Z', 'X', 'C', 'V',
		'B', 'N', 'M', ',', '.', '/',0x10, '*',0x12, ' ',   0,   0,   0,   0,   0,   0,
		0,     0,   0,   0,   0,   0,   0, '7', '8', '9', '-', '4', '5', '6', '+', '1',
		'2', '3', '0', '.',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
		0,     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
		0,     0,   0,0x5c,   0,   0,   0,   0,0x1c,   0,0x1d,   0,   0,0x5c,   0,   0
	};
	int ret = keytable[i];
	return ret;
}

// HSPタスクのmain
void hsp_task(void)
{
	int i;
	hsptimer = timer_alloc();
	timer_init(hsptimer, &hsptask->fifo, 2);
	fifo32_put(&hsptask->fifo, 1);

	while (1) {
		io_cli();
		if (fifo32_status(&hsptask->fifo) == 0) {
			task_sleep(hsptask);
			io_sti();
		} else {
			i = fifo32_get(&hsptask->fifo);
			io_sti();
			if (i == 1) {
				InitHSP();
				__HspEntry();
				Prgcmd(17, 0);
			}
			if (i == 2) {
				if (onclick_jmp != -1) {
					TaskSwitch(onclick_jmp);
				}
				if (onkey_jmp != -1) {
					wparam = key2vk(i-256);
					TaskSwitch(onkey_jmp);
				}
			}
			if (i == 3) {
			}
			if (256 <= i && i <= 511) {
				if (onkey_jmp != -1) {
					wparam = key2vk(i-256);
					if (wparam != 0) {
						TaskSwitch(onkey_jmp);
					}
				}
			}
			if (i == 0x7ff) {
				/* stop */
			}
			if (i >= 0x800) {
				/* エラー発生 */
			}
		}
	}
	return;
}

// HSPタスクの初期化
void InitHSP(void)
{
	color.r = color.g = color.b = 0;
	pos.x = pos.y = 1;
	hspredraw = 1;
	hspcnt = 0;
	hspstrsize = 0;
	boxfillA(sht_back->buf, sht_back->bxsize, 255,255,255, 0, 0, sht_back->bxsize, sht_back->bysize);
	sheet_refresh(sht_back, 0, 0, sht_back->bxsize, sht_back->bysize);
	StackInit();
	return;
}

void PushStr(char *str)
{
	// 文字列をpush
	StackPushStr(str, strlen(str));
}

void PushInt(int value)
{
	// 整数をpush
	StackPushInt(value);
}

void PushLabel(int label)
{
	// ラベルをpush
	StackPushLabel(label);
}

void PushVar(PVal *var, int i)
{
	// 変数の内容をpush
	
	switch (var->type) {
	case ST_INT:
		StackPushInt(var->ival);
		break;

	//case ST_DBL:
	//	StackPushDouble(var->idbl);
	//	break;

	case ST_STR:
		StackPushStr(var->str, var->strsize);
		break;

	case ST_LABEL:
		StackPushLabel(var->ival);
		break;
	}
}

void PushVAP(PVal *var, int i)
{
	// 変数自体へのポインタをpush
	// TODO
	PushVar(var, i);
}

void PushExtvar(int num, int i)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
	extern int *mousex;
	extern int *mousey;
	
	if (num == 0) {	/* mousex */
		StackPushInt(*mousex);
	}
	if (num == 1) {	/* mousey */
		StackPushInt(*mousey);
	}
	if (num == 256) {	/* ginfo TODO TBD ReqImp */
		int b = StackPop().ival;
		if (b == 0) {	/* マウスX座標 */
			StackPushInt(*mousex);
		}
		if (b == 1) {	/* マウスY座標 */
			StackPushInt(*mousey);
		}
		if (b == 2) {	/* アクティブなウインドウID TBD */
			StackPushInt(0);
		}
		if (b == 3) {	/* 操作先ウィンドウID TBD */
			StackPushInt(0);
		}
		if (b == 4) {	/* ウィンドウの左上X座標 */
			StackPushInt(0);
		}
		if (b == 5) {	/* ウィンドウの左上Y座標 */
			StackPushInt(0);
		}
		if (b == 6) {	/* ウィンドウの右下X座標 */
			StackPushInt(binfo->scrnx);
		}
		if (b == 7) {	/* ウィンドウの右下Y座標 */
			StackPushInt(binfo->scrny);
		}
		if (b == 8) {	/* ウィンドウの描画基点X座標 */
			StackPushInt(0);
		}
		if (b == 9) {	/* ウィンドウの描画基点Y座標 */
			StackPushInt(0);
		}
		if (b == 10) {	/* ウィンドウ全体のXサイズ */
			StackPushInt(0);
		}
		if (b == 11) {	/* ウィンドウ全体のYサイズ */
			StackPushInt(0);
		}
		if (b == 12) {	/* クライアント領域Xサイズ */
			StackPushInt(0);
		}
		if (b == 13) {	/* クライアント領域Yサイズ */
			StackPushInt(0);
		}
		if (b == 14) {	/* メッセージの出力Xサイズ TODO */
		}
		if (b == 15) {	/* メッセージの出力Yサイズ TODO */
		}
		if (b == 16) {	/* 現在設定されているカラーコード(R) */
			StackPushInt(color.r);
		}
		if (b == 17) {	/* 現在設定されているカラーコード(G) */
			StackPushInt(color.g);
		}
		if (b == 18) {	/* 現在設定されているカラーコード(B) */
			StackPushInt(color.b);
		}
		if (b == 19) {	/* デスクトップのカラーモード */
			StackPushInt(1);
		}
		if (b == 20) {	/* デスクトップ全体のXサイズ */
			StackPushInt(binfo->scrnx);
		}
		if (b == 21) {	/* デスクトップ全体のYサイズ */
			StackPushInt(binfo->scrny);
		}
		if (b == 22) {	/* カレントポジションのX座標 */
			StackPushInt(pos.x);
		}
		if (b == 23) {	/* カレントポジションのY座標 */
			StackPushInt(pos.y);
		}
		if (b == 24) {	/* メッセージ割り込み時のウィンドウID TODO */
		}
		if (b == 25) {	/* 未使用ウィンドウID TODO */
		}
		if (b == 26) {	/* 画面の初期化Xサイズ */
			StackPushInt(binfo->scrnx);
		}
		if (b == 27) {	/* 画面の初期化Yサイズ */
			StackPushInt(binfo->scrny);
		}
	}
}

void PushIntfunc(int num, int i)
{
	if (num == 0) {		/* int TODO */
	}
	if (num == 1) {		/* rnd ReqImp */
		if (i == 1) {
			int n = StackPop().ival;
			rndseed = (rndseed * 1103515245UL + 12345UL) & 2147483647UL;
			StackPushInt(rndseed % n);
		}
	}
	if (num == 2) {		/* strlen */
		char *s = StackPop().str;
		StackPushInt(strlen(s));
	}
	if (num == 3) {		/* length TODO */
	}
	if (num == 4) {		/* length2 TODO */
	}
	if (num == 5) {		/* length3 TODO */
	}
	if (num == 6) {		/* length4 TODO */
	}
}

void PushSysvar(int num, int i)
{
	if (num == 4) {		/* cnt */
		StackPushInt(hspcnt);
	}
	if (num == 6) {		/* strsize */
		StackPushInt(hspstrsize);
	}
	if (num == 10) {	/* wparam */
		StackPushInt(wparam);
	}
	return;
}

void PushFuncEnd(void)	/* TBD */
{
	return;
}

void VarSet(PVal *var, int i)
{
	*var = StackPop();
}

void VarInc(PVal *var, int i)
{
	var->ival++;
}

void CalcAddI(void)
{
	static char s[256];
	PVal a, b;
	b = StackPop();
	a = StackPop();
	if (a.type == ST_STR && b.type == ST_STR) {
		strcpy(s, a.str);
		strcat(s, b.str);
		StackPushStr(s, strlen(s));
	} else if (a.type == ST_STR && b.type == ST_INT) {
		sprintf(s, "%s%d", a.str, b.ival);
		StackPushStr(s, strlen(s));
	} else if (a.type == ST_INT && b.type == ST_STR) {
		sprintf(s, "%d%s", a.ival, b.str);
		StackPushStr(s, strlen(s));
	}  else {
		StackPushInt(a.ival + b.ival);
	}
}

void CalcSubI(void)
{
	PVal a, b;
	b = StackPop();
	a = StackPop();
	StackPushInt(a.ival - b.ival);
}

void CalcMulI(void)
{
	PVal a, b;
	b = StackPop();
	a = StackPop();
	StackPushInt(a.ival * b.ival);
}

void CalcEqI(void)
{
	PVal a, b;
	b = StackPop();
	a = StackPop();
	StackPushInt(a.ival == b.ival);
}

void CalcNeI(void)
{
	PVal a, b;
	b = StackPop();
	a = StackPop();
	StackPushInt(a.ival != b.ival);
}

void CalcLtI(void)
{
	PVal a, b;
	b = StackPop();
	a = StackPop();
	StackPushInt(a.ival < b.ival);
}

void CalcGtI(void)
{
	PVal a, b;
	b = StackPop();
	a = StackPop();
	StackPushInt(a.ival > b.ival);
}

void CalcLtEqI(void)
{
	PVal a, b;
	b = StackPop();
	a = StackPop();
	StackPushInt(a.ival <= b.ival);
}

void CalcGtEqI(void)
{
	PVal a, b;
	b = StackPop();
	a = StackPop();
	StackPushInt(a.ival >= b.ival);
}

void CalcOrI(void)
{
	PVal a, b;
	b = StackPop();
	a = StackPop();
	StackPushInt(a.ival || b.ival);
}

/* TODO */
void VarCalc(PVal *var, int i, int j)
{
	if (i == 0) {
		PVal a = StackPop();
		StackPushInt(a.ival + var->ival);
	}
	return;
}

int HspIf(void)
{
	int ret = StackPop().ival;
	return !ret;
}

void mes(char *s)
{
	putfonts8_asc_sht(sht_back, pos.x, pos.y, color, 0, s, strlen(s));
	pos.y += 16;
}

void line(int x0, int y0, int x1, int y1)
{
	int i, x, y, len, dx, dy;

	dx = x1 - x0;
	dy = y1 - y0;
	x = x0 << 10;
	y = y0 << 10;
	if (dx < 0)	dx = - dx;
	if (dy < 0)	dy = - dy;
	if (dx >= dy) {
		len = dx + 1;
		if (x0 > x1) {
			dx = -1024;
		} else {
			dx = +1024;
		}
		if (y0 <= y1) {
			dy = ((y1 - y0 + 1) << 10) / len;
		} else {
			dy = ((y1 - y0 - 1) << 10) / len;
		}
	} else {
		len = dy + 1;
		if (y0 > y1) {
			dy = -1024;
		} else {
			dy = +1024;
		}
		if (x0 <= x1) {
			dx = ((x1 - x0 + 1) << 10) / len;
		} else {
			dx = ((x1 - x0 - 1) << 10) / len;
		}
	}
	for (i = 0; i < len; i++) {
		sht_back->buf[(y >> 10) * sht_back->bxsize + (x >> 10)] = RGB(color.r, color.g, color.b);
		x += dx;
		y += dy;
	}

	pos.x = x0;
	pos.y = y0;
	sheet_refresh(sht_back, 0, 0, sht_back->bxsize, sht_back->bysize);

	return;
}

void Intcmd(int num, int i)
{
	if (num == 2) {		/* onkey */
		onkey_jmp = StackPop().ival;
	}
	if (num == 3) {		/* onclick */
		onclick_jmp = StackPop().ival;
	}
	if (num == 17) {	/* exist */
		int n = -1;
		FILE *fp;
		if ((fp = fopen(StackPop().str, "r")) != NULL) {
			n = fexist(fp);
		}
		hspstrsize = n;
		fclose(fp);
	}
	if (num == 39) {	/* randomize */
		if (i == 0) {
			rndseed = getseed();
		}
		if (i == 1) {
			rndseed = StackPop().ival;
		}
	}
}

void Extcmd(int num, int i)
{
	PVal pv, pv2, pv3, pv4;
	int tmp;
	if (num == 0x0c) {	/* pset */
		if (i == 0) {
			sht_back->buf[pos.y * sht_back->bxsize + pos.x] = RGB(color.r, color.g, color.b);
			sheet_refresh(sht_back, pos.x, pos.y, pos.x+1, pos.y+1);
		}
		if (i == 2) {
			pos.x = StackPop().ival;
			pos.y = StackPop().ival;
			sht_back->buf[pos.y * sht_back->bxsize + pos.x] = RGB(color.r, color.g, color.b);
			sheet_refresh(sht_back, pos.x, pos.y, pos.x+1, pos.y+1);
		}
	}
	if (num == 0x0f) {	/* mes */
		pv = StackPop();
		if (pv.type == ST_INT) {
			char s[15];
			sprintf(s, "%d", pv.ival);
			mes(s);
		} else {
			mes(pv.str);
		}
	}
	if (num == 0x10) {	/* title TBD */
	}
	if (num == 0x11) {	/* pos */
		if (i == 2) {
			pos.x = StackPop().ival;
			pos.y = StackPop().ival;
		}
	}
	if (num == 0x13) {	/* cls ReqImp */
		pos.x = pos.y = 0;
		if (i == 0) {
			boxfillA(sht_back->buf, sht_back->bxsize, COLA_FFFFFF, 0, 0, sht_back->bxsize, sht_back->bysize);
			sheet_refresh(sht_back, 0, 0, sht_back->bxsize, sht_back->bysize);
		}
		if (i == 1) {
			pv = StackPop();
			color.r = color.g = color.b = pos.x = pos.y = 0;
			if (pv.ival == 0) {
				tmp = RGB(0xff,0xff,0xff);
			}
			if (pv.ival == 1) {
				tmp = RGB(0xcc,0xcc,0xcc);
			}
			if (pv.ival == 2) {
				tmp = RGB(0x99,0x99,0x99);
			}
			if (pv.ival == 3) {
				tmp = RGB(0x33,0x33,0x33);
			}
			if (pv.ival == 4) {
				tmp = RGB(0x00,0x00,0x00);
			}
			boxfillA(sht_back->buf, sht_back->bxsize,
					 getRGB16(tmp).r, getRGB16(tmp).g, getRGB16(tmp).b,
					 0, 0, sht_back->bxsize, sht_back->bysize);
			sheet_refresh(sht_back, 0, 0, sht_back->bxsize, sht_back->bysize);
		}
	}
	if (num == 0x17) {	/* picload */
		if (loadimg(StackPop().str, 0, 0)) {
			mes("画像ファイルが見つかりません。");
			while(1);
		}
	}
	if (num == 0x18) {	/* color */
		if (i == 0) {
			color.r = color.g = color.b = 0;
		}
		if (i == 3) {
			color.r = StackPop().ival;
			color.g = StackPop().ival;
			color.b = StackPop().ival;
		}
	}
	if (num == 0x22) {	/* hsvcolor TODO */
	}
	if (num == 0x2f) {	/* line */
		if (i == 0) {
			line(0, 0, pos.x, pos.y);
		}
		if (i == 2) {
			pv  = StackPop();
			pv2 = StackPop();
			line(pos.x, pos.y, pv.ival, pv2.ival);
			pos.x = pv.ival;
			pos.y = pv2.ival;
		}
		if (i == 4) {
			pv  = StackPop();
			pv2 = StackPop();
			pv3 = StackPop();
			pv4 = StackPop();
			line(pv.ival, pv2.ival, pv3.ival, pv4.ival);
		}
	}
	if (num == 0x31) {	/* boxf ReqImp */
		if (i == 0) {
			boxfillA(sht_back->buf, sht_back->bxsize, color.r, color.g, color.b, 0, 0, sht_back->bxsize, sht_back->bysize);
			sheet_refresh(sht_back, 0, 0, sht_back->bxsize, sht_back->bysize);
		}
		if (i == 2) {
			pv  = StackPop();
			pv2 = StackPop();
			boxfillA(sht_back->buf, sht_back->bxsize, color.r, color.g, color.b, pv.ival, pv2.ival, sht_back->bxsize, sht_back->bysize);
			sheet_refresh(sht_back, pv.ival-1, pv2.ival-1, sht_back->bxsize, sht_back->bysize);
		}
		if (i == 4) {
			pv  = StackPop();
			pv2 = StackPop();
			pv3 = StackPop();
			pv4 = StackPop();
			boxfillA(sht_back->buf, sht_back->bxsize, color.r, color.g, color.b, pv.ival, pv2.ival, pv3.ival, pv4.ival);
			sheet_refresh(sht_back, pv.ival-1, pv2.ival-1, pv3.ival+1, pv4.ival+1);
		}
	}
	if (num == 44) {	/* mouse */
		if (i >= 1) {
			pv  = StackPop();
			if (i >= 2) {
				pv2 = StackPop();
			}
		}

		if (i == 0) {
			mouse(0, 0, 2);
		}
		if (i == 1) {
			if (pv.ival == -1) {
				mouse(0, 0, 1);
			} else {
				mouse(pv.ival, -1, 0);
			}
		}
		if (i == 2) {
			if (pv.ival == -1 || pv2.ival == -1) {
				mouse(0, 0, 1);
			} else {
				mouse(pv.ival, pv2.ival, 0);
			}
		}
	}
	if (num == 41) {	/* buffer TODO */
	}
	return;
}

#define MAX_NEST	128

int loopcount[MAX_NEST];
int loopmode[MAX_NEST];
int jcount[MAX_NEST];
int endjmp[MAX_NEST];
int repjmp[MAX_NEST];
int nestnow = 0;

void Prgcmd(int num, int i)
{
	PVal pv1;
	if (num == 0) {		/* goto TODO */
	}
	if (num == 1) {		/* gosub TODO */
	}
	if (num == 2) {		/* return TODO */
	}
	if (num == 3) {		/* break TODO */
	}
	if (num == 4) {		/* repeat */
		if (i == 3) {
			hspcnt = 0;
			nestnow++;
			loopmode[nestnow] = 0;
			loopcount[nestnow] = 0;
			repjmp[nestnow] = StackPop().ival;
			endjmp[nestnow] = StackPop().ival;
			jcount[nestnow] = StackPop().ival;
			TaskSwitch(repjmp[nestnow]);
		}
		if (i == 2) {
			nestnow = 0;
			loopmode[nestnow] = -1;
			repjmp[nestnow] = StackPop().ival;
			TaskSwitch(repjmp[nestnow]);
		}
	}
	if (num == 5) {		/* loop */
		if (loopmode[nestnow] == 0) {
			loopcount[nestnow]++;
			hspcnt = loopcount[nestnow];
			if (jcount[nestnow] <= loopcount[nestnow]) {
				hspcnt = 0;
				TaskSwitch(endjmp[nestnow--]);
			}
		}
		TaskSwitch(repjmp[nestnow]);
	}
	if (num == 6) {		/* continue TODO */
	}
	if (num == 7) {		/* wait ReqImp */
		pv1 = StackPop();
		if (pv1.ival != 0) {
			timer_settime(hsptimer, pv1.ival);
			task_sleep(hsptask);
			hsptimer->fifo->free = 128;
		}
	}
	if (num == 8) {		/* await TODO */
	}
	if (num == 9) { 	/* dim TODO */
	}
	if (num == 10) {	/* sdim TODO */
	}
	if (num == 11) {	/* foreach TODO */
	}
	if (num == 13) {	/* dimtype TODO */
	}
	if (num == 14) {	/* dup TODO */
	}
	if (num == 15) {	/* dupptr TODO */
	}
	if (num == 16) {	/* end */
		int tmp = initAcpi();
		if (tmp == 0) {
			acpiPowerOff();
		} else {
			io_cli();
			fifo32_put(&hsptask->fifo, 0xff);
		}
		while(1) io_hlt();
	}
	if (num == 17) {	/* stop ReqImp */
		fifo32_put(&hsptask->fifo, 0x7ff);
	}
	return;
}

inline void TaskSwitch(int a)
{
	char (*p)(void);
	p = __HspTaskFunc[a];
	(*p)();
	return;
}

/* end of hsp.c */
