Пример #1
0
static kbool_t KBuilder_VisitMethodCallNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk)
{
	kshort_t a = AssignStack(thunk), espidx = expr->stackbase, thisidx = espidx + K_CALLDELTA;
	DBG_ASSERT(a <= espidx);
	kMethod *mtd = CallNode_getMethod(expr);
	DBG_ASSERT(IS_Method(mtd));
	int i, s = kMethod_Is(Static, mtd) ? 2 : 1;
	int argc = CallNode_getArgCount(expr);
	for (i = s; i < argc + 2; i++) {
		intptr_t a = thisidx + i - 1;
		kNode *paramNode = kNode_At(expr, i);
		if(!kNode_IsValue(paramNode) && paramNode->stackbase != a) {
			DBG_P("a=%d, stackbase=%d", a, paramNode->stackbase);
			DBG_ASSERT(paramNode->stackbase == a);
		}
		SUGAR VisitNode(kctx, builder, paramNode, &a);
	}
	if(kMethod_Is(Final, mtd) || !kMethod_Is(Virtual, mtd)) {
		ASM(NSET, NC_(thisidx-1), (intptr_t)mtd, KClass_Method);
		if(kMethod_Is(Virtual, mtd)) {
			// set namespace to enable method lookups
			ASM(NSET, OC_(thisidx-2), (intptr_t)kNode_ns(expr), KClass_NameSpace);
		}
	}
	else {
		ASM(NSET, OC_(thisidx-2), (intptr_t)kNode_ns(expr), KClass_NameSpace);
		ASM(LOOKUP, SFP_(thisidx), kNode_ns(expr), mtd);
	}
	int esp_ = SFP_(espidx + argc + K_CALLDELTA + 1);
	ASM(CALL, builder->common.uline, SFP_(thisidx), esp_, KLIB Knull(kctx, KClass_(expr->attrTypeId)));
	ReAssignNonValueNode(kctx, builder, a, expr);
	return true;
}
Пример #2
0
static void kMethod_genCode(KonohaContext *kctx, kMethod *mtd, kBlock *bk)
{
	DBG_P("START CODE GENERATION..");
	INIT_GCSTACK();
	if(ctxcode == NULL) {
		kmodcode->h.setup(kctx, NULL, 0);
	}
	KLIB kMethod_setFunc(kctx, mtd, MethodFunc_runVirtualMachine);
	DBG_ASSERT(kArray_size(ctxcode->codeList) == 0);
	kBasicBlock* lbINIT  = new_BasicBlockLABEL(kctx);
	kBasicBlock* lbBEGIN = new_BasicBlockLABEL(kctx);
	ctxcode->lbEND = new_BasicBlockLABEL(kctx);
	PUSH_GCSTACK(lbINIT);
	PUSH_GCSTACK(lbBEGIN);
	PUSH_GCSTACK(ctxcode->lbEND);
	ctxcode->currentWorkingBlock = lbINIT;
//	BUILD_pushLABEL(kctx, NULL, lbBEGIN, lbEND);
	ASM(THCODE, _THCODE);
	ASM(CHKSTACK, 0);
	ASM_LABEL(kctx, lbBEGIN);
	BLOCK_asm(kctx, bk, 0);
	ASM_LABEL(kctx, ctxcode->lbEND);
	if (mtd->mn == MN_new) {
		ASM(NMOV, OC_(K_RTNIDX), OC_(0), CT_(mtd->typeId));   // FIXME: Type 'This' must be resolved
	}
	ASM(RET);
	assert(ctxcode->lbEND);/* scan-build: remove warning */
//	BUILD_popLABEL(kctx);
	BUILD_compile(kctx, mtd, lbINIT, ctxcode->lbEND);
	ctxcode->lbEND = NULL;
	RESET_GCSTACK();
}
Пример #3
0
  void halWdtInit(void)
  {
    ASM("clr r1");
#elif defined(__ICCAVR__)

  __task void halWdtInit(void)
  {
    ASM("clr r15");
#else
  #error 'Compiler not supported.'
#endif

    if (TEMP_WARM_RESET != halResetReason)
    {
      halResetReason = MCUSR & MEANING_BITS;

      if (halResetReason & POWER_ON_RESET)
        halResetReason = POWER_ON_RESET;
    }
    else
    {
      halResetReason = WARM_RESET;
    }
    MCUSR = 0;
    WDTCSR |= (1 << WDCE) | (1 << WDE);
    WDTCSR = 0x00;

  #ifdef _SYS_ASSERT_ON_
    halJumpNullHandler();
  #endif
  }
Пример #4
0
void idtReboot()
{
	ASM("cli");
	idtPtr.addr = 0;
	idtPtr.limit = 0;
	loadIDT();
	ASM("int $0x70");
	while (1) ASM("cli; hlt");
};
Пример #5
0
static void NMOV_asm(KonohaContext *kctx, int a, ktype_t ty, int b)
{
	if(TY_isUnbox(ty)) {
		ASM(NMOV, NC_(a), NC_(b), CT_(ty));
	}
	else {
		ASM(NMOV, OC_(a), OC_(b), CT_(ty));
	}
}
Пример #6
0
void threadExit(Thread *thread, int status)
{
	if (thread->pid == 0)
	{
		panic("a kernel thread tried to threadExit()");
	};

	if (thread->pid == 1)
	{
		panic("init terminated with status %d!", status);
	};

	// don't break the CPU runqueue
	ASM("cli");
	lockSched();

	// init will adopt all orphans
	Thread *scan = thread;
	do
	{
		if (scan->pidParent == thread->pid)
		{
			scan->pidParent = 1;
		};
		scan = scan->next;
	} while (scan != thread);

	// terminate us
	thread->status = status;
	thread->flags |= THREAD_TERMINATED;

	// find the parent
	Thread *parent = thread;
	do
	{
		parent = parent->next;
	} while (parent->pid != thread->pidParent);

	// tell the parent that its child has died
	siginfo_t siginfo;
	siginfo.si_signo = SIGCHLD;
	if (status >= 0)
	{
		siginfo.si_code = CLD_EXITED;
	}
	else
	{
		siginfo.si_code = CLD_KILLED;
	};
	siginfo.si_pid = thread->pid;
	siginfo.si_status = status;
	siginfo.si_uid = thread->ruid;
	sendSignal(parent, &siginfo);
	unlockSched();
	ASM("sti");
};
Пример #7
0
static kbool_t MiniVM_VisitNullNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk)
{
	if(KType_Is(UnboxType, node->typeAttr)) {
		ASM(NSET, NC_(builder->stackbase), 0, KClass_(node->typeAttr));
	} else {
		ASM(NUL, OC_(builder->stackbase), KClass_(node->typeAttr));
	}
	builder->Value = builder->stackbase;
	return true;
}
Пример #8
0
static kbool_t KBuilder_VisitNullNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk)
{
	kshort_t a = AssignStack(thunk);
	if(KType_Is(UnboxType, expr->attrTypeId)) {
		ASM(NSET, NC_(a), 0, KClass_(expr->attrTypeId));
	}
	else {
		ASM(NUL, OC_(a), KClass_(expr->attrTypeId));
	}
	return true;
}
Пример #9
0
void compare_arith_a(A a, T l, T r, UC code) {
  choose_regs(a);
  switch (arith_t2(l,r)) {
    case Z_t: ASM(a, CMP,a->i[0],a->i[1]);
              break;
    case R_t: a_RfromT(a,l,a->i[0],a->i[0]);
              a_RfromT(a,r,a->i[1],a->i[1]);
              ASM(a, UCOMISD,a->i[0],a->i[1]); break;
    default: return;
  }
  ASM(a, SETX,a->o,code);
  ASM(a, MOVZX4,a->o,a->o);
}
Пример #10
0
static void AND_asm(KonohaContext *kctx, kStmt *stmt, int a, kExpr *expr, int shift, int espidx)
{
	int i, size = kArray_size(expr->cons);
	kBasicBlock*  lbTRUE = new_BasicBlockLABEL(kctx);
	kBasicBlock*  lbFALSE = new_BasicBlockLABEL(kctx);
	for(i = 1; i < size; i++) {
		EXPR_asmJMPIF(kctx, stmt, a, kExpr_at(expr, i), 0/*FALSE*/, lbFALSE, shift, espidx);
	}
	ASM(NSET, NC_(a), 1/*O_data(K_TRUE)*/, CT_Boolean);
	ASM_JMP(kctx, lbTRUE);
	ASM_LABEL(kctx, lbFALSE); // false
	ASM(NSET, NC_(a), 0/*O_data(K_FALSE)*/, CT_Boolean);
	ASM_LABEL(kctx, lbTRUE);   // TRUE
}
Пример #11
0
static struct KVirtualCode *MiniVM_GenerateVirtualCode(KonohaContext *kctx, kMethod *mtd, kUntypedNode *block, int option)
{
	KVirtualCode *vcode;
	KBuffer wb;
	KBuilder builderbuf = {{0}}, *builder = &builderbuf;
	kNameSpace *ns = kUntypedNode_ns(block);

	INIT_GCSTACK();
	KLIB KBuffer_Init(&(kctx->stack->cwb), &wb);
	builder->common.api = ns->builderApi;
	builder->constPools = ns->NameSpaceConstList;
	builder->bbBeginId  = new_BasicBlockLABEL(kctx);
	builder->bbReturnId = new_BasicBlockLABEL(kctx);
	builder->bbMainId   = builder->bbBeginId;
	builder->currentMtd = mtd;
	builder->Value      = 0;
	builder->stackbase  = 0;
	builder->InstructionSize = 0;

	builder->common.api = &CollectLocalVar_BuilderAPI;
	KLIB VisitNode(kctx, builder, block, NULL);
	builder->stackbase += builder->localVarSize + 1/* == this object */;
	builder->common.api = ns->builderApi;

	KLIB KArray_Init(kctx, &builder->localVar, sizeof(LocalVarInfo) * builder->stackbase);

	ASM(THCODE, 0, _THCODE);
	ASM(CHKSTACK, 0);

	KLIB VisitNode(kctx, builder, block, NULL);

	if(!Block_HasTerminatorInst(kctx, builder->bbMainId)) {
		MiniVMBuilder_JumpTo(kctx, builder, builder->bbReturnId);
	}

	MiniVMBuilder_setBlock(kctx, builder, builder->bbReturnId);
	if(mtd->mn == MN_new) {
		// FIXME: Type 'This' must be resolved
		ASM(NMOV, OC_(K_RTNIDX), OC_(0), KClass_(mtd->typeId));
	}
	ASM(RET);
	vcode = CompileVirtualCode(kctx, builder, builder->bbBeginId, builder->bbReturnId);

	KLIB KArray_Free(kctx, &builder->localVar);
	RESET_GCSTACK();
	KLIB KBuffer_Free(&wb);
	return vcode;

}
Пример #12
0
void
panic(const char *message) {
	scr_set_color(COLOR_RED | COLOR_BRIGHT, COLOR_BLACK);
	kprintf(message);
	ASM("cli\n\t"
		"hlt");
}
Пример #13
0
void kyield()
{
	while (getCurrentThread()->flags & THREAD_WAITING)
	{
		ASM("sti; hlt");
	};

#if 0
	cli();
	uint64_t counter = switchTaskCounter;
	apic->timerInitCount = 0;
	sti();
	
	// at this point, we have 2 possiblities:
	// 1) the APIC timer fired before we turned it off above. in this case, "switchTaskCounter" changed,
	//    and we have already rescheduled, so just return.
	// 2) we turned the APIC timer off before it fired, so "switchTaskCounter" did not change. in this case
	//    we must reprogram it to 1, and we can be sure that we reschedule before this function returns.
	
	if (switchTaskCounter == counter)
	{
		apic->timerInitCount = 2;
		nop();				// make sure it fires before we return by using at least 1 CPU cycle
	};
#endif
};
Пример #14
0
void __putchar(const char c)
{
  #if defined(CFG_USB) && defined(CFG_PRINTF_USBCDC)
    if (usb_isConfigured())
    {
      while(usb_cdc_isConnected() && !usb_cdc_putc(c) ) // blocking
      {
        ASM("nop");
      }
    }
  #endif

  #ifdef CFG_PRINTF_UART
    uartSendByte(c);
  #endif

  /* Handle PRINTF_DEBUG redirection for Crossworks for ARM */
  #ifdef __CROSSWORKS_ARM
    #ifdef CFG_PRINTF_DEBUG
      #if defined CFG_MCU_FAMILY_LPC13UXX
        /* On the M3 we can check if a debugger is connected */
        if ((CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk)==CoreDebug_DHCSR_C_DEBUGEN_Msk)
        {
          debug_putchar(c);
        }
      #else
        /* On the M0 the processor doesn't have access to CoreDebug, so this
         * will cause problems if no debugger is connected! */
        debug_putchar(c);
      #endif
    #endif
  #endif
}
Пример #15
0
static kbool_t KBuilder_VisitConstNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk)
{
	DBG_ASSERT(!KType_Is(UnboxType, expr->attrTypeId));
	kObject *v = KBuilder_AddConstPool(kctx, builder, expr->ObjectConstValue);
	kshort_t a = AssignStack(thunk);
	ASM(NSET, OC_(a), (uintptr_t)v, KClass_(expr->attrTypeId));
	return true;
}
Пример #16
0
static kbool_t MiniVM_VisitUnboxConstNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk)
{
	uintptr_t Val = node->unboxConstValue;
	DBG_ASSERT(KType_Is(UnboxType, node->typeAttr));
	ASM(NSET, NC_(builder->stackbase), Val, KClass_(node->typeAttr));
	builder->Value = builder->stackbase;
	return true;
}
Пример #17
0
static kbool_t MiniVM_VisitConstNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk)
{
	kObject *v = MiniVM_AddConstPool(kctx, builder, node->ObjectConstValue);
	DBG_ASSERT(!KType_Is(UnboxType, node->typeAttr));
	ASM(NSET, OC_(builder->stackbase), (uintptr_t) v, KClass_(node->typeAttr));
	builder->Value = builder->stackbase;
	return true;
}
Пример #18
0
/***********************************************************************************
 * @fn          lcdControl
 *
 * @brief       Send command to display
 *
 * @param       uint8 command
 *
 * @return      none
 */
static void lcdControl(uint8 command)
{
	P1_2 = 0;
    //LCD_SPI_BEGIN();
	P0_0 = 0;
    //LCD_DO_CONTROL();
    LCD_SPI_TX(command);
    LCD_SPI_WAIT_RXRDY();
    __asm_begin
    ASM(nop)
    ASM(nop)
    ASM(nop)
    ASM(nop)
    __asm_end;
    P1_2 = 1;
    //LCD_SPI_END();
}
Пример #19
0
static kBasicBlock* EXPR_asmJMPIF(KonohaContext *kctx, kStmt *stmt, int a, kExpr *expr, int isTRUE, kBasicBlock* label, int shift, int espidx)
{
	EXPR_asm(kctx, stmt, a, expr, shift, espidx);
	if(isTRUE) {
		ASM(BNOT, NC_(a), NC_(a));
	}
	return ASM_JMPF(kctx, a, label);
}
Пример #20
0
/******************************************************************************
Jump to NULL handler.
Parameters:
  none.
Returns:
  none.
******************************************************************************/
void halJumpNullHandler(void)
{
  if (0 == halResetReason) // was jump on NULL
  {
    register volatile uint16_t tmp = SP;
    uint32_t delay;

    ASM ("cli");
    DDRE |= (1 << 2) | (1 << 3) | (1 << 4);
    PORTE &= ~((1 << 2) | (1 << 3) | (1 << 4));

    /* Init UART*/
    UBRR1H = 0;
    #if (F_CPU == 4000000ul)
      UBRR1L = 12;
    #elif (F_CPU == 8000000ul)
      UBRR1L = 25;
    #elif (F_CPU == 16000000ul)
      UBRR1L = 51;
    #endif
    UCSR1A = (1 << U2X1);
    UCSR1B = (1 << TXEN1);
    UCSR1C = (3 << UCSZ10);  // 8-bit data

    /* Init timer counter 4.*/
    OCR4A = 0;
    /* Disable TC4 interrupt */
    TIMSK4 &= ~(1 << OCIE4A);
    /* main clk / 8 */
    TCCR4B = (1 << WGM12) | (1 << CS11);

    while (1)
    {
      do
      { /* Send byte to UART */
        while (!(UCSR1A & (1 << UDRE1)));
        UDR1 = *((uint8_t *)SP);
        SP++;
      } while (RAMEND >= SP);
      SP = tmp;


      PORTE ^= (1 << 2);
      for (delay = 0; delay < DELAY_VALUE; delay++)
        asm("nop");

      PORTE ^= ((1 << 2) | (1 << 3));
      for (delay = 0; delay < DELAY_VALUE; delay++)
        asm("nop");

      PORTE ^= ((1 << 3) | (1 << 4));
      for (delay = 0; delay < DELAY_VALUE; delay++)
        asm("nop");

      PORTE ^= (1 << 4);
    }
  }
}
Пример #21
0
void swspiDelay(uint32_t ticks)
{
  uint32_t i;

  for (i = 0; i < ticks/4; i++)
  {
    ASM("nop");
  }
}
Пример #22
0
static void CreateBranch(KonohaContext *kctx, KBuilder *builder, intptr_t src, bblock_t ThenBB, bblock_t ElseBB, bool emitJumpToThenBlock)
{
	BasicBlock *ThenBlock, *ElseBlock;
	BasicBlock *bb = BasicBlock_FindById(kctx, builder->bbMainId);
	DBG_ASSERT(bb != NULL);
	DBG_ASSERT(/*bb->nextid == -1 &&*/ bb->branchid == -1);
	ASM(JMPF, NULL, NC_(src));
	if(emitJumpToThenBlock) {
		ASM(JMP, NULL);
	}
	bb = BasicBlock_FindById(kctx, builder->bbMainId);
	ThenBlock = BasicBlock_FindById(kctx, ThenBB);
	ElseBlock = BasicBlock_FindById(kctx, ElseBB);
	bb->branchid = ElseBB;
	bb->nextid   = ThenBB;
	ThenBlock->incoming += 1;
	ElseBlock->incoming += 1;
}
Пример #23
0
static kbool_t KBuilder_VisitFieldNode(KonohaContext *kctx, KBuilder *builder, kNode *expr, void *thunk)
{
	kshort_t a = AssignStack(thunk);
	kshort_t index = (kshort_t)expr->index;
	kshort_t xindex = (kshort_t)(expr->index >> (sizeof(kshort_t)*8));
	KClass *ty = KClass_(expr->attrTypeId);
	ASM(NMOVx, TC_(a, ty), OC_(index), xindex, ty);
	return true;
}
Пример #24
0
void _panic(const char *filename, int lineno, const char *funcname, const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);

	ASM ("cli");
	unlockConsole();
	kprintf("In function %s at %s:%d\n", funcname, filename, lineno);
	kprintf("Kernel panic: ");
	kvprintf(fmt, ap);
	
	while (1)
	{
		ASM ("cli; hlt");
	};

	/* no need for cleanup because the CPU is halted */
};
Пример #25
0
/*
    The same general process applies to starting the kernel as per usual

    We can either:
        1) Simulate a return from an exception manually to start the first
           Thread_t, or..
        2) Use a software exception to trigger the first "Context Restore
            /Return from Interrupt" that we have otherwised used to this point.

    For 1), we basically have to restore the whole stack manually, not relying
    on the CPU to do any of this for us.  That's certainly doable, but not all
    Cortex parts support this (due to other members of the family supporting
    priveleged modes).  So, we will opt for the second option.

    So, to implement a software interrupt to restore our first Thread_t, we will
    use the SVC instruction to generate that exception.

    At the end of Thread_t initialization, we have to do 2 things:

    -Enable exceptions/interrupts
    -Call SVC

    Optionally, we can reset the MSP stack pointer to the top-of-stack.
    Note, the default stack pointer location is stored at address
    0x00000000 on all ARM Cortex M0 parts

    (While Mark3 avoids assembler code as much as possible, there are some
    places where it cannot be avoided.  However, we can at least inline it
    in most circumstances.)
*/
void ThreadPort_StartFirstThread( void )
{
    ASM (
        " mov r0, #0 \n"
        " ldr r1, [r0] \n"
        " msr msp, r1 \n"
        " cpsie i \n"
        " svc 0 \n"
    );
}
Пример #26
0
static kbool_t MiniVM_VisitBoxNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk)
{
	/*
	 * [box] := box(this)
	 **/
	KLIB VisitNode(kctx, builder, node->NodeToPush, thunk);
	ASM(BOX, OC_(builder->stackbase), NC_(MiniVM_getExpression(builder)), KClass_(node->typeAttr));
	builder->Value = builder->stackbase;
	return true;
}
Пример #27
0
static void ASM_SAFEPOINT(KonohaContext *kctx, int espidx)
{
	kBasicBlock *bb = ctxcode->currentWorkingBlock;
	size_t i;
	for(i = 0; i < BasicBlock_codesize(bb); i++) {
		VirtualMachineInstruction *op = BBOP(bb) + i;
		if(op->opcode == OPCODE_SAFEPOINT) return;
	}
	ASM(SAFEPOINT, SFP_(espidx));
}
Пример #28
0
static kbool_t MiniVM_VisitAssignNode(KonohaContext *kctx, KBuilder *builder, kUntypedNode *node, void *thunk)
{
	/*
	 * [LetExpr] := lhs = rhs
	 * expr->NodeList = [NULL, lhs, rhs]
	 **/

	intptr_t dst = -1;
	kUntypedNode *left = kUntypedNode_At(node, 1);
	kUntypedNode *right = kUntypedNode_At(node, 2);
	ktypeattr_t type = left->typeAttr;
	ksymbol_t symbol;

	assert(IS_Token(left->TermToken));
	symbol = left->TermToken->symbol;
	if(kUntypedNode_node(left) == KNode_Local) {
		if((dst = MiniVMBuilder_FindLocalVar(kctx, builder, symbol, type, left->index)) == -1) {
			dst = AddLocal(kctx, builder, left->index, symbol, type);
		}
		KLIB VisitNode(kctx, builder, right, thunk);
		CreateUpdate(kctx, builder, type, dst, MiniVM_getExpression(builder));
		builder->Value = dst;
	}
	else {
		khalfword_t index  = (khalfword_t)left->index;
		khalfword_t xindex = (khalfword_t)(left->index >> (sizeof(khalfword_t)*8));
		KClass *lhsClass = KClass_(left->typeAttr);
		KClass *rhsClass = KClass_(right->typeAttr);
		assert(kUntypedNode_node(left) == KNode_Field);
		if((dst = MiniVMBuilder_FindLocalVar(kctx, builder, symbol, KType_Object, index)) == -1) {
			dst = AddLocal(kctx, builder, index, symbol, KType_Object);
		}
		KLIB VisitNode(kctx, builder, right, thunk);
		ASM(XNMOV, OC_(index), xindex, TC_(MiniVM_getExpression(builder), rhsClass), lhsClass);
		if(node->typeAttr != KType_void) {
			builder->Value = builder->stackbase;
			ASM(NMOVx, TC_(builder->stackbase, rhsClass), OC_(index), xindex, lhsClass);
		}
	}
	return true;
}
Пример #29
0
static void jumpToTask()
{
	// switch kernel stack
	ASM("cli");
	_tss.rsp0 = ((uint64_t) currentThread->stack + currentThread->stackSize) & (uint64_t)~0xF;

	// reload the TSS
	reloadTR();

	// switch address space
	if (currentThread->pm != NULL) SetProcessMemory(currentThread->pm);
	ASM("cli");

	// make sure IF is set
	currentThread->regs.rflags |= (1 << 9);

	// switch context
	fpuLoad(&currentThread->fpuRegs);
	apic->timerInitCount = quantumTicks;
	switchContext(&currentThread->regs);
};
Пример #30
0
//---------------------------------------------------------------------------
static void Thread_Switch(void)
{
#if KERNEL_USE_IDLE_FUNC
    // If there's no next-thread-to-run...
    if (g_pstNext == Kernel_GetIdleThread())
    {
        g_pstCurrent = Kernel_GetIdleThread();

        // Disable the SWI, and re-enable interrupts -- enter nested interrupt
        // mode.
        KernelSWI_DI();

        K_UCHAR ucSR = _SFR_IO8(SR_);

        // So long as there's no "next-to-run" thread, keep executing the Idle
        // function to conclusion...

        while (g_pstNext == Kernel_GetIdleThread())
        {
           // Ensure that we run this block in an interrupt enabled context (but
           // with the rest of the checks being performed in an interrupt disabled
           // context).
           ASM( "sei" );
           Kernel_IdleFunc();
           ASM( "cli" );
        }

        // Progress has been achieved -- an interrupt-triggered event has caused
        // the scheduler to run, and choose a new thread.  Since we've already
        // saved the context of the thread we've hijacked to run idle, we can
        // proceed to disable the nested interrupt context and switch to the
        // new thread.

        _SFR_IO8(SR_) = ucSR;
        KernelSWI_RI( true );        
    }
#endif
    g_pstCurrent = (Thread_t*)g_pstNext;
}