Ebiroll / qemu_esp32

Add tensilica esp32 cpu and a board to qemu and dump the rom to learn more about esp-idf
Apache License 2.0
421 stars 53 forks source link

float.s instructions causing unexpected exceptions? #31

Closed gourryinverse closed 3 years ago

gourryinverse commented 3 years ago

this is FreeRTOS code for a screen using the float() function in device/display/frame_buffer.h

XRatio = float(getBufferWidth())/float(getScreenWidth()+1); YRatio = float(getBufferHeight())/float(getScreenHeight()+1);

putting aside the screen for a moment (not relevant), this translates to a float.s instruction which is implemented in translate.c as

case 12: /*FLOAT.Sf*/ case 13: /*UFLOAT.Sf*/ if (gen_window_check1(dc, RRR_S) && gen_check_cpenable(dc, 0)) { TCGv_i32 scale = tcg_const_i32(-RRR_T); if (OP2 == 13) { gen_helper_uitof(cpu_FR[RRR_R], cpu_env, cpu_R[RRR_S], scale); } else { gen_helper_itof(cpu_FR[RRR_R], cpu_env, cpu_R[RRR_S], scale); } tcg_temp_free(scale); } break;

the relevant check here is gen_check_cpenable(dc, 0) which is causing the exception to be thrown

Guru Meditation Error: Core 0 panic'ed (Coprocessor exception)

This is what cpenable is defined as in core-esp32/gdb-config.c

XTREG(137,548, 8, 4, 4,0x02e0,0x0007,-2, 2,0x1000,cpenable, 0,0,0,0,0,0) no = 0x2e0 flags = 0x7 (b0111)

when dumping 'info all-registers' at the offending instruction, i find cpenable is completely 0

(gdb) info all-register excsave7 0x0 0 cpenable 0x0 0 interrupt 0x0 0

The gen_check_cpenable(dc,0) check is a little strange itself if the option is not enabled, we return true and don't throw an exception (that seems strange, shouldn't it exception?) if the option is enabled, but the bit is clear, we throw an exception (that seems correct) if the option is enabled, and the bit is not clear, we return true and don't throw an exception

the issue I have is this code runs without issue on a real ESP32, and it throws an exception on QEMU. It's a bit bizarre.

A few possible leads:

1) Is it possible that cpenable is being initialized incorrectly?

2) Is it possible FreeRTOS is using cpenable unintialized and the real device happens to have in initialized to CP0 being 1?

3) Is there a possibility that a lazy-enable situation is happening here and isn't being handled correctly?

gourryinverse commented 3 years ago

It appears it is the result of a lazy-enable issue, as following this code further

https://github.com/espressif/esp-idf/blob/1cb31e50943bb757966ca91ed7f4852692a5b0ed/components/freertos/port/xtensa/xtensa_vectors.S

into

call0   XT_RTOS_CP_STATE                /* a15 = new owner's save area */

https://github.com/espressif/esp-idf/blob/1cb31e50943bb757966ca91ed7f4852692a5b0ed/components/freertos/port/xtensa/portasm.S

_frxt_task_coproc_state:

getcoreid a3 movi a15, port_xSchedulerRunning /* if (port_xSchedulerRunning */ addx4 a15, a3,a15 l32i a15, a15, 0 beqz a15, 1f

this appears to be the culprit. port_xSchedulerRunning is false, and therefore this returns false because no task is running.

This has to be a FreeRTOS issue rather than a qemu_esp32 issue, sorry for the confusion.

Ebiroll commented 3 years ago

Thanks for the Information anyways. I think my newer version of qemu , has better support for the floating point coprocessor. https://github.com/Ebiroll/qemu-xtensa-esp32s2 It is basically a clone of https://github.com/espressif/qemu with some additions.

gourryinverse commented 2 years ago

@Ebiroll awesome! I will try it again!