GENWiki

Premier IT Outsourcing and Support Services within the UK

User Tools

Site Tools


archive:programming:more65
    ====================================================================
DR  6502    AER 201S Engineering Design 6502 Execution Simulator
    ====================================================================
    Supplementary Notes                                   By: M.J.Malone
    
    			   More 6502 Assembly Code
    			   =======================
    
    There  were  several  instructions not introduced in the first
    introductory file 'START65.DOC'.  The  remaining  6502  instructions
    will be discussed here.
    Operator Instructions
    ---------------------
    
   These  are  instructions  of  only  one  argument  and  include
     incrementing, decrementing and bit shifts.
INC arg        Increases the value of 'arg' by one
DEC arg        Decreases the value of 'arg' by one
INX            Increment .X
INY            Increment .Y
DEX            Decrement .X
DEY            Decrement .Y
ROR arg        Rotates the argument and C flag bits one to the right
ROL arg        Rotates the argument and C flag bits one to the left
LSR arg        Logical Shift Right: shifts bits one to the right
ASL arg        Arithmetic Shift Left: shifts bits one to the left

The increment and decrement instructions are very useful when

    dealing with pointers and vectors.  Since the .X and  .Y  are  index
    registers  used to index within memory spaces, the INX, INY, DEX and
    DEY instructions are used to move on the the next or previous memory
    entry.  The .X and .Y are also used as quick counters and here again
    the increment and decrement are very useful.
   The bit rotating and shifting instructions  are  used  both  in
    arithmetic  operations and bit pattern manipulation for encoding and
    decoding.  An LSR can be thought of as dividing by 2 and the ASL  as
    multiplying  by  2.   Along with the ADC and SBC, these instructions
    are key to multiplication and division.

Flag Setting and Clearing

  1. ————————

The programmer is able to directly influence the flags through

    the following statements:

CLC Clears the Carry Flag

           SEC            Sets the Carry Flag
           CLD            Clears 'Decimal' Mode
           SED            Sets 'Decimal' Mode
           CLI            Clears the Interrupt Disable Flag
           SEI            Sets Interrupt Disable Flag
           BRK            Break Instruction
           CLV            Clears the Overflow Flag

page 2

Carry Flag

   The  carry  flag  is  set  and  cleared by arithme tic and shift
    statements and is influenced by comparisons.  In general the flag is
    used as follows: In ROL, ROR, ASL and LSR statements the carry  flag
    is  used  as  a  9th  bit  in  the accumulator either above the most
    significant bit (MSB) or below the least significant bit (LSB).   In
    SBC  and ADC statements it is used as a 9th bit above the MSB to act
    as a carry or a borrow.  Since comparisons use  a  subtraction,  the
    carry flag reflects a similar state for CMP, CPX, and CPY as for the
    statement  SBC.  The carry flag is NOT used as a borrow-from in CMP,
    CPX or CPY.  For example using CMP to compare #$05 and #$05  results
    in a result of zero regardless of the state of the carry flag before
    the  comparison.   After the comparison however, if a borrow was not
    required to do the comparison the carry flag will be set  indicating
    no  borrow  has  occurred.   The above comparison will result in the
    carry flag being set.  Increment instructions DO NOT  influence  the
    carry flag, nor do AND, ORA or EOR.

Negative and Zero Flags

   Neither  the  negative  or  zero  flag can be explicitly set or
    cleared in a SEx or CLx instruction.   All  instructions  that  move
    data  to  a  location inside the processor or compare data within in
    any way except pulling from the stack  influence  the  negative  and
    zero flags.  That means all instructions except JMP, JSR, RTS, Sets,
    Clears, Pushes, Pulls, STA, STX, STY and Branches alter the negative
    and  zero  flags.   If  the  data  being transferred is zero or if a
    calculation results in the number zero, regardless of the  state  of
    the  carry flag, the zero flag will be set (Z=1).  The negative flag
    will have the same logic state as the MSB of the data moved  or  the
    result of the calculation.  As a result, the negative and zero flags
    will  never both be set at the same time because a zero has all bits
    including the MSB clear.  The zero flag and testing  for  zero:  BNE
    (Z=0?) and BEQ (Z=1?) are quite straight forward.
   The  negative  flag  has  some peculiar properties.  First note
    that there is no such thing as a negative number in  the  6502.   If
    required  to judge if a number is negative, the 6502 will assume all
    numbers between  #$FF  and  #$80  are  negative  correspond  to  the
    numbers  -#$01  to -#$80 respectively.  The numbers between #$00 and
    #$7F  are  assumed  positive  corresponding  to  +#$00   and   +#$7F
    respectively.   The  comparison  and  subtraction instructions often
    cause students confusion in relation to the negative flag.  Often  a
    following will be required:

;

    ; If arg1<arg2 then ****
    ;
	  lda arg1
	  cmp arg2
	  bmi ****
    ;

On the surface this seems to be ok but remember the limits on a

    negative  number  for the 6502.  If arg1=#$02 and arg2=#$05 then the
    result is #$FD which falls into the range #$FF to #$80 and hence  is
    considered negative and the N flag is set.  Looking at this from the
    point  of  view  of  the 6502, we move the logic value of the MSB of

page 3

#$FD to the N flag and we get N=1. 2-5<0 and N=1 so there is no

    problem.   The  problem comes when arg1=#$02 and arg2=#$85 (meant to
    be the positive number +#$85) since the result  is  #$7D.   We  know
    that #$02-#$85<0 but the MSB of #$7D is 0 so as a result N=0 and the
    above  code  example  would  malfunction.   The  important  thing to
    remember is that the negative flag does not actually tell you  if  a
    number  is  negative  but  instead whether the highest bit is set or
    not.

Decimal Mode Flag

   When set, the 6502 works in a 'decimal'  mode  when  performing
    the  ADC  or  SBC  instructions.   This  mode  uses the binary coded
    decimal (BCD) storage format.  The BCD representation of the decimal
    number 25 would be #$25 or #%0010 0101.  In BCD mode the  6502  will
    use  only 100 of the possible $100 (256) states for the value in the
    accumulator.  The 6502 automatically does all adjustments  to  cause
    results  to be in BCD mode and all arguments must be valid BCD coded
    numbers.  For example #$55+#$27  in  BCD  mode  =  #$82.   There  is
    absolutely  nothing magic about decimal mode and almost as little of
    interest.  One common bug in an IRQ interrupt program is  forgetting
    to  clear  the  decimal  flag before doing any calculations.  If the
    main program uses decimal mode sometimes the IRQ may occur when  the
    decimal  mode is in effect.  This can cause very unusual problems if
    the programmer is unaware of the problem.

Interrupt Masking Flag

   If your IRQ (interrupt request) pin is connected to a source of
    interrupt pulses then the processor will  be  interrupted  and  will
    begin  executing  the interrupt program.  The interrupt program is a
    separate program that the programmer must write  if  interrupts  are
    used.  The IRQ is a maskable interrupt meaning that the software can
    instruct  the  processor  to  ignore  it.   The method of doing this
    involves  setting  the interrupt disable bit in the processor status
    register.  The instruction SEI prevents  interrupts  from  occurring
    and CLI allows them.
   The  6502  has  a  second  interrupt request pin, the NMI which
    stands for non-maskable interrupt request.   SEI  and  CLI  have  no
    effect  on  this  interrupt: it will always be obeyed.  On the 65C02
    the RST (reset) pin  behaves  as  a  particular  type  of  interrupt
    similar to the NMI.

Break Flag

   There  is  one  instruction  in  the  6502's  set  that is very
    confusing to many students; it is the BRK  break  instruction.   The
    break  does  not actually stop the execution of the processor like a
    HALT type instruction might.  The 6502 has no instruction that  will
    HALT  execution.   There  are  many undefined operation codes on the
    NMOS 6502 that do unpredictable  things  and  some  that  crash  the
    processor.   These 'crash codes' could be considered HALT statements
    since after them nothing happens.  The break instruction simulates a
    hardware IRQ with the one difference that it sets the B=1 break flag
    in the processor status register.  Since  there  are  no  statements
    that  directly  test  the break flag this will be explained later in
    the stack operations section.  The programmer must be aware that  if
    they use both BRK instructions in there code and IRQ interrupts, the
    IRQ  program  should test the break flag to discover how the routine
    was initiated.

page 4

Overflow Flag

   The overflow flag is used for  the  ADC  and  SBC  instructions
    only.  It represents an arithmetic overflow.  Note the overflow flag
    can  also be set by a pulse on the SO (set overflow) pin of the 6502
    and if used cleverly can be a very  fast  input  pin  in  a  polling
    loop.

Flag Summary

   It  is  the  interrelation of instructions and the system flags
    that makes  efficient  code.   In  the  following  loop  it  is  the
    interrelation  between  the DEx instruction and the Z zero flag that
    allows branching without a comparison statement, saving at  least  3
    clock cycles per iteration resulting in a execution time 38% faster.

;

	  ldx #$00
	  ldy #$00
    Delay       ???????
	  inx
	  bne Delay
	  inx
	  bne Delay
    ;

This routine is often used for software delays where clock cycle

    counts  are important but even more important is its use in counting
    loops for measurements.  If the ?'s were replaced  by  some  polling
    instructions  testing  say  the  overflow  flag set by some external
    source it could be a very powerful measurement tool.  The faster the
    counting  executes,  the  more  accurate  the  measurement  of  time
    periods.   Mastery  of  the  flags is an important ingredient in the
    efficient use of 6502 assembly code.

Stack Operations

  1. —————

The stack is a reserved area in memory from $0100 to $01FF

    which is referred to as page 1 of the 6502 memory.   The  .SP  stack
    pointer  register  is  used  to  index within this space.  The stack
    pointer starts at #$FF which points to  $01FF.   The  stack  pointer
    points   to  the  next  free  stack  location.   The  stack  pointer
    decrements as the stack fills and increments as the  stack  empties.
    There  is  nothing  (in  hardware)  to  prevent the stack from being
    pushed below #$00 to #$FF again or being  pulled  from  #$FF  around
    to  #$00.   When  a Push instruction is executed, the pushed data is
    put in the free stack space that the pointer is  currently  pointing
    to and the stack pointer is decremented by one.  In a pull operation
    the  stack  pointer  is  incremented  and  the data is read from the
    location that is being pointed to.

PHA Pushes the .A into the stack

 PLA            Pulls .A out of the stack
 PHP            Pushes the status register (.R) into the stack
 PLP            Pulls the .R out of the stack

page 5

PHX *Pushes the .X register into the stack

 PLX           *Pulls the .X register out of the stack
 PHY           *Pushes the .Y register into the stack
 PLY           *Pulls the .Y register out of the stack
  • 65C02 only

For those unfamiliar with the use of stacks, it is recommended

    that computer theory text be consulted  if  a  full  description  is
    desired.  In practice in 6502 assembly language the stack is used by
    the  hardware  in  the JSR-RTS and IRQ/NMI/BRK/RST-RTI instructions.
    The user has direct access to the data in the stack through the  PHx
    and  PLx  instructions.  The most important concept is balancing the
    number of pushes on any program path with the number of pulls in the
    path.  This is required so that the stack will not continue  filling
    endlessly,  overflowing or empty past the point that useful data was
    first pushed in.  It is also necessary  to  balance  the  number  of
    pushes   and   pulls   on  a  particular  program  path  within  all
    subroutines.  This is required since  the  stack  is  used  for  the
    return  addresses  for  the  subroutine  call.   If any user data is
    pushed on top of the return address  then  it  must  be  pulled  off
    before  the  RTS  statement  so  that the program/subroutine nesting
    structure, recorded  in  the  return  addresses  in  the  stack,  is
    preserved.
    IRQ/NMI and BRK routines require the stack as well, pushing in
    not  only the return address but the processor status register (.R).
    Though it is not required, I cannot imagine an IRQ routine where the
    user does not first push the .A, .X and .Y registers into the  stack
    as  well  to preserve the processor context.  The reason for this is
    simple.  The IRQ could come at any time, perhaps in the middle of  a
    calculation  where  all of the register values are critical.  If the
    IRQ must preserve the values of all registers so  that  upon  return
    the  main program continues as if the IRQ had not occurred.  In this
    way it is possible to make the execution of IRQ programs transparent
    to the main program.
    The stack can also be used with the combination of PHP  \  PLA
    to   transfer  data  from  the  processor  status  register  to  the
    accumulator.  This is very useful  to  test  flags  that  cannot  be
    directly tested in a branch instruction.  The break or decimal flags
    are examples of such flags.

Miscellaneous

  1. ————

BRK Break Instruction

           BIT arg        Bit Test
          *TRB arg        Test and Reset Bits
          *TSB arg        Test and Set Bits
           RTI            Return from Interrupt
           NOP            No Operation
  • 65C02 only

The BRK break instruction, as said before under the flags and

    stack discussion, does  not  actually  halt  the  execution  of  the

page 6

processor. The following instruction will effectively halt the

    execution of the processor:

;

    Halt        JMP Halt
    ;

This is of course nothing more than an endless loop. The break

    instruction  actually  simulates  an  IRQ  in  software with the one
    difference that it also sets the  B  break  flag  in  the  processor
    status  register.   When  a  BRK instruction is reached, a $00 as an
    operation code, the processor pushes the  program  counter  and  the
    processor  status register onto the stack.  The processor then loads
    the $FFFE-FFFF IRQ vector position  into  the  program  counter  and
    begins executing instructions.
   The  BIT  bit  test  instruction is somewhat strange.  It first
    fetches the argument and copies its 7th (MS) bit into  the  negative
    flag  and  its  6th  bit into the overflow flag.  It then performs a
    logical AND with the accumulator discarding the result  but  setting
    the zero flag accordingly.
   The  TRB  test and reset bits instruction is similar to the BIT
    instruction in that bits 7 and 6 of the argument are copied into the
    N and V flags.  A logical AND with the complement of the accumulator
    resets the bits of the argument  that  are  set  to  a  one  in  the
    accumulator.   The  Z  flag  is  set according to the result and the
    result is stored back into the memory location referred  to  in  the
    argument.
   The  TSB  test  and  set bits instruction is similar to the TRB
    instruction in that bits 7 and 6 of the argument are copied into the
    N and V flags.  A logical OR with the accumulator sets the  bits  of
    the  argument  that are set to a one in the accumulator.  The Z flag
    is set according to the result and the result is  stored  back  into
    the memory location referred to in the argument.
   The  TSB and TRB instructions were added to the instruction set
    to allow multiple processor systems to  share  resources  through  a
    series of semaphores.
   The RTI return from interrupt instruction returns the processor
    from an IRQ, NMI or BRK interrupt.  On the 65C02, since the RST line
    is  treated  by  the  processor  as  just  another  interrupt, it is
    possible to RTI to the program that  was  running  previous  to  the
    signal  on  the reset line.  RTI retrieves processor status register
    and the program counter from the stack and returns to executing  the
    original program.
   The  NOP  no  operation instruction is just that, no operation.
    If the processor encounters this instruction it does nothing for two
    machine cycles.  The NOP instruction does not change  the  processor
    status register.

page 7

65C02 Expansions

  1. —————

STZ arg Store #$00 to the memory location 'arg'

           BRA offset     Always do a relative branch by 'offset' bytes
           PHX            Push .X into the stack
           PHY            Push .Y into the stack
           PLX            Pull .X from the stack
           PLY            Pull .Y from the stack
           TRB arg        Test and Reset Bits
           TSB arg        Test and Set Bits

All of these instructions have been explained in the previous

    sections  explaining  the  6502  instruction  set.

Rockwell 65C02 Expansions

  1. ————————

BBRx arg,offset

           BBSx arg,offset
           RMBx arg
           SMBx arg

These instructions are present only on the Rockwell version of

    the 65C02.  Though some students have  found  this  version  of  the
    processor,  there  is no guarantee that the next batch of processors
    ordered will be of the Rockwell variety.  As  a  result  it  is  not
    recommended  that  students  base  their  software structures on the
    presence of these instructions since last minute problems may result
    in a change of processor.
   Rockwell added four types of instructions to their processor to
    make the use of  bit  fields  easier.   For  each  instruction,  the
    numbers  0-7  must  be  substituted  for  the 'x' to give the actual
    operation codes.  There are therefore eight RMBx instructions: RMB0,
    RMB1, RMB2, RMB3, RMB4, RMB5, RMB6, and RMB7.  Note that these  four
    instruction types are the only 6502 instructions that do not conform
    to the standard of 3 character mnemonic codes.
   The BBRx and BBSx are branch statements.  These statements test
    a particular bit (bit 'x') of the argument which must be on the zero
    page  and  branches  if  it is set (BBSx) or branches if it is reset
    (BBRx).  The branch is a relative branch by 'offset'  bytes  in  the
    same way as regular branches.
   The  RMBx reset memory bit and SMBx set memory bit instructions
    are used to reset or set individual memory bits anywhere on the zero
    page of memory.  The argument is the memory  location  and  the  'x'
    specifies the bit number to be manipulated.



/home/gen.uk/domains/wiki.gen.uk/public_html/data/pages/archive/programming/more65.txt · Last modified: 2000/12/16 02:37 by 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki