677 lines
23 KiB
Plaintext
677 lines
23 KiB
Plaintext
====================================================================
|
||
DR 6502 AER 201S Engineering Design 6502 Execution Simulator
|
||
====================================================================
|
||
|
||
Supplementary Notes By: M.J.Malone
|
||
|
||
|
||
Addressing Modes - The Meaning of Arg, Offset and Dest
|
||
======================================================
|
||
|
||
Arg, Offset and Dest are the arguments for various
|
||
instructions. Since the arguments of instructions are usually
|
||
referred to by their addresses, the different methods of expressing
|
||
arguments are called addressing modes. 'Arg' type addressing modes
|
||
refer to a piece of data usually by its address. The 'Offset'
|
||
addressing mode is used by branch statements to give a program
|
||
destination by an offset byte. 'Dest' addressing modes are used to
|
||
point to a destination in the program.
|
||
|
||
|
||
The Use of Labels
|
||
=================
|
||
|
||
Assembly code more often uses assembler labels than actual
|
||
numbers as arguments to increase the readability. In the following
|
||
example the address of the VIA port, a commonly used memory
|
||
location, will be assigned a descriptive name to make its later
|
||
occurrences in assembly code more legible:
|
||
|
||
;
|
||
Port_A = $A001
|
||
;
|
||
|
||
Here is another example where a label is assigned the value of a
|
||
commonly used constant for improved readability:
|
||
|
||
;
|
||
MotorBit_Mask = %0000111
|
||
;
|
||
|
||
The use of labels can vastly change the appearance of assembly
|
||
but does not alter the behavior of addressing modes at all.
|
||
|
||
The Addressing Modes
|
||
====================
|
||
|
||
If there are No Arguments:
|
||
--------------------------
|
||
|
||
|
||
0) Implied
|
||
|
||
Some instructions (ie. CLC, SEC, CLD, NOP, BRK, PHA, RTI, RTS
|
||
etc) do not require arguments. In this case the argument is said to
|
||
be 'IMPLIED' in the instruction. This is called the implied
|
||
addressing mode.
|
||
|
||
In Assembly: CLC
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
page 2
|
||
|
||
'Arg': Refers to a place to find data, usually a memory location
|
||
-----------------------------------------------------------------
|
||
|
||
|
||
1) Accumulator
|
||
|
||
The vast majority of statements manipulate data in one way or
|
||
another and require data for arguments. The first and easiest piece
|
||
of data to use as an argument is the .A accumulator. Operator
|
||
instructions such as ROL, ROR, ASL and LSR (and INC and DEC in the
|
||
65C02) can use the ACCUMULATOR addressing mode.
|
||
|
||
In Assembly: ROR A
|
||
|
||
|
||
|
||
2) Immediate
|
||
|
||
Often a constant (a number) is required in calculations. LDA
|
||
#$00 takes the number (#) $00 and places it in the accumulator.
|
||
This is called the IMMEDIATE addressing mode. The following
|
||
statements can be used with the immediate addressing mode: ADC, AND,
|
||
CMP, CPX, CPY, EOR, LDA, LDX, LDY, ORA and SBC.
|
||
|
||
In Assembly: ADC #$01
|
||
LDA #Constant
|
||
EOR #Bit_Mask
|
||
CMP #5
|
||
|
||
|
||
3) Zero Page
|
||
|
||
The memory of the 6502 is divided into $100 (256) pages of
|
||
$100 (256) bytes each. The pages are numbered from 0 through $FF.
|
||
Page 0 address are in the range $0000-$00FF. Because 'Zero Page'
|
||
addresses can be specified in just one byte, instructions using them
|
||
as arguments can be executed more quickly by the 6502. The
|
||
statement LDA $80 causes the 6502 to fetch the value from memory
|
||
location $0080 and place it in the accumulator. Note that the only
|
||
difference between the immediate and zero page syntax is the #
|
||
number sign. LDA #$80 means load the number (#) $80 into the
|
||
accumulator. LDA $80 means load the contents of memory location
|
||
$0080 into the accumulator. When reading assembly code, the
|
||
difference is subtle but very important. Zero page addressing can
|
||
be used with every instruction that uses a data type argument.
|
||
(This excludes only those that use no argument: CLC, RTI, NOP etc.
|
||
or a program go to type argument JMP xxxx, JSR xxxx etc.)
|
||
|
||
In Assembly: ADC $80
|
||
LDA Temp ( Assuming $00 <= Temp <= $FF )
|
||
|
||
|
||
4) X and Y Indexed Zero Page
|
||
|
||
Often data is organized into groups of bytes as a table, an
|
||
array or a record. In this case it is convenient to specify an
|
||
address as an offset relative to the beginning of the data
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
page 3
|
||
|
||
structure. The 6502 implements this method using INDEXED
|
||
addressing. In this case the .X or .Y register is used to add to a
|
||
zero page address to result in an effective address. IE: LDA $80,X
|
||
(when .X=#$05) results in a fetch from memory location
|
||
($0080+$05)=$0085. This is called the ZERO PAGE X INDEXED
|
||
addressing mode. The zero page x indexed addressing mode can be
|
||
used with all instructions except BIT, CPX, CPY, LDX and STX. Note
|
||
that the .X and .Y registers can take on values of only $00-$FF so
|
||
the data table is limited in size to $100 bytes.
|
||
|
||
There is also a Y indexed zero page addressing mode but it can
|
||
be used only with the LDX and STX instructions. This may seem very
|
||
limiting at first but consider the high level expression:
|
||
|
||
code = Data[ Index_Pointer[i] ];
|
||
|
||
Where Index_Pointer[] is a small look-up table of pointers to data
|
||
in the look-up table Data[]. This can be coded easily as:
|
||
|
||
LDY i
|
||
LDX Index_Pointer,Y
|
||
LDA Data,X
|
||
STA code ; 14 machine cycles total
|
||
|
||
Note that indexed zero page addressing cannot result in an effective
|
||
address outside the zero page. If the sum of the value in the .X
|
||
register and the base address exceed $FF then the fetch will wrap
|
||
around to $00 again. For example if the .X register were #$20 then
|
||
the following memory fetch 'LDA $F0,X' would result in the effective
|
||
address of ($00F0+$20)=$0110 but the memory fetch would be done on
|
||
address $0010, still on the zero page.
|
||
|
||
Note that indexed zero page addressing always takes one machine
|
||
cycle more than non-indexed zero page addressing and hence should be
|
||
avoided. Often programmers get in the habit of creating small
|
||
indexed loops to perform operations resulting in a shorter length of
|
||
assembly code. In the case of mathematics subroutines that
|
||
manipulate multibyte numbers on the zero page, loops should never be
|
||
used. The extra overhead required in the INcrement or DEcrement and
|
||
the Branch instructions as well as the extra machine cycle in each
|
||
indexed reference can make these routines take almost twice as long
|
||
to execute as the unravelled equivalent non-indexed routines. 5)
|
||
Absolute
|
||
|
||
Usually arguments are not stored only on the zero page but
|
||
come from anywhere in memory. The easiest way to specify a general
|
||
memory address is to give the full 16 bit address. For example LDA
|
||
$8000, loads the 8 bit number ($00-$FF) from the memory location
|
||
$8000. This method of specifying an address is called the ABSOLUTE
|
||
addressing mode.
|
||
|
||
In Assembly: LDA Port_A
|
||
ADC $C000
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
page 4
|
||
|
||
6) X and Y Indexed Absolute
|
||
|
||
As with zero page addressing, absolute addressing can be
|
||
indexed as well allowing the entire address space of the 6502 to be
|
||
used in data tables. The X indexed absolute addressing mode may not
|
||
be used with: BIT, CPX, CPY, LDX, STX or STY but may be used with
|
||
LDY. The Y indexed absolute addressing has a similar list except it
|
||
can be used for LDX and not LDY and cannot be used for the operator
|
||
instructions ASL, DEC, INC, LSR, ROL or ROR.
|
||
The absolute X and Y indexed addressing modes require the SAME
|
||
number of clock cycles to perform as the non-indexed absolute mode.
|
||
There is therefore NO PENALTY in access time for referring to data
|
||
as part of a table through indexed addressing in absolute mode.
|
||
There is of course the INcrement or DEcrement statement, the Branch
|
||
and possibly the ComParison to create the indexed loop that requires
|
||
more time over sequential, direct, absolute fetches. The large size
|
||
of data tables located outside the zero page usually makes
|
||
sequential absolute fetches impractical since the number of assembly
|
||
language statements is directly dependent on the size of the table.
|
||
If the size of the table is variable then indexing must be used. It
|
||
is often desirable therefore to use indexed absolute addressing and
|
||
data tables to organize data and reduce the length of the code
|
||
through indexed loops.
|
||
There are exceptions to the above statement that indexed and
|
||
non-indexed absolute addressing require the same number of cycles to
|
||
execute. The first exception is the use of X indexing with the
|
||
operator instructions (Y indexing is not available) ASL, DEC, INC,
|
||
LSR, ROL and ROR. For these instructions, the indexed absolute
|
||
addressing mode always takes one additional cycle over the regular
|
||
absolute addressing mode.
|
||
The second exception has to do with memory pages. For absolute
|
||
indexed addressing, if the effective address calculation crosses to
|
||
the next memory page then an additional machine cycle is required
|
||
for the calculation of the effective address. If the .Y register
|
||
is #$80 then the memory fetch 'LDA $80C0,Y' crosses from memory
|
||
page $80 into memory page $81, since the effective address is $8140,
|
||
and therefore requires an extra machine cycle to perform. It is
|
||
recommended that data tables be placed entirely on one memory page
|
||
whenever possible to speed program execution.
|
||
|
||
In Assembly: LDA Game_Board,X
|
||
STA $1000,Y
|
||
|
||
|
||
7) Indirect
|
||
|
||
The indirect addressing mode is available on the 65C02 only.
|
||
In this mode a pointer is used to point to an address where the
|
||
actual data is stored. The 16 bit pointer is stored in two
|
||
consecutive memory locations on the zero page. The indirect memory
|
||
fetch 'LDA ($80)' causes the 6502 to look at memory locations $0080
|
||
and $0081 to form a 16 bit address. Memory location $0080 is
|
||
interpreted as the low byte of the address and $0081 as the high
|
||
byte. If the memory locations $0080 and $0081 hold the values $00
|
||
and $20 respectively then the vector ($80) is said to point to
|
||
address $2000. This method of indirection is standard in high level
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
page 5
|
||
|
||
languages and is very useful for pointer operations as in the C
|
||
programming language. The indirect addressing mode is used only for
|
||
the ADC, AND, CMP, EOR, LDA, ORA, SBC and STA.
|
||
|
||
|
||
In Assembly: LDA ($80)
|
||
STA (Data_Pointer)
|
||
|
||
|
||
8) Indexed Indirect
|
||
|
||
This addressing mode is used for tables of pointers to data.
|
||
Only the X index register can be used for the indexed indirect
|
||
addressing mode. In this case the .X register indexes through a
|
||
data table that is interpreted as 16 bit pointers. If the X
|
||
register is $04 then the statement: LDA ($80,X) takes value stored
|
||
in ($0080+$04)=$0084 as the low byte of the 16 bit pointer and the
|
||
value in $0085 as the high byte of the pointer. If the vector fetch
|
||
address exceeds $FF then it wraps around to $00 again as in zero
|
||
page indexed addressing. Note that the X register can only take on
|
||
meaningful values as an even number since each pointer is two bytes
|
||
long. One can easily remember how this mode works by remembering
|
||
that it is called 'Indexed Indirect' where the indexing is done
|
||
first and then the indirect pointer interpretation is done. Indexed
|
||
indirect addressing is used only for ADC, AND, CMP, EOR, LDA, ORA,
|
||
SBC and STA. Page boundaries have no effect on the indexed indirect
|
||
addressing mode.
|
||
|
||
|
||
In Assembly: LDA ($80,X)
|
||
ADC (Array_of_Pointers,X)
|
||
|
||
|
||
9) Indirectly Indexed
|
||
|
||
This addressing mode is used to index within a data table that
|
||
is pointed to by a vector on the zero page. Only the Y register can
|
||
be used for the indirectly indexed address mode. In this case a
|
||
vector on the zero page points to the first address in a data table
|
||
and then the Y register indexes through the table. If the Y
|
||
register is $04 and $0080 and $0081 contain the values $00 and $20
|
||
respectively then the instruction 'LDA ($80),Y' first fetches the
|
||
vector at $0080 and $0081 which points to $2000. The Y register is
|
||
then added for an effective fetch address of ($2000+$04)=$2004. One
|
||
can easily remember how this mode works by remembering that it is
|
||
called 'Indirectly Indexed'. This mode does the indirect pointer
|
||
interpretation first and then performs the indexing. Indirectly
|
||
indexed addressing is used only for ADC, AND, CMP, EOR, LDA, ORA,
|
||
SBC and STA.
|
||
Page boundaries do effect the indirectly indexed address mode.
|
||
If the Y index causes the effective address to cross into the next
|
||
memory page then the fetch requires an additional machine cycle.
|
||
The indirectly indexed addressing mode is very useful for
|
||
accessing very large arrays of data. When the size of the array
|
||
surpasses the $00-$FF limit of the Y index register, the high order
|
||
byte of the pointer can be incremented to point into the next memory
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
page 6
|
||
|
||
page. The following is an example of addressing such a large
|
||
array.
|
||
|
||
;
|
||
LDY #$00
|
||
Next_Char LDA (String_of_Char),Y ; Get the character from the
|
||
; string
|
||
BEQ End_Of_String ; String ends with a NULL - #$00
|
||
JSR Print_Char ; A Subroutine to print
|
||
; characters
|
||
INY ; Go on to next character
|
||
BNE Next_Char ; If have not finished the page
|
||
; - Next
|
||
INC String_of_Char+1 ; Finished page - Point to next
|
||
; page
|
||
JMP Next_Char ; Go on to first char of next
|
||
; page
|
||
;
|
||
;
|
||
End_Of_String
|
||
|
||
|
||
|
||
'Offset': Branch Destination
|
||
-----------------------------
|
||
|
||
|
||
10) Relative
|
||
|
||
The relative addressing mode is used by the Branch statements:
|
||
BCC, BCS, BEQ, BMI, BNE, BPL, BRA, BVC and BVS. The argument in
|
||
this case uses one byte as an offset byte. This offset byte allows
|
||
the branch instruction to branch up to 128 bytes forward and 127
|
||
bytes backward in the program machine code. This must seem like a
|
||
very 'coded', inconvenient, method of doing things. In actuality
|
||
this is taken care of by the assembler. This is one case where
|
||
assembler directives are used to make life easy for the programmer.
|
||
The programmer must however keep in mind that there are limits to
|
||
the range of relative branches when using them. The following is an
|
||
example of the assembly code use of a relative branch statement:
|
||
|
||
;
|
||
Check_Again LDA Port_A ; Wait for a bit to go high on Port A
|
||
BEQ Check_Again
|
||
;
|
||
|
||
In this example, the assembler records the position of the label
|
||
'Check_Again'. When the label is used in the relative branch
|
||
statement 'BEQ' the ASSEMBLER calculates the required offset byte
|
||
for the relative addressing mode used for the argument of 'BEQ'
|
||
instruction.
|
||
For the user, the only worry is a 'Branch Out of Range Error'
|
||
at assembly time. If this occurs, then the logic of the branch must
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
page 7
|
||
|
||
be reversed and a JuMP statement used. For example:
|
||
|
||
;
|
||
BEQ Where_to_Go ; <=== This branch is out of range
|
||
;
|
||
|
||
becomes:
|
||
|
||
;
|
||
BNE Continue_On ; <=== This branch is short - No problem
|
||
JMP Where_to_Go ; <=== JMP instructions are never out of
|
||
; range
|
||
Continue_On
|
||
;
|
||
|
||
The addition of the BRA - branch always statement to the 65C02 is
|
||
very helpful. If the user knows that the length of a JMP is within
|
||
range of a branch, it can be converted to a 'BRA Label' instruction
|
||
saving one machine cycle, critical on maximum repeat rate loops.
|
||
|
||
|
||
'Dest': Jump Destination
|
||
-------------------------
|
||
|
||
11) Absolute
|
||
|
||
This addressing mode is exactly the same in syntax as the
|
||
absolute addressing mode (see 5 above) except the memory location is
|
||
not used as a data argument as before but as a memory location at
|
||
which to find the next instruction operation code. The absolute
|
||
mode is used by the JMP and JSR instructions and is not influenced
|
||
by memory pages. Once again as in the relative addressing mode, the
|
||
ASSEMBLER keeps track of actual addresses within programs and the
|
||
program merely communicates their desires through the use of labels.
|
||
|
||
|
||
In Assembly: JMP Try_Another
|
||
JSR Print_a_Char
|
||
JMP $E000
|
||
|
||
|
||
12) Absolute Indirect
|
||
|
||
This addressing mode is used by the JuMP statement to jump to
|
||
an address pointed to by a vector. The vector, similar to the
|
||
pointers used in indirect data addressing, is stored as a 16 bit
|
||
pointer, low byte and high byte. The vector used in absolute
|
||
indirect addressing may be located anywhere in memory, not
|
||
necessarily based on the zero page as with indirect data argument
|
||
addressing. The following is an example:
|
||
|
||
;
|
||
JMP ($2000)
|
||
JMP (Prog_Start_Vector)
|
||
JMP ($FFFC) ; Simulate a Reset
|
||
;
|
||
Note that the address given in the instructions is an absolute, 16
|
||
bit address.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
page 8
|
||
|
||
13) Indexed Absolute Indirect
|
||
|
||
This addressing mode is also used by the JuMP statement to jump
|
||
to an address pointed to by a vector. As in absolute indirect, the
|
||
vector is stored as a 16 bit pointer, the low byte then the high
|
||
byte. In indexed absolute indirect addressing, the X register is
|
||
used to index a table of JuMP vectors in very much the same way as
|
||
Indexed Indirect (mode 8) data addressing indexes a table of data
|
||
pointers. Unlike the absolute indirect address mode, the table of
|
||
jump vectors must be based on the zero page. The following is an
|
||
example:
|
||
|
||
;
|
||
LDX Control_Var
|
||
JMP (On_Goto_List,X)
|
||
;
|
||
|
||
This is an example of using the indexed absolute indirect addressing
|
||
mode to simulate a BASIC 'ON GOTO' statement, similar to the case
|
||
and switch statements of structured languages.
|
||
|
||
In Assembly: JMP ($80,X)
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
page 9
|
||
|
||
Summary Table of Addressing Modes
|
||
---------------------------------
|
||
|
||
Type of Addressing Example Comments
|
||
=====================================================================
|
||
Implied CLC What no arguments is called
|
||
|
||
Accumulator ROR A When the .A accumulator is the arg
|
||
Immediate LDA #$00 When a (#) number is the argument
|
||
Zero Page LDA $00 When an address <$100 is used
|
||
Zero Page,X LDA $00,X Indexes a table starting at <$100
|
||
Zero Page,Y LDX $00,Y Indexes a table starting at <$100
|
||
Absolute LDA $1000 When a general address is used
|
||
Absolute,X LDA $1000,X Indexes a table anywhere in memory
|
||
Absolute,Y LDA $1000,Y Indexes a table anywhere in memory
|
||
*Indirect LDA ($80) Uses $80, $81 as a pointer to arg
|
||
Indexed Indirect LDA ($80,X) For a table of pointers to arg
|
||
Indirectly Indexed LDA ($80),Y For a pointer to a table of args
|
||
|
||
Relative BEQ $FE For relative branches
|
||
|
||
Absolute JMP $E000 JMPs to a particular address
|
||
Absolute Indirect JMP ($0080) Uses $80,$81 as a JMP vector
|
||
*Indexed Absolute
|
||
Indirect JMP ($80,X) Uses a table of JMP vectors
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
page 10
|
||
|
||
Summary of Addressing Mode Restrictions:
|
||
----------------------------------------
|
||
|
||
The instruction classes are listed from the most to the least
|
||
limiting and the modes available or unavailable to each instruction
|
||
class. Simply, BIT, TRB and TSB, the bit manipulating instructions
|
||
are most restrictive. CPx, LDx and STx for the X and Y registers
|
||
are next most restrictive. The operator instructions ASL, ROR, ROL,
|
||
LSR, INC and DEC are next most restrictive. The arithmetic and
|
||
logical instructions: ADC, AND, EOR, ORA, SBC and the accumulator
|
||
LDA, CMP and STA are least restrictive.
|
||
|
||
|
||
Instructions 6502 65C02
|
||
====================================================================
|
||
|
||
|
||
BIT Zero Page and Added: Immediate, and X indexed
|
||
Absolute only Zero Page and Absolute
|
||
|
||
|
||
|
||
TRB, TSB Zero Page and Absolute only
|
||
|
||
|
||
|
||
CPX, CPY Immediate, Zero Page
|
||
and Absolute only
|
||
|
||
|
||
|
||
STX Zero Page,Y \
|
||
Zero Page and Absolute
|
||
STY Zero Page,X /
|
||
|
||
|
||
|
||
STZ Absolute, Zero Page and
|
||
X indexed Absolute and Zero Page
|
||
|
||
|
||
|
||
LDX Y indexed Zero Page and Absolute \
|
||
and:
|
||
LDY X indexed Zero Page and Absolute /
|
||
|
||
Immediate, Zero Page and Absolute
|
||
|
||
|
||
|
||
|
||
ASL, LSR, Accumulator, Zero Page,
|
||
ROR, ROL Absolute, X indexed
|
||
Zero Page and Absolute
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
page 11
|
||
|
||
DEC, INC, Zero Page, Absolute and Added: Accumulator
|
||
X indexed Zero Page and
|
||
Absolute
|
||
|
||
|
||
|
||
STA All except Immediate
|
||
and:
|
||
Added: Indirect
|
||
|
||
ADC, AND, CMP, All except Accumulator
|
||
EOR, LDA, ORA, and Zero Page,Y
|
||
SBC
|
||
|