You want to link C and Motorola 68000 (or 68k) Assembly together on an Amiga to get the best of both worlds. But is it possible?
One can link C and 68000 Assembly code on Amiga together. This requires a linker. The C and Assembly source code files are compiled respectively assembled and then linked together. Finally a make tool is used to generate an Amiga executable file.
If you want to see some examples and what tools you can use just read on. This and more information is part of this article.
How to link C and 68k Assembly Code on Amiga
First of all it is important to know that you don’t really write the code together. Instead you write two different programs and then link C and Assembly together on Amiga.
The main part of the program is in C. From this program you can call “functions” or routines from assembly code. Then you compile the C file and assemble the assembly file which will generate object files for both. These object files can then be linked together by a linker so that the C program knows the symbols that it calls from within the assembly code. Finally the linked program can be turned into an executable file.
Call an Assembly Function from C with no Parameter
The first example is very simple. We just write the main Function in C, read a value from assembly code and print this value to the console in C again.
Assembly Code:
1 2 3 4 5 6 7 |
_get_important_value: move.l #42,d0 rts public _get_important_value |
C Code:
1 2 3 4 5 6 7 8 9 |
#include <stdio.h> long get_important_value( void ); int main() { long important_value = get_important_value(); printf("Attention! Important Value is %ld\n", important_value); return 0; } |
This is the convention: You decide how to name the function or routine you want to call from the assembly code. In this case it is get_important_value. Then you declare a global symbol in the assembly code and prefix it with an underscore. Again, in this case it is _get_important_value. Now you can call the function in C and work with the returned value.
Please Note: If you change any other register than d0 or d1 you will have to restore the previous contents of them before you return from the routine.
Call an Assembly Function from C with Parameters
If you want to add parameters to your assembly code call, you should provide them in registers. This is because an assembly routine would normally expect that to be the case. In C, on the other hand, parameters are pushed to the stack. So this would be unnecessary work for the assembly routine.
In this example we again fetch a number from the assembly code. But this time we provide two numbers beforehand and let the assembly code calculate a sum of them. The result will then be returned.
Assembly Code:
1 2 3 4 5 |
_add_two_nubers: add.l d1,d0 rts public _add_two_nubers |
C Code:
1 2 3 4 5 6 7 8 9 |
#include <stdio.h> long add_two_numbers(__reg("d0") long a, __reg("d1") long b); int main() { long result = add_two_numbers(3,2); printf("The result of 3+2 is %ld\n", result); return 0; } |
The difference in comparison to the last example is that we now provide two arguments for our function. By using the global symbol __reg(“”) we can link our parameters to the registers in the assembly code.
Warning: The syntax that links the registers to the parameters is compiler-specific. If you want to code compiler-independent, the parameters should be kept on the stack.
Call an Assembly Function from C with Parameters (Compiler Independent)
Instead of using the __reg(“”) syntax, which is compiler-specific, you could do it the C way by using the stack. In this case the same example from above would look like the following code.
Assembly Code:
1 2 3 4 5 6 |
_add_two_numbers: move.l 4(sp),d0 add.l 8(sp),d0 rts public _add_two_numbers |
C Code:
1 2 3 4 5 6 7 8 9 10 11 |
#include <stdio.h> long add_two_numbers(long a, long b); int main (void) { long a = add_two_numbers(3,2); printf ("The result of 3 + 2 is %ld\n",a); return 0; } |
The return address is 0 (sp), the beginning of the Stack Pointer. The parameters are put on the Stack in reverse order, so the 8 (sp) corresponds to parameter b and the 4 (sp) corresponds to parameter a.
Show Assembly Code from a C routine
If you want too see how a C program would look like in Assembly Code, you can compile it with the Option -s. This gives you the assembler output from the compiler. For a program named test this would look like:
1 |
vc -S test.c -o test.asm |
Why mix C and 68k Assembly Code
As nice as it may seem, but why should you mix source code of different languages? Let us first look at the advantages of both languages. C is much more readable than Assembly Code as it uses words from the english language. It is also portable. That means you can use the same source code on different machines without rewriting it. With Assembly Code on the other hand you can get directly to the point. If used reasonably, you will get a faster execution speed than in high level programming languages like C.
The approach of mixing both together is a little bit like getting the best of both worlds. Most of the time you will want to use C, because it provides a higher development speed. But when it comes to the time critical parts of your program, you may want to use the Assembly Language.
The developers of Amiga Demo Prototype 1 (link opens in new tab) for example used C to develop the 3D engine and some effects. For the time critical parts like texture-mapping inner-loops, chunky to planar conversion, they used Assembly Language.
Programming Tools for the Amiga
In order to write programs like the examples above, you will need three tools: An assembler, a compiler and a linker. If you want to generate an Amiga executable you will need a make-like tool. It is important that the tools fit your style and do the job right. If you, for example, want to map parameters to registers with __reg(“”), you have to use an assembler and a compiler which will support that.
If you don’t have an old Amiga at home or just want to program on big monitors with decent IDEs and shorter compile times, you may want to use an Amiga Emulator.
This listing is by no means complete, but it gives a good overview over the most used and best known Tools
(All links open in a new tab)
Assembler
- ASM-One Macro Assembler
- vasm (as part of the vbcc package)
- Devpac Assembler
Compiler
Linker
Make
Emulator
Conclusion
Now you know why it can be useful to combine C and 68000 Assembly Code on an Amiga. You also should have an idea about what tools to use. As a programming starting point you can use the examples above as a “Hello World” and take off from there.