// Main event loop int main() { proc_interface_t hwti; // Get HWTI base address from user PVR register int hwti_base; getpvr(1,hwti_base); // Enable instruction cache (reduce PLB load) microblaze_init_icache_range(0, 8192); microblaze_enable_icache(); while(1) { // Setup interface // * Perform this upon each iteration, just in case the memory // map for the MB-HWTI is corrupted. initialize_interface(&hwti,(int*)(hwti_base)); // Wait to be "reset" // -- NOTE: Ignore reset as it has no meaning to the MB-HWTI // and it seems causes a race, as the controlling processor // sends a reset, immediately followed by a "go" command. Therefore // the "reset" command can be missed. //wait_for_reset_command(&hwti); // Wait to be "started" wait_for_go_command(&hwti); //xil_printf("Thread started (fcn @ 0x%08x), arg = 0x%08x!!!\r\n",*(hwti.fcn_reg), *(hwti.arg_reg)); // Setup r20 for thread (only needed for PIC code, i.e. print-related functions) mtgpr(r20, *(hwti.fcn_reg)); // Boostrap thread // * Pull out thread argument, and thread start function _bootstrap_thread(&hwti, *(hwti.fcn_reg), *(hwti.arg_reg)); //_bootstrap_thread(&hwti, factorial_thread, *(hwti.arg_reg)); // Use this when hard-coding functionality } return 0; }
int main() { proc_interface_t hwti; // Get HWTI base address from user PVR register int hwti_base; getpvr(1,hwti_base); // Disable instruction and data cache microblaze_invalidate_icache(); microblaze_disable_icache(); microblaze_invalidate_dcache(); microblaze_disable_dcache(); // Nano-kernel loop... while(1) { // Setup interface // * Perform this upon each iteration, just in case the memory // map for the MB-HWTI is corrupted. initialize_interface(&hwti,(int*)(hwti_base)); #if 0 // Commented out as this is not necessary and it creates the opportunity for a race between reset and start commands // Wait to be "reset" // -- NOTE: Ignore reset as it has no meaning to the MB-HWTI // and it seems causes a race, as the controlling processor // sends a reset, immediately followed by a "go" command. Therefore // the "reset" command can be missed. wait_for_reset_command(&hwti); #endif // Wait to be "started" wait_for_go_command(&hwti); //xil_printf("Thread started (fcn @ 0x%08x), arg = 0x%08x!!!\r\n",*(hwti.fcn_reg), *(hwti.arg_reg)); // Setup r20 for thread, this can be used to enforce -fPIC (Position-independent code) for the MB // (r20 is used as part of the GOT, to make things PC-relative) mtgpr(r20, *(hwti.fcn_reg)); // Boostrap thread (wraps up thread execution with a thread exit) // * Pull out thread argument, and thread start function _bootstrap_thread(&hwti, *(hwti.fcn_reg), *(hwti.arg_reg)); } return 0; }
static sval decode_spr_ins(struct cpu_thread* thr, uval addr, uval32 ins) { struct thread_control_area *tca = get_tca(); uval id = thr->vregs->active_vsave; struct vexc_save_regs *vr = &thr->vregs->vexc_save[id]; sval ret = -1; uval opcode = extract_bits(ins, 0, 6); uval type = extract_bits(ins, 21, 10); uval spr_0_4 = extract_bits(ins, 16, 5); uval spr_5_9 = extract_bits(ins, 11, 5); uval gpr = extract_bits(ins, 6, 5); uval spr = (spr_0_4 << 5) | spr_5_9; /* mfmsr */ if (opcode == 31 && type == 83) { //hprintf("mfmsr r%ld at 0x%lx\n",gpr, addr); mtgpr(thr, gpr, thr->vregs->v_msr); tca->srr0 += sizeof(uval32); return 0; } /* mtmsrd */ if (opcode == 31 && (type == 178 || type == 146)) { uval64 val = mfgpr(thr, gpr); //hprintf("mtmsrd r%ld <- 0x%llx at 0x%lx\n", gpr, val, addr); uval64 chg_mask = ~0ULL; uval l = extract_bits(ins, 15, 1); if (type == 146) { // mtmsr , 32-bits chg_mask = 0xffffffff; } if (l == 1) { chg_mask = (MSR_EE | MSR_RI); } /* These are the only bits we can change here */ val = (val & chg_mask) | (thr->vregs->v_msr & ~chg_mask); set_v_msr(thr, val); val = thr->vregs->v_msr; val |= V_LPAR_MSR_ON; val &= ~V_LPAR_MSR_OFF; tca->srr1 = val; tca->srr0 += sizeof(uval32); return 0; } /* mfspr */ #define SET_GPR(label, src) \ case label: mtgpr(thr, gpr, src); break; if (opcode == 31 && type == 339) { ret = 0; switch (spr) { SET_GPR(SPRN_SRR0, vr->v_srr0); SET_GPR(SPRN_SRR1, vr->v_srr1); SET_GPR(SPRN_PVR, mfpvr()); SET_GPR(SPRN_PIR, mfpir()); case SPRN_DSISR: case SPRN_DAR: mtgpr(thr, gpr, 0); break; case SPRN_HID0: case SPRN_HID1: case SPRN_HID4: case SPRN_HID5: mtgpr(thr, gpr, 0xdeadbeeffeedfaceULL); break; default: ret = -1; break; } if (ret != -1) { tca->srr0 += sizeof(uval32); return ret; } } #define SET_VREG(label, field) \ case label: thr->vregs->field = mfgpr(thr, gpr); break; /* mtspr */ if (opcode == 31 && type == 467) { ret = 0; switch (spr) { SET_VREG(SPRN_SPRG0, v_sprg0); SET_VREG(SPRN_SPRG1, v_sprg1); SET_VREG(SPRN_SPRG2, v_sprg2); SET_VREG(SPRN_SPRG3, v_sprg3); case SPRN_DEC: partition_set_dec(thr, mfgpr(thr, gpr)); thr->vregs->v_dec = mfgpr(thr, gpr); break; case SPRN_SRR0: vr->v_srr0 = mfgpr(thr, gpr); break; case SPRN_SRR1: vr->v_srr1 = mfgpr(thr, gpr); break; case SPRN_DSISR: case SPRN_DAR: break; default: ret = -1; break; } if (ret != -1) { tca->srr0 += sizeof(uval32); return ret; } } /* rfid */ if (opcode == 19 && type == 18) { uval val = vr->v_srr1; set_v_msr(thr, val); val |= V_LPAR_MSR_ON; val &= ~V_LPAR_MSR_OFF; tca->srr1 = val; tca->srr0 = vr->v_srr0; hprintf("rfid: %lx -> %lx\n",addr, vr->v_srr0); return 0; } if (ret == -1) { hprintf("Decode instruction: %ld %ld %ld %ld\n", opcode, type, spr, gpr); } return ret; }
/** * * This function is the primary interrupt handler for the driver. It must be * connected to the interrupt source such that is called when an interrupt of * the interrupt controller is active. It will resolve which interrupts are * active and enabled and call the appropriate interrupt handler. It uses * the AckBeforeService flag in the configuration data to determine when to * acknowledge the interrupt. Highest priority interrupts are serviced first. * This function assumes that an interrupt vector table has been previously * initialized.It does not verify that entries in the table are valid before * calling an interrupt handler. In Cascade mode this function calls * XIntc_CascadeHandler to handle interrupts of Master and Slave controllers. * This functions also handles interrupts nesting by saving and restoring link * register of Microblaze and Interrupt Level register of interrupt controller * properly. * @param DeviceId is the zero-based device ID defined in xparameters.h * of the interrupting interrupt controller. It is used as a direct * index into the configuration data, which contains the vector * table for the interrupt controller. Note that even though the * argument is a void pointer, the value is not a pointer but the * actual device ID. The void pointer type is necessary to meet * the XInterruptHandler typedef for interrupt handlers. * * @return None. * * @note For nested interrupts, this function saves microblaze r14 * register on entry and restores on exit. This is required since * compiler does not support nesting. This function enables * Microblaze interrupts after blocking further interrupts * from the current interrupt number and interrupts below current * interrupt proirity by writing to Interrupt Level Register of * INTC on entry. On exit, it disables microblaze interrupts and * restores ILR register default value(0xFFFFFFFF)back. It is * recommended to increase STACK_SIZE in linker script for nested * interrupts. * ******************************************************************************/ void XIntc_DeviceInterruptHandler(void *DeviceId) { u32 IntrStatus; u32 IntrMask = 1; int IntrNumber; XIntc_Config *CfgPtr; u32 Imr; /* Get the configuration data using the device ID */ CfgPtr = &XIntc_ConfigTable[(u32)DeviceId]; #if XPAR_INTC_0_INTC_TYPE != XIN_INTC_NOCASCADE if (CfgPtr->IntcType != XIN_INTC_NOCASCADE) { XIntc_CascadeHandler(DeviceId); } else #endif { /* This extra brace is required for compilation in Cascade Mode */ #if XPAR_XINTC_HAS_ILR == TRUE #ifdef __MICROBLAZE__ volatile u32 R14_register; /* Save r14 register */ R14_register = mfgpr(r14); #endif volatile u32 ILR_reg; /* Save ILR register */ ILR_reg = Xil_In32(CfgPtr->BaseAddress + XIN_ILR_OFFSET); #endif /* Get the interrupts that are waiting to be serviced */ IntrStatus = XIntc_GetIntrStatus(CfgPtr->BaseAddress); /* Mask the Fast Interrupts */ if (CfgPtr->FastIntr == TRUE) { Imr = XIntc_In32(CfgPtr->BaseAddress + XIN_IMR_OFFSET); IntrStatus &= ~Imr; } /* Service each interrupt that is active and enabled by * checking each bit in the register from LSB to MSB which * corresponds to an interrupt input signal */ for (IntrNumber = 0; IntrNumber < CfgPtr->NumberofIntrs; IntrNumber++) { if (IntrStatus & 1) { XIntc_VectorTableEntry *TablePtr; #if XPAR_XINTC_HAS_ILR == TRUE /* Write to ILR the current interrupt * number */ Xil_Out32(CfgPtr->BaseAddress + XIN_ILR_OFFSET, IntrNumber); /* Read back ILR to ensure the value * has been updated and it is safe to * enable interrupts */ Xil_In32(CfgPtr->BaseAddress + XIN_ILR_OFFSET); /* Enable interrupts */ Xil_ExceptionEnable(); #endif /* If the interrupt has been setup to * acknowledge it before servicing the * interrupt, then ack it */ if (CfgPtr->AckBeforeService & IntrMask) { XIntc_AckIntr(CfgPtr->BaseAddress, IntrMask); } /* The interrupt is active and enabled, call * the interrupt handler that was setup with * the specified parameter */ TablePtr = &(CfgPtr->HandlerTable[IntrNumber]); TablePtr->Handler(TablePtr->CallBackRef); /* If the interrupt has been setup to * acknowledge it after it has been serviced * then ack it */ if ((CfgPtr->AckBeforeService & IntrMask) == 0) { XIntc_AckIntr(CfgPtr->BaseAddress, IntrMask); } #if XPAR_XINTC_HAS_ILR == TRUE /* Disable interrupts */ Xil_ExceptionDisable(); /* Restore ILR */ Xil_Out32(CfgPtr->BaseAddress + XIN_ILR_OFFSET, ILR_reg); #endif /* * Read the ISR again to handle architectures * with posted write bus access issues. */ XIntc_GetIntrStatus(CfgPtr->BaseAddress); /* * If only the highest priority interrupt is to * be serviced, exit loop and return after * servicing * the interrupt */ if (CfgPtr->Options == XIN_SVC_SGL_ISR_OPTION) { #if XPAR_XINTC_HAS_ILR == TRUE #ifdef __MICROBLAZE__ /* Restore r14 */ mtgpr(r14, R14_register); #endif #endif return; } } /* Move to the next interrupt to check */ IntrMask <<= 1; IntrStatus >>= 1; /* If there are no other bits set indicating that all * interrupts have been serviced, then exit the loop */ if (IntrStatus == 0) { break; } } #if XPAR_XINTC_HAS_ILR == TRUE #ifdef __MICROBLAZE__ /* Restore r14 */ mtgpr(r14, R14_register); #endif #endif } }
int main() { proc_interface_t hwti; // Get HWTI base address from user PVR register int hwti_base; unsigned char cpu_id; // only 8bits getpvr(1,hwti_base); // Disable instruction and data cache microblaze_invalidate_icache(); microblaze_enable_icache(); microblaze_invalidate_dcache(); microblaze_disable_dcache(); //Determine if uB is first on bus getpvr(0, cpu_id); // Timer pointers volatile unsigned long long * timer = (unsigned long long *) LOCAL_TIMER; volatile unsigned int * timer_reset = (unsigned int *) (LOCAL_TIMER + RESET_REG); // Reset timer *timer_reset = CMD_RESET; // Indicate to CoreTest.c running on host that this processor is running volatile unsigned int * check = (unsigned int *) EXTRA_BRAM; // assign cpus_per_bus offset check = (unsigned int *) ((unsigned int) check + ( ((unsigned int) cpu_id) * 0x100)); // write OKAY_VALUE to common memory (extra_bram) *check = OKAY_VALUE; // Nano-kernel loop... while(1) { // Setup interface // * Perform this upon each iteration, just in case the memory // map for the MB-HWTI is corrupted. initialize_interface(&hwti,(int*)(hwti_base)); #if 0 // Commented out as this is not necessary and it creates the opportunity for a race between reset and start commands // Wait to be "reset" // -- NOTE: Ignore reset as it has no meaning to the MB-HWTI // and it seems causes a race, as the controlling processor // sends a reset, immediately followed by a "go" command. Therefore // the "reset" command can be missed. wait_for_reset_command(&hwti); #endif // Wait to be "started" wait_for_go_command(&hwti); //xil_printf("Thread started (fcn @ 0x%08x), arg = 0x%08x!!!\r\n",*(hwti.fcn_reg), *(hwti.arg_reg)); // Setup r20 for thread, this can be used to enforce -fPIC (Position-independent code) for the MB // (r20 is used as part of the GOT, to make things PC-relative) mtgpr(r20, *(hwti.fcn_reg)); // Boostrap thread (wraps up thread execution with a thread exit) // * Pull out thread argument, and thread start function _bootstrap_thread(&hwti, *(hwti.fcn_reg), *(hwti.arg_reg)); } return 0; }