#include "interpret.h"

#include <stdio.h>

#include "communication_interface.h"
#include "interpret.h"
#include "task.h"
#include "mem.h"

extern struct MTask *current_task;

#ifdef STACK_CHECKING
#define inc_sp(i)\
	if (stack+(i++) >= mem_max_sp()) {\
		send_message((struct MTMessageFro)\
			{ .cons=MTFException_c\
			, .data={ .MTFException=\
				{ .cons=MTEStackOverflow_c }\
			}});\
		return false;\
	}
#else /* STACK_CHECKING */
#define inc_sp(i) i++;
#endif /* STACK_CHECKING */

//Helper functions to convert {{{
#define uint16_t22uint32_t(x, y) (((uint32_t)x << 16) + (uint32_t)y)
#define from16(p, i) p[i]*256+p[i+1]
//}}}

//Binary operators {{{
#define binop(op) {\
	stack[sp-2] = (int16_t)stack[sp-2] op (int16_t)stack[sp-1];\
	sp -= 1;\
}

#define binop2lhs uint16_t22uint32_t(stack[sp-4], stack[sp-3])
#define binop2rhs uint16_t22uint32_t(stack[sp-2], stack[sp-1])
#define binop2(op) {\
	*PALIGN(uint32_t, stack+sp)\
		= (int32_t)binop2lhs op (int32_t)binop2rhs;\
	stack[sp-4] = *PALIGN(uint32_t, stack+sp) >> 16;\
	stack[sp-3] = *PALIGN(uint32_t, stack+sp) & 0xffff;\
	sp -= 2;\
}
#define binopr(op) {\
	*PALIGN(uint32_t, stack+sp) = float2uint32_t(\
		uint32_t2float(binop2lhs) op uint32_t2float(binop2rhs));\
	stack[sp-4] = *PALIGN(uint32_t, stack+sp) >> 16;\
	stack[sp-3] = *PALIGN(uint32_t, stack+sp) & 0xffff;\
	sp -= 2;\
}
#define boolop2(op) {\
	stack[sp-4] = (int32_t)binop2lhs op (int32_t)binop2rhs;\
	sp -= 3;\
}
#define boolopr(op) {\
	stack[sp-4] = uint32_t2float(binop2lhs) op uint32_t2float(binop2rhs);\
	sp -= 3;\
}
//}}}

bool interpret(uint8_t *program, uint16_t pc, uint16_t sp, uint16_t *stack)
{
	uint16_t fp = sp, i, j;
	struct TaskTree *tt = NULL;
	msg_debug(SC("Interpreting code starting from stack: %p\n"), stack);
	msg_debug(SC("Interpreting code starting from sp: %u\n"), sp);
	msg_debug(SC("Interpreting code starting from prog: %p\n"), program);
	while (true) {
		//Make sure the dogs are fed
		real_yield();

		switch (program[pc++]) {
#define BCRETURNC(returnwidth, argwidth) {/*{{{*/\
	msg_debug(SC("Return width: %u, arg: %u\n"), returnwidth, argwidth);\
	sp = stack[fp-(argwidth)-3]+(returnwidth);  /*Reset the stack pointer*/\
	pc = stack[fp-(argwidth)-1];                /*Reset program counter*/  \
	uint16_t _i = stack[fp-(argwidth)-2];       /*Safe the frame pointer*/ \
	for (uint16_t _j = 0; _j<(returnwidth); _j++) {\
		stack[fp-(argwidth)-3+_j] = stack[fp+_j];\
	}\
	if (sp-(returnwidth) == 0) {\
		return true;\
	} else {\
		fp = _i;                            /*Reset frame pointer*/    \
	}\
} //}}}
#define BCROTC(depth, rotations) {/*{{{*/\
	for (; (rotations)>0; (rotations)--) {\
		for (uint8_t _k = 0; _k<depth; _k++) {\
			stack[sp-_k] = stack[sp-_k-1];\
		}\
		stack[sp-depth] = stack[sp];\
	}\
}//}}}
#define BCARGC(arg) { /*{{{*/\
		msg_debug(SC("arg(%u)\n"), arg);\
		stack[sp] = stack[fp-1-(arg)];\
		inc_sp(sp);\
} //}}}
		case BCLabel_c:
			die("This should not happen!");
			break;
//Return instructions {{{
		case BCReturn1_0_c:
			BCRETURNC(1, 0);
			break;
		case BCReturn1_1_c:
			BCRETURNC(1, 1);
			break;
		case BCReturn1_2_c:
			BCRETURNC(1, 2);
			break;
		case BCReturn1_c:
			i = program[pc++];
			BCRETURNC(1, i);
			break;
		case BCReturn2_0_c:
			BCRETURNC(2, 0);
			break;
		case BCReturn2_1_c:
			BCRETURNC(2, 1);
			break;
		case BCReturn2_2_c:
			BCRETURNC(2, 2);
			break;
		case BCReturn2_c:
			i = program[pc++];
			BCRETURNC(2, i);
			break;
		case BCReturn3_0_c:
			BCRETURNC(3, 0);
			break;
		case BCReturn3_1_c:
			BCRETURNC(3, 1);
			break;
		case BCReturn3_2_c:
			BCRETURNC(3, 2);
			break;
		case BCReturn3_c:
			i = program[pc++];
			BCRETURNC(3, i);
			break;
		case BCReturn_0_c:
			i = program[pc++];
			BCRETURNC(i, 0);
			break;
		case BCReturn_1_c:
			i = program[pc++];
			BCRETURNC(i, 1);
			break;
		case BCReturn_2_c:
			i = program[pc++];
			BCRETURNC(i, 2);
			break;
		case BCReturn_c:
			//get return width
			i = program[pc++];
			//get arg width
			j = program[pc++];
			BCRETURNC(i, j);
			break;
//}}}
//Jumping and function calls {{{
		case BCPushPtrs_c:
			stack[sp] = sp; /* push sp */
			inc_sp(sp);
			stack[sp] = fp; /* push fp */
			inc_sp(sp);
			stack[sp] = 0;  /* reserve space for pc */
			inc_sp(sp);

			msg_debug(SC("Ptrs pushed: (sp: %u, fp: %u, pc: %u)\n"),
				stack[sp-3], stack[sp-2], stack[sp-1]);
			break;
		case BCJumpF_c:
			msg_debug(SC("Jumpf (%s: %u)\n"),
				stack[sp-1] ? SC("true") : SC("false"),
				from16(program,pc));
			if (stack[--sp]) {
				pc = pc + 2;
			} else {
				pc = from16(program,pc);
			}
			break;
		case BCJump_c:
			msg_debug(SC("Jump to %u\n"), from16(program,pc));
			pc = from16(program,pc);
			break;
		case BCJumpSR_c:
			//Fetch the arity
			i = program[pc++];
			msg_debug(SC("Jump to sr at %u with arity %u\n"),
				from16(program,pc), i);
			msg_debug(SC("sr[0] = %u\n"), *(program+pc));
			msg_debug(SC("sr[1] = %u\n"), *(program+pc+1));
			msg_debug(SC("sr    = %u\n"),
				program[pc]*256+program[pc+1]);
			msg_debug(SC("sr    = %u\n"), from16(program,pc));

			stack[sp-i-1] = pc+2;    // Set PC using backpatching
			fp = sp;                 // Set new fp
			pc = from16(program,pc); // Jump to sr

			break;
		case BCTailcall_c:
			//Argwidth of the current function
			i = program[pc++];
			//Argwidth of the to jump to function
			j = program[pc++];
			//increment rotation depth with the argwidth of the jump
			//and pointers
			i += 3 + j;
			BCROTC(i, j);
			//j is mangled now
			//Reset the stack pointer to the original stack frame
			//compensated for the difference in argument width
			//Remove our old args, add the new args and go one up
			//i and j are mangled because of BCROTC
			fp = (fp - program[pc-2]) + program[pc-1];
			sp = fp;
			pc = from16(program,pc);
			break;
//}}}
// Arguments {{{
		case BCStepArg_c:
			//Skip over the step number
			pc+=2;
			i = program[pc++];
			BCARGC(i);
			break;
		case BCArg0_c:
			BCARGC(0); break;
		case BCArg1_c:
			BCARGC(1); break;
		case BCArg2_c:
			BCARGC(2); break;
		case BCArg3_c:
			BCARGC(3); break;
		case BCArg4_c:
			BCARGC(4); break;
		case BCArg10_c:
			BCARGC(1); BCARGC(0); break;
		case BCArg21_c:
			BCARGC(2); BCARGC(1); break;
		case BCArg32_c:
			BCARGC(3); BCARGC(2); break;
		case BCArg43_c:
			BCARGC(4); BCARGC(3); break;
		case BCArg_c:
			i = program[pc++];
			BCARGC(i);
			break;
		case BCArgs_c:
			//from
			i = program[pc++] + 1;
			//to
			j = program[pc++] + 1;
			msg_debug(SC("BCArgs from %u to %u\n"), i - 1, j - 1);
			if (i >= j) {
				for ( ; i>=j; i--)
					BCARGC(i - 1);
			} else {
				for ( ; i<=j; i++)
					BCARGC(i - 1);
			}
			break;
//}}}
//Task node creation {{{
		case BCMkTask_c:
			msg_debug(SC("Task: \n"));
			tt = mem_alloc_tree();
			if (tt == NULL)
				return NULL;
			msg_debug(SC("Alloced: %p\n"), tt);
			tt->task_type = program[pc++];
			msg_debug(SC("task_type set: %u\n"), tt->task_type);
			tt->ptr = (struct TaskTree *)current_task;
			msg_debug(SC("rptr: %u\n"), tt->ptr);
			tt->trash = false;
			msg_debug(SC("trash: %u\n"), tt->trash);
			// Default refresh rate is [1,0]
			// Min value bigger then max value means
			// that the value is calculated
			tt->seconds = false;
			tt->refresh_min = 1;
			tt->refresh_max = 0;
			switch (tt->task_type) {
//Constant node values {{{
			case BCStableNode_c:
				msg_debug(SC("Stable node\n"));
				tt->data.stablenode.next = mem_ptr(stack[--sp]);
				msg_debug(SC("next: %u\n"), stack[sp]);
				tt->data.stablenode.w = program[pc++];
				msg_debug(SC("width: %u\n"), program[pc]);
				tt->data.stablenode.stable[1] = stack[--sp];
				msg_debug(SC("b0: %u\n"), stack[sp]);
				tt->data.stablenode.stable[0] = stack[--sp];
				msg_debug(SC("b1: %u\n"), stack[sp]);
				tt->data.stablenode.next->ptr = tt;
				break;
			case BCStable0_c:
				msg_debug(SC("Stable0\n"));
				break;
			case BCStable1_c:
				tt->data.stable[0] = stack[--sp];
				msg_debug(SC("Stable1: %u\n"),
					tt->data.stable[0]);
				break;
			case BCStable2_c:
				tt->data.stable[1] = stack[--sp];
				tt->data.stable[0] = stack[--sp];
				msg_debug(SC("Stable2: %u %u\n"),
					tt->data.stable[0], tt->data.stable[1]);
				break;
			case BCStable3_c:
				tt->data.stable[2] = stack[--sp];
				tt->data.stable[1] = stack[--sp];
				tt->data.stable[0] = stack[--sp];
				msg_debug(SC("Stable3: %u %u %u\n"),
					tt->data.stable[0], tt->data.stable[1],
					tt->data.stable[2]);
				break;
			case BCStable4_c:
				tt->data.stable[3] = stack[--sp];
				tt->data.stable[2] = stack[--sp];
				tt->data.stable[1] = stack[--sp];
				tt->data.stable[0] = stack[--sp];
				msg_debug(SC("Stable4: %u %u %u %u\n"),
					tt->data.stable[0], tt->data.stable[1],
					tt->data.stable[2], tt->data.stable[3]);
				break;
			case BCUnstableNode_c:
				msg_debug(SC("Unstable node\n"));
				tt->data.unstablenode.next =
					mem_ptr(stack[--sp]);
				tt->data.unstablenode.w = program[pc++];
				tt->data.unstablenode.unstable[1] = stack[--sp];
				tt->data.unstablenode.unstable[0] = stack[--sp];
				tt->data.unstablenode.next->ptr = tt;
				break;
			case BCUnstable0_c:
				msg_debug(SC("Unstable0\n"));
				break;
			case BCUnstable1_c:
				tt->data.unstable[0] = stack[--sp];
				msg_debug(SC("Unstable: %u\n"),
					tt->data.unstable);
				break;
			case BCUnstable2_c:
				tt->data.unstable[1] = stack[--sp];
				tt->data.unstable[0] = stack[--sp];
				msg_debug(SC("Stable2: %u %u\n"),
					tt->data.stable[0], tt->data.stable[1]);
				break;
			case BCUnstable3_c:
				tt->data.unstable[2] = stack[--sp];
				tt->data.unstable[1] = stack[--sp];
				tt->data.unstable[0] = stack[--sp];
				msg_debug(SC("Stable3: %u %u %u\n"),
					tt->data.stable[0], tt->data.stable[1],
					tt->data.stable[2]);
				break;
			case BCUnstable4_c:
				tt->data.unstable[3] = stack[--sp];
				tt->data.unstable[2] = stack[--sp];
				tt->data.unstable[1] = stack[--sp];
				tt->data.unstable[0] = stack[--sp];
				msg_debug(SC("Stable4: %u %u %u %u\n"),
					tt->data.stable[0], tt->data.stable[1],
					tt->data.stable[2], tt->data.stable[3]);
				break;
//}}}
//Pin IO {{{
			case BCReadD_c:
				msg_debug(SC("ReadD\n"));
				tt->data.readd = translate_pin(stack[--sp]);
				break;
			case BCWriteD_c:
				msg_debug(SC("WriteD\n"));
				tt->data.writed.value = stack[--sp];
				tt->data.writed.pin = translate_pin(stack[--sp]);
				break;
			case BCReadA_c:
				msg_debug(SC("ReadA\n"));
				tt->data.reada = translate_pin(stack[--sp]);
				break;
			case BCWriteA_c:
				msg_debug(SC("WriteA\n"));
				tt->data.writea.value = stack[--sp];
				tt->data.writea.pin = translate_pin(stack[--sp]);
				break;
			case BCPinMode_c:
				msg_debug(SC("PinMode\n"));
				tt->data.pinmode.pin = translate_pin(stack[--sp]);
				tt->data.pinmode.pinmode = program[pc++];
				break;
//}}}
// Interrupts {{{
			case BCInterrupt_c:
				msg_debug(SC("Interrupt\n"));
				tt->data.interrupt.pin = translate_pin(stack[--sp]);
				tt->data.interrupt.mode = program[pc++];
				tt->data.interrupt.triggered = false;
				tt->data.interrupt.status = false;
				tt->data.interrupt.initialized = false;
				break;
//}}}
// Repeat, delay and step {{{
			case BCRepeat_c:
				msg_debug(SC("REPEAT\n"));
				tt->data.repeat.oldtree = mem_ptr(stack[--sp]);
				tt->data.repeat.tree = NULL;
				tt->data.repeat.done = false;
				tt->data.repeat.start = 0;
				tt->data.repeat.oldtree->ptr = tt;
				break;
			case BCDelay_c:
				tt->data.delay = stack[--sp];
				msg_debug(SC("delay : %lu\n"), tt->data.delay);
				break;
			case BCDelayUntil_c:
				die("delay until, shouldn't happen");
				break;
			case BCStep_c:
				msg_debug(SC("step: "));
				tt->data.step.w = program[pc++];
				tt->data.step.lhs = mem_ptr(stack[--sp]);
				tt->data.step.rhs = from16(program,pc);
				pc+=2;
				msg_debug(SC("step: %u %lu %lu\n"),
					tt->data.step.w, tt->data.step.lhs,
					tt->data.step.rhs);
				tt->data.step.lhs->ptr = tt;
				break;
			case BCStepUnstable_c:
				msg_debug(SC("stepunstable: "));
				tt->data.stepu.w = program[pc++];
				tt->data.stepu.lhs = mem_ptr(stack[--sp]);
				tt->data.stepu.rhs = from16(program,pc);
				pc+=2;
				msg_debug(SC("stepu: %u %lu %lu\n"),
					tt->data.stepu.w, tt->data.stepu.lhs,
					tt->data.stepu.rhs);
				tt->data.stepu.lhs->ptr = tt;
				break;
			case BCStepStable_c:
				msg_debug(SC("stepstable: "));
				tt->data.steps.w = program[pc++];
				tt->data.steps.lhs = mem_ptr(stack[--sp]);
				tt->data.steps.rhs = from16(program,pc);
				pc+=2;
				msg_debug(SC("steps: %u %lu %lu\n"),
					tt->data.steps.w, tt->data.steps.lhs,
					tt->data.steps.rhs);
				tt->data.steps.lhs->ptr = tt;
				break;
			case BCSeqStable_c:
				msg_debug(SC("seq stable: "));
				tt->data.seqs.w = program[pc++];
				tt->data.seqs.rhs = mem_ptr(stack[--sp]);
				tt->data.seqs.lhs = mem_ptr(stack[--sp]);
				msg_debug(SC("seq stable: %p %p\n"),
					tt->data.seqs.lhs, tt->data.seqs.rhs);
				tt->data.seqs.lhs->ptr = tt;
				tt->data.seqs.rhs->ptr = tt;
				break;
			case BCSeqUnstable_c:
				msg_debug(SC("seq unstable: "));
				tt->data.sequ.w = program[pc++];
				tt->data.sequ.rhs = mem_ptr(stack[--sp]);
				tt->data.sequ.lhs = mem_ptr(stack[--sp]);
				msg_debug(SC("seq unstable: %lu %lu\n"),
					tt->data.sequ.lhs, tt->data.sequ.rhs);
				tt->data.sequ.lhs->ptr = tt;
				tt->data.sequ.rhs->ptr = tt;
				break;
//}}}
//Parallel {{{
			case BCTOr_c:
				tt->data.tor.rhs = mem_ptr(stack[--sp]);
				tt->data.tor.lhs = mem_ptr(stack[--sp]);
				msg_debug(SC("(-||-) %u %u \n"),
					tt->data.tor.lhs, tt->data.tor.rhs);
				tt->data.tor.lhs->ptr = tt;
				tt->data.tor.rhs->ptr = tt;
				break;
			case BCTAnd_c:
				tt->data.tand.rhs = mem_ptr(stack[--sp]);
				tt->data.tand.lhs = mem_ptr(stack[--sp]);
				msg_debug(SC("(-&&-) %u %u\n"),
					tt->data.tand.lhs, tt->data.tand.rhs);
				tt->data.tand.lhs->ptr = tt;
				tt->data.tand.rhs->ptr = tt;
				break;
//}}}
//Sds {{{
			case BCSdsSet_c:
				tt->data.sdsset.sds = sds_get(program[pc++]);
				tt->data.sdsset.data =
					mem_cast_tree(stack[--sp]);
				msg_debug(SC("set sds: %u at %u with at %u\n"),
					program[pc-1], tt->data.sdsset.sds,
					tt->data.sdsset.data);
				tt->data.sdsset.data->ptr = tt;
				break;
			case BCSdsGet_c:
				tt->data.sdsget = sds_get(program[pc++]);
				msg_debug(SC("get sds: %u at %u\n"),
					program[pc-1], tt->data.sdsget);
				break;
			case BCSdsUpd_c:
				tt->data.sdsupd.sds = sds_get(program[pc++]);
				tt->data.sdsupd.fun = from16(program,pc);
				pc+=2;
				tt->data.sdsupd.ctx = mem_ptr(stack[--sp]);
				msg_debug(SC("upd sds at %u with fun %u\n"),
					program[pc-3], tt->data.sdsupd.fun);
				break;
//}}}
//Peripherals {{{
//RateLimit {{{
			case BCRateLimit_c:
				tt->data.ratelimit.task = mem_ptr(stack[--sp]);
				msg_debug(SC("rate limit: %p\n"),
					tt->data.ratelimit.task);
				tt->data.ratelimit.last_execution = 0;
				tt->data.ratelimit.storage = NULL;
				tt->data.ratelimit.task->ptr = tt;
				break;
//}}}
//DHT {{{
#ifdef HAVE_DHT
			case BCDHTTemp_c:
				msg_debug(SC("Read dht temp %d\n"),
					program[sp-1]);
				tt->data.dhttemp =
					peripheral_get(program[pc++]);
				break;
			case BCDHTHumid_c:
				msg_debug(SC("Read dht humid %d\n"),
					stack[sp-1]);
				tt->data.dhthumid =
					peripheral_get(program[pc++]);
				break;
#else /* HAVE_DHT */
			case BCDHTTemp_c:
				pc++;
				break;
			case BCDHTHumid_c:
				pc++;
				break;
#endif /* HAVE_DHT */
//}}}
//I2CButton {{{
#ifdef HAVE_I2CBUTTON
			case BCAButton_c:
				msg_debug(SC("abutton: %d\n"), stack[sp-1]);
				tt->data.abutton =
					peripheral_get(program[pc++]);
				break;
			case BCBButton_c:
				msg_debug(SC("bbutton: %d\n"), stack[sp-1]);
				tt->data.bbutton =
					peripheral_get(program[pc++]);
				break;
#else /* HAVE_I2CBUTTON */
			case BCAButton_c:
				pc++;
				break;
			case BCBButton_c:
				pc++;
				break;
#endif /* HAVE_I2CBUTTON */
//}}}
//{{{LightSensor
#ifdef HAVE_LIGHTSENSOR
			case BCGetLight_c:
				tt->data.lightsensor =
					peripheral_get(program[pc++]);
				break;
#else /* HAVE_LIGHTSENSOR */
			case BCGetLight_c:
				pc++;
				break;
#endif /* HAVE_LIGHTSENSOR */
//}}}
//{{{AirQualitySensor
#ifdef HAVE_AIRQUALITYSENSOR
			case BCSetEnvironmentalData_c:
				tt->data.setenvironment.humid =
					uint32_t2float(
						(stack[sp-2] << 16) +
						 stack[sp-1]
					);
				tt->data.setenvironment.temp =
					uint32_t2float(
						(stack[sp-4] << 16) +
						 stack[sp-3]
					);
				sp-=4;
				tt->data.setenvironment.sensor =
					peripheral_get(program[pc++]);
				msg_debug(SC("set environment %u\n"),
						tt->data.setenvironment.sensor);
				break;
			case BCTVOC_c:
				tt->data.airqualitysensor =
					peripheral_get(program[pc++]);
				msg_debug(SC("get air quality voc %u\n"),
						tt->data.airqualitysensor);
				break;
			case BCCO2_c:
				tt->data.airqualitysensor =
					peripheral_get(program[pc++]);
				msg_debug(SC("get air quality co2 %u\n"),
						tt->data.airqualitysensor);
				break;
#else /* HAVE_AIRQUALITYSENSOR */
			case BCSetEnvironmentalData_c:
				sp-=4;
				pc++;
				break;
			case BCTVOC_c:
			case BCCO2_c:
				pc++;
				break;
#endif /* HAVE_AIRQUALITYSENSOR */
//}}}
//{{{GestureSensor
#ifdef HAVE_GESTURESENSOR
			case BCGesture_c:
				tt->data.gesturesensor =
					peripheral_get(program[pc++]);
				msg_debug(SC("get gesture %u\n"),
						tt->data.gesturesensor);
				break;
#else /* HAVE_GESTURESENSOR */
			case BCGesture_c:
				pc++;
				break;
#endif /* HAVE_GESTURESENSOR */
//}}}

//LEDMatrix {{{
#ifdef HAVE_LEDMATRIX
			case BCLEDMatrixDisplay_c:
				//msg_log(SC("LED matrix display\n"));
				tt->data.ledmatrixdisplay =
					peripheral_get(program[pc++]);
				break;
			case BCLEDMatrixIntensity_c:
				//msg_log(SC("LED matrix intensity to: %d\n"),
				//	stack[sp-1]);
				tt->data.ledmatrixintensity.id =
					peripheral_get(program[pc++]);
				tt->data.ledmatrixintensity.intensity
					= stack[--sp];
				break;
			case BCLEDMatrixDot_c:
				//msg_log(SC("LED matrix dot to: s=%d y=%d x=%d\n"),
				//	stack[sp-1], stack[sp-2], stack[sp-3]);
				tt->data.ledmatrixdot.id =
					peripheral_get(program[pc++]);
				tt->data.ledmatrixdot.s = stack[--sp];
				tt->data.ledmatrixdot.y = stack[--sp];
				tt->data.ledmatrixdot.x = stack[--sp];
				break;
			case BCLEDMatrixClear_c:
				//msg_log(SC("LED matrix clear\n"));
				tt->data.ledmatrixclear =
					peripheral_get(program[pc++]);
				break;
#else /* HAVE_LEDMATRIX */
			case BCLEDMatrixDisplay_c:
				pc++;
				break;
			case BCLEDMatrixIntensity_c:
				pc++;
				sp--;
				break;
			case BCLEDMatrixDot_c:
				pc++;
				sp-=3;
				break;
			case BCLEDMatrixClear_c:
				pc++;
				break;
#endif /* HAVE_LEDMATRIX */
//}}}
//}}}
			}
			msg_debug(SC("Task pushed at %p %lu: "),
				tt, mem_rptr(tt));
			tasktree_print(tt, 0);
			msg_debug(SC("\n"));
			stack[sp] = mem_rptr(tt);
			inc_sp(sp);
			break;
//}}}
//Task node refinement {{{
		case BCTuneRateSec_c:
			msg_debug(SC("TuneRateSec\n"));
			tt->seconds = true;
			/*fallthrough*/
		case BCTuneRateMs_c:
			msg_debug(SC("TuneRateMs\n"));
			tt->refresh_max = stack[--sp];
			tt->refresh_min = stack[--sp];
		break;
//}}}
//Task value ops {{{
		case BCIsNoValue_c:
			msg_debug(SC("IsNoValue\n"));
			stack[sp-1] = stack[sp-1] == MTNoValue_c;
			break;
		case BCIsUnstable_c:
			msg_debug(SC("IsUnStable\n"));
			stack[sp-1] = stack[sp-1] == MTUnstable_c;
			break;
		case BCIsStable_c:
			msg_debug(SC("IsStable\n"));
			stack[sp-1] = stack[sp-1] == MTStable_c;
			break;
		case BCIsValue_c:
			msg_debug(SC("IsValue\n"));
			stack[sp-1] = stack[sp-1] != MTNoValue_c;
			break;
//}}}
//Stack ops {{{
		case BCRot_c:
			msg_debug(SC("Rot\n"));
			//depth
			i = program[pc++];
			//rotations
			j = program[pc++];
			BCROTC(i,j);
			break;
		case BCDup_c:
			msg_debug(SC("Dup\n"));
			stack[sp] = stack[sp-1];
			sp++;
			break;
		case BCPop4_c:
			sp-=4;
			msg_debug(SC("Pop4\n"));
			break;
		case BCPop3_c:
			sp-=3;
			msg_debug(SC("Pop2\n"));
			break;
		case BCPop2_c:
			sp-=2;
			msg_debug(SC("Pop2\n"));
			break;
		case BCPop1_c:
			sp--;
			msg_debug(SC("Pop\n"));
			break;
		case BCPop_c:
			msg_debug(SC("Popn\n"));
			sp-=program[pc++];
			break;
		case BCPush1_c:
			stack[sp] = program[pc++];
			inc_sp(sp);
			msg_debug(SC("Push1: %u\n"), stack[sp-1]);
			break;
		case BCPush2_c:
			stack[sp] = from16(program,pc);
			msg_debug(SC("Push2: %u\n"), stack[sp]);
			inc_sp(sp);
			pc+=2;
			break;
		case BCPush3_c:
			stack[sp++] = from16(program,pc);
			pc+=2;
			stack[sp] = program[pc++];
			inc_sp(sp);
			msg_debug(SC("Push3: %u\n"), stack[sp-1]);
			break;
		case BCPush4_c:
			stack[sp++] = from16(program,pc);
			pc+=2;
			stack[sp] = from16(program,pc);
			inc_sp(sp);
			pc+=2;
			msg_debug(SC("Push4: %u\n"), stack[sp-1]);
			break;
		case BCPush_c:
			i = program[pc++];
			msg_debug(SC("Push %u\n"), i);
			for (j = 0; j<i; j++)
				if (j % 2 == 0) {
					stack[sp] = program[pc++]*256;
					inc_sp(sp);
				} else {
					stack[sp-1] += program[pc++];
				}
			break;
		case BCPushNull_c:
			stack[sp] = MT_NULL;
			inc_sp(sp);
			break;
//}}}
//Casting {{{
		case BCItoR_c:
			i = stack[sp-1];
			stack[sp-1] =
				float2uint32_t((float)(int16_t)i) >> 16;
			stack[sp] =
				float2uint32_t((float)(int16_t)i) &  0xffff;
			inc_sp(sp);
			break;
		case BCItoL_c:
			i = stack[sp-1];
			stack[sp-1] = ((int32_t)i) >> 16;
			stack[sp]   = ((int32_t)i) &  0xffff;
			inc_sp(sp);
			break;
		case BCRtoI_c:
			i = stack[sp-2];
			j = stack[sp-1];
			sp--;
			stack[sp-1] = (int16_t)uint32_t2float(
				uint16_t22uint32_t(i, j));
			break;
		case BCRtoL_c:
			i = stack[sp-2];
			j = stack[sp-1];
			stack[sp-2] = ((int32_t)uint32_t2float(
				uint16_t22uint32_t(i, j))) >> 16;
			stack[sp-1] = ((int32_t)uint32_t2float(
				uint16_t22uint32_t(i, j))) &  0xffff;
			break;
		case BCLtoI_c:
			i = stack[sp-2];
			j = stack[sp-1];
			sp--;
			stack[sp-1] = uint16_t22uint32_t(i, j);
			break;
		case BCLtoR_c:
			i = stack[sp-2];
			j = stack[sp-1];
			sp--;
			stack[sp-2] = ((int32_t)uint32_t2float(
				uint16_t22uint32_t(i, j))) >> 16;
			stack[sp-1] = ((int32_t)uint32_t2float(
				uint16_t22uint32_t(i, j))) &  0xffff;
			break;
//}}}
//Integer arith {{{
		case BCAddI_c:
			msg_debug(SC("Add\n"));
			binop(+);
			break;
		case BCSubI_c:
			msg_debug(SC("Sub\n"));
			binop(-);
			break;
		case BCMultI_c:
			msg_debug(SC("Mult\n"));
			binop(*);
			break;
		case BCDivI_c:
			msg_debug(SC("Div\n"));
			binop(/);
			break;
//}}}
//Long arith {{{
		case BCAddL_c:
			msg_debug(SC("Add2\n"));
			binop2(+);
			break;
		case BCSubL_c:
			msg_debug(SC("Sub2\n"));
			binop2(-);
			break;
		case BCMultL_c:
			msg_debug(SC("Mult2\n"));
			binop2(*);
			break;
		case BCDivL_c:
			msg_debug(SC("Div2\n"));
			binop2(/);
			break;
//}}}
//Real arith {{{
		case BCAddR_c:
			msg_debug(SC("Addr\n"));
			binopr(+);
			break;
		case BCSubR_c:
			msg_debug(SC("Subr\n"));
			binopr(-);
			break;
		case BCMultR_c:
			msg_debug(SC("Multr\n"));
			binopr(*);
			break;
		case BCDivR_c:
			msg_debug(SC("Divr\n"));
			binopr(/);
			break;
//}}}
//Bool arith {{{
		case BCAnd_c:
			msg_debug(SC("And\n"));
			binop(&&);
			break;
		case BCOr_c:
			msg_debug(SC("Or\n"));
			binop(||);
			break;
		case BCNot_c:
			msg_debug(SC("Not\n"));
			stack[sp-1] = !stack[sp-1];
			break;
//}}}
//Equality {{{
		case BCEqI_c:
			msg_debug(SC("Eq\n"));
			binop(==);
			break;
		case BCEqL_c:
			msg_debug(SC("Eq2\n"));
			boolop2(==);
			break;
		case BCNeqI_c:
			msg_debug(SC("Neq\n"));
			binop(!=);
			break;
		case BCNeqL_c:
			msg_debug(SC("Eq2\n"));
			boolop2(!=);
			break;
// }}}
// Integer comparison {{{
		case BCLeI_c:
			msg_debug(SC("Le\n"));
			binop(<);
			break;
		case BCGeI_c:
			msg_debug(SC("Ge\n"));
			binop(>);
			break;
		case BCLeqI_c:
			msg_debug(SC("Leq\n"));
			binop(<=);
			break;
		case BCGeqI_c:
			msg_debug(SC("Geq\n"));
			binop(>=);
			break;
//}}}
//Long comparison {{{
		case BCLeL_c:
			msg_debug(SC("Le2\n"));
			boolop2(<);
			break;
		case BCGeL_c:
			msg_debug(SC("Ge2\n"));
			boolop2(>);
			break;
		case BCLeqL_c:
			msg_debug(SC("Leq2\n"));
			boolop2(<=);
			break;
		case BCGeqL_c:
			msg_debug(SC("Geq2\n"));
			boolop2(>=);
			break;
//}}}
//Real comparison {{{
		case BCLeR_c:
			msg_debug(SC("Le2\n"));
			boolopr(<);
			break;
		case BCGeR_c:
			msg_debug(SC("Ge2\n"));
			boolopr(>);
			break;
		case BCLeqR_c:
			msg_debug(SC("Leq2\n"));
			boolopr(<=);
			break;
		case BCGeqR_c:
			msg_debug(SC("Geq2\n"));
			boolopr(>=);
			break;
//}}}
		default:
			break;
		}
	}
}
