# Megamax C

This document is based on Megamax C version 1.1.
Megamax C is composed of several command line tools (`*.TTP`). It also includes a shell and an editor that are not described here.

- MMCC.TTP: C Compiler
- MMIMP.TTP: Code Improver
- MMDIS.TTP: Disassembler
- MMLIB.TTP: Librarian
- MMLINK.TTP: Linker
- MAKE file

## MMCC.TTP: C Compiler

### Overview

The compiler takes a `.c` source code file as input and produces a `.o` object code file with the same name as output. Compilation error messages are written to a file named `ERRORS.OUT`. This file is deleted if no errors are found during compilation.

Command line: `mmcc.ttp MAIN.C`

Command line parameters:

- `-D`: Define a constant. Specifying `-DNAME=VALUE` on the command line is equivalent to `#define NAME VALUE` in source code.
- `-I`: Include path. Specifying `-IC:\INCLUDE` on the command line instructs the compiler to look for files specified with the `#include` directive in the specified folder.
- `-d`: No effect. This parameter sets a global variable to 1 (at address -$FA6(a4)), but this value has no effect.

### Supported C language

The Megamax C compiler implements the C language as described in the book "The C Programming Language" by Kernighan & Ritchie 1st edition.

The following C keywords are supported (extracted from the `init!` segment in MMCC.TTP):

    auto    static  extern  register
    typedef char    short   int     long    unsigned
    float   double  struct  union
    if      else    while   do      for
    switch  case    default break   continue
    return  goto    sizeof

The `entry` keyword is also supported (reserved) but has no effect and was withdrawn in K&R 2nd edition.

The `unsigned short` type is not supported.

The following keywords are not supported because they were introduced in K&R 2nd edition: `const enum signed void volatile`.

- `void`: All functions return a value. If not specified, the returned type is `int`. If no value is explicitly returned in the code then the returned value is undefined (it is the value in register D0 at the end of the function).
- `signed`: Integer types are implicitly signed when the `unsigned` keyword is not specified.

The following preprocessor directives are supported: `#define #undef #include #ifdef #ifndef #endif #line`

All comments must be enclosed in `/* */`. Comments starting with `//` are not supported.

Hexadecimal character constants like `0x81` are not supported. Only decimal like `129` and octal like `\201` are supported.

The compiler does not check the number nor the types of parameters when compiling function calls: it is possible to call any function with any number of parameters of any type.

Identifiers (names of variables, functions, parameters, #define) can be arbitrarily long but the compiler only uses the first 10 characters. Warning: from the compiler point of view, `COMPILERVARIABLE1` and `COMPILERVARIABLE2` both refer to the same identifier `COMPILERVA`.

### Extensions to the language

Megamax C implements some extensions that are not part of the original C language:

#### Inline assembly

Use `asm {}` in the source code to include a block of inline 68000 assembly code inside the curly brakets.
Register names must be uppercase.
Parameter names, global and local variable names can be used directly with or without the `(A4)` suffix (for global variables) or the `(A6)` suffix (for parameters and local variables)
If a label inside an `asm {}` block must be available from C code outside the block as a pointer (to code or to data), the same label must be declared as an `extern` function. Example:

    asm {
    EntryPoint: rts
    }
    extern EntryPoint();

#### Overlays

Megamax C generates position independant code which means it does not use absolute addresses for branch and jump instructions. It uses only relative offsets for branch and jump instructions which are limited to +/- 32768 bytes. Consequently, it cannot compile code segments larger than 32KB maximum.
In order to build larger programs, use `overlay "<ovname>"` in the C source code to tell the compiler in which segment to store the code following that statement.
A call to a function located inside the same segment as the caller function use instructions with offsets relative to the `PC` register (program counter).
A call to a function located inside another segment use instructions with offsets relative to the `A5` register which always contain the address of a jumptable. The linker generates this jumptable at the beginning of the `.PRG` file and it is the only place where absolute addresses are used. Because of these absolute addresses, the linker also generates a relocation table in the `.PRG` file to update the jumptable based on the effective address where the program is loaded in memory.

#### Structures

Megamax C allows the use of structures as function parameters, as return values and for assignment. The compiler adds calls to functions supplied in the Megamax C System Library (SYSLIB file) to manage these features: `_blockcmp` (to compare two structures) and `_blockmv` (to copy a structure).

#### pascal keyword

This keyword was probably meant to support the pascal calling convention where the callee cleans parameters from the stack instead of the caller as in the C calling convention. However implementation of this keyword seems buggy.
Syntax: `pascal int foobar(a, b)`

### Inner workings

The compiler uses the 68000 registers in the following way:

- Register A7 is only used to store the address of the top of the stack.
- Register A6 is only used to store the address of the stack frame. Inside a function, all accesses to function parameters and non `register` local variables are performed using A6 (positive offsets for parameters, negative offsets for local variables).
- Register A5 is only used to store the address of the jump table.
- Register A4 is only used to store the address of the DATA segment (positive offsets to A4) and BSS segment (negative offsets to A4).
- Registers A3 and A2 are only used for the first two function parameters or local variables that are pointers and are declared with the `register` keyword. The `register` keyword is ignored for subsequent pointer parameters or local variables.
- Registers D7, D6, D5 and D4 are only used for the first four function parameters or local variables that are not pointers and are declared with the `register` keyword. The `register` keyword is ignored for subsequent non pointer parameters or local variables.
- When registers among A3, A2, D7, D6, D5 and D4 are actually used in a function, their previous values are preserved (backed up to the stack at the beginning of the function and restored from the stack at the end).
- Registers A0, A1, D0, D1, D2, D3 are used for processing and their values are not preserved during the execution of a function Exception: when a `register` variable is the destination of the result of an expression, the corresponding register is used directly instead of D0 or D1.
- Register D0 is used to store the return value of all functions.

Sometimes while evaluating an expression, the compiler needs to temporarily store a value in memory because it considers all registers as exhausted. In such cases, it creates a 10 bytes large local variable to store the value (no matter the actual size of the value to store).

The compiler only stores text strings in the DATA segment. Each string is aligned on word boundaries. All strings are terminated by a 00h byte. An additional 00h byte is added for padding to ensure alignment.

Some helper functions supplied in the Megamax C System Library (SYSLIB) are automatically called by the compiler when using some features in the source code. For example, if you multiply two long variables, the compiler will call `_lmul` to perform the actual operation. Here is a list of these helper functions (extracted from MMCC.TTP):

- `_incfloat`
- `_incdouble`
- `_decfloat`
- `_decdouble`
- `_0from_float`
- `_0to_float`
- `_0to_long`
- `_0from_long`
- `_fpreg0`
- `_ffunc`
- `_ulmul`: Multiply unsigned long integers
- `_lmul`: Multiply signed long integers
- `_ldiv`: Divide long integers
- `_blockcmp`: Compare two structures
- `_blockmv`: Copy a structure (used when passing a structure as a parameter)

### Known bugs (in version 1.1):

- Assembly instructions `dc.l` are not processed correctly in some situations and produce wrong machine code. Workaround: use `dc.w` instructions.
- The compiler generates wrong offsets to access data in a bit field if multiple bit fields are defined in a single `struct`. Workaround: use only a single bit field per `struct`
- Compilation errors occur if there are no statements after a label. Workaround: use `{}` or `;` after the label.
- When the compiler automatically generates a 10 bytes large local variable to temporarily store a byte sized variable while evaluating an expression, the generated machine code is wrong: read and write accesses to the data are not performed on the same byte! This issue does not occur with word or long sized variables.

## MMIMP.TTP: Code Improver

The code improver takes a `.o` file (object code) as input and improves the code in this file (the output overwrites the input file).
There is only one improvement: the program looks for .w (word sized) branch instructions and replaces them with .s (byte sized) variants wherever possible. It repeatedly makes passes through the `.o` file until two successive passes produce identical results.
Command line: `mmimp.ttp MAIN.O`

## MMDIS.TTP: Disassembler

The disassembler takes a `.o` file (object code) as input and produces a `.s` file (assembly source code) as output.
Command line: `mmdis.ttp MAIN.O -o MAIN.S`

## MMLIB.TTP: Librarian

Several `.o` files (object code) can be grouped in a single `.L` file (library file format).
Megamax C comes with several library files. SYSLIB (system library containing implementations of some C standard library functions as well as other helper code) is also a library file although it does not have the `.L` extension.
This tool can create and open library files in order to add/remove `.o` files to/from a library file.
The easiest way to use this tool is to use the GUI shell.
Command line parameters:

- `d`: Delete `.o` from library.
- `r`: Register `.o` in library.
- `x`: Extract `.o` from library
- `t`: Table of contents
- `v`: Verbose. Displays more information on screen. Can be associated with any other of the parameters.

As an example, here are the command lines to remove `init.o` from SYSLIB and then add a custom version in the SYSLIB:

- `mmlib.ttp dv SYSLIB init.o`: Delete `init.o` from the SYSLIB library file.
- `mmlib.ttp rv SYSLIB init.o`: Register `init.o` into the SYSLIB library file.
- `mmlib.ttp xv SYSLIB init.o`: eXtract `init.o` from the SYSLIB library file. `init.o` remains in SYSLIB.
- `mmlib.ttp tv SYSLIB`: Table of contents. List `.o` files stored in the SYSLIB library file.

## MMLINK.TTP: Linker

### Overview

The linker takes a series of `.o` files (object code) as input and produces a `.PRG` file (standard Atari ST executable file) as output.

Command line: `mmlink.ttp -o PROJECT.PRG MAIN.O MODULE1.O MODULE2.O -M PROJECT.MAP`

Command line parameters

- `-o`: specify the name of the output executable file. If not used the default name `A.PRG` is used.
- `-M`: specify the name of the output map file. If not used, the default name `A.MAP` is used.

You can list object files (`.o`, up to 100 files) or library files (`.L`, up to 20 files). If there are too many file names to fit on the command line, you can list the file names on a single line inside a `.LNK` file.
There can be up to 60 segments in a single executable.

### Inner workings

When building a `PRG` file, the linker automatically and silently links the `init.o` module stored in SYSLIB to the resulting executable. This is the C loader which is the very first code executed by any program produced by the linker. The file `init.c` supplied with Megamax C contains the source code of this loader.
The linker will also automatically link other helper functions from the SYSLIB file after linking all the `.o` files supplied on the command line.

When the Megamax linker builds the PRG file, it looks for the following global symbols:

1. `_main`: very first code run by the PRG.
   This code is found in object file `init.o`, which is included in the SYSLIB. `init.c` contains the source code, mainly assembly code.
2. `_init`: code called by _main whose purpose is to initialize BSS segment (global variables and static variables).
   The code for this routine is automatically generated by the compiler (in a dedicated segment named `init!`).
   The very minimum code output by the linker for this consists of an `RTS` instruction.
3. `_initargcv`: code called by `_main` whose purpose is to initialize the standard argc and argv parameters of the `main` function.
   The very minimum code output by the linker for this consists of an `RTS` instruction.
4. `main`: in the program source code.

Notes:

- The linker output on screen indicates the segment names, their numbers and sizes. The `.MAP` file contains the global symbols in the form: `MAIN=1:238` which means function `MAIN` is located at offset 238 in segment #1.
- Note that the symbol names in the MAP file are converted to upper case (but the linker uses the symbols as they are in the source files, including for computing hashes of the symbol names in order to manage them).
- In the error message when a label is not found, `0foobar` means label `foobar` in segment #0.

The linker reads `.o` files as input and dispatches their content into segments. Each segment has a name and an index.
The DATA segment of the PRG file consists of a single segment named `s!` (hardcoded by the compiler) and with segment index #0 (hardcoded by the linker). The compiler only puts strings into this segment (global variables, static local variables, strings passed as parameters in function calls).
The BSS segment of the PRG file consists of a single segment named `bss` (hardcoded by the compiler) and has no index (this is an exception because there is no actual data stored in the PRG file for the BSS segment, only its total size). The compiler puts all global variables and static variables into this segment (except strings).
The maximum size of the DATA and BSS segments is 32KB each.
The TEXT segment of the PRG file consists of multiple segments. Segments are stored in the PRG file in the order of increasing segment numbers.
The linker always loads the file init.o from SYSLIB first. This file creates two segments named `main` (segment index #1) and `init!` (segment index #2).
Then the linker loads each `.o` file supplied on the command line sequentially from the first to the last.
When a segment name (overlay) is encountered for the first time, a new segment with that name is created and is assigned the next available segment index (starting at #3).
Content is then added to the segment specified in the `.o` file. A single `.o` file can contain data for the `s!` segment, data for the `bss` segment, and code for multiple segments (declared using the `overlay` keyword).

Jump table generation: The jumptable contains a group of `jmp` instructions for each code segment. Each group contains jumps to the functions in that segment that are referenced in other segments (all `jmp` to functions in the first declared code segment, then all jmp to functions in the second declared code segment, etc.). The order of functions in a group is determined by the hash of the function name (a symbol) as performed by the linker to speed up access to symbols. The hash is the 8 bit sum of each character in the symbol (up to 10 characters per symbol, subsequent characters are accepted but ignored).

### Known bug (in version 1.1)

- Crash if source code contains `goto MYLABEL;` and `MYLABEL` does not exist.

## MAKE file

The shell allows using a simple MAKE file to build a project. The MAKE file should contain:

- First line: list of `.c` files to compile
- Second line: command line for the linker

Example:
`MAIN.C MODULE1.C MODULE2.C
MMLINK.TTP -o PROJECT.PRG MAIN.O MODULE1.O MODULE2.O -M PROJECT.MAP`