Cross compilation of Atari TOS binaries under Cygwin/Linux
List of contents:
- Introduction
- Cross compiling and setting up of cygwin and gcc 4.4.0 under win XP
- Cross compiling and setting up of cygwin and gcc 4.4.0 with vasm as a m68k assembly compiler under win XP
- Cross compiling with VBCC under win XP with TOS/MiNT targets
- Installing and setting up FreeMiNT environment under Aranym and/or STEEM as a testbed for our programs
- Debugging your programs
- How to incorporate m68k assembly code (GAS) in GCC C/C++ programs
- How to incorporate m68k assembly code (VASM) in GCC C/C++ programs
- External references
- Credits
Last updates:
- 03.06.2010 Added info about using gcc 4.4/4.5 with VASM. I’ve also added some pointers and information about debugging your programs and link to one-stop Atari documentation website (see external references section).
- 09.07.2009 Added some pointers to free resources about Unix/Linux development in general (can be useful for people new to Unix environment), info about C/C++ ISO standards and added new info about Git (distributed source control system which is new alternative for old versioning systems like CVS/SVN/..).
- 14.06.2009 Added info about compiling SDL from sources and properly installing it under Cygwin environment. Corrected the gcc version (it should be 4.4.0 not 4.4.3 ;-) )
- 22.02.2008 Added info about building, installing, invoking VASM under Cygwin, some clean ups. Added installation of Cygwin m68k cross-compiler.
- 20.02.2008 Initial version
1) Introduction
This article is an attempt to gather all the needed instructions to set up fully working development environment that will enable you writing and compiling programs for TOS/MiNT based machines under modern operating systems.
The benefits of this approach are pretty clear:
- lightning fast compilation time
- use of modern compilers (quality of generated code is alot better than in older, native C/C++ compilers), there is also a lot of other options to play with, possibility to use an inline assembly etc..
- easy code generation for different m68k Atari targets
- possibility to automate tasks with custom bash scripts
- possibility to generate optimised m68060 code (old native compilers just can’t do that)
I will cover here few options available:
- cross compiling and setting up of cygwin and gcc 4.4.0 under win XP
- cross compiling with VBCC under win XP with TOS/MiNT targets
- cross compiling and setting up of cygwin and gcc 4.4.0 with vasm as a m68k assembly compiler.(under win XP )
- installing and setting up FreeMiNT environment under Aranym and/or STEEM as a testbed for our programs
There is possibility to debug your applications with gdb (natively or under cross development environment with X11 DDD frontend).
There also other options like using VBCC under Mac OSX and cross-development with gcc under Linux, but they will be not covered here. Instead, I will put some references regarding this topic in the end of this article.
I will also try to cover some basic how-to’s regarding setting up makefiles for different targets (CPU wise and release-wise), using additional tools that will help during development process (packing, generation of documentation).
I don’t think that I will cover all the issues involved (it’s not physically possible). If you think that something should be added, you’ve spotted an error or you have an idea what is missing and you can provide the missing parts then contact me and I will incude it.
Note: This page at this moment contains some missing parts, which will be added gradually.
2) Cross compiling and setting up of cygwin and gcc 4.4.0 under Windows XP
Follow the instructions contained on the Vincent Riviere page.
As an additional step you can add two lines in your .bashrc file from your $HOME folder:
... export PATH=$PATH:~/m68k-cross-tools/usr/local/cross-mint/bin export PATH=$PATH:~/m68k-cross-tools/usr/local/cross-mint/m68k-atari-mint/bin
In the end you will not have to retype all the export commands each time you launch Cygwin.
Note: ‘~’ means current user $HOME folder.
Setting up SDL and other libraries
First thing is to get the sources of SDL. You can grab the sources from Patrice Mandin’s webpage or get the latest snapshot from official SDL SVN repository (http://svn.libsdl.org/branches/SDL-1.2) and rebuild it from sources. Rebuilding from sources is recommended, because it guarantees the proper installation of libraries in your environment.
First thing is generation of configure script, after that we will be launching configure script, we will compile and install library afterwards. Very important is the –prefix switch.
It must point to the directory, where cross compiler is installed. If it will be wrongly specified configure script will be unable to find falcon.h, mintbind.h headers and will be unable to find the correct tools.
./autogen.sh ./configure --disable-threads --enable-static --disable-shared --disable-video-opengl / --host=m68k-atari-mint --prefix=/path/to/usr/local/cross-mint/m68k-atari-mint make make install
If everything will be all right then SDL will be installed in /path/to/usr/local/cross-mint/m68k-atari-mint .
Note: When I’ve downloaded SDL from SVN I’ve got some errors related to bad file encoding. If something will go wrong when launching autogen.sh script then for sure there is something wrong with script file encoding, converting file to UN*X one will solve the problem.
Configure script invocation when running gcc cross-compiler
…
3) Cross compiling and setting up of cygwin and gcc 4.4.0 with vasm as a m68k assembly compiler under win XP
I assume here that you have native gcc compiler in your Cygwin installation (for example I’ve used gcc 3.4.4 and some tools like autoconf, make etc..). Just launch the Cygwin setup, download and install missing tools.
Firstly you will need daily snapshot of VASM which can be found here. Download it and extract for example in your $HOME folder in “vasm” directory. After that type in your Cygwin bash shell:
$ cd ~/vasm $ make CPU=m68k SYNTAX=mot
After that gcc 3.4.4 (or another gcc version that you have) will build two files:
- vasmm68k_mot
- vobjdump
Rename them and move them to Cygwin /bin directory:
$ mv vasmm68k_mot /bin/vasm68k_mot.exe $ mv vobjdump /bin/vobjdump.exe
Now you can check if the vasm is visible in your Cygwin environment by typing in bash:
$ cd ~ $ vasmm68k_mot
The following message should appear:
vasm 1.3d (c) in 2002-2009 Volker Barthelmann vasm M68k/CPU32/ColdFire cpu backend 1.0c (c) 2002-2009 Frank Wille vasm motorola syntax module 2.7d (c) 2002-2009 Frank Wille vasm test output module 1.0 (c) 2002 Volker Barthelmann fatal error 16: no input file specified aborting...
Now to compile with VASM file “test.s” just type in:
vasmm68k_mot -Ftos test.s -o test.tos
4) Cross compiling with VBCC under win XP with TOS/MiNT targets
….
5) Installing and setting up freemint environment under Aranym and/or STEEM as a testbed for our programs
….
6) Debugging your programs
Binaries produced by GCC can be debugged in any Atari debugger (run on Atari machine or emulator). You only have to enable debug flags during compilation (”-g” in CFLAGS and “-Wl,–traditional-format” in linker ’s LDFLAGS).
After that you can load binary in your favourite debugger. At DHS you can find several native debuggers/disassemblers. Worth mentioning are MonST found in Devpac package, Bugaboo and Adebug Reloaded. The last one I’ve discovered recently after some issues with Devpac MonST, which hanged when entering exception handler, hopefully Adebug behaved much better and I was astonished how many features it has. Adebug Reloade can also be downloaded from Removers website.
Disassemblers are Desert Drain, TTdigger (which as far I know is the only one which supports 060 processors) and Easyrider.
On Vincent Riviere compiler page you can also find how to debug with gdb and DDD remotely with Aranym(GDB section). Unfortunately it has some issues. I haven’t tested it though. The option will be worth chcecking when I will have working ethernet setup on my Atari Falcon, so instead of using Aranym we could use native machine. The second thing worth investigating would be debugging on remote machine via rs232 port.
7) How to incorporate m68k assembly code (GAS) in GCC C/C++ programs
There are two options of using assembler with GCC :
- use inline assembly
- use separate .s files (compile with m68k-atari-mint-gcc as usual)
In either case, your assembly code will be interpreted by GAS (GNU assembler). It has the reputation of not being a nice assembler (designed primarily to assemble GCC output), however it has been improved and supports Motorola syntax. You cannot write advanced macros, however anything else will work.
Inline assembly is nice, but the syntax for specifying inputs, outputs and clobbered registers is difficult.
An example of separate asm function (not tested)
.globl _plus | This symbol will be externally visible
_plus:
move.l 4(sp),d0
add.l 8(sp),d0
rts
Comments begin with a pipe “|”.
Registers may be prefixed by % like %d0 but in our binutils configuration this is not mandatory.
Beware at the symbols exported with .globl: they must begin with an underscore to be accessible from C code (without _).
Put the following prototype in your C header:
#ifndef __PLUS_H__
#define __PLUS_H__ ;we want to include header once
#ifdef __cplusplus
extern "C" {
#endif
long plus(long a, long b);
#ifdef __cplusplus
}
#endif
#endif
The #ifdefs are necessary only if you plan to call the function from C++ code.
Below is a standalone Hello, World ! program. It has similar syntax to HiSOFT Devpac one.
* A simple TOS program pea msg move.w #9,-(sp) trap #1 | Cconws() addq.w #6,sp move.w #8,-(sp) trap #1 | Cnecin() addq.w #2,sp clr.w -(sp) trap #1 | Pterm0() msg: .ascii "Hello !\r\n\0"
The following directives will be quite useful too (they have their counterparts in Devpac) :
.text
.data
.bss
.rept
.endr
.dc.b
.dc.w
.dc.l
.ds.b
.ds.w
.ds.l
GAS supports a special jump instructions named “jbsr” and “jbra”. They are replaced by the smallest possible jump instruction. For example, GCC always call the functions using jbsr.
By default, jsr XX will be replaced bu jsr XX(pc), which is very annoying when you want to determine exatly what code is generated. You can avoid this behavior by using the -S assembler option.
One word about assembler options. The assembler is m68k-atari-mint-as, but it is probably easier to always use the frontend m68k-atari-mint-gcc. If you want to pass the -S option to the assemblet by using gcc, you must use the -Wa option to forward the option to the assembler. For example :
m68k-atari-mint-gcc -c hw.s -Wa,-S
Same applies with -Wl for linker options. For example, if you link your program with :
m68k-atari-mint-gcc *.o -o prog.prg -Wl,--traditional-format
the generated program will contain DRI debugging information instead of GNU. Thus, gdb will be unusable, but you will see the function labels in traditional ST debuggers like MonST. Note that in that case, m68k-atari-mint-strip will be unusable, too.
GCC inline m68k assembly explained (a little )
A simple example is a wrapper around Cconws() :
static __inline__ void Cconws(const char* s)
{
__asm__ __volatile__
(
"move.l %0,-(%%sp)\n\t"
"move.w #9,-(%%sp)\n\t"
"trap #1\n\t"
"addq.w #6,sp\n\t"
: /* outputs */
: "g"(s) /* inputs */
: "d0", "d1", "d2", "a0", "a1", "a2" /* clobbered regs */
);
}
First, the double underscores. “__inline__” is the same as “inline”, but GCC will never complain because it is a nonstandard extension. It is very useful in .h which may be compiled with -pedantic flag for example.
The function is declared with “static inline”, so it will always be inlined (except when optimization is turned off). “asm” begins an assembly block, “volatile” tells GCC to never remove the contents of the block, even it thinks it is useless.
The first parameter of “asm” is the assembly string. Every line must be ended with “\n\t”. The % character must be escaped as %%, so if you choose to prefix register names (not yet mandatory), you must use things like %%d0. Motorola syntax is welcome, as the string is directly transmitted to gas.
The second parameter is ths list of output variables (not used in this example).
The third parameter is the list of the input variables. The letter “g” means general, it can be replaced by a register or a memory variable. (s) is the C variable associated with this input, here it refers to the function parameter “s”. This parameter is referred in the assembly string with %0.
The fourth parameters is the list of clobbered (trashed) registers. GCC will never try to store data in that registers before calling the assembly block (but it may do it if you forget a register in the clobber list).
Here is another example. If is similar to what is found in <mint/osbind.h>:
#define SuperFromUser() \
(void*)__extension__ \
({ \
register long retvalue __asm__("%d0"); \
\
__asm__ __volatile__ \
( \
"clr.l -(%%sp)\n\t" \
"move.w #0x20,-(%%sp)\n\t" \
"trap #1\n\t" \
"addq.w #6,%%sp\n\t" \
: "=r"(retvalue) /* outputs */ \
: /* inputs */ \
: "%d1", "%d2", "%a0", "%a1", "%a2" /* clobbered regs */ \
); \
\
retvalue; \
})
This example uses a preprocessor macro and an “extension” block instead of an inline function (the former example one is ‘more preferable’ approach).
An extension block behaves like an expression (it can be used inside formulas or other expressions), but contains a body with several instructions. The value of the resulting expression is the last expression evaluated in the block.
The variable “retvalue” is declared with “register” and asm(”%d0″), so the compiler will always store this variable in the register d0 rather in the memory. You can see the line “retvalue;” at the end of the block. That means : the value of the extension block is what is left in the d0 register after calling the inline assembly block.
Here, the output list is used. It is “=r”(retvalue), “=” indicates it is an output (mandatory here), “r” indicates that this output is a register, and “retvalue” is the associated variable.
Notes:
- Output variable is not referred inside the assembly block, because it is implicitly filled by “trap #1″. If it would be referred, it would be as “%0″.
- If the assembly block contains 3 outputs and 2 inputs, the outputs would be %0, %1 and %2, and the inputs %3 and %4. Inputs are numbered after outputs.
8) How to incorporate m68k assembly code (VASM) in GCC C/C++ programs
I’ve got good news. It’s easy :). Bad news, it cannot be inlined in GCC (very predictable). VASM is pretty cool compiler, because it has HiSoft Devpac like syntax, so anyone who has coded with it in the past will be feeling like home. When incorporating m68k code we have several general use scenarios.
Use of variables from C/C++ code in m68k modules
You have to add XREF in m68k assembler source with label name found in C source prefixed with one underscore(”_”). If C code is compiled as C++, then you have to put label into extern “C” {…}; section, otherwise there will be linking errors.
Use of external variables from m68k code in C/C++ modules
Firstly you have declare variable prefixed with underscore “_” (via standard ds.l/dc.l) and add XDEF with variable name in m68k source code.
After that you have to declare variable somewhere in C code as extern. If C code is compiled as C++, then you have to put label into extern “C” {…}; section, otherwise there will be linking errors. And that’s it.
Invoking m68k assembler functions from C/C++ modules
If you have assembler function declared in you m68k asm source (prefixed with underscore “_”) then you have to:
add XDEF function name to your assembler source, this will make label visible for other modules
add in C header function as extern without underscore and normal parameter list. If C code is compiled as C++, then you have to put label into extern “C” {…}; section, otherwise there will be linking errors.
From now on you can use the function in your C programs.
Invoking C functions from m68k assembly code
You have to add XREF in m68k assembler source with label name of function found in C source prefixed with one underscore(”_”). If C code is compiled as C++, then you have to put label into extern “C” {…}; section, otherwise there will be linking errors.
After that you can jump to soubroutine via standard jsr or bsr directive. If additional parameters are needed then you have to pass them via stack, return values are put in d0 register.
Linking troubleshooting
In case of linking problems you can check labels generated by compiler by running:
$ m68k-atari-mint-objdump -t my_gcc_object.o
or
$ m68k-atari-mint-nm my_gcc_object.o
This is very useful thing, C labels in general are prefixed usually with one underscore “_” if the labels are more complex then it means that you have compiled code as C++ code. C++ labels include additionally the return type and argument types of the function. To force compiler to C code generation you have to pass to CFLAGS “-std=c99″ or “-std=c89″ parameter.
You have also to check if your variables are in global scope not the local. C variables forwarded with “static” keyword aren’t visible from external modules.
If C variables are modified outside of normal program flow then you have to add “volatile” keyword before their declaration. This is especially true if you are modyfying variables from exception handler.
Assembler flags used for compilation
Usually I’m invoking VASM in following way:
$ vasmm68k_mot source.s -Faout -quiet -x -m68000 -spaces -showopt -o output.o
The one drawback is that VASM can handle one source at time, you cannot input more source files and combine them into the one object file, but this is not problem at all.
The line above will compile GCC compatibile object file named output.o from source.s compatibile with m68000 instruction set. All optimisations made by compiler will be outputted to console. Generated object file can be passed to gcc linker at later stages.
9) External references
Atari documentation
- Atari Document Archive This site has it all.
GCC
- m68k-atari-mint page Vincent Riviere m68k Cygwin package. Here you will find recent version of GCC packages for Atari cross-development.
- Cygwin Home of Cygwin, Unix-like environment for Windows operating systems.
- GCC 3.3.6 usage with Atari projectsAn article that explains setting up gcc cross-compiler under Linux.
- Incompatibilities Between
ISO C and ISO C++ Discusses the incompatibilities of C/C++ on examples and indicates possible source of problems. There is also small introduction about C/C++ ISO standards. - GNU Autoconf, automake, libtool book
GCC assembler (gcc 4.3.3) documentation reference
VBCC
- VBCC/VASM for m68k Atari TOS/MiNTVBCC packages, compiler for MiNT and files for TOS and MiNT targets. Page contains also VASM(m68k assembler which also outputs gcc compatible code) and VLINK(m68k linker)
- VBCC under Mac OSX VBCC package for Atari cross development on Mac OSX.
GCC Atari TOS/MiNT specific libraries
- EasyMiNT MiNT installation package for Atari computers and Aranym.
- LDG Dynamically loaded libraries for Atari TOS/MiNT machines, it’s similar thing to SLB on MiNT and DLL on win32
- Windom library C library for programming GEM applications. It looks pretty good and some nice apllicatons were written with use of this library.
- SDL Home of Atari SDL port. There are also other SDL utility packages available as well(SDL_mixer, SDL_image …)
- Freemint Portal Contains MiNT ports of various software packages found on Unix machines
Testbeds
- Aranym Atari Running on Any Machine, still updated and developed.
- STEEM Very good Atari ST emulator, not updated from the long time though.
- HATARI The newest 16/32 bit Atari emulator. It has premilinary Atari Falcon030 support.
- Aranym 3D pack A premade Aranym installation. Just to unpack it and launch. The drawback is, that it wasn’t updated pretty long time.
- SainT It seems to be most accurate Atari ST emulator, still maintained and updated.
Free resources about Linux/Unix development in general:
There is also video in which Linus Torvalds speaks about Git and why he hates CVS so much ;) . It’s really funny to watch. It doesn’t deal about working with Git, but rather explains ideas behind it.
10) Credits
This is the place to say thanks to several people that provided input to this page:
- Vincent Riviere for his explanations, pointing out useful information and resources about gcc inline assembler and his Cygwin/Linux cross-development package.
- Frank Willie for VBCC/VASM Atari port
- Patrice Mandin for his work on Atari SDL port
- All the known and unknown heroes from FreeMiNT mailing list

