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

  • You could do it just the way they do it with setjmp/longjmp, that is, extract address of the return point from the system stack and than use it as a pointer to a function. You don't even have to resort to assembler. But you have to take into account the memory model in use (whether function calls are 'near' or 'far').
    Good luck!
    Mike.

  • The simplest code is to use a switch statement.

    enum{ State0, State1, State2 };
    
    void irq (void) interrupt 0x14 using irq_level_2
    {
      static unsigned char State;
    
      switch( State )
      {
      State0:
        //do stuff
        State = State1;
        break;
      State1:
        //do stuff
        State = State2;
        break;
      State2:
        //do stuff
        State = State0;
        break;
      }
    }
    

  • Hello,

    I don't want to determine an address at run time, rather I want to get the address of labels, which are constants at run time and are known to the compiler at compile time, of course.

    To jump to an address stored in a register variable (what I meant with goto *) I could inline-assemble a JMPI. But to do this, I must use something like a register placeholder to be replaced by the register actually used for the variable.
    As an alternative, I could force the compiler to use an explicitly given register for that variable.

    Unfortunately, I don't know how to realise all three things. But I don't believe that this is impossible, so maybe you could help me to do this.

    Thanks - Peter

  • If the only problem is to find a register which can be used safely, then you could use the following:

    #pragma asm
    PUSH REG
    MOV REG, #?function_name?label_name
    PUSH REG
    RETP REG
    #pragma endasm
    
    It should be equivalent to:
    #pragma asm
    MOV REG, #?function_name?label_name
    JMPI [REG]
    #pragma endasm
    
    with the difference that in the end the contents of REG are preserved (see C166 Instruction Set Manual).
    I think this should do the trick.
    Good luck!
    Mike

  • 1) The two instructions
    PUSH REG
    MOV REG, #value
    can be replaced by a single one:
    SCXT REG, #value
    2) In the proposed code you must not use R0 as REG if the code can be interrupted (because interrupting code will assume that R0 holds the address of the top of the user stack).

  • Hello,

    Thanks so far, I will try it.
    But I've got another question:
    If I write:

    register int jumploc;
    
    I could write
    #pragma asm
    JMPI [REG]
    #pragma endasm
    
    if I only guess the REG where jumploc is stored in.
    But I don't want to guess...

    Tanks - Peter

  • 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