@@ -299,13 +299,26 @@ _handle_kernel_exc:
299299
300300 . global _handle_level1
301301_handle_level1:
302- // --- allocate 96 - byte exception frame on the interrupted stack ---
302+ // EXCCAUSE 5 (AllocaCause) is a MOVSP window - spill request , not a fault , so
303+ // it is checked before any state is touched: a0 is still in EXCSAVE1.
304+ // Xtensa ISA Reference Manual , Table 4 - 64 "Exception Causes" .
305+ rsr a0 , EXCCAUSE
306+ bnei a0 , 5 , 1f
307+ j _xt_alloca_exc
308+ 1 :
309+ rsr a0 , EXCSAVE1 // restore a0 clobbered by the EXCCAUSE read
310+
311+ // --- allocate the exception frame on the interrupted stack ---
303312 // Layout (offsets from a1 after adjustment):
304313 // 0 : a0 4 : a1(orig) 8 : a2 12 : a3 16 : a4 20 : a5
305314 // 24 : a6 28 : a7 32 : a8 36 : a9 40 : a10 44 : a11
306315 // 48 : a12 52 : a13 56 : a14 60 : a15
307- // 64 : SAR 68 : EPC1 72 : PS
308- addi a0 , a1 , - 96 // a0 = new frame pointer
316+ // 64 : SAR 68 : EPC1 72 : PS 76 : WINDOWBASE 80 : WINDOWSTART
317+ //
318+ // 128 , not the 84 the layout needs: the low 16 bytes are the interruptee's
319+ // windowed - ABI base save area , as in ESP - IDF's XT_STK_FRMSZ ( + 0x20 ).
320+ // https://github.com/espressif/ esp - idf/blob/master/components/xtensa/include/xtensa_context.h
321+ addi a0 , a1 , - 128 // a0 = new frame pointer
309322 s32i a1 , a0 , 4 // save original a1 ( SP )
310323 mov a1 , a0 // a1 = frame pointer
311324
@@ -339,6 +352,14 @@ _handle_level1:
339352 // level - 1 interrupts.
340353 rsr a2 , PS
341354 s32i a2 , a1 , 72 // save PS (with EXCM= 1 set by hardware)
355+
356+ // Captured here , not in the C handler: getting there costs a callx4 and the
357+ // printfs rotate and spill windows , so they would report their own state.
358+ rsr a3 , WINDOWBASE
359+ s32i a3 , a1 , 76
360+ rsr a3 , WINDOWSTART
361+ s32i a3 , a1 , 80
362+
342363 movi a3 , ~ 0x1F // mask: clear INTLEVEL (bits 0 - 3 ) + EXCM (bit 4 )
343364 and a2 , a2 , a3
344365 movi a3 , 1 // INTLEVEL = 1
@@ -412,6 +433,37 @@ _handle_level1:
412433
413434 rfe
414435
436+ // Alloca (MOVSP) exception: rotate back to the MOVSP window , fix PS.OWB , then
437+ // fall into the matching window underflow handler , which spills and rfwu's back.
438+ // Ported from ESP - IDF _xt_alloca_exc:
439+ // https://github.com/espressif/ esp - idf/blob/master/components/xtensa/xtensa_vectors.S
440+ .balign 4
441+ . global _xt_alloca_exc
442+ _xt_alloca_exc:
443+ rsr a0 , WINDOWBASE // grab WINDOWBASE before rotw changes it
444+ rotw - 1 // WINDOWBASE goes to a4 , new a0 - a3 are scratch
445+ rsr a2 , PS
446+ extui a3 , a2 , 8 , 4 // a3 = PS.OWB (shift 8 , 4 bits)
447+ xor a3 , a3 , a4 // bits th at changed from old to current WB
448+ rsr a4 , EXCSAVE1 // restore the interruptee's a0 (now in a4)
449+ slli a3 , a3 , 8
450+ xor a2 , a2 , a3 // flip those bits in PS.OWB
451+ wsr a2 , PS // PS.OWB now matches the new WINDOWBASE
452+ rsync
453+
454+ // Dispatch on the call size in bits 31 : 30 of the interruptee's a0 ; plain `j`
455+ // because _bbci.l's 8 - bit range cannot reach the underflow vectors.
456+ // Xtensa ISA Reference Manual , RETW , section 8 . 3 . 253 , p. 565 (a0 encoding).
457+ _bbsi.l a4 , 31 , 1f
458+ j _window_underflow4
459+ 1 :
460+ rotw - 1 // interruptee's a0 moves to a8
461+ _bbsi.l a8 , 30 , 2f
462+ j _window_underflow8
463+ 2 :
464+ rotw - 1
465+ j _window_underflow12
466+
415467// -----------------------------------------------------------------------
416468// Default weak espradio_user_exception: infinite loop halt.
417469// Overridden by the strong definition in espradio's isr.c when linked.
0 commit comments