Discuss here different C compiler set ups, and compiling executables for the ESP8266

User avatar
By cal
#18374 Moin Angus,

thanks for the exhaustive answer!
I added my comments below!

[quote="projectgus"][quote="cal"]
How to you typically start a ocd debugging session?
Setting breakpoints upfront and then starting the hardware?
Calling into the debugger using a break op code?
Using some ctrl-c or break signal to interrupt the cpu?
[/quote]

If I'm debugging on a different platform, like ARM Cortex-M, I'll often run a 'reset halt' in openocd which resets the CPU and then halts it immediately after reset, PC still set to the reset vector address, before any instructions are executed. Once it halts you can set the breakpoints you want in gdb, and run 'continue' from gdb to get it to run.

Once the breakpoints are set, gdb will keep them set through future 'reset halt' cycles.

[/quote]
OK, thats similiar to the typical "start program and halt on main".
And - as you write below - the breakpoints will typically be set again by gdb on step/continue.
[quote]

Sometimes I'll press ctrl-c to randomly halt a running CPU 'now', if I don't understand what's happening (usually it's gotten stuck in an infinite loop somewhere).

[/quote]
Yes, thats a cool feature. I implemented that via serial break detection.
Will the ocd debugger set you at the position where your code runs or stop in the CTRL-c handler? [quote]

On esp8266, there's not a proper 'reset halt' yet (at least on openocd) so it's a bit more haphazard. My technique so far has been to halt as soon as possible after reset and set up the debugger state then.
[/quote]
Where is that? Could that be that me made earlier by modifying the boot loader?
[quote]

Which works OK as long as you're not debugging early startup code.

Also, as you've mentiond, with esp8266 you only have one hardware breakpoint so you have to keep deleting the current breakpoint after you add a new one (the breakpoints don't get written to the hardware until you 'continue'). On a "normal" platform openocd will tell gdb where the flash regions vs the RAM regions of the address space are, so gdb will automatically choose soft vs hard breakpoints depending on the target address. This isn't supported yet for openocd, it might work for xt-ocd!

[/quote]Is it possible to provide that information to gdb via config?
Providing XML files via esp8266 seems to waste precious resources IMHO.[quote]

I have once or twice used:

[code]
asm("break 0, 0");
[/code]

... to compile in a software breakpoint.

[quote="cal"]
What ways to continue after break?
[/quote]

Usually I just type 'c' in gdb.
[/code]
The PC will be on the break point instruction after break.
That would imply for me, that the debugger does implicitly advance the PC before continuing.
Something not needed for STEPI as it seems.
[code]

[quote="cal"]
Do you have to manipulate the cpu state before continue?
E.g. set $pc += 3 or the like?
I struggle with "c" (continue) vs. "Cxx" (continue with signal).
[/quote]

You can do this, but you don't need to for normal execution if you just want to continue from the next instruction.

There's also 'step', si/stepi, finish. All worth looking at (see 'help xxx' for a quick summary.
[/quote]
Yes, I used them with success.
[quote]

[quote="cal"]
What happens with interrupts when single stepping?
int 1 level interrupts execute callbacks on intlevel 0 and so single stepping may be suddenly applied to that code
if not taken care of. I wonder, how?
[/quote]

Openocd should step into an int1 interrupt handler if you're stepping and an interrupt comes. I don't know about xt-ocd.

The single higher level interrupt (NMI) is currently ignored by the debugger due to the debug level set by openocd. I want to change eventually so it's an openocd parameter, so you can into the NMI handler if you want (or alternatively you could set it so that you don't step into interrupt handlers). The NMI seems to be called a lot (it's related to the radio layer), so it can be quite confusing to constantly step into it!
[/quote]
Really the NMI?
How could that be handled if the whole content of the NMI vector is an "return from interrupt"?
[quote]

Remember that the debug (interrupt) level is a CPU state not something in the code, so if level 1 interrupt calls a callback in your code then the CPU debug level stays at level 1, until the callback returns and the interrupt handler ends. (Unless I'm misunderstanding the question.)[/quote]

Thats what I meant.
And executing the int handler on current int level is what I expecte.

But the rom int 1 exception handler (_xtos_l1int_handler) lowers the int level before
calling the registered handler:

[code]
400004ff: 0060f0 rsil a15, 0
[/code]

Do I miss something?

Cal
User avatar
By projectgus
#18460
cal wrote:

Sometimes I'll press ctrl-c to randomly halt a running CPU 'now', if I don't understand what's happening (usually it's gotten stuck in an infinite loop somewhere).


Yes, thats a cool feature. I implemented that via serial break detection.
Will the ocd debugger set you at the position where your code runs or stop in the CTRL-c handler?


If you press Ctrl-C in gdb, it will ask openocd to halt via a gdb remote command. openocd will send XTensa OCD TAP operations over JTAG to halt the CPU. Once openocd reads back an indication that the CPU has halted, it tells gdb that the CPU is halted and gdb updates its register state/PC/etc.

Where is that? Could that be that me made earlier by modifying the boot loader?


If you look for 'reset halt' in the openocd source code (src/target/xtensa.c) then you'll see it. It could be made earlier by modifyingthe early boot code to add a sleep or something (at least on the flash side, the ROM bootloader parts are obviously fixed!) But the correct way to fix it will be to figure out a way to make the CPU halt on reset.

Is it possible to provide that information to gdb via config?
Providing XML files via esp8266 seems to waste precious resources IMHO.


Openocd provides the information to gdb, it doesn't need to be in the esp8266 itself.

If you look in openocd's config files, you'll see most target configs (under tcl/target directory) have some flash region information. esp8266.cfg doesn't have any yet, because there's no flash driver yet. The flash regions are used as a signal to openocd that "these regions can't use soft breakpoints", and it then reports this back to gdb.

Really the NMI?
How could that be handled if the whole content of the NMI vector is an "return from interrupt"?


Good question. This led me to go doing some poking around, because a lot of what I thought was just based on assumptions from symbol names.

I've been digging around in the RTOS SDK in particular (for a project I hope to announce soon). the standard IoT SDK seems to be totally different!

In the RTOS SDK, the exception vectors that are used are actually defined in libmain and are specified in the linker script to load into the beginning of IRAM. In the IoT SDK they do seem to be defined in ROM, reading the VECBASE special register at runtime would confirm this (it could be that the ones in ROM are defaults and the vectors get loaded elsewhere as part of the boot process).

In the RTOS SDK the _NMIExceptionVector (@ 0x40100020) calls to 0x40100178. This isn't labelled as a symbol directly (it gets linked, but I'm unsure how!) That routine is defined in libmain - it saves the complete CPU state then calls wDev_ProcessFiq (defined in libpp.a) which does a bunch of things. I believe this is the interrupt that gets called whenever the radio receives a raw data packet. I don't know what FIQ stands for.

However it may be done totally differently in the XTOS-based IoT SDK.

Thats what I meant.
And executing the int handler on current int level is what I expecte.

But the rom int 1 exception handler (_xtos_l1int_handler) lowers the int level before
calling the registered handler:

Code: Select all400004ff:       0060f0          rsil    a15, 0


Do I miss something?


Not at all, you've picked up on something I totally missed! I think this might be more differences in the IoT SDK compared to the RTOS SDK.

I haven't worked out exactly how level 1 interrupts work in the RTOS SDK, the UserExceptionVector seems to call through to _xt_timer_int (defined in libmain), but it looks like it may do other stuff as well - there are branches I haven't explored. There's also a separate handler on the FreeRTOS side, _xt_isr_handler, that hooks in somewhere.

I don't see the RTOS SDK exception code setting the interrupt level back to zero, but I might be missing it.
User avatar
By cal
#18484 Moin Angus,

thanks for the information!

projectgus wrote:
cal wrote:Where is that? Could that be that me made earlier by modifying the boot loader?


If you look for 'reset halt' in the openocd source code (src/target/xtensa.c) then you'll see it. It could be made earlier by modifyingthe early boot code to add a sleep or something (at least on the flash side, the ROM bootloader parts are obviously fixed!) But the correct way to fix it will be to figure out a way to make the CPU halt on reset.

OK. Looked briefly at the xtensa.c code. Most code seems to be jtag related but I think I saw the piece you meant.

Is it possible to provide that information to gdb via config?
Providing XML files via esp8266 seems to waste precious resources IMHO.


Openocd provides the information to gdb, it doesn't need to be in the esp8266 itself.

As far as I see the gdbserver role provides that information and thats openocd for you and the esp8266 for me.

If you look in openocd's config files, you'll see most target configs (under tcl/target directory) have some flash region information. esp8266.cfg doesn't have any yet, because there's no flash driver yet. The flash regions are used as a signal to openocd that "these regions can't use soft breakpoints", and it then reports this back to gdb.

I assume the purpose of a flash driver is providing flash reads/writes/updates over gdb remote protocol?
I will take a look but expect somethink like the following: https://sourceware.org/gdb/onlinedocs/g ... Map-Format

Really the NMI?
How could that be handled if the whole content of the NMI vector is an "return from interrupt"?


Good question. This led me to go doing some poking around, because a lot of what I thought was just based on assumptions from symbol names.

I've been digging around in the RTOS SDK in particular (for a project I hope to announce soon). the standard IoT SDK seems to be totally different!
Yes indeed it seems to be different. I didn't know the RTOS SDK but improve my knowledge of the XTOS stuff.

In the RTOS SDK, the exception vectors that are used are actually defined in libmain and are specified in the linker script to load into the beginning of IRAM. In the IoT SDK they do seem to be defined in ROM, reading the VECBASE special register at runtime would confirm this (it could be that the ones in ROM are defaults and the vectors get loaded elsewhere as part of the boot process).
The vecbase is in ROM, correct.
I didn't know that it is relocated for the RTOS SDK so I assumed that the NMI handler is fixed to a return.
After quite a few struggles I managed to relocate the vecbase of the XTOS firmware.
May have been easier looking at the RTOS SDK...

In the RTOS SDK the _NMIExceptionVector (@ 0x40100020) calls to 0x40100178. This isn't labelled as a symbol directly (it gets linked, but I'm unsure how!) That routine is defined in libmain - it saves the complete CPU state then calls wDev_ProcessFiq (defined in libpp.a) which does a bunch of things. I believe this is the interrupt that gets called whenever the radio receives a raw data packet. I don't know what FIQ stands for.

wDev_ProcessFiq is mapped to (level 1?) interrupt number "0" in the XTOS firmware, preparation of
the register stack frame is done by the xtos1 int1 handler in cooperation with vecbase interrupt vector.

However it may be done totally differently in the XTOS-based IoT SDK.

Thats what I meant.
And executing the int handler on current int level is what I expecte.

But the rom int 1 exception handler (_xtos_l1int_handler) lowers the int level before
calling the registered handler:

Code: Select all400004ff:       0060f0          rsil    a15, 0


Do I miss something?


Not at all, you've picked up on something I totally missed! I think this might be more differences in the IoT SDK compared to the RTOS SDK.

I haven't worked out exactly how level 1 interrupts work in the RTOS SDK, the UserExceptionVector seems to call through to _xt_timer_int (defined in libmain), but it looks like it may do other stuff as well - there are branches I haven't explored. There's also a separate handler on the FreeRTOS side, _xt_isr_handler, that hooks in somewhere.

I don't see the RTOS SDK exception code setting the interrupt level back to zero, but I might be missing it.


Sounds like another space interesting to explore. :D

Do you happen to know how the RTOS SDK keeps the watchdog happy? I would like to track a watchdog reset
down and would like to know how that is done by the SDK itself.
I know about writing 0x73 to the wdt register for custom code but like to know the place where it is done
for SDK itself if any.
I think about setting a CCOMPARE timer in parallel but slightly shorter and want to reset that at the
same rate (and/or place) the wdt is reset.
My timer than would note the pc state of execution to find out where the wdt event happened.

Is wdt reset on hardware level or on interrupt level? Or even be NMI?

Cal
User avatar
By jcmvbkbc
#18485
cal wrote:But the rom int 1 exception handler (_xtos_l1int_handler) lowers the int level before
calling the registered handler:

Code: Select all400004ff:       0060f0          rsil    a15, 0


Do I miss something?

IIRC it does so after masking corresponding IRQ line in the intenable SR, so that this IRQ doesn't happen again until handled, but nesting for other IRQs is possible.