Tutorial: Extension writing

As mentioned before, an extension is simply an XC=BASIC source code file. You can define procedures, functions and constants in your extension just the way you'd do it in an XC=BASIC program.

Naming your symbols

To avoid naming collisions, you should choose a quasi namespace for the extension and prepend all your symbols with this string. For example, if you're about to write an extension that does math calculations, choose a namespace, let's say, math_ and prepend all constants, procedures and functions with the string math_:

rem * Math extension
rem * by John Doe
rem * namespace: math_

const MATH_PI% = 3.14159265359
const MATH_E%  = 2.71828182845

fun math_pow(base!, exponent!)
  result = cast(base!)
  for i! = 1 to exponent! - 1
    result = result * base!
  next i!
  return result
endfun

Adding new commands

Since procedures can be called using the procedure name only, they are perfect for defining new commands. Combining with the ASM directive, you can write assembly code for your new commands. For example:

rem * Border coloring extension
rem * by John Doe
rem * namespace: bg_

const BG_BORDER = $d020

proc bg_color(color!)
  asm "
    lda {self}.color
    sta _BG_BORDER
  "
endproc

Thereafter, any program using this extension can issue the new command:

include "path/to/extension.bas"

bg_color 13

Notice that bg_color 13 is equivalent to call bg_color(13).

Adding new functions

Simply use the FUN ... ENDFUN block to define new functions.

Referencing XC=BASIC symbols in assembly language

To speed things up, you should write functions in assembly language. To be able to do this, you need to know how to access XC=BASIC symbols and features in assembly. The following table serves as a guide:

Type XC=BASIC symbol Assembly symbol
Constant EXAMPLE _EXAMPLE
Global variable example _example
Local variable example _procname.example or {self}.example within the procedure
Argument of procedure or function example _procname.example or {self}.example within the procedure

The following example attempts to demonstrate how to write a function in assembly language.

rem ** This function returns one if fire button
rem ** in joystick port #1 or port#2 is pressed, zero otherwise

const JOY_PORT2 = $dc00
const JOY_PORT1 = $dc01

fun joy_firepressed!(port!)
  dim result!
  asm "
    ; This is how to refer to a function's argument
    lda {self}.port
    ; Port #2 becomes 0, Port #1 remains 1
    and     #%00000001
    tax
    ; This is how to refer to a global constant
    lda.wx  _JOY_PORT2
    eor     #%11111111
    and     #%00010000
    lsr
    lsr
    lsr
    lsr
    ; A now holds the return value of our function
    ; Write it to the variable 'result!'
    sta {self}.result
  "
  return result!
endfun

Publishing your extension

When you're done with your extension, please follow these steps:

  1. Test all functions and commands carefully. Write a detailed test program
  2. Name your extension xcb-ext-<extension_name>.bas
  3. Write a detailed documentation to let users know how to use the extension
  4. Create a GitHub repo with this name: xcb-ext-<extension_name>, upload your files and notify me in email (feketecsaba [at] gmail) about the new extension and I'll add it to the extensions/ folder as a submodule