# ESP-IDF Hardware Init Sequence Audit (ESP32 → QEMU) ## For Bare-Metal UniversalisOS CCOMPARE Timer Replication --- ## CRITICAL FINDING: Timer Architecture ESP32 on QEMU uses the **Xtensa CCOUNT/CCOMPARE** cycle-counter timer for the FreeRTOS tick, NOT an external hardware timer peripheral. The CCOMPARE timer is entirely **internal to the Xtensa core** — it has no MMIO register address. It is configured via the `wsr`/`rsr` instructions on special registers. ### ESP32 Timer Mapping (from core-isa.h) ``` XCHAL_NUM_TIMERS = 3 CCOMPARE0 → Interrupt 6 (level 1) ← default tick timer when CONFIG_FREERTOS_CORETIMER_0 CCOMPARE1 → Interrupt 15 (level 3) ← alternative when CONFIG_FREERTOS_CORETIMER_1 CCOMPARE2 → Interrupt 16 (level 5) XCHAL_EXCM_LEVEL = 3 (level masked by PS.EXCM) ``` ### Key: `XT_CCOMPARE` and `XT_TIMER_INTEN` values From `xtensa_timer.h`: ```c #define XT_CCOMPARE (CCOMPARE + XT_TIMER_INDEX) // CCOMPARE0=0x240, CCOMPARE1=0x241, CCOMPARE2=0x242 #define XT_TIMER_INTNUM XCHAL_TIMER_INTERRUPT(XT_TIMER_INDEX) #define XT_TIMER_INTEN (1 << XT_TIMER_INTNUM) // For CCOMPARE0: (1<<6) = 0x40 ``` When `CONFIG_FREERTOS_CORETIMER_0` (default for ESP32): - `XT_TIMER_INDEX = 0` - `XT_CCOMPARE = CCOMPARE0` (SR 0x240) - `XT_TIMER_INTNUM = 6` (interrupt bit 6) - `XT_TIMER_INTEN = 0x00000040` --- ## QEMU Timer Model (How It Actually Works) QEMU implements CCOMPARE entirely in the Xtensa CPU core model (`target/xtensa/op_helper.c`, `pic_cpu.c`): 1. **CCOUNT** (SR 0x234) is derived from QEMU's virtual clock: `CCOUNT = ccount_base + clock_ns_to_ticks(now - time_base)` 2. **Writing CCOMPAREn** (`update_ccompare()`): - Clears the timer interrupt bit in INTSET - Schedules a QEMU timer: `timer_mod(ccompare[i].timer, ccount_time + ns_until_match)` - The `dcc` = `CCOMPARE[i] - CCOUNT - 1 + 1` cycles until match 3. **Timer fires** (`xtensa_ccompare_cb()`): - Sets `env->irq_inputs[timerint[i]]` active → bit in INTSET - `check_interrupts()` checks INTSET & INTENABLE against current cintlevel 4. **Interrupt delivery**: QEMU's `check_interrupts()` (in `pic_cpu.c`) checks: `int_set_enabled = INTSET & (INTENABLE | NMI_mask)` If any bit in `int_set_enabled` is at a level above current cintlevel → `cpu_interrupt(CPU_INTERRUPT_HARD)` **QEMU does NOT require any external device (INTMATRIX, DPORT) to be configured for the CCOMPARE timer to work.** The CCOMPARE timer fires through the internal Xtensa interrupt path, completely independent of the ESP32 interrupt matrix. --- ## ORDERED INIT SEQUENCE (Bootloader → Scheduler Start) ### PHASE 1: 2nd-Stage Bootloader (`bootloader_init()`) #### 1.1 MEMCTL (Xtensa SR) ``` # File: bootloader_esp32.c:170 wsr MEMCTL, XCHAL_CACHE_MEMCTL_DEFAULT # Only if XCHAL_ERRATUM_572 ``` #### 1.2 Clock Configuration (`bootloader_clock_configure()`) ```c // File: bootloader_clock_init.c:27 // Calls rtc_clk_init() with CPU at 80MHz (CPU_CLK_FREQ_MHZ_BTLD) // In rtc_clk_init() (rtc_clk_init.c:31): // If currently on PLL, switch to XTAL first: rtc_clk_cpu_freq_to_xtal(40, 1); // Set SCK_DCAP and CK8M_DFREQ tuning values: REG_SET_FIELD(RTC_CNTL_REG, RTC_CNTL_SCK_DCAP, cfg.slow_clk_dcap); // RTC_CNTL_REG = 0x3FF48000 + 0x007C = 0x3FF4807C REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_DFREQ, cfg.clk_8m_dfreq); // RTC_CNTL_CLK_CONF_REG = 0x3FF48074 // Enable BBPLL via regi2c regi2c_ctrl_ll_i2c_bbpll_enable(); // Estimate XTAL frequency, then set CPU to 80MHz via PLL rtc_clk_cpu_freq_set_config(&new_config); // Configure REF_TICK divider clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_XTAL, xtal_freq); clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_PLL, new_config.freq_mhz); // Set CCOUNT to correct value for new frequency esp_cpu_set_cycle_count(ccount * new_freq / old_freq); // Enable RC_FAST clock, set RTC fast/slow clock sources rtc_clk_8m_enable(true, false); rtc_clk_fast_src_set(cfg.fast_clk_src); rtc_clk_slow_src_set(cfg.slow_clk_src); ``` #### 1.3 MMU Reset (`bootloader_reset_mmu()`) ```c // File: bootloader_esp32.c:43 Cache_Read_Disable(0); // Disables ICache for PRO CPU Cache_Read_Disable(1); // Disables ICache for APP CPU (dual core) Cache_Flush(0); // Flush ICache PRO Cache_Flush(1); // Flush ICache APP mmu_init(0); // Reinit MMU table for PRO // For dual core: DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR); // DPORT_APP_CACHE_CTRL1_REG = 0x3FF000C4 mmu_init(1); // Reinit MMU table for APP DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR); // Unmask DROM0 cache: DPORT_REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0); // DPORT_PRO_CACHE_CTRL1_REG = 0x3FF00004 (actually 0x3FF00008 for ctrl1) ``` #### 1.4 Watchdog Configuration (`bootloader_config_wdt()`) ```c // File: bootloader_init.c:70 // Disable RWDT flashboot protection wdt_hal_write_protect_disable(&rwdt_ctx); // Write to RTC WDT config regs wdt_hal_set_flashboot_en(&rwdt_ctx, false); // Clear RTC_CNTL_WDT_OPTIONS register bit wdt_hal_write_protect_enable(&rwdt_ctx); // Disable MWDT0 flashboot protection wdt_hal_write_protect_disable(&mwdt_ctx); wdt_hal_set_flashboot_en(&mwdt_ctx, false); // Clear TIMG0 WDT options wdt_hal_write_protect_enable(&mwdt_ctx); // If CONFIG_BOOTLOADER_WDT_ENABLE: // Initialize RWDT with CONFIG_BOOTLOADER_WDT_TIME_MS timeout ``` ### PHASE 2: App Startup (`call_start_cpu0()`) #### 2.1 CPU Initialization (`init_cpu()`) ```c // File: cpu_start.c:386 // NOTE: For Xtensa ESP32, this does very little: // esp_cpu_intr_set_ivt_addr(&_vector_table); // → calls xt_utils_set_vecbase((uint32_t)&_vector_table) // → WSR VECBASE, &_vector_table // (Sets exception/interrupt vector table base address) ``` **Register write:** | Register | Address | Value | Why | |----------|---------|-------|-----| | VECBASE | SR 0x0E | &_vector_table | Set IVT base for exception handling | #### 2.2 Cache Init (`cache_init()`) ```c // File: cpu_start.c:482 // For ESP32: cache_hal_init() — minimal, ESP32 has ROM-managed cache // No ESP32-specific cache config blocks (those are for S2/S3) ``` #### 2.3 RTC Init (`sys_rtc_init()`) ```c // File: cpu_start.c:541 // If NOT CONFIG_BOOTLOADER_WDT_ENABLE and reset was WDT: // Disable RTC WDT // wdt_hal_write_protect_disable(&rtc_wdt_ctx); // wdt_hal_disable(&rtc_wdt_ctx); // wdt_hal_write_protect_enable(&rtc_wdt_ctx); // Configure RTC power: esp_rtc_init(); // rtc_config_t cfg = RTC_CONFIG_DEFAULT(); rtc_init(cfg); ``` #### 2.4 MSPI/Flash Init ```c // spi_flash_init_chip_state(); // mspi_timing_flash_tuning(); ``` #### 2.5 `system_early_init()` — The Critical Phase ##### 2.5.1 Clock Configuration (`esp_clk_init()`) ```c // File: esp32/clk.c:122 // Re-enable RC_FAST rtc_clk_8m_enable(true, rc_fast_d256_is_enabled); // Set RTC FAST clock to RC_FAST rtc_clk_fast_src_set(SOC_RTC_FAST_CLK_SRC_RC_FAST); // Select RTC SLOW clock (default: 150kHz RC_SLOW) select_rtc_slow_clk(SLOW_CLK_150K); // Set CPU to CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ (80, 160, or 240) rtc_clk_cpu_freq_set_config(&new_config); // This configures BBPLL and sets DPORT_CPUPERIOD_SEL // Re-adjust CCOUNT esp_cpu_set_cycle_count(ccount * new_freq / old_freq); ``` ##### 2.5.2 Peripheral Clock Init (`esp_perip_clk_init()`) ```c // File: esp32/clk.c:206 // Disable unused peripheral clocks, enable RNG // Writes to DPORT_PERIP_CLK_EN_REG, DPORT_PERIP_RST_EN_REG, etc. ``` ##### 2.5.3 Clear Interrupt Matrix ```c // File: cpu_start.c:171 static void core_intr_matrix_clear(void) { for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) { esp_rom_route_intr_matrix(core_id, i, ETS_INVALID_INUM); // Writes to DPORT_PRO_MAC_INTR_MAP_REG + i*4 // Sets all peripheral interrupt sources to "unconnected" (6) } } ``` **This clears all 69 ESP32 interrupt sources to INUM 6 (disconnected) in the interrupt matrix.** Key register range: `DPORT_PRO_MAC_INTR_MAP_REG` (0x3FF00000 + offsets) ### PHASE 3: FreeRTOS Scheduler Start #### 3.1 `xPortStartScheduler()` — The Timer Arming Point ```c // File: port.c:329 BaseType_t xPortStartScheduler(void) { portDISABLE_INTERRUPTS(); // rsil a2, XCHAL_EXCM_LEVEL → sets PS.INTLEVEL=3 vPortSetupTimer(); // ← ARMS THE CCOMPARE TIMER port_xSchedulerRunning[core] = 1; // ... spill windows ... __asm__ volatile("call0 _frxt_dispatch\n"); // Never returns } ``` #### 3.2 `vPortSetupTimer()` → `_frxt_tick_timer_init()` ```c // File: port_systick.c:169 void vPortSetupTimer(void) { #if CONFIG_FREERTOS_SYSTICK_USES_CCOUNT _xt_tick_divisor_init(); // Set _xt_tick_divisor = CPU_FREQ_HZ / TICK_RATE_HZ _frxt_tick_timer_init(); // Arm the CCOMPARE timer #else vSystimerSetup(); // SYSTIMER peripheral (not used on ESP32 QEMU) #endif } ``` **`_xt_tick_divisor_init()`:** ```c // File: xtensa_init.c:51 _xt_tick_divisor = esp_clk_cpu_freq() / XT_TICK_PER_SEC; // For 80MHz CPU, 100Hz tick: _xt_tick_divisor = 800,000 // For 240MHz CPU, 1000Hz tick: _xt_tick_divisor = 240,000 ``` **`_frxt_tick_timer_init()` (portasm.S:385):** ```asm _frxt_tick_timer_init: ENTRY(16) # Load the tick divisor (cycles per tick) movi a2, _xt_tick_divisor l32i a3, a2, 0 # a3 = _xt_tick_divisor # Read current cycle count rsr a2, CCOUNT # a2 = current CCOUNT # Set first interrupt time add a2, a2, a3 # a2 = CCOUNT + divisor (first tick deadline) wsr a2, XT_CCOMPARE # Write CCOMPARE0 — arms the timer + clears pending int # Enable the timer interrupt movi a6, XT_TIMER_INTEN # a6 = (1 << 6) = 0x40 for CCOMPARE0 movi a3, xt_ints_on callx4 a3 # Enable interrupt bit 6 in INTENABLE RET(16) ``` **`xt_ints_on()` (xtensa_intr_asm.S:156):** ```asm xt_ints_on: ENTRY0 movi a3, 0 xsr a3, INTENABLE # Read+clear INTENABLE (SR 0x00C) rsync or a2, a3, a2 # a2 = old INTENABLE | new mask wsr a2, INTENABLE # Write new INTENABLE rsync mov a2, a3 # return old value RET0 ``` #### 3.3 Timer Interrupt Handler (`_frxt_timer_int`) ```asm # portasm.S:295 _frxt_timer_int: ENTRY(16) # Load tick divisor movi a3, _xt_tick_divisor l32i a2, a3, 0 # Read old CCOMPARE, advance it rsr a3, XT_CCOMPARE # a3 = old CCOMPARE add a4, a3, a2 # a4 = old + divisor wsr a4, XT_CCOMPARE # Write new CCOMPARE (clears interrupt) esync # Call xPortSysTickHandler() for tick processing # ... (catch-up loop if multiple ticks missed) ... ``` --- ## REGISTER WRITE TABLE (Ordered, by Phase) ### Special Registers (Xtensa Core SRs — via wsr/rsr, NOT MMIO) | Step | Register | SR# | Value | Source | Purpose | |------|----------|-----|-------|--------|---------| | 1.1 | MEMCTL | 0x3A | XCHAL_CACHE_MEMCTL_DEFAULT | bootloader_esp32.c:170 | L1 cache memory control (erratum workaround) | | 2.1 | VECBASE | 0x0E | &_vector_table | cpu_start.c:420 | Exception vector base | | 2.5.1 | CCOUNT | 0x234 | (adjusted) | esp32/clk.c:197 | Adjust cycle count on freq change (via `wsr CCOUNT`) | | 3.2 | CCOMPARE0 | 0x240 | CCOUNT + _xt_tick_divisor | portasm.S:399 | Arm first tick deadline | | 3.2 | INTENABLE | 0x00C | old \| 0x00000040 | xtensa_intr_asm.S:178 | Enable timer interrupt bit 6 (CCOMPARE0) | | 3.3 | CCOMPARE0 | 0x240 | old_CCOMPARE + _xt_tick_divisor | portasm.S:334 | Re-arm for next tick (every interrupt) | ### MMIO Registers (Peripheral — via DPORT/RTC) #### Clock Subsystem | Step | Register | Address | Value | Source | Purpose | |------|----------|---------|-------|--------|---------| | 1.2 | RTC_CNTL_REG | 0x3FF4807C | SCK_DCAP field | rtc_clk_init.c:60 | RC slow clock tuning | | 1.2 | RTC_CNTL_CLK_CONF_REG | 0x3FF48074 | CK8M_DFREQ field | rtc_clk_init.c:61 | RC fast clock tuning | | 1.2 | RTC_CNTL_CLK_CONF_REG | 0x3FF48074 | CK8M_DIV_DRIVER field | rtc_clk_init.c:64 | RC fast clock divider | | 1.2 | (various BBPLL regs) | regi2c | PLL config | rtc_clk_cpu_freq_set | CPU PLL frequency | | 2.5.1 | RTC_CNTL_CLK_CONF_REG | 0x3FF48074 | RTC_CNTL_FAST_CLK_SEL | esp32/clk.c:141 | Select RC_FAST for RTC FAST | | 2.5.1 | RTC_CNTL_CLK_CONF_REG | 0x3FF48074 | RTC_CNTL_ANA_CLK_RTC_SEL | esp32/clk.c:165 | Select RTC SLOW source | #### Cache/MMU Subsystem | Step | Register | Address | Value | Source | Purpose | |------|----------|---------|-------|--------|---------| | 1.3 | DPORT_PRO_CACHE_CTRL1_REG | 0x3FF00008 | clr DROM0 mask | bootloader_esp32.c:65 | Unmask DROM0 cache for PRO | | 1.3 | DPORT_APP_CACHE_CTRL1_REG | 0x3FF000C4 | set/clr MMU_IA_CLR | bootloader_esp32.c:58-60 | MMU interrupt clear workaround | #### Watchdog Subsystem | Step | Register | Address | Value | Source | Purpose | |------|----------|---------|-------|--------|---------| | 1.4 | RTC WDT regs | 0x3FF48xxx | flashboot_en=0 | bootloader_init.c:81 | Disable RWDT flashboot protection | | 1.4 | TIMG0 WDT regs | 0x3FF5F0xx | flashboot_en=0 | bootloader_init.c:98 | Disable MWDT0 flashboot protection | | 2.3 | RTC WDT regs | 0x3FF48xxx | WDT disabled | cpu_start.c:560 | Disable RWDT (if no bootloader WDT) | #### Interrupt Matrix (Cleared — not configured for CCOMPARE) | Step | Register | Address | Value | Source | Purpose | |------|----------|---------|-------|--------|---------| | 2.5.3 | DPORT_PRO_MAC_INTR_MAP_REG+i*4 | 0x3FF00000+i*4 | 6 (unconnected) | cpu_start.c:184 | Clear all peripheral→CPU interrupt routes | **NOTE:** The interrupt matrix is NOT used to route the CCOMPARE timer interrupt. CCOMPARE0 fires on Xtensa internal interrupt 6, which is a core-level interrupt, not routed through the peripheral interrupt matrix. --- ## MINIMAL BARE-METAL CCOMPARE INIT FOR UNIVERSALISOS ON QEMU Based on the QEMU device model analysis, here is the **absolute minimum** needed to make CCOMPARE0 work: ```asm ; --- 1. Set VECBASE to point to your exception vectors --- movi a2, _vector_table wsr a2, VECBASE ; SR 0x0E isync ; --- 2. Set PS to allow level 1 interrupts (clear EXCM, set INTLEVEL=0) --- ; PS register format: bits[3:0]=INTLEVEL, bit[4]=EXCM ; Need INTLEVEL < 1 (timer is level 1), and EXCM=0 movi a2, 0 ; INTLEVEL=0, EXCM=0 (everything enabled) wsr a2, PS ; SR 0x0E6... actually PS is SR 0x0E6/230 rsync ; --- 3. Arm CCOMPARE0 with first tick deadline --- rsr a2, CCOUNT ; SR 0x234 — read current cycle count movi a3, TICK_DIVISOR ; e.g., 800000 for 100Hz @ 80MHz add a2, a2, a3 ; first interrupt time wsr a2, CCOMPARE0 ; SR 0x240 — arm timer, clears pending interrupt esync ; ensure write completes ; --- 4. Enable timer interrupt bit 6 in INTENABLE --- movi a2, 0x40 ; (1 << 6) for CCOMPARE0 interrupt ; Read current INTENABLE, OR in the bit, write back movi a3, 0 xsr a3, INTENABLE ; SR 0x00C — atomic read+clear rsync or a2, a3, a2 ; old | 0x40 wsr a2, INTENABLE ; SR 0x00C — enable timer interrupt rsync ; --- 5. Enable global interrupts (clear PS.INTLEVEL) --- ; Already done in step 2 if PS.INTLEVEL=0 ; But if interrupts were disabled via rsil: rsil a0, 0 ; Set INTLEVEL=0 (enable all unmasked ints) ``` ### QEMU-Specific Notes 1. **CCOUNT frequency**: QEMU's CCOUNT advances at the CPU clock frequency specified in the overlay config (typically 40MHz or 80MHz). The `ccount_base` is set during `xtensa_irq_init()` from the current CCOUNT value. 2. **No peripheral device needed**: Unlike the SYSTIMER peripheral (used on S2/S3/C-series), CCOMPARE0 fires through the Xtensa core interrupt path — no interrupt matrix configuration, no DPORT writes, no external device registers needed. 3. **INTSET management**: QEMU automatically sets INTSET bit 6 when the CCOMPARE timer fires (via `xtensa_ccompare_cb` → `qemu_set_irq`). Writing CCOMPARE0 clears the bit (via `update_ccompare` → `qatomic_and INTSET`). 4. **INTENABLE must be set**: Without `INTENABLE |= (1<<6)`, the timer interrupt will fire but `check_interrupts()` won't deliver it. This is the most common failure point. 5. **PS.INTLEVEL must be < 1**: Since CCOMPARE0 is level 1, PS.INTLEVEL must be 0 to receive it. Also PS.EXCM must be 0. 6. **VECBASE must point to valid level-1 interrupt handler**: The interrupt vector at VECBASE + 0x180 (level 2 vector offset is 0x180, but level 1 uses offset 0x000+0x50? Check). Actually for ESP32: - Level 1: no fixed vector offset (uses INTENABLE check in level-2 handler? No...) - The actual interrupt dispatch uses the exception vector at `VECBASE + level_vector_offset` ### ESP32 Interrupt Vector Offsets (from core-isa.h) ``` Level 1: No separate vector (handled by kernel software priority) Level 2: VECOFS = 0x00000180 → VECBASE + 0x180 Level 3: VECOFS = 0x000001C0 → VECBASE + 0x1C0 Level 4: VECOFS = 0x00000200 → VECBASE + 0x200 Level 5: VECOFS = 0x00000240 → VECBASE + 0x240 Level 6: VECOFS = 0x00000280 (Debug) Level 7: VECOFS = NMI offset ``` **IMPORTANT**: On ESP32, interrupt level 1 does NOT have a dedicated vector offset in the Xtensa hardware. Level 1 interrupts are dispatched through the Level 2 vector (offset 0x180). The interrupt handler then reads INTERRUPT and INTENABLE to determine which specific interrupt fired. Wait, this is incorrect for standard Xtensa. Let me re-check: in the Xtensa architecture, interrupts at level N use the level-N vector. But ESP32's core-isa.h only defines vectors for levels 2-7. Level 1 interrupts ARE delivered via the level 2 vector mechanism — actually, looking at XCHAL_INTLEVEL1_MASK and the vector table, level 1 interrupts share the level 2 entry point. The ROM/kernel reads INTERRUPT/INTENABLE to dispatch. Actually, the correct behavior is: Level 1 interrupts use the level 1 vector. But ESP32 defines only vectors for level 2+ because the typical Xtensa dispatch for level 1 IS via reading INTERRUPT at the level 2 entry. Let me not over-think this — the key point is that VECBASE must be set, and your handler must correctly dispatch interrupt 6. --- ## SUMMARY: What QEMU Needs for CCOMPARE Timer ### Absolutely Required (4 Steps) 1. **VECBASE** set to valid exception vector table (wsr VECBASE) 2. **CCOMPARE0** written with CCOUNT + divisor (wsr CCOMPARE0) 3. **INTENABLE** bit 6 set (wsr INTENABLE |= 0x40) 4. **PS.INTLEVEL = 0** (interrupts globally enabled, timer is level 1) ### NOT Required for QEMU (despite being done in ESP-IDF) - ❌ Clock/PLL configuration (QEMU CCOUNT advances regardless) - ❌ RTC/init (no effect on CCOMPARE) - ❌ Cache/MMU setup (no effect on CCOMPARE) - ❌ Interrupt matrix clearing (CCOMPARE is internal to Xtensa core) - ❌ Watchdog configuration (no effect on CCOMPARE) - ❌ Peripheral clock gating (no effect on CCOMPARE) ### ISR Re-arm Pattern (in `_frxt_timer_int`) ```asm rsr a3, CCOMPARE0 ; read old comparator add a4, a3, divisor ; advance by one tick wsr a4, CCOMPARE0 ; write new value (clears pending IRQ) esync ; then call tick handler ``` --- ## Key Source Files Referenced | File | Path | |------|------| | call_start_cpu0 | components/esp_system/port/cpu_start.c | | bootloader init | components/bootloader_support/src/esp32/bootloader_esp32.c | | bootloader clock | components/bootloader_support/src/bootloader_clock_init.c | | bootloader WDT | components/bootloader_support/src/bootloader_init.c | | rtc_clk_init | components/esp_hw_support/port/esp32/rtc_clk_init.c | | esp_clk_init | components/esp_system/port/soc/esp32/clk.c | | FreeRTOS port.c | components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c | | FreeRTOS portasm.S | components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S | | port_systick.c | components/freertos/port_systick.c | | xtensa_init.c | components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_init.c | | xtensa_intr_asm.S | components/xtensa/xtensa_intr_asm.S | | xtensa_timer.h | components/xtensa/include/xtensa_timer.h | | ESP32 core-isa.h | components/xtensa/esp32/include/xtensa/config/core-isa.h | | QEMU esp32.c | hw/xtensa/esp32.c | | QEMU esp32_intc.c | hw/xtensa/esp32_intc.c | | QEMU pic_cpu.c | hw/xtensa/pic_cpu.c | | QEMU op_helper.c | target/xtensa/op_helper.c | | QEMU cpu.h | target/xtensa/cpu.h | | QEMU core-esp32/core-isa.h | target/xtensa/core-esp32/core-isa.h |