|
|
View previous topic :: View next topic |
Author |
Message |
gustnado
Joined: 23 Apr 2005 Posts: 21 Location: Phoenix,AZ
|
|
Posted: Tue May 03, 2005 12:40 pm |
|
|
Yeah, I was afraid of that. I can't make a short program that fails! But the big one does. It is, of course, possible that the big one is clobbering the jump environment, but it is unlikely - I am not using any dynamic variables (no malloc, etc).
Anyway, thanks for your help. Since setjmp seems to be buggy, I am currently trying to write a simple setjmp/longjmp in assembly language, but I am not very familiar with PIC assembly and it is a bit odd (RAM in banks, no address registers but powerful FSR functions). Right now I am trying to figure out how to read the top of stack registers. My approach is to call my own setjmp from the mainline, save away the TOS, and in longjmp restore TOS, set _RETURN_ and return. But I don't know how to get at TOS. It cannot be written using MOVFF, although it would seem to be readable that way (except my experiment doesn't work).
Here's my code... any help would be appreciated:
Code: |
#byte TOSU= 0xFFF
#byte TOSH= 0xFFE
#byte TOSL= 0xFFD
#byte STKPTR= 0xFFC
#byte FSR0H= 0xFEA
#byte FSR0L= 0xFE9
#byte POSTINC0= 0xFEE
#separate
int tvsenv_addr[3];
tvssetjmp() {
disable_interrupts(global);
#asm
lfsr 0,TOSU
movff POSTINC0,tvsenv_addr
movff POSTINC0,tvsenv_addr+1
movff POSTINC0,tvsenv_addr+2
#endasm
enable_interrupts(global);
return 0;
}
|
Unfortunately, this code puts a value in tvsenv_addr that is not the return address from which tvssetjmp was called.
Any clues to either problem? How to get the calling off the TOS and how to put it back (or to put it into the PC directly) when MOVFF cannot use PCL, or any TOS register as a destination?
As an aside, the compiler originally generated a branch to the code rather than a call. I had to trick it into doing a call by adding another use of setjmp that couldn't actually happen. _________________ The best weather is bad weather |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue May 03, 2005 1:15 pm |
|
|
You said you can't make a short program that fails.
One way to make a large program is with floating point code.
This little program below, uses 34% of an 18F452 when compiled
with PCH vs. 3.188.
Could you use a program like this, and add setjmp code to it
and make it fail ?
Code: | #include <18F452.h>
#fuses XT, NOWDT, NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#include <math.h>
//========================================
void main()
{
float a;
float b;
float result;
a = 123.456789;
b = 456.789012;
result = a + b;
result = a - b;
result = a * b;
result = a / b;
result = floor(a);
result = pow(a, b);
result = cos(a);
result = asin(a);
result = atan(a);
result = atan2(a, b);
result = log(a);
result = sqrt(a);
printf("%f ", result);
while(1);
} |
|
|
|
gustnado
Joined: 23 Apr 2005 Posts: 21 Location: Phoenix,AZ
|
|
Posted: Tue May 03, 2005 1:57 pm |
|
|
I think it takes a complex program to fail. I believe I have created one, after analyzing the longjmp code, which fails to save the contents of the top of stack, only saving the stack pointer.
The following program will continuously restart. Here is the output
Code: |
Start
B: i = 0
C
before longjmp
Start
B: i = 0
C
before longjmp
Start
B: i = 0
C
before longjmp
Start
|
etc...
Here is the program. Do you see anything wrong with it?
Code: |
#include <18f452.h>
#device ICD=TRUE
#fuses HS,NOLVP,NOWDT,PUT
#use delay(clock=20000000)
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#include<setjmp.h>
jmp_buf env;
two() {
printf("before longjmp\r\n");
longjmp(env, 2);
}
one() {
two();
}
C() {
printf("C\r\n");
}
B() {
int i;
i = setjmp(env);
printf("B: i = %d\n\r", i);
return i;
}
A() {
if ( 0 == B() ) {
C();
one();
}
}
main()
{
printf("Start\n\r");
A();
printf("Done\n\r");
while(1);
}
|
_________________ The best weather is bad weather |
|
|
gustnado
Joined: 23 Apr 2005 Posts: 21 Location: Phoenix,AZ
|
|
Posted: Tue May 03, 2005 3:11 pm |
|
|
Sigh. A friend reminds me that the code above should not work. longjmp must be at a call level below (or maybe the same) as the setjmp, not in another call tree. _________________ The best weather is bad weather |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue May 03, 2005 3:25 pm |
|
|
Near the end of this page, it gives some warnings about using longjmp.
http://publibn.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf2/setjmp.htm
It says:
Quote: | if the subroutine that made the corresponding call to the setjmp
subroutine has already returned, then the results of the longjmp
subroutine are undefined. |
I think that's what you're doing. Subroutine B() has already returned
when you call longjmp in subroutine two().
Also, CCS doesn't have the longjmperror() routine that is referred to
in that page. |
|
|
gustnado
Joined: 23 Apr 2005 Posts: 21 Location: Phoenix,AZ
|
|
Posted: Tue May 03, 2005 4:58 pm |
|
|
That is true in the example, but not in the actual application, where the setjmp call is from the mainline and the longjmp call is from a few subroutines down from the mainline.
This is sure frustrating. The only way I think my program could cause this would be if the memory used by the setjmp is being clobbered, but I am not using dynamic memory and only one array that I don't think is overflowing. I wonder if there is an optimization problem. _________________ The best weather is bad weather |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|