mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 06:11:06 +00:00 
			
		
		
		
	fix(freertos): workaround a hardware bug related to HWLP coprocessor
This commit manually sets the HWLP context to dirty when a Task that needs it is scheduled it.
This commit is contained in:
		@@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
 | 
			
		||||
 * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 */
 | 
			
		||||
@@ -186,14 +186,21 @@ rtos_save_\name\()_coproc_norestore:
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Restore the HWLP registers contained in the dedicated save area if the given task ever used it.
 | 
			
		||||
     *        This routine sets the HWLP context to clean in any case.
 | 
			
		||||
     *        This routine sets the HWLP context to dirty if the task ever used it and any of the loop counter
 | 
			
		||||
     *        is not zero. Else, it sets it to clean.
 | 
			
		||||
     *
 | 
			
		||||
     * @param a0 StaticTask address for the newly scheduled task
 | 
			
		||||
     */
 | 
			
		||||
hwlp_restore_if_used:
 | 
			
		||||
    addi  sp, sp, -16
 | 
			
		||||
    sw    ra, (sp)
 | 
			
		||||
    /* Check if the HWLP was in use beforehand */
 | 
			
		||||
    /* Re-enable the HWLP coprocessor */
 | 
			
		||||
    csrwi CSR_HWLP_STATE_REG, HWLP_CLEAN_STATE
 | 
			
		||||
    /* Check if the HWLP was ever used by this task, if yes:
 | 
			
		||||
     * - Set HWLP state to DIRTY if any of the HWLP counter is != 0.
 | 
			
		||||
     *   Please note that the `hwlp_restore_regs` macro will set the DIRTY bit!
 | 
			
		||||
     * - Keep the state as CLEAN if both counters are 0.
 | 
			
		||||
     */
 | 
			
		||||
    li    a1, 0
 | 
			
		||||
    li    a2, HWLP_COPROC_IDX
 | 
			
		||||
    call  pxPortGetCoprocArea
 | 
			
		||||
@@ -201,13 +208,22 @@ hwlp_restore_if_used:
 | 
			
		||||
    lw    a1, RV_COPROC_ENABLE(a0)
 | 
			
		||||
    /* To avoid having branches below, set the coprocessor enable flag now */
 | 
			
		||||
    andi  a2, a1, 1 << HWLP_COPROC_IDX
 | 
			
		||||
    beqz  a2, _hwlp_restore_never_used
 | 
			
		||||
    beqz  a2, _hwlp_restore_end
 | 
			
		||||
    /* Enable bit was set, restore the coprocessor context */
 | 
			
		||||
    lw    a0, RV_COPROC_SA+HWLP_COPROC_IDX*4(a0)      /* a0 = RvCoprocSaveArea->sa_coprocs[HWLP_COPROC_IDX] */
 | 
			
		||||
    /* This will set the dirty flag for sure */
 | 
			
		||||
    hwlp_restore_regs a0
 | 
			
		||||
_hwlp_restore_never_used:
 | 
			
		||||
    /* Clear the context */
 | 
			
		||||
#if SOC_CPU_HAS_HWLOOP_STATE_BUG && ESP32P4_REV_MIN_FULL <= 1
 | 
			
		||||
    /* The hardware doesn't update the HWLP state properly after executing the last instruction,
 | 
			
		||||
     * as such, we must manually put the state of the HWLP to dirty now if any counter is not 0 */
 | 
			
		||||
    csrr    a0, CSR_LOOP0_COUNT
 | 
			
		||||
    bnez    a0, _hwlp_restore_end
 | 
			
		||||
    csrr    a0, CSR_LOOP1_COUNT
 | 
			
		||||
    bnez    a0, _hwlp_restore_end
 | 
			
		||||
    /* The counters are 0, cleaning the state */
 | 
			
		||||
#endif /* SOC_CPU_HAS_HWLOOP_STATE_BUG && ESP32P4_REV_MIN_FULL <= 1 */
 | 
			
		||||
    csrwi CSR_HWLP_STATE_REG, HWLP_CLEAN_STATE
 | 
			
		||||
_hwlp_restore_end:
 | 
			
		||||
    lw   ra, (sp)
 | 
			
		||||
    addi sp, sp, 16
 | 
			
		||||
    ret
 | 
			
		||||
@@ -458,6 +474,11 @@ rtos_current_tcb:
 | 
			
		||||
    .global rtos_int_enter
 | 
			
		||||
    .type rtos_int_enter, @function
 | 
			
		||||
rtos_int_enter:
 | 
			
		||||
#if SOC_CPU_COPROC_NUM > 0
 | 
			
		||||
    /* Use s2 to store the state of the coprocessors */
 | 
			
		||||
    li      s2, 0
 | 
			
		||||
#endif /* SOC_CPU_COPROC_NUM > 0 */
 | 
			
		||||
 | 
			
		||||
#if ( configNUM_CORES > 1 )
 | 
			
		||||
    csrr    s0, mhartid                     /* s0 = coreID */
 | 
			
		||||
    slli    s0, s0, 2                       /* s0 = coreID * 4 */
 | 
			
		||||
@@ -483,7 +504,6 @@ rtos_int_enter:
 | 
			
		||||
    li      a0, 0                           /* return 0 in case we are going to branch */
 | 
			
		||||
    bnez    a1, rtos_int_enter_end          /* if (port_uxInterruptNesting[coreID] > 0) jump to rtos_int_enter_end */
 | 
			
		||||
 | 
			
		||||
    li      s2, 0
 | 
			
		||||
#if SOC_CPU_COPROC_NUM > 0
 | 
			
		||||
    /* Disable the coprocessors to forbid the ISR from using it */
 | 
			
		||||
#if SOC_CPU_HAS_PIE
 | 
			
		||||
@@ -525,6 +545,7 @@ rtos_int_enter:
 | 
			
		||||
    addi    a1, a1, -HWLP_DIRTY_STATE
 | 
			
		||||
    bnez    a1, 1f
 | 
			
		||||
    /* State is dirty! The hardware loop feature was used, save the registers */
 | 
			
		||||
    ori     s2, s2, 1 << HWLP_COPROC_IDX    /* Mark the HWLP coprocessor as enabled (dirty) */
 | 
			
		||||
    li      a1, 1                           /* Allocate the save area if not already allocated */
 | 
			
		||||
    li      a2, HWLP_COPROC_IDX
 | 
			
		||||
    mv      s1, ra
 | 
			
		||||
@@ -537,8 +558,6 @@ rtos_int_enter:
 | 
			
		||||
    /* Get the area where we need to save the HWLP registers */
 | 
			
		||||
    lw      a0, RV_COPROC_SA+HWLP_COPROC_IDX*4(a0)      /* a0 = RvCoprocSaveArea->sa_coprocs[\coproc_idx] */
 | 
			
		||||
    hwlp_save_regs a0
 | 
			
		||||
    /* Disable the HWLP feature so that ISR cannot use them */
 | 
			
		||||
    csrwi   CSR_HWLP_STATE_REG, HWLP_CLEAN_STATE
 | 
			
		||||
1:
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -559,9 +578,16 @@ rtos_int_enter:
 | 
			
		||||
    ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE a0 a1
 | 
			
		||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
 | 
			
		||||
 | 
			
		||||
rtos_int_enter_end:
 | 
			
		||||
    /* Disable the HWLP coprocessor for ISRs */
 | 
			
		||||
#if SOC_CPU_HAS_HWLOOP
 | 
			
		||||
    csrwi   CSR_HWLP_STATE_REG, HWLP_OFF_STATE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if SOC_CPU_COPROC_NUM > 0
 | 
			
		||||
    /* Return the coprocessor context from s2 */
 | 
			
		||||
    mv      a0, s2
 | 
			
		||||
rtos_int_enter_end:
 | 
			
		||||
#endif /* SOC_CPU_COPROC_NUM > 0 */
 | 
			
		||||
    ret
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -577,8 +603,8 @@ rtos_int_enter_end:
 | 
			
		||||
    .type rtos_int_exit, @function
 | 
			
		||||
rtos_int_exit:
 | 
			
		||||
    /* To speed up this routine and because this current routine is only meant to be called from the interrupt
 | 
			
		||||
     * handler, let's use callee-saved registers instead of stack space. Registers `s5-s11` are not used by
 | 
			
		||||
     * the caller */
 | 
			
		||||
     * handler, let's use callee-saved registers instead of stack space */
 | 
			
		||||
    mv      s10, ra
 | 
			
		||||
    mv      s11, a0
 | 
			
		||||
#if SOC_CPU_COPROC_NUM > 0
 | 
			
		||||
    /* Save a1 as it contains the bitmap with the enabled coprocessors */
 | 
			
		||||
@@ -586,10 +612,10 @@ rtos_int_exit:
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ( configNUM_CORES > 1 )
 | 
			
		||||
    csrr    a1, mhartid                     /* a1 = coreID */
 | 
			
		||||
    slli    a1, a1, 2                       /* a1 = a1 * 4 */
 | 
			
		||||
    csrr    s7, mhartid                     /* s7 = coreID */
 | 
			
		||||
    slli    s7, s7, 2                       /* s7 = s7 * 4 */
 | 
			
		||||
    la      a0, port_xSchedulerRunning      /* a0 = &port_xSchedulerRunning */
 | 
			
		||||
    add     a0, a0, a1                      /* a0 = &port_xSchedulerRunning[coreID] */
 | 
			
		||||
    add     a0, a0, s7                      /* a0 = &port_xSchedulerRunning[coreID] */
 | 
			
		||||
    lw      a0, (a0)                        /* a0 = port_xSchedulerRunning[coreID] */
 | 
			
		||||
#else
 | 
			
		||||
    lw      a0, port_xSchedulerRunning      /* a0 = port_xSchedulerRunning */
 | 
			
		||||
@@ -599,7 +625,7 @@ rtos_int_exit:
 | 
			
		||||
    /* Update nesting interrupts counter */
 | 
			
		||||
    la      a2, port_uxInterruptNesting     /* a2 = &port_uxInterruptNesting */
 | 
			
		||||
#if ( configNUM_CORES > 1 )
 | 
			
		||||
    add     a2, a2, a1                      /* a2 = &port_uxInterruptNesting[coreID] // a1 already contains coreID * 4 */
 | 
			
		||||
    add     a2, a2, s7                      /* a2 = &port_uxInterruptNesting[coreID] // s7 already contains coreID * 4 */
 | 
			
		||||
#endif /* ( configNUM_CORES > 1 ) */
 | 
			
		||||
    lw      a0, 0(a2)                       /* a0 = port_uxInterruptNesting[coreID] */
 | 
			
		||||
 | 
			
		||||
@@ -611,84 +637,66 @@ rtos_int_exit:
 | 
			
		||||
    bnez    a0, rtos_int_exit_end
 | 
			
		||||
 | 
			
		||||
isr_skip_decrement:
 | 
			
		||||
    /* If the CPU reached this label, a2 (uxInterruptNesting) is 0 for sure */
 | 
			
		||||
 | 
			
		||||
    /* Schedule the next task if a yield is pending */
 | 
			
		||||
    la      s7, xPortSwitchFlag             /* s7 = &xPortSwitchFlag */
 | 
			
		||||
#if ( configNUM_CORES > 1 )
 | 
			
		||||
    add     s7, s7, a1                      /* s7 = &xPortSwitchFlag[coreID] // a1 already contains coreID * 4  */
 | 
			
		||||
#endif /* ( configNUM_CORES > 1 ) */
 | 
			
		||||
    lw      a0, 0(s7)                       /* a0 = xPortSwitchFlag[coreID] */
 | 
			
		||||
    beqz    a0, no_switch_restore_coproc    /* if (xPortSwitchFlag[coreID] == 0) jump to no_switch_restore_coproc */
 | 
			
		||||
 | 
			
		||||
    /* Preserve return address and schedule next task. To speed up the process, and because this current routine
 | 
			
		||||
     * is only meant to be called from the interrupt handle, let's save some speed and space by using callee-saved
 | 
			
		||||
     * registers instead of stack space. Registers `s3-s11` are not used by the caller */
 | 
			
		||||
    mv      s10, ra
 | 
			
		||||
#if ( SOC_CPU_COPROC_NUM > 0 )
 | 
			
		||||
    /* In the cases where the newly scheduled task is different from the previously running one,
 | 
			
		||||
     * we have to disable the coprocessors to let them trigger an exception on first use.
 | 
			
		||||
     * Else, if the same task is scheduled, restore the former coprocessors state (before the interrupt) */
 | 
			
		||||
    call    rtos_current_tcb
 | 
			
		||||
    /* Keep former TCB in s9 */
 | 
			
		||||
    mv      s9, a0
 | 
			
		||||
#endif
 | 
			
		||||
    call    vTaskSwitchContext
 | 
			
		||||
#if ( SOC_CPU_COPROC_NUM == 0 )
 | 
			
		||||
    mv      ra, s10                         /* Restore original return address */
 | 
			
		||||
#endif
 | 
			
		||||
    /* Clears the switch pending flag (stored in s7) */
 | 
			
		||||
    sw      zero, 0(s7)                     /* xPortSwitchFlag[coreID] = 0; */
 | 
			
		||||
 | 
			
		||||
#if ( SOC_CPU_COPROC_NUM > 0 )
 | 
			
		||||
    /* If the Task to schedule is NOT the same as the former one (s9), keep the coprocessors disabled */
 | 
			
		||||
    /* Keep the current TCB in a0 */
 | 
			
		||||
    call    rtos_current_tcb
 | 
			
		||||
    mv      ra, s10                         /* Restore original return address */
 | 
			
		||||
    beq     a0, s9, no_switch_restore_coproc
 | 
			
		||||
 | 
			
		||||
#if SOC_CPU_HAS_HWLOOP
 | 
			
		||||
    /* We have to restore the context of the HWLP if the newly scheduled task used it before. In all cases, this
 | 
			
		||||
     * routine will also clean the state and set it to clean */
 | 
			
		||||
    mv      s7, ra
 | 
			
		||||
    /* a0 contains the current TCB address */
 | 
			
		||||
    call    hwlp_restore_if_used
 | 
			
		||||
    mv      ra, s7
 | 
			
		||||
#endif /* SOC_CPU_HAS_HWLOOP */
 | 
			
		||||
 | 
			
		||||
#if SOC_CPU_HAS_FPU
 | 
			
		||||
    /* Disable the FPU in the `mstatus` value to return */
 | 
			
		||||
    li      a1, ~CSR_MSTATUS_FPU_DISABLE
 | 
			
		||||
    and     s11, s11, a1
 | 
			
		||||
#endif /* SOC_CPU_HAS_FPU */
 | 
			
		||||
    j       no_switch_restored
 | 
			
		||||
 | 
			
		||||
#endif /* ( SOC_CPU_COPROC_NUM > 0 ) */
 | 
			
		||||
 | 
			
		||||
no_switch_restore_coproc:
 | 
			
		||||
    /* We reach here either because there is no switch scheduled or because the TCB that is going to be scheduled
 | 
			
		||||
     * is the same as the one that has been interrupted. In both cases, we need to restore the coprocessors status */
 | 
			
		||||
    /* Schedule the next task if a yield is pending */
 | 
			
		||||
    la      s6, xPortSwitchFlag             /* s6 = &xPortSwitchFlag */
 | 
			
		||||
#if ( configNUM_CORES > 1 )
 | 
			
		||||
    add     s6, s6, s7                      /* s6 = &xPortSwitchFlag[coreID] // s7 already contains coreID * 4  */
 | 
			
		||||
#endif /* ( configNUM_CORES > 1 ) */
 | 
			
		||||
    lw      a1, 0(s6)                       /* a1 = xPortSwitchFlag[coreID] */
 | 
			
		||||
    bnez    a1, context_switch_requested    /* if (xPortSwitchFlag[coreID] != 0) jump to context_switch_requested */
 | 
			
		||||
 | 
			
		||||
no_context_switch:
 | 
			
		||||
    /* No need to do anything on the FPU side, its state is already saved in `s11` */
 | 
			
		||||
 | 
			
		||||
#if SOC_CPU_HAS_HWLOOP
 | 
			
		||||
    /* Check if the ISR altered the state of the HWLP */
 | 
			
		||||
    csrr    a1, CSR_HWLP_STATE_REG
 | 
			
		||||
    addi    a1, a1, -HWLP_DIRTY_STATE
 | 
			
		||||
    bnez    a1, 1f
 | 
			
		||||
    /* ISR used the HWLP, restore the HWLP context! */
 | 
			
		||||
    mv      s7, ra
 | 
			
		||||
    /* a0 contains the current TCB address */
 | 
			
		||||
    call    hwlp_restore_if_used
 | 
			
		||||
    mv      ra, s7
 | 
			
		||||
    csrwi   CSR_HWLP_STATE_REG, HWLP_CLEAN_STATE
 | 
			
		||||
    /* If the HWLP coprocessor has a hardware bug with its state, manually set the state to DIRTY
 | 
			
		||||
     * if it was already dirty before the interrupt, else, keep it to CLEAN */
 | 
			
		||||
#if SOC_CPU_HAS_HWLOOP_STATE_BUG && ESP32P4_REV_MIN_FULL <= 1
 | 
			
		||||
    andi    a1, s8, 1 << HWLP_COPROC_IDX
 | 
			
		||||
    beqz    a1, 1f
 | 
			
		||||
    /* To re-enable the HWLP coprocessor, set the status to DIRTY */
 | 
			
		||||
    csrwi   CSR_HWLP_STATE_REG, HWLP_DIRTY_STATE
 | 
			
		||||
1:
 | 
			
		||||
    /* Else, the ISR hasn't touched HWLP registers, we don't need to restore the HWLP registers */
 | 
			
		||||
#endif /* SOC_CPU_HAS_HWLOOP_STATE_BUG && ESP32P4_REV_MIN_FULL <= 1 */
 | 
			
		||||
#endif /* SOC_CPU_HAS_HWLOOP */
 | 
			
		||||
 | 
			
		||||
#if SOC_CPU_HAS_PIE
 | 
			
		||||
    andi    a0, s8, 1 << PIE_COPROC_IDX
 | 
			
		||||
    beqz    a0, 2f
 | 
			
		||||
    pie_enable a0
 | 
			
		||||
2:
 | 
			
		||||
    /* Re-enable the PIE coprocessor if it was used */
 | 
			
		||||
    andi    a1, s8, 1 << PIE_COPROC_IDX
 | 
			
		||||
    beqz    a1, 1f
 | 
			
		||||
    pie_enable a1
 | 
			
		||||
1:
 | 
			
		||||
#endif /* SOC_CPU_HAS_PIE */
 | 
			
		||||
    j restore_stack_pointer
 | 
			
		||||
 | 
			
		||||
no_switch_restored:
 | 
			
		||||
context_switch_requested:
 | 
			
		||||
#if ( SOC_CPU_COPROC_NUM > 0 )
 | 
			
		||||
    /* Preserve former TCB in s9 */
 | 
			
		||||
    mv      s9, a0
 | 
			
		||||
#endif /* ( SOC_CPU_COPROC_NUM > 0 ) */
 | 
			
		||||
    call    vTaskSwitchContext
 | 
			
		||||
    /* Clears the switch pending flag (stored in s6) */
 | 
			
		||||
    sw      zero, 0(s6)                     /* xPortSwitchFlag[coreID] = 0; */
 | 
			
		||||
 | 
			
		||||
#if ( SOC_CPU_COPROC_NUM > 0 )
 | 
			
		||||
    /* If the Task to schedule is NOT the same as the former one (s9), keep the coprocessors disabled. */
 | 
			
		||||
    /* Check if the new TCB is the same as the previous one */
 | 
			
		||||
    call    rtos_current_tcb
 | 
			
		||||
    beq     a0, s9, no_context_switch
 | 
			
		||||
#endif /* ( SOC_CPU_COPROC_NUM > 0 ) */
 | 
			
		||||
 | 
			
		||||
#if SOC_CPU_HAS_HWLOOP
 | 
			
		||||
    call    hwlp_restore_if_used
 | 
			
		||||
#endif /* SOC_CPU_HAS_HWLOOP */
 | 
			
		||||
 | 
			
		||||
restore_stack_pointer:
 | 
			
		||||
 | 
			
		||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
 | 
			
		||||
    /* esp_hw_stack_guard_monitor_stop(); pass the scratch registers */
 | 
			
		||||
@@ -698,10 +706,8 @@ no_switch_restored:
 | 
			
		||||
 | 
			
		||||
#if ( configNUM_CORES > 1 )
 | 
			
		||||
    /* Recover the stack of next task and prepare to exit */
 | 
			
		||||
    csrr    a1, mhartid
 | 
			
		||||
    slli    a1, a1, 2
 | 
			
		||||
    la      a0, pxCurrentTCBs               /* a0 = &pxCurrentTCBs */
 | 
			
		||||
    add     a0, a0, a1                      /* a0 = &pxCurrentTCBs[coreID] */
 | 
			
		||||
    add     a0, a0, s7                      /* a0 = &pxCurrentTCBs[coreID] */
 | 
			
		||||
    lw      a0, 0(a0)                       /* a0 = pxCurrentTCBs[coreID] */
 | 
			
		||||
    lw      sp, 0(a0)                       /* sp = previous sp */
 | 
			
		||||
#else
 | 
			
		||||
@@ -724,4 +730,5 @@ no_switch_restored:
 | 
			
		||||
 | 
			
		||||
rtos_int_exit_end:
 | 
			
		||||
    mv      a0, s11                         /* a0 = new mstatus */
 | 
			
		||||
    mv      ra, s10
 | 
			
		||||
    ret
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD
 | 
			
		||||
 * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 */
 | 
			
		||||
@@ -236,6 +236,16 @@ _panic_handler:
 | 
			
		||||
    la    ra, _return_from_exception
 | 
			
		||||
    /* EXT_ILL CSR should contain the reason for the Illegal Instruction */
 | 
			
		||||
    csrrw a0, EXT_ILL_CSR, zero
 | 
			
		||||
#if SOC_CPU_HAS_HWLOOP
 | 
			
		||||
    /* Check if the HWLP bit is set. */
 | 
			
		||||
    andi a1, a0, EXT_ILL_RSN_HWLP
 | 
			
		||||
    beqz a1, hwlp_not_used
 | 
			
		||||
    /* HWLP used in an ISR, abort */
 | 
			
		||||
    mv   a0, sp
 | 
			
		||||
    j    vPortCoprocUsedInISR
 | 
			
		||||
hwlp_not_used:
 | 
			
		||||
#endif /* SOC_CPU_HAS_HWLOOP */
 | 
			
		||||
 | 
			
		||||
    /* Hardware loop cannot be treated lazily, so we should never end here if a HWLP instruction is used */
 | 
			
		||||
#if SOC_CPU_HAS_PIE
 | 
			
		||||
    /* Check if the PIE bit is set. */
 | 
			
		||||
 
 | 
			
		||||
@@ -523,6 +523,10 @@ config SOC_CPU_HAS_HWLOOP
 | 
			
		||||
    bool
 | 
			
		||||
    default y
 | 
			
		||||
 | 
			
		||||
config SOC_CPU_HAS_HWLOOP_STATE_BUG
 | 
			
		||||
    bool
 | 
			
		||||
    default y
 | 
			
		||||
 | 
			
		||||
config SOC_CPU_HAS_PIE
 | 
			
		||||
    bool
 | 
			
		||||
    default y
 | 
			
		||||
 
 | 
			
		||||
@@ -179,6 +179,7 @@
 | 
			
		||||
#define SOC_CPU_HAS_FPU                 1
 | 
			
		||||
#define SOC_CPU_HAS_FPU_EXT_ILL_BUG     1       // EXT_ILL CSR doesn't support FLW/FSW
 | 
			
		||||
#define SOC_CPU_HAS_HWLOOP              1
 | 
			
		||||
#define SOC_CPU_HAS_HWLOOP_STATE_BUG    1       // HWLOOP state doesn't go to DIRTY after executing the last instruction of a loop
 | 
			
		||||
/* PIE coprocessor assembly is only supported with GCC compiler  */
 | 
			
		||||
#define SOC_CPU_HAS_PIE                 1
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user