Caution: Use RES Only After Instructions and Data

It's important to use RES only after the final instructions and data in a logical assembly program. Placing RES in a prior location could have unintended results as explained below.

Remember that assembly instructions and data are placed in the application memory image in the exact order entered in source, independent of the assembly pointer. This is because launched assembly code must be loaded in order, starting with the designated routine label. However, since RES does not generate any data (or code), it has absolutely no effect on the memory image of the application; RES only adjusts the value of the assembly pointer.

By nature of the RES directive, any data or code appearing after a RES statement will be placed immediately after the last non-RES entity, in the same logical space as the RES entities themselves. Consider the following example where the code, from above, has the order of the Time and Delay declarations reversed.

DAT
           org        0
AsmCode    mov        Time, cnt      'Get system counter
           add        Time, Delay    'Add delay
:Loop      waitcnt    Time, Delay    'Wait for time window
           nop                       'Do something useful
           jmp        #:Loop         'Loop endlessly 

Time       res        1              'Time window workspace
Delay      long       6_000_000      'Time window size 

This example would be launched into a cog as follows:

Symbol

Address

Instruction/Data

AsmCode
0
mov        Time, cnt
 
1
add        Time, Delay
:Loop
2
waitcnt    Time, Delay
 
3
nop
 
4
jmp        #:Loop
Time
5
6_000_000
Delay
6
?

Notice how Time and Delay are reversed with respect to the previous example but their data is not? Here's what happened:

  • First, the assembler placed everything in the object's memory image exactly as it did before up to and including the JMP instruction.
  • The assembler reached the Time symbol, which is declared with a RES directive, so it equated Time to address 5 (the current assembly pointer value) and then incremented the assembly pointer by 1. No data was placed in the application memory image due to this step.
  • The assembler reached the Delay symbol, which is declared as a LONG of data, so it equated Delay to address 6 (the current assembly pointer value), incremented the assembly pointer by 1, then placed the data, 6_000_000, into the next available location in the memory image right after the JMP instruction which happens to be where Time is logically pointing.

The effect when launched into a cog is that the Time symbol occupies the same Cog RAM space that Delay's initial value does, and Delay exists in the next register that contains unknown data. The code will fail to run as intended.

For this reason, it is best to place RES statements after the last instruction and after the last defined data that your assembly code relies upon, as shown in the first example. 

Unless otherwise noted, content on this site is licensed under the
Creative Commons Attribution-ShareAlike 4.0 International License.