Recursive function calls in PASM?
Heater.
Posts: 21,230
Using PASMs CALL and RET we can easily write functions that call functions that call functions... What we can't do is have a function that calls itself, directly or indirectly. That's because CALL only save one return address in a fixed location, a recursive call would over write the first return address. Recursive calls require a stack of return addresses.
Now, over on the Fourier thread I have managed to gain enough understanding of the Fast Fourier Transform to be able to write, for the first time, an FFT of my own. This implementation requires recursive calls. For now, and the foreseeable future, I don't see myself understanding the more normal non-recursive, in-place, implementations.
So of course I'd like to cast my FFT in PASM. This will require recursive function calls and a stack.
I have some ideas has to how to go about this but have to ask has anyone tackled this issue before?
Initially I'm thinking of keeping the stack in HUB, this would make the pointer handling easier and remove any COG space issues.
Looks like I need:
1) JMPRET to make the calls, placing the return address in some LONG somewhere, retAddr.
3) On entry to the routine save that retAddr to the stack in HUB and adjust the stack pointer. A push.
4) To return, fetch the return address into to retAddr, adjust the SP and JMP indirectly through the retAddr. A pop.
Then of course I have some parameters to stack up as well....
Anyone got ideas about this?
My recursive FFT may be a bit slower than a pukka in-place FFT but it might also be a lot smaller code wise. Assuming the stack ops don't eat the COG space.
Now, over on the Fourier thread I have managed to gain enough understanding of the Fast Fourier Transform to be able to write, for the first time, an FFT of my own. This implementation requires recursive calls. For now, and the foreseeable future, I don't see myself understanding the more normal non-recursive, in-place, implementations.
So of course I'd like to cast my FFT in PASM. This will require recursive function calls and a stack.
I have some ideas has to how to go about this but have to ask has anyone tackled this issue before?
Initially I'm thinking of keeping the stack in HUB, this would make the pointer handling easier and remove any COG space issues.
Looks like I need:
1) JMPRET to make the calls, placing the return address in some LONG somewhere, retAddr.
3) On entry to the routine save that retAddr to the stack in HUB and adjust the stack pointer. A push.
4) To return, fetch the return address into to retAddr, adjust the SP and JMP indirectly through the retAddr. A pop.
Then of course I have some parameters to stack up as well....
Anyone got ideas about this?
My recursive FFT may be a bit slower than a pukka in-place FFT but it might also be a lot smaller code wise. Assuming the stack ops don't eat the COG space.
Comments
Brilliant, I seem to have missed your fftdemo along the way.
No, you did not miss anything. I guess you have used a traditional in-place (output goes where input was) FFT with a bit reversal stage at the beginning. And so you have no need for recursive calls. This is normal.
I, on the other hand, am not normal:) My problem is that I have no idea how or why an in-place FFT works yet.
What I am able to understand is:
1) Take the definition of a DFT. As a sum of complex exponentials multiplied by input samples.
2) Split that sum into two sums.
3) Factor out the so called "twiddle" factors from the second sum.
4) Realize that the two sums we now have are the same.
5) Therefore see that the DFT can be written as a recursive algorithm.
6) Create an implementation of that in C++.
This approach is outlined on wikipedia: http://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm
My C++ effort works well, it is about half the speed of a common in-place FFT in C but that is still hundreds of times faster than a naive DFT implementation. It may reach parity when I redo it in C.
It looks like this:
Given that this is what I understand, this is what I want to do in PASM.
Anyway the question about recursive calls in PASM may have other uses.
The value of stackptr would need to be initialized to point to a block of hub RAM that would serve as the stack. Also, any variables that are used recursively would need to be stored on the stack as well.
Dave
Just now my recursive FFT is taking about 50% longer for a 16K sample set than a "normal" FFT in C I found on the net somewhere. Not bad considering the code is a lot easier to understand (for me anyway). I moved a few things around and removed the N and s parameters like below. Probably I can remove the X and Y parameters as well.
I now have a version of my C++ FFT with no parameters, oops it's not on this computer so I can't post it. Removing those does not speed things up noticeable for my C++ running on a PC but it would simplify any PASM implementation a lot and probably gain some speed as it would not be required to PUSH and POP them from a stack in HUB.
I'll have a look at this mode flag idea... First I need to get rid of the complex class.