This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

goto to a pointer

Hello NG,
I've got the following problem: I want to store the current position in a interrupt routine and leave it. By entering the routine after the next interrupt, I want to jump to this stored position. My first idea was the following:

void irq (void) interrupt 0x14 using irq_level_2
{
static int flag = 0;
static void (*cont_here) ();

if (flag!=0) goto *cont_here;
...
if (something)
{
flag = 1;
cont_here = &here1;
goto end_irq;
}
here1:
...
if (something_else)
{
flag = 1;
cont_here = &here2;
goto end_irq;
}
here2:
...
end_irq:
}

But it doesn't work, 'cause labels and variables aren't the same and goto *bla doesn't work.
Is there a solution besides the using of setjmp and longjump (which got too much, in this case, senseless overhead)?

Thanks for any ideas - Peter

Parents Reply Children
  • Well, I don't think there is a way to know which register holds which variable unless you look at the compiled code. You cannot even be sure that a 'register' variable is actually stored in a register (imagine that you've declared more 'register' variables than there are registers).
    In this particular case you could try to use the system stack:

    void function(void)
    {
      int jumplock;
      /* ... */
      _push_(jumplock);
    #pragma asm
      RET
    #pragma endasm
    }
    
    or simply a C-style call:
    ( (void (*)(void)) jumplock )();
    return;
    
    Chances are that the compiler will generate 'JMPI' instead of 'CALLI/RET'.

  • Hello,

    sounds well.

    > Chances are that the compiler will generate
    > 'JMPI' instead of 'CALLI/RET'.
    May this depend on some optimizing level?

    So far, the problem remains to put the address of a label in a variable. Your examples brought me to an idea like the following:

    #pragma asm
    PUSH REG
    MOV REG, #?function_name?label_name
    MOV ?function_name?variable_name, REG
    POP REG
    #pragma endasm
    Does this work? Does the second MOV work with Static or Automatic variables? B.t.w.: Where can I read something about the ?function_name?label_name stuff?

    Thanks so far - Peter

  • If you need to jump to one of a few points in a function, maybe you should use 'switch/case' as Jon Young proposed because that is exactly what 'switch' does ('case X' labels work just like ordinary labels, although you cannot 'goto case X').
    If you are determined to use C/asm mixing (which in my view is only justified when 'C approach' has proved too slow) then you will have to deal with low-level stuff like C166 instruction set, interfacing between C and assembler, naming conventions, memory models and so on. To find out how it works I compiled C code and looked through generated *.SRC files (that's how I knew about ?function_name?label_name).
    As for storing address of a label in a variable and using it as a target for a jump (which does not look like an elegant solution at all), this is one of the ways to go:

    void (*fptr)(void) = 0;
    void isr(void) interrupt INT_NO using RB
    {
    	if ( fptr )
    	{
    		fptr();
    		return;
    // or
    		_push_((int)fptr);
    #pragma asm
    		RET
    #pragma endasm
    	}
    	if ( /* some condition */ )
    	{
    #pragma asm
    		SCXT R1, #?isr?label1
    		MOV  fptr, R1
    		POP  R1
    #pragma endasm
    	}
    	else
    	{
    #pragma asm
    		SCXT R1, #?isr?label2
    		MOV  fptr, R1
    		POP  R1
    #pragma endasm
    	}
    label1:
    	_nop_();
    label2:
    	_nop_();
    }
    
    > Chances are that the compiler will generate
    > 'JMPI' instead of 'CALLI/RET'.
    I've seen something like that before, but it will not happen in interrupt service routines (because they use RETI instead of RET). The only way to find out is to see the generated code.
    Good luck!
    Mike

  • Thanks, Mike!
    I will continue to find a solution at monday.
    So have a nice Weekend - Peter