We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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
#pragma asm MOV REG, #?function_name?label_name JMPI [REG] #pragma endasm
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;
#pragma asm JMPI [REG] #pragma endasm
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 }
( (void (*)(void)) jumplock )(); return;
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
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_(); }
Thanks, Mike! I will continue to find a solution at monday. So have a nice Weekend - Peter