BBC ASSEMBLY LANGUAGE - SIMPLIFIED
EXPLANATION
Revised Version May 1993
Daniel Shimmin, The Queen's College,
OXFORD.
Memory & Storage
================
A BIT is a single section of the
computer's memory. It can be either on
or off. If it is on it represents the
value one, if it is off it represents
the value zero. To store larger
numbers eight bits are grouped
together into a BYTE. A byte can store
any whole number between 0 and 255.
The computer's memory contains 65536
bytes, numbered between 0 and 65535 in
decimal or between &0000 and &FFFF in
hexadecimal.
(HEXADECIMAL is a numbering system
that uses the letters A to F as well
as the numbers 0 to 9. The details of
hexadecimal mathematics are fairly
dull and mostly irrelevant, but do not
confuse hexadecimal and decimal
numbers; the hex ones have the &
symbol before them.)
The location of an individual byte in
memory is an ADDRESS. It will be a
number between &0000 and &FFFF, since
hex is nearly always used for
addresses.
The contents of a byte in memory can
be printed on the screen from BASIC by
PRINT ?&addr
or PRINT CHR$(?&addr)
where addr is the hex address of the
byte, or loaded into the accumulator
in assembly language by
LDA &addr
If we want to store an address in
memory we must use TWO bytes. This is
because one byte can only hold up to
255, and an address could be up to
65535 (&FFFF) as explained above.
Addresses are therefore called
SIXTEEN-BIT ADDRESSES since to store
them you need two bytes of eight bits
each.
The 6502 Registers
==================
The registers in the 6502 are like
variables, but there are a lot less of
them. They are:
The accumulator (A)
The X register (X)
The Y register (Y)
The status register
All of these registers contain eight
bits and so can store any whole number
between zero and 255. Remember that a
byte in memory can also only store a
number up to 255.
All programming in assembly language
involves using at least one of the
registers to store numbers. The status
register cannot normally be used.
The Assembler
=============
Most of the BBC series of computers
contain an assembler that works in
BASIC. This allows you to write
assembly language in a BASIC listing.
The best syntax is as follows:
10 FOR I%=1 TO 2
20 P%=&900
30 [ OPT I%
40
.. -assembly language here-
270
280 ]
290 NEXT
To execute the machine code created by
this program from BASIC, you would
type,"CALL &900".
How the assembler works
=======================
Every assembly language instruction
(e.g. LDA or JMP) has a hex value that
represents it (e.g. A9 or 4C). It is
NOT necessary to learn these values
since the assembler will assemble them
in for you.
What the assembler does is to take
each instruction in your assembly
language program and place it in
memory, starting at the address that
you have chosen (P%).
When the assembler comes to a variable
that you have put into the program,
e.g.
510 .loop
it will simply set up a BASIC variable
called "loop" with the value of the
address that it is currently
assembling at. For example if, when
the computer gets to line 510, it is
assembling in at &907, it will set up
loop as the decimal equivalent of
&907.
This means that if later you want to
put in a JMP command that will make
the program jump back to the point
where "loop" is in the assembly
language, you do not need to type in
JMP &907
but you can just type
JMP loop
and the computer will fill in the
address (&907) for you.
Note that if the assembler comes to a
variable (e.g. JMP loop) that has not
been set up yet (by .loop) it will
simply ignore it. When it goes through
the assembly language the second time
(since you are using a FOR...NEXT loop
it will go through it twice) it will
fill it in then.
For example, if your assembly language
program started like this:
.loop LDA #37
JMP loop
the assembler would assemble this at
these addresses (all in hex):
addr value assembly language
------------------------------------
0900 A9 LDA #
0901 25 37
0902 4C JMP
0903 00 ) Address of loop, i.e.
0904 09 ) &900
When the BASIC assembler assembles
code into memory it also produces a
listing of the code being compiled in
to make things simpler. It often helps
to study this listing carefully so
that you know what is going on.
Comments (cf. BASIC REM statements)
can be added to assembly language
programs by inserting a backslash (½),
then the comment after it.
Subroutines
===========
The BBC contains a number of
subroutines which can be used to
perform certain functions. To execute
these subroutines you can use either
CALL &addr
from BASIC where addr is the
sixteen-bit address of the routine, or
JSR &addr
in assembly language.
Most of these routines require you to
supply them with certain parameters
(numbers) to work with, and this is
done by loading the accumulator and/or
the X and Y registers with the
necessary eight-bit number.
Similarly some of the routines will
return certain values in some of the
registers.
---------------
JSR &FFE0 will wait for a key to be
pressed and will then return the ASCII
value of the key pressed in the
accumulator.
JSR &FFEE will print on the screen the
ASCII value held in the accumulator.
JSR &FFE3 does the same as &FFEE but
will do a carriage return (i.e. RETURN
on the keyboard) if the ASCII value is
13.
JSR &FFF4 performs *FX calls. On
calling the subroutine A should hold
the first FX value, X the second and Y
the third.
JSR &FFF7 does operating system ("*")
commands. This routine requires a
string of characters ending in 13
somewhere in memory. This string will
be the command that the routine will
carry out.
The high byte of the address of the
string (addresses need two bytes,
remember?) should be loaded into X and
the low byte into Y. This is most
easily done by
LDX #addr MOD 256
LDY #addr DIV 256
JSR &FFF7
.addr EQUS"CAT" : EQUB 13