02-13-2012 03:31 PM
I have a rather simple question but rather than going too far down the wrong path I thought i'd poll the board for suggestions.
I have a simple picoblaze routine that allows for a interrupt to basically revert the program back to some known state (entry point). One simple way to accomplish this is to use a 'JUMP' in the interrupt handler to a known entry point and known initialization point. This works but of course since i'm not using the 'RETURNI' instruction the stack will grow. The picoblaze user guide notes that the CALL/RETURN stack is a circular buffer so my assumption is if it overflows and wraps (and over-writes the oldest item) this is a don't-care. However, the cycle simulator accurately gives me an error (pblaze) about the stack overflow (after a lot of interrupts) which begged the question of how the hardware will react to this. I'm sure if I thought long enough I could come up with a scheme to avoid this, but it would be less simple and straightforward than what I'm doing. For reasons i'd rather not get into I don't have an easy way to simply set a 'global' with an ISR triggered flag since the code i'm trying to escape from could be tied up and not checking, too many places to insert global flag checks.
Maybe there is an obvious idiom others have used for this issue, or maybe someone can confirm that the stack overflow in this particular case is of no consequence.
02-13-2012 04:46 PM
I'm not sure if it would be appropriate for your application, but how about using the 'reset' signal instead of an interrupt? The contents of registers are preserved during a reset, if that helps.
02-13-2012 06:21 PM
Hmm, that made me think for a second but I unfortuantely need to have 2 different mechanisms here when the interrupt fires, there are 2 sources for the interrupt and each one starts over the sequence a bit differently.
Thanks for the suggestion.
Does anyone know if overflowing the stack (if you think you know what you're doing) is a problem? I can try to make a simulation test bench to test the behavior, that was my original course of action prior to asking the forum.
02-13-2012 06:26 PM
Can't you just check the interrupt type at reset time too?
You can differentiate a power-on from an interrupt by setting a register flag once you've initialised the processor. If it's zero, the FPGA reinitialised. If it's not zero, you were reset. If it was a reset, proceed with your existing interrupt handler mechanism.
No idea about the stack overflow. I suppose it wouldn't be a problem, but it'd be worth simulating.
02-14-2012 03:46 AM
This is a good opportunity for me to emphasize the difference between the call and return stack in KCPSM3 verses KCPSM6.
The stack in KCPSM3 is indeed a cyclic buffer meaning that should you call or interrupt too many times without corresponding returns then the oldest return vector will be overwritten. Likewise, should you execute a return more times than you previously called a subroutine or interrupted then you would underflow the stack (the program flow would return to a previously valid return vector but almost certainly not to the place you intended). However, providing you remain within the limits then everything works perfectly. Furthermore, and as this particular forum thread raises, it is also perfectly valid to apparently break all the rules and execute a ‘JUMP 000’ or similar providing you really do intend to discard (or ignore) the complete contents of the stack and start afresh.
Unfortunately, for every user that has deliberately intended to discard the contents of the stack in KCPSM3 there has almost certainly been another that through a silly coding mistake has experienced a stack overflow or underflow during what was supposed to be normal operation. I have personally found myself in both groups and the unexpected and often uncontrolled nature of the undesirable case was enough to convince me that KCPMS6 needed to be different (see pages 92 and 103 of ‘KCPSM6_User_Guide_30Sept11.pdf’).
In KCPSM6 the stack is linear with a maximum depth of 30 levels. Should execution of your code or an interrupt cause the stack to overflow or underflow then KCPSM6 will automatically reset itself. This may still be an unexpected event but at least it has a predictable and controlled outcome especially if the first things you included in your program are initialisation or recovery functions. As ‘joelby’ has pointed out, a reset does not clear the registers or scratch pad memory so it is possible for you to arrange your program in such a way that it is able to determine if it is a truly cold start or a warm restart if that is important.
So what would I do if I really wanted KCPSM6 to reset under certain conditions like ‘jkeuema’ required at the start of this forum thread. Well, one way would be to exploit the fact that KCPSM6 is a processor inside a programmable device and provide it with a simple hardware circuit that allowed KCPSM6 to write to an output port which in turn generated a hardware reset pulse to itself. For example, decode a suitable ‘port_id’ ANDed with ‘write_strobe’ such that executing an OUTPUT instruction to that port would generate a single clock cycle pulse which is applied to the reset input. Whilst in theory this additional hardware is not needed with the older KCPSM3 it might still be the more elegant method anyway.
However, there is a way to force KCPSM6 to reset itself without any additional hardware; you just need to deliberately force the situation in which the stack will overflow. Hence executing the following instruction would achieve that in 2 to 60 clock cycles depending on how full the stack is when reaching it (and assuming the processor is not in sleep mode!).
force_self_reset: CALL force_self_reset
Principal Engineer, Xilinx UK
02-14-2012 03:35 PM
Wow you two are really helpful. So it hadn't occurred to me that I could restructure the initialization routine to differentiate the cold versus warm reset conditions, and this seems easy enough to do. My approach could then be to write to an output port to set the reset 'reason' and then force the stack overflow like Ken suggested or use the external hardware reset circuit, in any case this seems do-able and allows for a fairly simple way to accomplish this. I like this approach since the interrupt is truly a case where I need to do something specific no matter where the main loop code is at or doing. Since the reset does not wipe out the scratchpad/registers then that also makes things a little simpler.
Thanks for clarifying the differences on KCPSM3 and KCPSM6.
02-14-2012 03:38 PM
02-15-2012 05:27 AM
I generally use a scratch pad memory to remember any ‘run time variables’. All scratch pad will be initialised to zero when the device is configured so any values greater than zero will only occur as a result of your program execution and will not be cleared by a reset during operation. In KCPSM3 you have 64 scratch pad memory locations and in KCPSM6 you have the choice of 64 (default), 128 or 256.
Principal Engineer, Xilinx UK