```      ====================================================================
DR  6502    AER 201S Engineering Design 6502 Execution Simulator
====================================================================

Supplementary Notes                                   By: M.J.Malone

Starting to Program in 6502 Assembly Code
=========================================

Quotes of Murphy's Kin:

1) It is impossible to make anything fool-proof because fools are
so ingenious.

2)  If  you  explain  something so thoroughly and clearly so that
everyone will understand, someone will not understand.

Introduction to the 6502
------------------------

Accumulator and Assembler Basics

The 6502 has several 'registers'.  Registers are special memory
locations that are  internal  to  the  processor  and  are  directly
involved  in processor instruction codes.  The accumulator (.ACC) is
one such register.  The code fragment that would transfer data  from
one  memory  location  (A_loc) to another (B_loc) would be coded as:
(Note that the numbers \$0400 and \$0800 are hexidecimal numbers which
do have decimal equivalents.  The conversion  between  hex,  decimal
and binary will be explained later.)

;
A_loc = \$0400
B_loc = \$0800
;
LDA A_loc
STA B_loc
;

Where  LDA  is the mnemonic for LoaD Accumulator and STA is the
mnemonic  for  STore  Accumulator.   In   this   example   the   two
assignments  'A_loc='  and  'B_loc=' give values to the labels A_loc
and B_loc.  Note that A_loc and B_loc are NOT variables  but  labels
or constants used to replace numerical values and make the code more
readable.   The  locations described by A_loc and B_loc will contain
data important to the running of the program,  the  variables.   Now
A_loc  and  B_loc  are  not  very  descriptive  but  'Abs_Value' and
'Buffer_ptr' are also legal labels.  The assembler  sees  the  above
code fragment as:

;
LDA \$0400
STA \$0800
;

with  the labels substituted into the code.  This fragment loads the
value from address \$0400 into the accumulator and  then  stores  the
value into memory address \$0800.

page 2

You may think of labels 'Buffer_ptr' as a variable as in a high
level  language when you go 'LDA Buffer_ptr' to get the value of the
variable into the accumulator.  Remember  that  the  assembler  sees
Buffer_ptr  as  an  address  of  a  location  in  memory,  it is the
programmer who decides that that location has a special  meaning  or
purpose and gives it a meaningful name.

The .X and .Y Registers and Indexing

The  .X  and  .Y  registers  are  similar  to  the .ACC in most
respects, data can be loaded into them and stored into  memory  from
them.   The above example could as easily be programmed with LDX and
STX as it was with LDA and STA as follows:

;
A_loc = \$0400
B_loc = \$0800
;
LDX A_loc
STX B_loc
;

The same code could also be written  for  the  .Y  but  there  is  a
special  purpose  reserved  for  the  .X  and  .Y registers.  In the
previous section we saw that labels  were  used  to  name  important
memory  locations  and  simulate  the  function of variables for the
programmer.  The assignment 'b=a' in a higher level language may  be
coded  using  the example above.  If the programmer wanted to use an
array and say assign 'b~=a' it may be done as follows:

;
A_loc         = \$0400
B_array_start = \$0800
;
LDA A_loc
LDX #3
STA B_array_start,X
;

As before, the value of  memory  location  'A_loc'  is  loaded  into
memory.   The  value  of  the  array  index '3' is loaded into the X
register.  The statement 'STA B_array_start,X' takes  the  value  in
the memory and stores it into the location (B_array_start+.X).  Here
B_array_start  is the first address for the array and .X acts as the
offset INDEX into the memory space that  follows.   This  is  called
simple  indexing  and  can  be used to store and recall data that is
organized into tables.

The 6502 as an 8 bit Processor

For programmers accustomed to high level  languages  often  the
assembly  language  of  processors  seems very limiting.  So far the
implementation of higher level language  assignment  statements  has
seemed  to be as simple as a few substitutions, a few LDA and STA to

page 3

get the job done.  Unfortunately this  is  about  the  easiest  high
level language concept to transfer to assembly and then only in very
restricted cases.
The 6502 is an 8 bit processor and all memory fetches (LDA etc)
read  values from 8 bit memory locations.  All numbers stored in the
accumulator are in the range of 0-255 or \$00-\$FF.   The  .X  and  .Y
registers  are  also  8  bit as is the .SP the stack pointer for the
6502.  This limits  the  stack  to  256  memory  locations  (located
between  addresses  \$0100-\$01FF).   The  program counter is a 16 bit
number which varies between \$0000 and \$FFFF.  The address  space  is
defined  as  the range of memory locations that can be pointed to by
the program counter.  In the case of the 6502, 16 bits, \$0000-\$FFFF,
0-65535 represents an address space of 64K, where 1K is  defined  as
1024 for binary applications.

Number Conversions
The  conversions  between hex and decimal representation can be
done however students should be aware that since the 6502  is  an  8
bit  machine,  everything  is  much  more  convenient  in  hex.  For
instance the address \$8000 is immediately recognizable as the  first
address  in the upper half of memory (because it begins \$80), at the
beginning of a memory page (because it ends in 00).  The  equivalent
number  in decimal 32768, unless memorized for what it is, cannot be
recognized as easily.  Similarly it is necessary when  dealing  with
I/O  ports to control individual bits of a memory location.  In this
case  the  binary  representation   of   %1010000   is   immediately
recognizable  as bits 7 and 5 of the byte set whereas the meaning of
the equivalent decimal number 160 is not nearly so clear.
It  is  advisable  to  use  hexidecimal  numbers for addresses,
binary numbers where  bit  on/off  states  are  important.   Decimal
numbers  should  be  used  only  when 'magic' numbers are such as 26
letters in the alphabet, 24 hours in a day, 30 days in a  month  etc
that  we  are accustomed to seeing as decimal are needed.  Note that
numbers 9 or smaller are the same in hex as decimal so there  is  no
problem for small constants.
The conversion between hex, binary and decimal will most likely
be  done  on  students  hand  calculators however recalling what you
learned in grade 3: There are 10 symbols for digits in  the  decimal
number  system  0-9.   All  numbers are stated with these 10 symbols
(note the number 10 is expressed in decimal).  Numbers larger than 9
are stated using ten's and unit's digits:

98 = 9*10 + 8

or more generally:

34256 = 3*10^4 + 4*10^3 + 2*10^2 + 5*10^1 + 6*10^0

Hexidecimal numbers are represented with 16 symbols  (\$10  =  16  in
hex),  the  symbols  0-9  and the letters A-F.  As units digits, 0-9
correspond to the decimal numbers 0-9, ie: 5 =  \$5  etc.   As  units
digits,  A-F correspond to the decimal numbers 10-15.  A hexidecimal
number can be expressed:

\$7A3F = \$7*\$10^3 + \$A*\$10^2 + \$3*\$10^1 + \$F*\$10^0

page 4

So far this is parallel to the representation of a decimal number as
above.  To  perform  a  conversion  you  would  simply  convert  the
hexidecimal numbers in the expansion to decimal.

\$7A3F = 7*16^3 + 10*16^2 + 3*16^1 + 15*16^0  =   31295 decimal

A  similar  operation  can be done in binary but once the meaning of
units, ten's and hundreds digits is understood then  the  expansions
of  binary  numbers  are  as  easily  calculated  as for hexidecimal
numbers.
Often conversions between hexidecimal and binary or the reverse
are necessary.  Similar expansions as above could be  performed  but
there is a short cut.  Noting that 2^4 = 16 and 2 is the base of the
binary  system  and  16 is base of the hexidecimal system, groups of
four binary digits must somehow correspond  to  hexidecimal  digits.
Observing that:

%0000 = \$0        %1000 = \$8
%0001 = \$1        %1001 = \$9
%0010 = \$2        %1010 = \$A
%0011 = \$3        %1011 = \$B
%0100 = \$4        %1100 = \$C
%0101 = \$5        %1101 = \$D
%0110 = \$6        %1110 = \$E
%0111 = \$7        %1111 = \$F

The  conversion  of  multidigit  hexidecimal  numbers   becomes
straight forward.

\$7A3F = \$7,A,3,F = %0111,1010,0011,1111 = %0111101000111111

This  is  very  useful when hardware tests have to be done.  If
the program counter of the 6502 were pointing at address \$7A3F  then
the  binary  representation  would  be  useful for understanding the
voltage values on the address pins of the  6502  chip.   In  digital
circuits,  5  volts  corresponds  to  logic  1  or binary 1; 0 volts
corresponds to logic 0 or binary 0.  The  binary  representation  of
the  address  %0111101000111111  is  also  the  logic levels for the
would read (counting from Adr15 to 0): 0V, 5V, 5V, 5V, 5V,  0V,  5V,
0V,  0V,  0V,  5V,  5V,  5V,  5V,  5V and 5V.  Summary of 6502 Basic
Structure

By now you  should  be  realizing  that  operation  of  digital
computers  are  really  not so mysterious at all.  True the internal
workings of a 6502 are very complex, it is not hard  to  imagine  it
being  made  up  of  a great number of smaller blocks that interpret
voltages as  logic  levels  and  perform  logical  operations.   The
acculumator  is  in fact eight circuits that can each hold a voltage
of 0 or 5 volts, organized into a unit that is  routed  out  of  the
processor  to memory by the STA instruction for instance.  Since the
actual  operations,  when  reduced   to   voltages   and   switching
transistors  are  very simple, they are very fast.  Even the 6502, a
relatively slow processor can perform a STA operation in  as  little
as  3  microseconds  or  perform 333,333 such STA's in one second of

page 5

operation in the slowest 1 MHz implementation.
We have been introduced to the accumulator and the  .X  and  .Y
index  registers.   As  mentioned  before  the  system  8  bit stack
pointer .SP points into an area of memory from \$0100-\$01FF.  For now
suffice it to say that the stack is very important to the  operation
of  the processor and the actual instructions that involve the stack
will be discussed later.  The program counter is a 16  bit  register
that  points  to  the  instruction in memory that is currently being
executed.   The  processor  status  register  which  has  not   been
discussed  until now, is a group of flags that represent the current
state of the processor and  the  results  of  the  last  calculation
performed.

Classes of 6502 Instructions
----------------------------

The  reader  will  be  introduced  to  several  classes of 6502
instructions.  Some instructions require arguments and some  do  not
and this is indicated where appropriate.

Data Transfer Instructions
There  are  several instructions in the family of data transfer
instructions but basically they  fall  into  two  categories,  those
which  move  data  between  memory and registers and those that move
data between registers.

LDA, LDX, LDY  arg    Load 'arg' into Accumulator, X or Y registers
STA, STX, STY  arg    Store the Accumulator, X or Y registers to memory 'arg'
STZ            arg   *Store the value zero into a memory location 'arg'

TAX, TAY           Transfer .A to .X, .A to .Y
TXA, TYA           Transfer .X to .A, .Y to .A
TXS, TSX           Transfer .X to .SP, .SP to .X

*65C02 Only

These instructions are very straight forward, they  move  an  8
bit  value  (\$00-\$FF)  from  the  one  place  to another.  After the
instruction, the data is in two places, where it was  and  where  it
was moved to.

Go to Instructions

The go to instructions are as follows:

JMP  dest          Jump, Set the Program Counter = 'dest'

JSR  dest          Jump to a Subroutine, saving the return address
RTS                Return from subroutine

The  JMP  statement  is  a  pure  'go to' which simply sets the
program counter to a new address and continues the execution of  the
code  at  that  point.   The  JSR statement first takes that current
program counter position and pushes it into the stack and then jumps

page 6

to the new address.  When the RTS instruction is encountered at  the
end  of the subroutine, the previous program location is pulled from
the stack and the processor continues after the subroutine call.

Compare Instructions

So far we have examined ways of moving data and unconditionally
changing the path of the program.  We  will  now  look  at  ways  to
conditionally  change  the path of the program.  In machine language
this is divided into two operations,  a  comparison  and  a  branch.
There are three compare statements:

CMP arg        Compare the .A
CPX arg                    .X
CPY arg                    .Y  to  'arg'

The  results  of  these  comparisons are recorded in the system
flags N-negative,  Z-zero  and  C-carry  for  later  use  in  branch
instructions.

Branch Instructions
Branch  instructions  test  the  state  of  one of the flags and
either branch or not.  Branches are relative jumps up to  128  bytes
forward  or back in the code determined by the offset argument.  The
branch instructions are:

BNE offset    Branch on result not equal    , result not zero: Z=0
BEQ offset    Branch on result equal        , result zero    : Z=1
BMI offset    Branch on result greater      , result <0      : N=1
BPL offset    Branch on result less or equal, result =>0     : N=0
BCC offset    Branch on carry clear                          : C=0
BCS offset    Branch on carry set                            : C=1
BVC offset    Branch on overflow clear                       : V=0
BVS offset    Branch on overflow set                         : V=1
BRA offset   *Branch always

*65C02 only

Arithmetic and Logical Instructions

We  have  examined  data  moving  and  comparing  instructions,
conditional  branches and unconditional changes to the program flow.
The last class of instructions we will examine  are  the  arithmetic
and  logical  instructions  where actual computations occur.  All of
these instructions involve the accumulator as one of the arguments.

ADC arg   Add with carry        .A + 'arg' + C  ==> .A  (C,V,N,Z)
SBC arg   Subtract with borrow  .A - 'arg' - !C ==> .A  (C,V,N,Z)
AND arg   Logical bitwise And   .A and 'arg'    ==> .A    (N,Z)
ORA arg   Logical bitwise Or    .A  or 'arg'    ==> .A    (N,Z)
EOR arg   Logical bitwise XOr   .A xor 'arg'    ==> .A    (N,Z)

The ADC and SBC use the carry to allow multibyte  additions  to
be  done using the C flag to carry to or borrow from the next higher

page 7

byte of the operation.  The V flag is the overflow flag.  It is  set
whenever a computation exceeds \$FF or goes under \$00.  Note that the
overflow  flag  can also be set using the SO set overflow pin on the
6502 allowing an additional input line to the processor.

Instruction Summary
-------------------
There are other instructions for the 6502  but  they  are  less
commonly  used then those introduced above.  It would be most useful
now to attempt to  use  the  instructions  learned  in  a  few  code
fragments to see how instructions interrelate.
```

### Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-1) was last changed on 04-Apr-2010 19:57 by Carsten Strotmann
G’day (anonymous guest) My Prefs
Articles
Hardware
Software
Applications
Memory Map Topic list
MicroUSB
AllNews
FAQ
Index
Languages
Code

What's New?

Voice and Data Cassettes
Atari Program Exchange (APX)
Atari Learning System Software
PLATO (Programmed Logic for Automated Teaching Operation)
Official country specific Atari software
• Belgium-Netherlands-Luxembourg • France • Germany • Italy • United Kingdom Thanks
Rarity 10
Statistics
All content in the Wiki is licensed under Creative Commons Share Alike License , unless otherwise noted.