BitMagic
The Complete Development Environment for the Commander X16.

The Compiler

Please note the documentation is a currently a work in progress while the old docs are brought up to date.

The Compiler can compile assembly code .bmasm text files into .prg or .bin files which can be used by the Commander X16.

65c02 Syntax

The compiler accepts standard 6502\65c02 syntax.

It is enhanced by macros written in c#. These can be used like macros in those in other assemblers to generate code before it is compiled. Please see the Template Engine section for more details.

For 65c02 code, each line can either start with a valid opcode or start with a period to denote a compiler instruction. Otherwise it is assumed to be part of a C# macro.

Compiler instructions are how we define the structures, scopes or set other functionality for the compiler.

Comments

BitMagic uses ; to define the start of a comment if the line starts with a . or a 65c02 opcode. Otherwise as the line is C#, it will define the end of a command as is normal for that syntax.

Compiler Instructions

Labels are single words which start with . and end with a :. There can’t be anything before the first period, but commends are allowed after the colon. Opcodes are not allowed after the label definition. See label for more information.

The instructions supported are below with their parameters defined in the table below.

The parameters can either be name value pairs, or entered in order that they are in the table. For example:

.const name=example, value=$1234
.const example $1234
Verb Description Parameters
machine Set the machine the code is for. This will typically set global variables such as the VERA register names. name
segment Area of memory which will be used, or written to a specific file. name, address, maxsize, filename
endsegment End of the current segment, sets the segment back to default.  
scope Scope block for defining variables or constants. name
endscope End of the scope, sets the scope back to default.  
proc A defined range with a defined entry point and which its own scope. name
endproc End of the procedure, sets the procedure back to _default.  
const Defines a constant named value. name, value
constvar Defines a constant pointer to a defined variable. type, name, value
var Allocates a area within the segment for a variable. type, name, value
org Pad the segment to a given address. address
pad Pad the segment with the specified number of bytes. size
padvar Pad the segment with an variable of the specified type. type, name
align Pad the segment to the given alignment. boundary
insertfile Insert a file into the source file. Inserted post macro processing. filename
byte Insert one or more bytes into the segment. …data…
word Insert one of more words into the segment. …data…

Segments

In BitMagic a segment is an area of ram which can hold code or variable definitions and optionally be written to a file.

The default segment called Main starts at $801 and will be written to a .prg file with the same name as the source file.

If a segment has code defined, but no filename, you will receive a compiler error. You can however have a segment defined with only ‘variables’, for example useful for defining variable locations within the ZP.

A segment can be defined with a maximum size to ensure it is constrained within the correct bounds. For example:

.segment ZP $02 $fd

The segments in your application can be viewed in the compiler output by setting DisplaySegments compiler option. For example:

Segment                   Start Size  End
Main                      $0801 $0145 $0946

Scopes

Scopes are to provide constant separation to avoid collisions. As they don’t define something that is output, the scopes are not defined at a segment or procedure level. You can switch scope as you want to access or separate different constants.

In normal operation there is a set scope hexarchy of App:Main:Proc:Constant, for example:

.proc test
.const something $1234
.endproc

In this case something can be thought of as App:Main:test:something. The : is a separator between the different levels of the hierarchy. As procedures can’t be nested, this hierarchy will always hold true unless the scope keyword is used.

When a custom scope is defined it is considered to be global, so will sit under App. (App is the global scope, where machine constants can be placed.)

Note, the current scope is always closed with a .endproc.

This can better be explained with an example:

.proc test
    .const something $12
    lda #something              ; $12

    .scope newscope
        .const something $34
        lda #something          ; $34
    .endscope

    lda #something              ; $12
    lda #newscope:something     ; $34
    lda #App:newscope:something ; $34
.endproc

Scope Lookup Precedence

To find a constant BitMagic uses the current scope as the highest level of precedence, this is either the scope itself or at a proc level.

If no match, it will move up to the parent and then check the child scopes for an exact match which includes the full scope string.

If no match, it will perform the same operation at the parent scope.

Labels

Labels are defined points in memory, which help the programmer with process flow with branching or jump instructions. Although they can be used with any opcode as part of an expression.

When defined they are included within their current scope.

For example the following code is valid:

.byte $00
.loop:
    inc loop-1
    bne loop        ; will loop 256 times

Ambiguous Labels

Labels are special in that they can be defined multiple times to allow us to use them as ambiguous references. These are specifically intended for flow control.

If there are more than one label of the same name, when referencing them you will need to add a prefix of either - or + for the direction in which the compiler should look for the correct one. Multiple prefixes can be used.

Ambiguous labels cannot be used in expressions.

For example

.loop:          ; A
    ...
.loop:          ; B

    bne -loop   ; jumps to B
    bne --loop  ; jumps to A
    bne +loop   ; jumps to C
    bne ++loop  ; jumps to D
    bne loop    ; will error

.loop:          ; C
    ...
.loop:          ; D

Expressions

Both the compiler and the Template Engine support expressions. For the compiler, the expression syntax is based on the C# syntax with a few extensions. It is also more limited in what it supports, so its probably best to keep it to basic maths or similar.

As well as the standard functions the following have been added:

Operator Explanation Example
< Return the low byte from the value <$123456 returns $56
> Return the high byte from the value >$123456 returns $34
^ Return the top byte from the value ^$123456 returns $12

Referencing Constants

Constants such as labels or defined constants can be used within expressions, for example

    lda data + 3 ; loads $13 into the accumulator
    stp

.data:
    .byte $00, $11, $12, $13, $14

Constants are of course bound by their scope.