What methods of using control flow exist in 6502?

I am trying to understand the control flow in assembly 6502.

Let's say I have the following code:

ControlFlow: lda mem cmp #1 bne .sub_one cmp #2 bne .sub_two .sub_one: ; sub routine one goes here jmp .done ; <-------------- without this jmp, .sub_two will execute .sub_two: ; sub routine two goes here .done: rts 

Personally, I would like the switch statement or some other control flow structure. The jmp above applies to me as well. There seems to be a better way to handle a few cases without this type of spaghetti code.

+4
source share
7 answers

There is actually no better way, but there may be such an improvement as calling FlowControl as a subroutine and returning using RTS.

This is the main thread.

  jsr ControlFlow ; main routine continues here 

Here is the subroutine.

 ControlFlow: lda mem cmp #1 bne .sub_one cmp #2 bne .sub_two cmp #3 bne .sub_three ; case else here rts .sub_one: ; sub routine one goes here rts .sub_two: ; sub routine two goes here rts .sub_three: ; sub routine three goes here rts 

If the routines are too long, you need to use JMP, as mentioned earlier.

 .jump_to_sub_one jmp .sub_one .jump_to_sub_two jmp .sub_two .jump_to_sub_three jmp .sub_three ControlFlow: lda mem cmp #1 bne .jump_to_sub_one cmp #2 bne .jump_to_sub_two cmp #3 bne .jump_to_sub_three ; case else here rts .sub_one: ; sub routine one goes here rts .sub_two: ; sub routine two goes here rts .sub_three: ; sub routine three goes here rts 

How this is done and, unfortunately, there is no better way. This applies to many assembler languages, if not all.

+3
source

Transition tables can be useful if the number of cases is large enough. On the left is a template (untested) to go to the label, which pops the correct address for the stack and returns it. To the right of the jsr-based program, which will continue on the _out: label _out: after returning from each subroutine. The transfer logic is inverted to 6502, which means that the transfer will be set if (Acc> = Imm).

 ; goto label[n] vs. call label[n] lda variable cmp #MAX_PLUS_ONE bcs _out tax lda table_hi, X pha vs. sta jsrcmd+2 lda table_lo, X pha vs. sta jsrcmd+1 rts vs. jsrcmd: jsr 1000 ; self modify _out: 
+4
source

6502 provides the following functions to control the flow of a program, that is, to change the PC register.

  • Absolute absolute
  • Jmp indirect
  • Relative instructions Bxx
  • Absolute JSR with later version of RTS
  • BRK or another IRQ with a later version of RTI (or RTS if you pull .P from the stack)
  • Pushing two values โ€‹โ€‹onto the stack and then RTS / RTI
  • Hardware reset causes a jump through the reset vector

What is it. If you need something more complex, you need to create it using one or more of the above.

One way to implement the switch statement is to create a table of pointers to all the routines involved in the switch statement. Separate them according to the low bytes of the routines, and then the high bytes:

switchtab_lo .db >routine1, >routine2, >routine3

switchtab_hi .db <routine1, <routine2, <routine3

(I cannot remember if> means low byte or high byte, and different assemblers may have different syntax)

and then assuming that the value you want to include is in .X, and vector is two bytes that do not start at the end of the page (to avoid an indirect JMP error), and you make sure that this is a valid value:

 lda switchtab_lo,X sta vector lda switchtab_hi,X sta vector+1 jmp (vector) 

It is tiring to do this every time you need to switch, but why exactly high-level languages โ€‹โ€‹were invented.

+3
source

CMOS 6502 (i.e. 65c02) also has a JMP addressing mode (abs, X) , so you can take the input to A, shift 1 bit to the left with ASL A (because each address in the table takes up two places), and then pass him on X and make JMP (Addr_Table, X). Much easier. This is one of the many additions to the code code made in the CMOS version. (The CMOS version also fixed all errors in the NMOS version).

+1
source
  lda mem asl sta jump+1 jump jmp (vector) ;should be page aligned vector !word func1, func2, func3, func4 

if the list of vectors is not aligned, you must add the * 2 index to the entire vector address, slower but more efficiently with memory.

other parameters:

  lda mem asl clc adc mem ;we assume it does not overflow, so carry stays cleared sta branch+1 ;mem * 3 branch bcc * jmp func1 jmp func2 jmp func3 jmp ... 
+1
source

I do not know how you will do this on 6502, but switch es are often compiled into transition tables .

0
source

I have an article about using macros to create program structures in build 6502, http://wilsonminesco.com/StructureMacros/index.html . I did this for PIC, and there are links for the source code for both. Further additions come when I finish the project I'm working on.

OP is the ideal situation for IF ... ELSE ... END_IF. When more cases are required, the jump table works well if the numbers are sequential and you do not need to check the constraints to avoid jumping indirectly from outside the table and crashing. Otherwise, the CASE statement works great. http://forum.6502.org/viewtopic.php?f=2&t=2311&start=15 is the second page of this discussion, and I show how you can test individual cases, a range of numbers or a scattering of numbers, all in the same CASE statement. I do not have RANGE_OF and SET_OF written yet as 6502 macro assemblies. These are two, I only have in Fort.

The goal of these macros, of course, is to improve code control, simplifying what you are doing, and getting rid of the mass of labels and transitions that typically characterize assembly code. Macros allow you to fully control every piece of code installed by the assembler, but you do not need to constantly look at the internal details. In most cases, there is absolutely zero penalty in program memory or in execution speed. You get build performance with many of the benefits of higher-level languages. The code becomes faster to develop, more errors and easier to maintain, which means that it is easier for him to return later and find out what you did when you decide to add a function or change something.

0
source

All Articles