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.
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 :
How to install BASS
How to use BASS
- 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 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 top