Machine Code Article(s)
PART I
By Andrew Black
This series of articles are only meant to deal with the basics of
Machine Code and are NOT written by a expert!
The first few parts of the series will be more techincal information
that you need to understand and refer to before starting programming.
At about Part III I will begin the real programming stuff.
---------------------------------------------------------------------
This section is aimed to give a basic intoduction and explantion to
Machine Code programming.
---------------------------------------------------------------------
The 6502 Proccessor
-------------------
The BBC range of microcomputers uses the 6502 microprocessor, which
has a comprehensive set of instructions. Fortunately the BBC has a
built-in assembler so that we can write our programs in mnemonics
rather than pure machine code. The assembler may be used directly from
within BASIC programs. This means that machine code may be assembled
and called from a BASIC program while it is running, or the machine
code may be saved and loaded into memory without a BASIC program.
6502 Registers
--------------
The register structure of the 6502 is the ACCUMULATOR, PROGRAM
COUNTER, X and Y INDEX REGISTERS, STATUS REGISTER and STACK POINTER.
The diagram below illustrates this and shows that all the registers
are 8 bits wide, apart from the program counter which is 16 bits wide.
This allows 65,536 locations to be addressed (8 bits would give only
256 locations).
Diagram of 6502 registers
-------------------------
7 0 (bits)
--------
: A : Accumulator
--------
--------
: X :
-------- Index registers
: Y :
--------
--------
: P : Status register
--------
--------
: S : Stack pointer
--------
15 0 (bits)
------------------
: PCH : PCL : Program Counter
------------------
The Accumulator
---------------
The Accumulator can be reguarded as the main working area of the
proccessor. It is used to carry out all the arithmetic and logical
functions of the processor. The table below gives the list of all the
instructions that act on the Accumulator. We will be using only a few
of these to begin with.
ADC - Add with carry
AND - Logical AND
ASL - Arithmetic shift left
BIT - Compare memory bits
CMP - Compare with accumulator
EOR - Logical EOR
LDA - Load the accumulator
LSR - Logical shift right
ORA - Logical OR
PHA - Push accumulator
PLA - Pull accumulator
ROL - Rotate left
ROR - Rotate right
SBC - Subtract with complement of carry
STA - Store the accumulator
TAX - Transfer the accumulator to X register
TAY - Transfer the accumulator to Y register
TXA - Transfer the X register contents to the accumulator
TYA - Transfer the Y register contents to the accumulator
The Index registers
-------------------
The Index Registers are referred to as the X and Y registers, and are
often used to provide the 'offset' or index from a base address. They
can be incremented and decremented directly, unlike the accumulator,
which is why they are often used as counters. No arithmetic or logical
operations may be carried out on the contents of these registers, but
their contents can easily be transfered to the accumulator. The
following table gives the instructions that act upon the Index
Registers.
CPX - Compare the X register
CPY - Compare the Y register
DEX - Decrement the X register
DEY - Decrement the Y register
INX - Increment the X register
INY - Increment the Y register
LDX - Load the X register
LDY - Load the Y register
STX - Store the X register
STY - Store the Y register
TAX - Transfer the accumulator to X register
TAY - Transfer the accumulator to Y register
TXA - Transfer the X register contents to the accumulator
TYA - Transfer the Y register contents to the accumulator
The Program Counter
-------------------
The Program Counter contains the addresses of the next instructin to
be executed. It consists of two 8 bit registers making up the 16 bit
address. These two registers are referred to as Program Counter High
and Program Counter Low.
The Status register
-------------------
This is an 8 bit register which consists of the status flags and will
be looked at another time.
The Stack pointer
-----------------
The Stack Pointer is an important register when branchs need to be
executed. The Stack Pointer keeps track of where to find the next free
location in the stack. The stack is a special area of memory which
will also be looked at another time.
----------------------------------------------------------------------
The Assembler
-------------
In order to learn how to use the assembler from within a BASIC program
we will look at an example program.
Example 1.0 (File: ASS1)
-------------------------
10 REM * Example 1.0 *
20 SCREEN = &7C27
30 CLS
40 P% = &900
50 [
60 .START
70 LDA #65
80 STA SCREEN
90 RTS
100 ]
110 CALL START
* * This program will not work on any machine that uses shadow screen
* * memory as it addresses MODE 7 screen memory directly ie. the
* * Master. To make it work replace Line 80 with JSR &FFEE.
Load the file ASS1 and run it.
This program places the letter A at the top right hand corner of the
screen. The function of each line is as follows ...
Line 20 - Set the variable SCREEN to the address of the top right of
the screen (&7C27).
Line 40 - Assemble the machine code generated by the program at
location &900 onwards.
Line 50 - Indicate beginning of assembly langauge.
Line 60 - Use a label to mark the start of the assembly langauge.
Line 70 - Place the ASCII code for "A" in the accumulator register.
Line 80 - Store the contents of the accumulator at location SCREEN.
Line 90 - Return to BASIC.
Line 100 - Indicate end of assembly langauge.
Line 110 - Execute machine code.
As well as executing the program, the assembler outputs a listing of
the assembled machine code. This listing can be divided into five
fields:
Location Opcode Operand Operand Mnemonic
0900
0900 .START
0900 A9 41 LDA #65
0902 8D 27 7C STA SCREEN
0905 60 RTS
Note that the address of the screen location has been listed 'back to
front' with the low byte first. This is a result of the way in which
the 6502 works. It requires addresses to be given in low byte first
and the assembler has taken care of this for us.
Memory Usage (Where to place your program)
------------------------------------------
The variable P% is used to set the program counter and thus determines
where in memory the machine code is to be assembled. If the machine
code is going to be long then careful consideration must be given to
its location. I have used &900 in the first program and this is a
fairly safe area for about two pages of memory (512 bytes). Longer
machine code programs can be placed above the memory used by BASIC.
The Memory Map
--------------
Location Use
&00- &8F Current language use.
&90- &9F Econet use.
&A0- &A7 Current NMI owner use.
&A8- &AF OS command whilst executing
&B0- &BF Filing system scratch space
&C0- &CF Current FS use.
&D0- &E1 VDU driver use.
&E2 CFS status byte.
&E3 CFS *OPT byte.
&E4- &E6 General OS workspace.
&E7 Keyboard auto-repeat timer.
&E8- &E9 OSWORD input buffer pointer
&EA 6850 use / timer counter.
&EB CFS use.
&EC- &ED Two key rollover use.
&EE RAM copy of 1MHz bus reg.
&EF Acc. value for last OSBYTE/
OSWORD call.
&F0 X reg. " " " "
&F1 Y reg. " " " "
&F2- &F3 GSINIT/GSREAD text pointer.
&F4 RAM copy of ROMSEL (&FE30).
&F5 Speech/ROM FS use.
&F6- &F7 Pointer for paged ROM read.
&F8- &F9 NOT USED BY OS 1.2.
&FA- &FC OS workspace.
&FD- &FE Point to byte aftr last BRK
&FF Escape flag. (Bit 7 set)
&100- &1FF 6502 Stack.
&200- &235 OS Call vectors (QV)
&236- &28F Main system variables.
(Accessed by FX166 - FX255)
&290 *TV vertical adjust.
&291 *TV interlace flag.
&292- &29B System clock use.
&29C- &2A0 Event countdown timer.
&2A1- &2B0 Paged ROM type table.
&2B1- &2CE Various OS use.
&2CF- &2E9 Buffer flags + indices.
&2EA- &2ED CFS use.
&2EE- &2FF Space for OSFILE ctrl block
&300- &37F VDU workspace.
&380- &3DF CFS use.
&39F-&3A6 NOT USED BY OS1.2
&3E0- &3FF Keyboard input buffer.
&400- &7FF Current language use.
&800- &83F Sound workspace.
&840- &84F Sound channel 0 buffer.
&850- &85F Sound channel 1 buffer.
&860- &86F Sound channel 2 buffer.
&870- &87F Sound channel 3 buffer.
&880- &8BF Printer buffer.
&8C0- &8FF ENVELOPES 1 - 4.
&900- &9BF ENVELOPES 5 - 16
or RS423 output buffer
or Cassette output buffer.
&9C0- &9FF Speech buffer
or Cassette output buffer.
&A00- &AFF Cassette input buffer
or RS423 input buffer.
&B00- &CFF Econet workspace
(previously soft key expansion
buffer + char. definitions.)
&D00- &D9E NMI routines.
&D9F- &DEF Expanded vector set.
&DF0- &DFF Paged ROM workspc pointers
&E00-&7FFF User/screen RAM.
- Some of this may be taken
for paged ROM workspace
(eg DFS takes to &1900).
- Screen memory :-
&3000-&7FFF MODEs 0,1,2
&4000-&7FFF MODE 3
&5800-&7FFF MODEs 4,5
&6000-&7FFF MODE 6
&7C00-&7FFF MODE 7
&3000-&7FFF Shadow screen RAM
&8000-&BFFF Paged ROMs/RAMs.
The above memory map is very comprehensive and you really only to look
at it for occasional reference.
Areas &900 to &AFF can be used as a machine code area
Area &B00 to &BFF can be used with the loss of function keys
Area &C00 to &D00 can be used with the loss of charcter definitions
If you have a disc system your computer could use the area &D00 to
&1900 for disc workspace. If your computer does use this area DO NOT
place machine code programs in (the computer might crash).
When writing machine code programs using the assembler do NOT set the
P% to &1900 or anywhere that has the BASIC program, variables stored.
It will crash.
IF you want to place machine code above the areas set aside by the
operating system then you have to manipulate the values of PAGE,
LOMEM, HIMEM and TOP. These are pesudo-variables used by BASIC to
determine where in memory BASIC programs can store variables etc.
These techniques for small programs are really unnecessary.
You can use the DIM function to reserve memory space within the
program for the machine code. This is how you would use it:
10 DIM AREA 9 (area in bytes)
20 P% = AREA
40 [
.
. Machine code
.
100 ]
110 CALL AREA
Numbers
-------
The assembler accepts numbers in decimal or hexadecimal. Any number
preceded by an an amperstand (&) is considered a hex number, else it
is reguarded as decimal. eg.
65 - Decimal
&41 - Hexadecimal
Labels
------
When using a label to indicate a position within the program they must
begin with a full stop followed by a letter(s). A label name can have
up to 255 characters and must not have any spaces between the letters.
Labels are very useful since it is much easier to use CALL START than
CALL &D00. This is even more important when calling subroutines whose
locations would have to be calculated. eg ...
.hello_there
or
.abcdefghijklmnopqrstuvwxyz
Comments
--------
In BASIC REM statements are used to clarify pograms (wanna bet!), and
comments can also be inserted into assembly language programs. Instead
of writing REM the backslash (\) symbol is used. In MODE 7 this looks
like a half symbol.
70 LDA #67 \ Place ASCII value of 'C' in accumulator
Notes
-----
Machine Code mnemonics unlike BASIC commands can have mixed upper or
lower case letters eg.
LDA or lda or LdA or lDa or lDA or LDa are all perfectly valid.
However for clarity it is best just to use Upper case letters.
----------------------------------------------------------------------
This may seem like a lot learn but it is neccessary if you want to
program in machine code. Experiment with the the assembler, maybe
write a program to print your name in MODE 7.
By about Part III of this series we will start programming properly as
I will have gone over most of the assembler and proccessor commands.
The next part of this series will look at more functions of the 6502
and addition - subtraction in machine code.
----------------------------------------------------------------------
Any suggestions concerning machine programming or particular aspects,
write in and tell me and I will try to feature it.