Files
colour-maximite2-csub/README.md
T
2025-12-08 20:47:43 +11:00

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"

Description


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 0 indicates 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 LR instruction, 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 the simple symbol 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.


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.
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
  • 20420047 is the machine code word representing movs r0, #42 and bx 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.elf to disassemble and verify your machine code.
  • Compile C routines similarly, specifying -mcpu=cortex-m7 -mthumb in 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.