Calculating the backward offset of a branch

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Kris1978
Posts: 41
Joined: 21 May 2018

Re: Calculating the backward offset of a branch

Post by Kris1978 »

Chromatix wrote:
From my point of view, the CPU itself is pretty simple and easy to learn. There are three basic areas to master: the operations of the ALU, the addressing modes, and the ways to influence control flow.

What's not so simple is learning to use it effectively, because its simplicity means it has some pretty severe limitations; working around those limitations introduces complexity in your code that isn't inherent in the algorithm for solving your underlying problem. That's why I often sketch out my solutions in C or pseudo-C before translating them into assembly.

With more modern CPU architectures like ARM, the limitations of the CPU itself are much less severe, so your code often looks much more like the algorithm required.
My level of knowledge so far is not so great in order to fully appreciate your message/advice (I hope you get what I mean and not be offended) but I will keep it in the back of my mind for later use as my knowledge will be increased (hopefully)
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: Calculating the backward offset of a branch

Post by BigEd »

There's a great diagram of the programmer's model for the 6502 by Bob Sander-Cederlof - see here:
viewtopic.php?p=42766#p42766
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Calculating the backward offset of a branch

Post by Chromatix »

I looked at that diagram and immediately saw improvements that could be made. In the process of fixing it, I was also able to add the 65c02 instructions.

Code: Select all

                         TRANSFER OPERATIONS
                         -------------------

 +-----------------------------------------------------------------+
 |                             MEMORY                              |
 |                           $0000-$FFFF                           |
 +-----------------------------------------------------------------+
      ^    |         ^         ^    |                   ^    |
      |    |         |         |    |                   |    |
     STX  LDX       STZ       STA  LDA                 STY  LDY
      |    |                   |    |                   |    |
      |    V                   |    V                   |    V
 +--------------+         +--------------+         +---------------+
 |              |---TXA-->|              |<--TYA---|               |
 |  X-REGISTER  |         |  A-REGISTER  |         |  Y-REGISTER   |
 |              |<--TAX---|              |---TAY-->|               |
 +--------------+<-       +--------------+       ->+---------------+
      |    ^       \           ^    |           /
      |    |       PLX         |    |         PLY
     TXS  TSX        \        PLA  PHA        /
      |    |         PHX       |    |       PHY
      V    |           \       |    V       /
 +--------------+       ->+--------------+<-       +---------------+
 |              |         |              |---PLP-->|               |
 |  S-REGISTER  |         |    STACK     |         |  P-REGISTER   |
 |              |         | $0100-$01FF  |<--PHP---|   NV*BDIZC    |
 +--------------+         +--------------+         +---------------+


                           OTHER OPERATIONS
                           ----------------

 +-----------------------------------------------------------------+
 |               A-REGISTER    X-REGISTER    Y-REGISTER    MEMORY  |
 |-----------------------------------------------------------------|
 |  Arithmetic:  INC A         INX           INY           INC     |
 |               DEC A         DEX           DEY           DEC     |
 |               ADC           ---           ---           ---     |
 |               SBC           ---           ---           ---     |
 |                                                                 |
 |  Logical:     AND           ---           ---           TRB     |
 |               ORA           ---           ---           TSB     |
 |               EOR           ---           ---         SMB, RMB  |
 |                                                                 |
 |  Shift:       ASL           ---           ---           ASL     |
 |               LSR           ---           ---           LSR     |
 |               ROL           ---           ---           ROL     |
 |               ROR           ---           ---           ROR     |
 |                                                                 |
 |  Compare:     CMP, BIT      CPX           CPY           ---     |
 +-----------------------------------------------------------------+

 +----------------------------------------------------+
 |  Status:      SET           CLEAR         BRANCH   |
 |----------------------------------------------------|
 |       CARRY   SEC           CLC           BCC, BCS |
 |  O(V)ERFLOW   ---           CLV           BVC, BVS |
 |     DECIMAL   SED           CLD           -------- |
 |   INTERRUPT   SEI           CLI           -------- |
 |        ZERO   ---           ---           BEQ, BNE |
 |    NEGATIVE   ---           ---           BPL, BMI |
 |                           unconditional   BRA      |
 |                           zero page bit   BBR, BBS |
 +----------------------------------------------------+

    Jump:     JMP, JSR   -------------------------------------------
                         6502 Programming Model, Bob Sander-Cederlof
    Return:   RTS, RTI          Apple Assembly Line, May 1981
                         http://txbobsc.com/aal/1981/aal8105.html#a4
    Other:    NOP, BRK   -------------------------------------------
              STP, WAI   Extended for 65c02 by Jonathan Morton, 2018
Last edited by Chromatix on Wed Nov 14, 2018 12:42 pm, edited 1 time in total.
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: Calculating the backward offset of a branch

Post by BigEd »

Nicely done!
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Calculating the backward offset of a branch

Post by Chromatix »

Playing spot-the-difference with the original could be a fun pastime.

In particular, I moved BIT from "logical memory" to "compare accumulator", since it does actually perform a logical (as opposed to arithmetic) comparison and doesn't modify its operands. That made room for TRB and friends in the "logical memory" section. I also renamed the MINUS flag to NEGATIVE to match its initial, and highlighted the V of OVERFLOW. Everything else could be slotted in logically, more or less in-place.

The main concept missing from the diagram now is an explanation of the various addressing modes. English descriptions of these tend to be either wordy or ambiguous. WDC has reasonably clear diagrams in its datasheets, but those take up a lot of space and might still not be entirely clear to a complete beginner. I may be able to come up with something after some thought…
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: Calculating the backward offset of a branch

Post by BigEd »

BTW, Kris1978, you might want to check out the older thread
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Calculating the backward offset of a branch

Post by Chromatix »

This is my best effort of covering it in English:

Code: Select all

                           ADDRESSING MODES
                           ----------------

   MODE        SYNTAX    OPERAND LOCATION

 Implicit:               None.
 Immediate:     #00      Operand is literally the operand byte.
 Relative:      label    Operand byte is 2s-complement offset from byte following it.

 Zero Page:     $00      Zero-page address follows opcode, operand loaded from there.
 Absolute:      $0000    16-bit address follows opcode, operand loaded from there.

 ZP Index X:    $00,X    X register is added to zero-page address.
 ZP Index Y:    $00,Y    Y register is added to zero-page address.
 Indexed X:     $0000,X  X register is added to 16-bit address.
 Indexed Y:     $0000,Y  Y register is added to 16-bit address.

 ZP Indirect:  ($00)     Initial address (zero page or absolute) is actually the location
 Indirect:     ($0000)   of the 16-bit address of the operand.

 ZP PreIndex:  ($00,X)   As with Indirect, but the initial address has X added to find
 Index Indir:  ($0000,X) the location of the 16-bit operand address.

 ZP PostIndex: ($00),Y   After indirecting, the Y register is added to the address fetched
                         from zero page.  This is useful for iterating over an array.

 Some addressing modes are only available with specific instructions, and vice versa.

 Most distinct instructions use only the Implicit mode and have no operand; they modify
 an internal register and/or perform a stack operation.  These include SEC, CLC, SED, CLD,
 CLV, SEI, CLI, RTS, RTI, NOP, BRK, STP, WAI, INX, INY, DEX, DEY.
 
 The A-register transfer and ALU instructions form the "main group" and offer the most
 flexible addressing modes: LDA, STA, ADC, SBC, AND, ORA, EOR, CMP.  Each of these can be
 used with Immediate, Zero Page, Absolute, ZP Index X, Indexed X, Indexed Y, ZP Indirect,
 ZP PreIndex, and ZP PostIndex - except that STA Immediate does not exist.
 
 Most other instructions are much more restrictive in their choice of addressing mode.
 For example, CPX and CPY offer only Zero Page, Absolute, and Immediate modes.

 The index registers (X & Y) can only be loaded and stored using Immediate (loads only),
 Absolute, Zero Page, Indexed, & ZP Indexed, and can only be indexed by the opposite
 index register.  LDX and STX are the only users of the ZP Index Y mode.  STZ, which
 stores a zero, has the same modes as STY.
 
 The shift, rotate & increment instructions exist in two forms: one which operates on the
 A-register in Implicit mode (most assemblers will accept A as an operand for clarity),
 and one which supports the same addressing modes as STY and performs a read-modify-write
 operation.  This group is ROR, ROL, ASL, LSR, INC, DEC.  The index registers can be
 incremented and decremented using the Implicit-mode instructions INX, INY, DEX, DEY.
 
 The logical comparison instruction BIT offers the same addressing modes as LDY.  Its
 Immediate mode differs subtly from its memory-operand modes in terms of which flags it
 sets, so pay attention if you use it.

 Branch instructions (all starting with B) can only be used with Relative addressing.
 JSR can only be used with Absolute addressing.  JMP can be used with Absolute, Indirect,
 or Index Indir modes, and is the only instruction that can use the latter two modes.

 The SMB and RMB instructions offer only Zero Page mode without indexing.  The BBR and BBS
 instructions always use a combination of Zero Page and Relative modes.  They are also
 not available on all CMOS 6502s; in particular they are absent on the 65816.  This makes
 them less generally useful in practice.  Assemblers may omit these instructions if set
 to 65sc02 mode.
 
 Generally, if in doubt as to whether a particular instruction supports a particular
 addressing mode, either refer to documentation or just see whether your assembler
 accepts it.
Last edited by Chromatix on Wed Nov 14, 2018 5:31 pm, edited 4 times in total.
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: Calculating the backward offset of a branch

Post by BigEd »

Well done!
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Calculating the backward offset of a branch

Post by Chromatix »

I just expanded the addressing-mode table with a summary of which modes go with which instructions. There may possibly be some mistakes or omissions…
Kris1978
Posts: 41
Joined: 21 May 2018

Re: Calculating the backward offset of a branch

Post by Kris1978 »

BigEd wrote:
BTW, Kris1978, you might want to check out the older thread
The Visible Computer is awesome! Both manual and software! :)

Thank you BigEd for mentioning that old thread!
Post Reply