Home
Admin | Edit

BASS - BBC BASIC Assembler

Contents

This article talk about BASS and also act as its documentation.

BASS is my lightweight BBC BASIC V aided assembler framework built to focus on 100% assembly development for Acorn Archimedes and later Acorn computers up to ARM boards running RISC OS.

Download : https://github.com/grz0zrg/acorn-computers-dev

Why BASS ?


The first thing i looked when i started assembly programming on the Archimedes is the available development tools, i didn't want to rely on external tools (like vasm) and i liked that all the tools to program (BBC BASIC) were available on the machine so i started with the bundled BBC BASIC V which has inline assembly capabilities.

Doing full assembly programs was important to me because of eventually making sizecoding programs and demos for the Archimedes and later Acorn computers.

BBC BASIC V is complete enough but i didn't like much all the glue code (you have to do some BASIC setup code to do two-pass assembly and errors handling) so i started to write BASS to abstract that away and focus on the most important thing i wanted to write: ARM code. The process also helped me to understand some of the details of BBC BASIC V and RISC OS.

The most important goal of BASS is to have a lightweight assembly framework which can work on the original hardware (or in an emulator) and which does not require any external tools so i just need RISC OS 2 (or later) to kick-start an assembly project quickly. (i didn't test with Arthur OS but may work as well)

The other goals are to :
  • abstract all the 'big' BBC BASIC inline assembly setup code so i don't have to think about it again especially the setup code for a full two pass assembler (with errors handling) + writing out a binary which require some specific code
  • provide some way to adjust the BBC BASIC assembler / BASS through simple parameters passed via an Obey file (for debugging, adjusting memory etc.)
  • provide a small set of features like splitting assembly sources in multiple source files, embedding external data or static allocation to ease quick prototyping (no ARM code nor BBC BASIC code to do that)
  • still support BBC BASIC V code for high-level assembler features
  • provide a template project directory which one can copy / paste, rename and start programming with all the features above
Kick-starting an assembly project with BASS is just a matter of copying a BASS template project and writing ARM code right away. (see below)

BASS projects are lightweight / standalone because it is just a set of obey files (!assemble and !run), a small BBC BASIC V file !bass which is the assembler and two definition files data and sources.

BASS can be seen as a BBC BASIC V assembly wrapper, all code is just BBC BASIC V but it is structured for inline assembly / producing a binary.

How to install BASS


Drop BASS archive files (see GitHub) into a directory. To start a new project just copy a template directory in the projects directory.

See GitHub README for instructions on how to make the framework ready; you just have to change the file-type of the metapply script to Obey and run it, this initialize the files metadata so they are runnable.

BASS is also packed with my personal library which is required for the graphics templates.

Note : The !assemble Obey script of the template project always looks for BASS in parent directory which is why the layout below is recommended.


Here BASS is into 'projects' directory.
  • BASS is a directory with BASS sources
  • template1 is the simplest project template, it crash if you run it because there is no code (0 bytes binary); ideal to start projects from scratch
  • template2 is a retro (Archimedes era) graphics project template (320x256 256 colors with double buffering and FPS display) using my library; ideal for starting graphics project (the graphics setup can be changed easily)
  • template3 is a modern graphics project template (1920x1080 24 bit colors with double buffering and FPS display) using my library; ideal for starting graphics project (the graphics setup can be changed easily)
  • example is a project / template which demonstrate all features of BASS. (using multiple source files, using external binary data)

How to use BASS


Once you created your new project by copying a template directory you should see those files:

Just run !assemble and !run to assemble / run your program.

Here is a description of the files and directories of the template project :
  • !assemble is the Obey script to assemble your project
  • !run is the Obey script to run your binary
  • bin is the directory containing the binary after !assemble is successful
  • data is the directory containing any external data
  • datadef is the data definition file
  • sources is the sources definition file
  • src is the directory containing sources (it has the file main by default)
Note : The template layout is just a personal way of organizing my programs, you can of course organize it differently or even simplify it.

To code right away you add code to the src/main file, once satisfied you double click on !assemble which will produce a binary in bin named bin that you can launch with !run, as simple as that!

Here is the default content of the src/main file:

REM src.main
REM template program
DEF FNmain
[ OPT bassPass%
; asm code
]=0

As you can see it is a BBC BASIC file containing small amount of BBC BASIC code with inline assembly code.

Full knowledge of BBC BASIC is not really needed to use BASS (you can just do some ASM code between []) but i still recommend to look at the documentation if you are not accustomed to BBC BASIC and the syntax of its assembler, BASS is still vanilla BBC BASIC at heart.

The first line is important and must be the filename (or file-path), it is shown in case of an error in your code so i recommend to always add the filename as first line of your sources file.

The DEF FNmain is the entry point of the file (entry point is always named like the filename) which end up with =0, it is a regular BBC BASIC function, the function content is BBC BASIC inline assembly syntax.

If you have any errors in your code the file along the line at which the error happened will show up in the output :

How an error looks like, note that "src.main" is the first comment of the source file!


How a successful assembly looks like, last value is the output binary size.

Some assembly example code

Here is a program which print "Hello World!" and exit cleanly:

REM src.main
REM my program
DEF FNmain
[ OPT bassPass%
 ; print "Hello World!"
 swi "OS_WriteS" ; this will write the following null terminated string into all active output streams and jump to the code next to the string
  equs "Hello World!" ; define some string data
  equb 0 ; null terminate it
  align ; always align after some data definitions

 ; exit cleanly by returning 0 (see RISC OS documentation)
 ldr r1,returnString
 mov r2,#0
 swi "OS_Exit"
 .returnString
  equs "ABEX"
]=0

This is actually the same program as the BASS example project except the BASS example demonstrate all BASS features, it bundle the string into an external binary data file and use another file to define the print subroutine.

Note : You can use all BBC BASIC V constructs (FOR, conditions, procedures, functions etc.) since those sources are just BBC BASIC sources. This is useful for high-level assembler features, generating code and so on.

Note : If you use multiple inline assembly [] statements DO NOT FORGET to add OPT bassPass%, it is hacky (and quite ugly) but i did not found any better ways without compromising the the framework simplicity.

Using multiple sources


Using multiple sources is easy, you must define them in the sources definition file. The sources definition file is just a list of file-path (relative to project directory) that BASS will assemble in the order it is defined. It contain src.main by default. The first file defined in the sources file is considered as the program entry point.

Once defined you must add a BBC BASIC function named like the source filename. The source filename should be unique.

What BASS actually do is a call to the BBC BASIC function named like the filename.

See "Modules" below to separate the filename and function name.

ADFS Symbols for parent directory ^ and root directory $ are supported in the file-path.

Example of a sources definition file. You can put comments by starting lines with ;

Note : 256 files can be defined by default, increasing the number of files is possible by setting "BassMaxSources" environment variable to some higher value in the !assemble script.

Example

If you define a "src.mysource" file in the definition file, the content of the mysource file must look like :

REM src.mysource
REM some comments about mysource file
DEF FNmysource
[ OPT bassPass%
; asm code
]=0

All labels are defined globally (unless you use the LOCAL keyword) so all sources can access each other symbols.

Modules

BASS support a primitive notion of modules, ones can load (aka call) a list of specific functions from a defined source file.

The main point of modules is to include parts of a library file, it solve the issue of when you have specific code for 16 colors mode and 256 colors mode in your library file but you only need the 16 colors mode code to be included in your current program. One of the solution is to split the code into two files but that would be tedious if you have many small parts so modules can be used.

Modules also allow to separate the source filename from the function name which can be useful to decompose libraries into multiple components.

To use modules you just add a ':' at the end of your source line and you specify each functions (separated by ':') to call on the next line:

gfxUtils and gfxUtils16m functions contained in the gfxUtils file will be called

Using external data / static allocation


Adding external data to your program is easy and require you to define them into the datadef file.

The datadef file is just a list of labels and file-path (relative to project directory) on separate line, each files defined will be embedded into the binary and the label will define its starting address, the label can then be used directly in the sources, it is defined globally.

Additionally you can statically allocate some memory by defining a label (without file-path) which end by : plus the number of bytes you want to allocate. The label will then point to that address. It is a quick way to do a DIM basically.

You don't need to align your data, BASS automatically do it.

All data defined in the datadef file is contiguous.

Embedding data into the binary that way is very useful for prototyping which is the main reason i added it. May be useless with heavy data since you may hit hardware memory limit, it will be slower to assemble as well.

BASS also automatically (unless BassNoSugar variable is set to 1) provide some routines such as getLABELAddr (replace LABEL with a datadef label name) for each datadef labels, it is extremely useful in case of dense code where a mov r0,LABEL or a adr r0,LABEL wouldn't work so instead ones use bl getLABELAddr and get the address in r0 without specific code. Another routine allow to get the data size with getLABELSize .

Note : 256 data can be defined by default, increasing the number of data is possible by setting "BassMaxData" environment variable to some higher value in the !assemble script.

Example: Embedding external data and using it

datadef definition file example for the program below (note that you can put comments by starting line with ;)

REM src.main
REM my program
DEF FNmain
[ OPT bassPass%
 ; print "Hello World!", r0 is a pointer to a null-terminated string (our external data that will be embedded into the program)
 adr r0,helloWorldBinaryData
 swi "OS_Write0"

 ; you can also use someStaticallyAllocatedSpace label

 ; exit cleanly by returning 0 (see RISC OS documentation)
 ldr r1,returnString
 mov r2,#0
 swi "OS_Exit"
 .returnString
  equs "ABEX"
]=0

How the external file looks like (in data directory)

A look at the file content in a hex editor, note the null-terminated string

Program result when run

Debugging and the Obey files parameters (!assemble, !run)


You may want to dig deeper into the BASS Obey files if you need to modify the assembler pass parameter or increase BBC BASIC memory.

!assemble Obey script

The !assemble Obey script is the script used to assemble the program, it set some environment variables used to configure BASS, set the memory limit that BBC BASIC will use to assemble the project, set working directory and run BASS.

The !assemble Obey script content, note that it run in a TaskWindow so it doesn't block the OS while assembly is going on

By default BASS will not generate assembly listing output (which can be useful to debug) but you can turn it on by changing the BassPassOpt environment variable.

The assembly code will go into a buffer when being assembled, the size of that buffer is static and should be changed if you have an "assembler limit" error, it is set to 128KB by default and can be changed by modifying the BassBinaryBufferSize environment variable.

Program execution address can also be changed with BassOrg environment variable.

By default BASS put the code above the data, if you want all the data above the code in the generated binary set the BassDataFirst environment variable to 1. This will add a branch instruction as the first instruction of the binary so it jump to the code part at start.

Tweaking the memory allocated for BBC BASIC V can be done by modifying the min / max WimpSlot parameter (the one given as an argument to TaskWindow and the other one if you don't run BASS in a TaskWindow), this may be useful if BBC BASIC needs more memory to run which may happen if your BBC BASIC program is heavy. It is set to 256KB as default. Increase it if you have a "No room for this DIM..." error.

!run Obey script

The !run Obey script is the script used to run the program, it define the amount of memory that the program will use (typically the size of the binary), set the working directory and run the program. It is mainly useful to fine-tune the amount of memory that your program will use, it must generally be the size of the output binary. If you want someone to run your program it is probably better to distribute it with a !run script to make sure enough memory is allocated for the program.

The !run Obey script content

Caveats


Because BASS is yet another not so perfect personal hack you must be aware of its shortcomings.

Here is a list of BASS caveats that ones must be aware of when using it :
  • all inline assembly statements must have OPT bassPass% or the code may not work correctly (probably the most ugly things about BASS, it is standard BBC BASIC though so...)
  • there is some touchy globally defined BASS variables which all begins by bass, i suggest to never define symbols which begin by bass
  • if you get memory errors during assembly or when running your program: try to increase BBC BASIC V allocated memory / program memory (see !run Obey file), BASS doesn't make this easier yet
  • data / sources definition order may matter for your program, if you have some big data i recommend to put them at the end / close to where they are used
  • many errors relative to BASS are left to BBC BASIC, may be tough to debug if they happen
  • BASS use more memory than vanilla BBC BASIC, there is some ways to bypass that by adjusting BASS parameters but it will still have a small overhead compared to vanilla BBC BASIC
Also: not specific to BASS but when generating assembly code with BBC BASIC V constructs you may have to drop labels if you use them and instead relying on branch / PC register with direct values.

Conclusion / Future


BASS may evolve in the future with new features, it is right now a small personal tool that i use heavily to ease assembly coding for the Acorn computers. When i want to develop low level stuff for Acorn computers i just need to start some emulators and that is it, i can work on any platforms mostly which was the point. It is also BBC BASIC at heart so the code still works as-is without the framework.

There is also many more stuff which could be automated like end-user package; a script to produce a ready to use binary package with application icon and so on.

It works for modern RISC OS development but it was really targeted at Acorn computers of the late 80s and early 90s era. :)

Many thanks to the folks of the Stardot discord channel for answering my questions regarding BBC BASIC while i was making BASS. :)

back to topLicence Creative Commons