Where is this part of code?


How can you transfer the program counter (PC) to any register?

The easy way: by performing a CALL the PC is PUSHed onto the stack. Unfortunatedly, a JUMP will be executed with this instruction, and somewhere should be a RETURN instruction to POP the PC and continue with the execution.

But you are free to handle the stack as you like it. So, after the CALL you can POP the address from the stack and do whatever you like with it.

Don't be surprised: the two instructions

  Serial.println( (int) &whereAmI, HEX);
  Serial.println( (int) whereAmI, HEX);
will print the same address.



void setup() {
  Serial.begin(9600);
  Serial.println("\n" __FILE__);
  Serial.print("address of subroutine: ");
  Serial.println( (int) &whereAmI, HEX);
  Serial.print("address of label L1  : ");
  Serial.println(whereAmI(), HEX);
  Serial.print("address of subroutine: ");
  Serial.println( (int) whereAmI, HEX);
}

void loop() {}

int whereAmI() {
  byte high, low;
  asm(
    "nop \n\t"       // just for fun
    "call L1 \n\t"   // push program counter on the 
                     // stack and jump to label L1
    "L1: \n\t"
    "pop r0 \n\t"    // pops PC (low byte)
    "mov %0, r0 \n\t"
    "pop r0 \n\t"    // pops PC (high byte)
    "mov %1, r0 \n\t"
    : "=r" (high), "=r" (low)
  );
  return word(high, low);
}

/*
 * 2D8 / 2 = 16C (printed)
 * 2DE / 2 = 16F (printed)
 * 
000002d8 <_Z8whereAmIv>:
    "pop r0 \n\t"    // pops PC (low byte)
    "mov %0, r0 \n\t"
    "pop r0 \n\t"    // pops PC (high byte)
    "mov %1, r0 \n\t"
    : "=r" (low), "=r" (high)
  );
 2d8:  00 00         nop
 2da: 0e 94 6f 01   call  0x2de ; 0x2de <L1>

000002de <L1>:
 2de: 0f 90         pop r0
 2e0: 90 2d         mov r25, r0
 2e2: 0f 90         pop r0
 2e4: 80 2d         mov r24, r0
  return word(low, high);
}
 2e6: 08 95         ret
*/




contact: nji(at)gmx.de