💾 Archived View for gemini.spam.works › mirrors › textfiles › programming › more65.txt captured on 2022-04-29 at 00:32:09.

View Raw

More Information

⬅️ Previous capture (2020-10-31)

-=-=-=-=-=-=-

      ====================================================================
	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
      -------------------------
 
	   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
      ----------------
 
	    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
      -------------
 
             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
      ----------------
             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
      -------------------------
 
	     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.