ABI? After looking that one up I found that it means Application Binary Interface. Function parameters are passed through registers, starting from reg0. The return value is passed in reg0. There are 16 registers defined, going from reg0 to reg15. There is also a stack pointer called sp. Registers are allocated sequentially, starting with the next register after the function parameters. The following example uses reg0, reg1 and reg2 for the calling parameters and reg3 to reg15 for working registers.
int testfunc(char *ptr1, char *ptr2, int size)
{
int x, y, z;
return 10;
}
The variables x, y and z are stored on the stack. Functions are called using CALLD, such as "calld adra, #testfunc". On entry into the function the return address in adra is stored on the stack, then space is allocated on the stack for the local variables. On return, the return value is put in reg0, the local variable stack space is added back to the stack, and the return address is popped off of the stack.
Another thing that has to be done when calling a function is to save all of the caller's working registers and his own function parameters on the stack, and then move the calling parameters down to reg0. On return, the working registers and the function's calling parameters are restored from the stack. I may change this later on so that parameters are passed on the stack, but for now they are passed through registers.
What do you do when your register allocator runs out of registers?
In my opinion, it should be possible to write almost all code in C and very little or none in PASM. That seems to be the opposite of what is being proposed here, writing code in C or Spin and slowly migrating more and more of it to PASM.
I'd agree most code can be done in a HLL.
If that code works well enough, as written, why change it ?
The intent here is for those cases where the HLL does not quite cut it, to make PASM easy to use in-line.
With good ASM reporting, you can also often re-write the HLL to get "good enough", thus avoiding in-line asm.
Over time, most HLLs improve their ASM generation skills too.
Interrupts are one area where having ASM access can make quite a difference, and P2 now has interrupts.
In my opinion, it should be possible to write almost all code in C and very little or none in PASM. That seems to be the opposite of what is being proposed here, writing code in C or Spin and slowly migrating more and more of it to PASM.
I'd agree most code can be done in a HLL.
If that code works well enough, as written, why change it ?
The intent here is for those cases where the HLL does not quite cut it, to make PASM easy to use in-line.
With good ASM reporting, you can also often re-write the HLL to get "good enough", thus avoiding in-line asm.
Over time, most HLLs improve their ASM generation skills too.
Interrupts are one area where having ASM access can make quite a difference, and P2 now has interrupts.
I agree that inline ASM or at least separately compiled ASM is necessary around the edges. As you say, it is almost certainly necessary for interrupt handlers. I would just hate to see main program logic sprinkled with lots of inline assembly just to gain a bit of extra efficiency that is not really needed. Many of us here enjoy writing tight assembly code but I think the average programmer would be better off using libraries or language constructs that encapsulate that low-level logic.
Taz will continue to allocate registers beyond the number available. qasm will generate errors saying that they don't exist. Clearly there isn't sufficient error checking right now. In the future I'll probably use the stack once the registers have run out.
All this talk about using taz instead of GCC is way too premature, and doesn't make much sense. In my opinion, GCC is definitely the way to go for the P2. We just need to change the code generator to generate P2 code instead of P1.
I assumed there is an ongoing effort to port GCC to the P2. I would be happy to help, and I'm sure there are others that would like to help out also. Is Eric available? He certainly did a great job for P1.
Taz will continue to allocate registers beyond the number available. qasm will generate errors saying that they don't exist. Clearly there isn't sufficient error checking right now. In the future I'll probably use the stack once the registers have run out.
All this talk about using taz instead of GCC is way too premature, and doesn't make much sense. In my opinion, GCC is definitely the way to go for the P2. We just need to change the code generator to generate P2 code instead of P1.
I assumed there is an ongoing effort to port GCC to the P2. I would be happy to help, and I'm sure there are others that would like to help out also. Is Eric available? He certainly did a great job for P1.
As far as I know, the effort to port GCC to the P2 has not yet started. Some work has been done to remove the old P2 code generation from the gcc5 repository used by the propeller-gcc github project but as far as I know that is all that has been done so far.
Taz will continue to allocate registers beyond the number available. qasm will generate errors saying that they don't exist. Clearly there isn't sufficient error checking right now. In the future I'll probably use the stack once the registers have run out.
Can you easily increase the register set size, and can another set be allocated for interrupts ?
That way fast interrupt code is possible, with no reg-save/restore bottlenecks.
@David, I wonder what Parallax is waiting for. It seems to me that it's important to have GCC working early on. I think this will draw more people into playing with the P2, and maybe sell a few more FPGA boards.
One thing that I found working with C on the P2 is that it is a lot of fun. We will no longer have to worry about squeezing code and data into a miniscule 32K of memory. Having 512K removes a lot of the pain associated with not having enough memory. We'll be able to run programs with the full stdio, SD access and floating point, and still have enough memory available for data.
Hubexec also removes the need for an LMM interpreter. It makes things a lot easier when writing programs that execute from hub RAM.
@jmg, the current register setup for taz is quite rigid, but it should be fairly simple to make the register set size a compile-time option. At some point I want to add support for the register keyword so that register variables can be created. When generating position-independent-code I create a PIC table in cog memory that is essentially pointers stored in registers. It should be easy to include register variables in that table.
A separate register set could be defined for ISRs. I haven't really thought about the best way to handle it. On the P2 it is very efficient to store a large bank of registers in RAM using the SETQ/WRLONG combination. So it's possible to swap out register sets when in an ISR.
@David, I wonder what Parallax is waiting for. It seems to me that it's important to have GCC working early on. I think this will draw more people into playing with the P2, and maybe sell a few more FPGA boards.
I'd agree - maybe it has fallen thru the cracks a little, as they wait for Opcodes to be stable, but I think they are stable enough to start compiler work now ?
A separate register set could be defined for ISRs. I haven't really thought about the best way to handle it. On the P2 it is very efficient to store a large bank of registers in RAM using the SETQ/WRLONG combination. So it's possible to swap out register sets when in an ISR.
Yes, but Swap to HUB is slow, and indeterminate, and if you have reserved COG RAM anyway, why not just use those registers directly in the interrupt ?
This skips any block copies & is very fast...
There may be a use case to swap Reg sets to LUT, depends on the speed trade off there ?
Other register-based ideas :
IIRC, Sun had a register model that allows partial register bank realign on CALLS.
This means the upper eg 8 registers are kept as params, and the lower 8 are new local scratch Regs,
on return, the half shared can have return values.
This is quite RAM hungry so it would be used sparingly.
Could suit Hubexec ?
@David, I wonder what Parallax is waiting for. It seems to me that it's important to have GCC working early on. I think this will draw more people into playing with the P2, and maybe sell a few more FPGA boards.
I'd agree - maybe it has fallen thru the cracks a little, as they wait for Opcodes to be stable, but I think they are stable enough to start compiler work now ?
I have a 1-2-3 FPGA board and I intend to start working on porting binutils but I've been bogged down working on a WiFi loader lately. The first step will be to modify GAS for the new P2 assembly instructions. Then, the GCC code generator will need to be modified to use hubexec. I suppose it shouldn't take too long to get something working.
Sorry for sidetracking this discussion by talking about whether Taz could replace PropGCC. Let's get back to updates on Dave's progress with Taz. Whether or not it can be used as the official Parallax C compiler, it is certainly interesting on its own.
Dave: Where is the latest update posted? Can we move it to github? Do you want help in making a Makefile for it?
Why would pass by value or pass by reference make a difference?
A function call ways read and write through a pointer in R0, the reference, and then the last thing it does is overwrite the pointer in R0 with a return value.
@David, I will use github in the future. The next update may be a zip file, but after that I plan on using github. I'll also add Makefile's at some point. I just need to refresh my memory on the syntax again.
@msrobots, I think passing by reference is more of a C++ thing. However, I think the underlying mechanism uses pointers, which is how it is done in C. The return value is moved to reg0 just before the return is done, so there is no conflict with using reg0 to pass a value or a pointer.
One issue with passing parameters in registers is you can't get a pointer to them. In code that I written that required a pointer to a parameter I first have to copy it to a local stack variable, and then get a pointer to that variable. Of course, it's perfectly allowable to pass a pointer in a register parameter.
@David, I will use github in the future. The next update may be a zip file, but after that I plan on using github. I'll also add Makefile's at some point. I just need to refresh my memory on the syntax again.
I know what you mean about Makefile syntax. I have to look stuff up all the time as well.
In my ongoing effort to push CMake around here, I converted taz's build system. You can build it with the following:
unzip taz-cmake.zip
cd taz-cmake
mkdir cmake-bin
cd cmake-bin
cmake ..
make
This will build all executables for the host system (Windows or Linux) and libraries.
make install DESTDIR=bogus
will "install" to cmake-bin/bogus/usr/local, with two subdirectories: bin and lib.
To cross-compile for Windows using mingw-w64, it's almost the same but we generate the the cmake config a bit differently:
unzip taz-cmake.zip
cd taz-cmake
mkdir cmake-bin
cd cmake-bin
cmake -DCMAKE_TOOLCHAIN_FILE=../CMakeModules/Toolchain-mingw64.cmake ..
make
You can also have both versions - compiling for the Linux and Windows - going in two different directories but changing "cmake-bin" to some other name:
unzip taz-cmake.zip
cd taz-cmake
mkdir linux-bin
cd linux-bin
cmake ..
make
cd ..
mkdir win-bin
cd win-bin
cmake -DCMAKE_TOOLCHAIN_FILE=../CMakeModules/Toolchain-mingw64.cmake ..
make
Ubuntu can install cmake with "sudo apt-get install cmake". If the version is less than 3.0, download the latest from cmake.org: https://cmake.org/download/
I added configuration options for generating zip, deb, rpm and exe installers. Run the "package" target for make to generate all four. Note that you'll need various dependencies on your system for this, because CMake invokes the standard commands like rpmbuild to generate RPMs. You can test an individual packager with the following command (after running "make" to build binaries and libs): "cpack -G [ZIP|DEB|RPM|NSIS]"
So to generate just the zip, try:
unzip taz-cmake.zip
cd taz-cmake
mkdir cmake-bin
cd cmake-bin
cmake ..
make
cpack -G ZIP
@Dave, if you like the CMake solution, I'll spend the time to define custom languages and toolchains for the taz compiler, rather than "hacking" it with add_custom_command. Doing so would allow building binaries with taz as easily as it was to build taz itself (take a look at the difference beween taz/CMakeLists.txt and libsrc/CMakeLists.txt and you see what I mean). However, that's more than a 10-minute solution so I'm not keen on doing that if you're going to stick with vanilla Makefiles anyway.
@Dave, if you like the CMake solution, I'll spend the time to define custom languages and toolchains for the taz compiler, rather than "hacking" it with add_custom_command. Doing so would allow building binaries with taz as easily as it was to build taz itself (take a look at the difference beween taz/CMakeLists.txt and libsrc/CMakeLists.txt and you see what I mean). However, that's more than a 10-minute solution so I'm not keen on doing that if you're going to stick with vanilla Makefiles anyway.
Nice job! I tried this on my Mac and it worked without any problems.
I'm using an SD card wired into pins 0, 1, 2 and 3 on the waffle board plugged into the DE2-115. I think that's what Peter did for Tachyon also. I'm not sure if the FPGA image connects to the SD connector on the DE2-115, but I would use if it did.
Comments
If that code works well enough, as written, why change it ?
The intent here is for those cases where the HLL does not quite cut it, to make PASM easy to use in-line.
With good ASM reporting, you can also often re-write the HLL to get "good enough", thus avoiding in-line asm.
Over time, most HLLs improve their ASM generation skills too.
Interrupts are one area where having ASM access can make quite a difference, and P2 now has interrupts.
All this talk about using taz instead of GCC is way too premature, and doesn't make much sense. In my opinion, GCC is definitely the way to go for the P2. We just need to change the code generator to generate P2 code instead of P1.
I assumed there is an ongoing effort to port GCC to the P2. I would be happy to help, and I'm sure there are others that would like to help out also. Is Eric available? He certainly did a great job for P1.
Can you easily increase the register set size, and can another set be allocated for interrupts ?
That way fast interrupt code is possible, with no reg-save/restore bottlenecks.
One thing that I found working with C on the P2 is that it is a lot of fun. We will no longer have to worry about squeezing code and data into a miniscule 32K of memory. Having 512K removes a lot of the pain associated with not having enough memory. We'll be able to run programs with the full stdio, SD access and floating point, and still have enough memory available for data.
Hubexec also removes the need for an LMM interpreter. It makes things a lot easier when writing programs that execute from hub RAM.
@jmg, the current register setup for taz is quite rigid, but it should be fairly simple to make the register set size a compile-time option. At some point I want to add support for the register keyword so that register variables can be created. When generating position-independent-code I create a PIC table in cog memory that is essentially pointers stored in registers. It should be easy to include register variables in that table.
A separate register set could be defined for ISRs. I haven't really thought about the best way to handle it. On the P2 it is very efficient to store a large bank of registers in RAM using the SETQ/WRLONG combination. So it's possible to swap out register sets when in an ISR.
Yes, but Swap to HUB is slow, and indeterminate, and if you have reserved COG RAM anyway, why not just use those registers directly in the interrupt ?
This skips any block copies & is very fast...
There may be a use case to swap Reg sets to LUT, depends on the speed trade off there ?
Other register-based ideas :
IIRC, Sun had a register model that allows partial register bank realign on CALLS.
This means the upper eg 8 registers are kept as params, and the lower 8 are new local scratch Regs,
on return, the half shared can have return values.
This is quite RAM hungry so it would be used sparingly.
Could suit Hubexec ?
Dave: Where is the latest update posted? Can we move it to github? Do you want help in making a Makefile for it?
What if the first parameter in passed by reference, not by value?
confused,
Mike
A function call ways read and write through a pointer in R0, the reference, and then the last thing it does is overwrite the pointer in R0 with a return value.
@msrobots, I think passing by reference is more of a C++ thing. However, I think the underlying mechanism uses pointers, which is how it is done in C. The return value is moved to reg0 just before the return is done, so there is no conflict with using reg0 to pass a value or a pointer.
One issue with passing parameters in registers is you can't get a pointer to them. In code that I written that required a pointer to a parameter I first have to copy it to a local stack variable, and then get a pointer to that variable. Of course, it's perfectly allowable to pass a pointer in a register parameter.
This will build all executables for the host system (Windows or Linux) and libraries.
will "install" to cmake-bin/bogus/usr/local, with two subdirectories: bin and lib.
To cross-compile for Windows using mingw-w64, it's almost the same but we generate the the cmake config a bit differently:
You can also have both versions - compiling for the Linux and Windows - going in two different directories but changing "cmake-bin" to some other name:
Ubuntu can install cmake with "sudo apt-get install cmake". If the version is less than 3.0, download the latest from cmake.org: https://cmake.org/download/
So to generate just the zip, try:
I'm trying TAZ.
I'm getting "errorexit: -41" with filetest.bin loading through wrapper.spin and pnut.
Any idea what the SDCard pins would be for the DE2-115?
Found some pin-outs from an old post. Maybe the Nov 25 image doesn't have them defined.
Thanks.
--Steve
Got it working Dave.
Thanks.