Debug/Breakpoint Functionality
Seairth
Posts: 2,474
in Propeller 2
(Moved conversation to new thread. This starts with the 2015-10-10 FPGA release and matching documentation (https://docs.google.com/document/d/10qQn_-B7avY2ce0N1MDDdzOF1lACPNWUJkjHFyzITiY)
Yeah, I've been reading through that document! Thank you!
I like how you can get some introspection inside the ISR, but I am wondering how to safely use it. Since this would be writing into a cog's register space, I could potentially overwrite meaningful data. I suppose I could copy a block of the cog to hub memory first (as a backup), but I'd rather not have to do that. Another thought would be to extend your "shadow register" concept a bit further. Suppose you were expose 14 more registers for a total of 16 ($1F0-$1FF). Using SETBRK, you could toggle the entire range (not just INA/INB). This would give a relatively safe working space to hold some debugging information, and you could even use it for protected state-keeping between invocations of the debug ISR.
Chip,
When you call setbrk in the debug ISR, do the breakpoint settings persist through subsequent breaks, or do you have to set it every time before you leave the debug ISR? In other words, can you enable single-step mode just once, or do you have to re-enable it every time the debug ISR is called?
Also, how do you detect when you have exited the debug ISR? Must you use RETI0 (or CALLD INB, INB WC, WZ)? I ask because it would be nice to return with CALLD INA, INB WC, WZ to set up a continuation in the debugger.
Be sure to read the updated docs at the top of the thread, concerning the debug interrupt.
You do need to do a new SETBRK every time you exit the debug ISR, if you want another debug interrupt to occur. So, the SETBRK condition is cleared every time a debug interrupt occurs. This is why a single RETI0 is able to end debug interrupts.
What constitutes the end of a debug ISR is 'CALLD anyreg,INB WC,WZ'. So, you could definitely exit via 'CALLD INA,INB WC,WZ' and resume your ISR on the next debug interrupt. You can always detect if a cog was restarted because it will jump to $FFFCO + cogid*4, instead whatever you have updated the INA vector to.
Yeah, I've been reading through that document! Thank you!
I like how you can get some introspection inside the ISR, but I am wondering how to safely use it. Since this would be writing into a cog's register space, I could potentially overwrite meaningful data. I suppose I could copy a block of the cog to hub memory first (as a backup), but I'd rather not have to do that. Another thought would be to extend your "shadow register" concept a bit further. Suppose you were expose 14 more registers for a total of 16 ($1F0-$1FF). Using SETBRK, you could toggle the entire range (not just INA/INB). This would give a relatively safe working space to hold some debugging information, and you could even use it for protected state-keeping between invocations of the debug ISR.
Comments
If we knew what the universally-useful debug ISR routine needed to do, we could just put it into a small logic-implemented ROM in the cog. Then, it would be very fast And always there. It would probably only be 16 or 20 instructions. We won't really know what that code needs to be until we make debuggers.
It is possible to dump cog RAM into hub RAM, repurpose cog RAM, and then restore it later from hub RAM before RETI0, without any scratch pad in cog RAM. If your debug ISR started out with 'SETQ #$1F7' and 'WRLONG 0,##hub_buffer', it would have stored 99% of the cog's state, right there.
The cog state that is most difficult to deal with is the hub streamer. Hub exec would mess that up. To not mess it up, you would need some debug code planted in cog or lut.
Oh? I was under the impression the Streamer could co-exist with HubExec.
There is a hub RAM FIFO in the cog which is used to decouple hub RAM timing from cog timing. It is used in hub exec to supply instructions. RDFAST/WRFAST set up its operation. It can also be used by the transfer unit to do analog and digital i/o in the background where data is going to/from the hub. It can most simply be used by WFBYTE, WFWORD, WFLONG, RFBYTE RFWORD, and RFLONG.
The transfer unit is separate from the hub RAM FIFO, though it may use the hub RAM FIFO. In discussing these things, it's all become blurred by the use of the term 'streamer'.
I desperately need to clear these things up by writing documentation.
That is correct.