5.5 KiB
5.5 KiB
# Colour Maximite 2 - CSUB Example and ARM Cortex-M7 Embedded Code
This document demonstrates how to embed ARM Cortex-M7 machine code directly into your BASIC program on the Colour Maximite 2 using the `CSUB` directive. It covers a minimal example, explains the embedded machine code, and provides detailed instructions on writing, compiling, and embedding ARM Thumb-2 assembly or C routines.
---
## What is CSUB?
`CSUB` allows embedding raw ARM machine code or compiled C/assembly routines into Colour Maximite 2 BASIC programs. These embedded routines appear as BASIC commands or functions and run natively on the ARM Cortex-M7 processor, enabling efficient, low-level operations beyond standard BASIC capabilities.
According to the Colour Maximite 2 user manual:
> `CSUB name [type [, type] …]`
> hex [[ hex[…]]
> hex [[ hex[…]]
> `END CSUB`
>
> Defines the binary code for an embedded machine code program module written in C or ARM assembler. The module will appear in MMBasic as the command `name` and can be used in the same manner as a built-in command.
Multiple embedded routines can be used in a program, each defining a different module with a unique name. The first hex word is a 32-bit word representing the offset in bytes from the start of the CSUB to the entry point of the embedded routine (usually the function `main()`). The following hex words are the compiled binary code for the module.
---
## CSUB Code Example
```basic
CSUB simple
00000000 00004770
END CSUB
simple()
PRINT "Returned successfully"
What Does This Thumb-2 Machine Code Do?
CSUB simple
- Starts the definition of a machine-code subroutine named
simple. - Tells the BASIC runtime that the following hex words are compiled machine code to execute when
simple()is called.
00000000
- The entry point offset for the CSUB.
- A value of
0indicates execution starts immediately at the next word. - This word is metadata only; it is not executed as machine code.
00004770
- Encodes the Thumb instruction
BX LR(Branch to Link Register). - This instruction returns immediately from the subroutine to BASIC.
END CSUB
- Marks the end of the CSUB block.
- Signals that the machine code definition is complete, and BASIC execution continues normally.
simple()
- Calls the subroutine
simple. - Execution jumps to the CSUB, reads the entry point offset, executes the
BX LRinstruction, and immediately returns.
PRINT "Returned successfully"
- Prints a message to the BASIC console to indicate the subroutine returned successfully.
ARM Thumb-2 Assembly Example Corresponding to the Machine Code
.syntax unified
.thumb
.global simple
simple:
bx lr @ Return immediately
Explanation
.syntax unified: Use modern unified ARM assembler syntax..thumb: Assemble for the Thumb instruction set used by Cortex-M7..global simple: Declare thesimplesymbol as global (entry point).bx lr: Branch to the address stored in the Link Register (LR), returning control to the caller.
Note: In this minimal example, no values are returned to BASIC.
How to Compile, Link, and Extract Binary
Step 1: Save Assembly Code
Save the code above as main.s.
Step 2: Assemble to Object File
arm-none-eabi-as -mcpu=cortex-m7 -mthumb main.s -o main.o
-mcpu=cortex-m7: Target Cortex-M7 CPU.-mthumb: Use Thumb instruction set.
Step 3: Link to ELF Executable
arm-none-eabi-ld main.o -Ttext=0x0 -o main.elf
Or combine compiling and linking with GCC:
arm-none-eabi-gcc -mcpu=cortex-m7 -mthumb -nostartfiles -Wl,-Ttext=0x0 -o main.elf main.s
-nostartfiles: Avoid linking standard startup code.-Ttext=0x0: Set load address to 0.
Step 4: Extract Raw Binary
arm-none-eabi-objcopy -O binary main.elf main.bin
Step 5: View Machine Code as Hex
xxd -e main.bin
Sample output:
00000000: 20420047
20420047is the machine code word representingmovs r0, #42andbx lr.
Preparing the CSUB Block
- The first 32-bit word is the entry point offset (usually
00000000). - Following words are your compiled machine code in 32-bit hex words.
Example:
CSUB myfunc
00000000 20420047
END CSUB
myfunc()
PRINT "Returned value in R0 was 42"
Passing Arguments and Returning Data
- You can specify argument types in the CSUB definition, e.g.,
CSUB MySub integer, integer, string
- Up to 10 arguments are supported.
- Variables or arrays passed are pointers to their data, allowing embedded routines to modify passed data directly.
- Constants and expressions are passed as pointers to temporary memory containing their values.
- For longer-running routines, call
routinechecks()regularly to keep USB and watchdog timers active, or keep routine execution under a few milliseconds.
Additional Tips and Verification
- Use
arm-none-eabi-objdump -d main.elfto disassemble and verify your machine code. - Compile C routines similarly, specifying
-mcpu=cortex-m7 -mthumbin compiler flags. - Place CSUB blocks anywhere in your BASIC code; MMBasic will skip over them during execution.
- Each hex word must be exactly eight hex digits and separated by spaces or new lines.
- Formatting errors or incorrect hex data will cause runtime errors in MMBasic.
License
This document and any accompanying code are released under the MIT License.