RISC-V ULP interrupt context saving

Baoshi
Posts: 23
Joined: Sun Nov 22, 2015 3:30 am

RISC-V ULP interrupt context saving

Postby Baoshi » Tue Nov 19, 2024 1:58 pm

In ESP32-S3 RISC-V ULP interrupt code (ulp/ulp_riscv/ulp_core/ulp_riscv_vector.S), there is a note saying:

Code: Select all

Note: We don't save the callee-saved s0-s11 registers to save space
This causes some issues that the riscv32-esp-elf-gcc generated code do used s registers for function local variables. If I manually add saving/restore of s0-s11 then the issue is solved.

Is there an "elegant" way to solve this without touch the esp-idf code base?

Thanks

Baoshi

MicroController
Posts: 2661
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: RISC-V ULP interrupt context saving

Postby MicroController » Tue Nov 19, 2024 4:45 pm

Looks fine to me:

Code: Select all

static volatile uint32_t dummy;

void __attribute__((noinline)) testFunc() {
    // Force the compiler to create and hold a lot of local variables:
    uint32_t a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p;
    uint32_t z;
    a = dummy;
    b = dummy;
    c = dummy;
    d = dummy;
    e = dummy;
    f = dummy;
    g = dummy;
    h = dummy;
    i = dummy;
    j = dummy;
    k = dummy;
    l = dummy;
    m = dummy;
    n = dummy;
    o = dummy;
    p = dummy;

    z = dummy;
    dummy = (a==z) && (b==z) && (c==z) && (d==z) && (e==z) && (f==z) && (g==z) && (h==z) && (i==z) && (j==z) &&
        (k==z) && (l==z) && (m==z) && (n==z) && (o==z) && (p==z);
}
yields

Code: Select all

<testFunc()>:
addi sp,sp,-16
sw s0,12(sp)
sw s1,8(sp)
sw s2,4(sp)
sw s3,0(sp)
lw s3,788(zero) # 314 <dummy>

  ...
 
lw s0,12(sp)
sw a3,788(zero) # 314 <dummy>
lw s1,8(sp)
lw s2,4(sp)
lw s3,0(sp)
addi sp,sp,16
ret

Baoshi
Posts: 23
Joined: Sun Nov 22, 2015 3:30 am

Re: RISC-V ULP interrupt context saving

Postby Baoshi » Wed Nov 20, 2024 12:38 am

This is exactly where the problem is: A function can use s0-s11 for local variables, but when interrupt happens, sx registers are not preserved so when returning from ISR, variable values may change.

MicroController
Posts: 2661
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: RISC-V ULP interrupt context saving

Postby MicroController » Wed Nov 20, 2024 8:18 am

sx registers are not preserved so when returning from ISR, variable values may change.
No. Gcc does the right thing and makes the callee, i.e. the actual ISR function, save&restore the callee-saved registers. Saving the callee-saved registers before calling a function would be rather pointless.

Baoshi
Posts: 23
Joined: Sun Nov 22, 2015 3:30 am

Re: RISC-V ULP interrupt context saving

Postby Baoshi » Mon Nov 25, 2024 1:25 am

I think I found the reason of my problem:

In ulp_riscv_vectors.S, saving of registers are implemented as:

Code: Select all

  .equ SAVE_REGS, 17
    .equ CONTEXT_SIZE, (SAVE_REGS * 4)

/* Macro which first allocates space on the stack to save general
 * purpose registers, and then save them. GP register is excluded.
 * The default size allocated on the stack is CONTEXT_SIZE, but it
 * can be overridden.
 *
 * Note: We don't save the callee-saved s0-s11 registers to save space
 */
.macro save_general_regs cxt_size=CONTEXT_SIZE
    addi sp, sp, -\cxt_size
    sw   ra, RV_STK_RA(sp)
    sw   tp, RV_STK_TP(sp)
    sw   t0, RV_STK_T0(sp)
    sw   t1, RV_STK_T1(sp)
    sw   t2, RV_STK_T2(sp)
    sw   a0, RV_STK_A0(sp)
    sw   a1, RV_STK_A1(sp)
    sw   a2, RV_STK_A2(sp)
    sw   a3, RV_STK_A3(sp)
    sw   a4, RV_STK_A4(sp)
    sw   a5, RV_STK_A5(sp)
    sw   a6, RV_STK_A6(sp)
    sw   a7, RV_STK_A7(sp)
    sw   t3, RV_STK_T3(sp)
    sw   t4, RV_STK_T4(sp)
    sw   t5, RV_STK_T5(sp)
    sw   t6, RV_STK_T6(sp)
.endm
When this code is compiled, it generates the instructions below:

Code: Select all

00000010 <irq_vector>:
  10:	fbc10113          	add	sp,sp,-68
  14:	c206                	sw	ra,4(sp)
  16:	c812                	sw	tp,16(sp)
  18:	ca16                	sw	t0,20(sp)
  1a:	cc1a                	sw	t1,24(sp)
  1c:	ce1e                	sw	t2,28(sp)
  1e:	d42a                	sw	a0,40(sp)
  20:	d62e                	sw	a1,44(sp)
  22:	d832                	sw	a2,48(sp)
  24:	da36                	sw	a3,52(sp)
  26:	dc3a                	sw	a4,56(sp)
  28:	de3e                	sw	a5,60(sp)
  2a:	c0c2                	sw	a6,64(sp)
  2c:	c2c6                	sw	a7,68(sp)
  2e:	d8f2                	sw	t3,112(sp)
  30:	daf6                	sw	t4,116(sp)
  32:	dcfa                	sw	t5,120(sp)
  34:	defe                	sw	t6,124(sp)
It is clear they allocated 68 bytes in the stack to save 17 registers, but save actual registers to sp-124, that causes the problem.

MicroController
Posts: 2661
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: RISC-V ULP interrupt context saving

Postby MicroController » Mon Nov 25, 2024 9:17 am

Code: Select all

add	sp,sp,-68
...
sw	a7,68(sp)
sw	t3,112(sp)
sw	t4,116(sp)
sw	t5,120(sp)
sw	t6,124(sp)
:o Now that is actually a problem!
Apparently the RISC-V frame definitions RV_STK_... are way out of whack there.

MicroController
Posts: 2661
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: RISC-V ULP interrupt context saving

Postby MicroController » Mon Nov 25, 2024 9:27 am

riscv/rvruntime-frames.h - Yep. The definitions relate to a full RvExcFrame, which the ULP code doesn't allocate. That's a bug in the IDF.
Good find!

Was about to suggest you open an issue... but you're way ahead :D

Who is online

Users browsing this forum: Baidu [Spider], ChatGPT-User, Qwantbot and 3 guests