Pumpkin, Inc.

Pumpkin User Forums

Incorrect RAM page settings on return after OS_Yield

If you can't make Salvo do what you want it to do, post it here.

Incorrect RAM page settings on return after OS_Yield

Postby Colin Stocks » Tue Dec 04, 2001 2:10 am

Andrew,

Good to know I haven't completely lost it )

Compiler problems like this always give me the willies, because I'm never sure whether they may have occurred somwhere where the effects have been hidden from my testing, and are just waiting to show up at a customer's site.

On the other hand, now we know about it we can avoid it.

Regards,

Colin

Colin Stocks
 
Posts: 2
Joined: Mon Oct 22, 2001 11:00 pm
Location: Crowborough, East Sussex, UK

Re: Incorrect RAM page settings on return after OS_Yield

Postby cstocks » Tue Dec 04, 2001 7:25 am

The following is a section of a program I am debugging:

code:
RD = 1;
while (EEDATA != CR) {
if (TXIF == 1) {
TXREG = EEDATA;
++SequenceAddress;
EEADR = SequenceAddress;
RD = 1;
}
OS_Yield(SequenceCharWait);
} /* while */

It occurs within a larger function, but represents the area of interest. It compiles to the following:

code:
0770                   bsf    0x3,0x5
0771 bsf 0xC,0x0
0772 bcf 0x3,0x5
0773 movf 0xC,W
0774 xorlw 0xD
0775 bcf 0x3,0x6
0776 btfsc 0x3,0x2
0777 goto 0x798
0778 btfss 0xC,0x4
0779 goto 0x786
077A bsf 0x3,0x6
077B movf 0xC,W
077C bcf 0x3,0x6
077D movwf 0x19
077E bsf 0x3,0x5
077F bsf 0x3,0x6
0780 incf 0x19
0781 movf 0x19,W
0782 bcf 0x3,0x5
0783 movwf 0xD
0784 bsf 0x3,0x5
0785 bsf 0xC,0x0
0786 movlw 0xD1
0787 bcf 0x3,0x5
0788 bcf 0x3,0x6
0789 movwf 0x4E
078A movlw 0x1
078B movwf 0x4F
078C bcf 0xA,0x4
078D bcf 0xA,0x3
078E goto OSSaveRtnAddr
078F SequenceCharWait goto 0x772

When the scheduler returns to SequenceCharWait, both the RAM bank select bits are clear. Before EEDATA is read, RP1 needs to be set, but there are no instructions at 0x772 to do so, and the loop ends up reading from the wrong RAM bank (address 0x773 is the point where EEDATA should be read into W).

All the code in this program is "by the book" - I have defined no psects of my own, incorporated no assembler, etc. Is the problem due to:

1) Something I should have done, but haven't,

2) A bug in the latest version of the Hi-Tech compiler,

3) A bug in the way Salvo is arranging task scheduling?

Regards,

Colin

[This message has been edited by aek (edited December 04, 2001).]

cstocks
 
Posts: 7
Joined: Tue Oct 23, 2001 11:00 pm
Location: Crowborough, East Sussex, UK

Re: Incorrect RAM page settings on return after OS_Yield

Postby aek » Tue Dec 04, 2001 8:21 am

Hi Colin.

Looking at your disassembled code, isn't there also a

code:
076F                   bsf    0x3,0x6

because without it, the access to RD won't work properly...

1) You have a coding error. The first RD = 1 statement should be inside the while() loop in order to guarantee that it's set prior to the read ... I think you can do something like this:

code:
while ( ( RD = 1 ) && ( EEDATA != CR ) ) { // not RD == 1 !
if (TXIF == 1) {
TXREG = EEDATA;
EEADR = ++SequenceAddress;
}
OS_Yield(SequenceCharWait);
} /* while */

Regards,

------------------

[This message has been edited by aek (edited December 04, 2001).]

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Incorrect RAM page settings on return after OS_Yield

Postby cstocks » Tue Dec 04, 2001 8:35 am

Andrew,

You are correct that, prior to the loop, there is a bsf 0x3, 0x6 (though it's a little earlier than 076f), but I do not have a coding error. Look at the source, and you will see that there IS a RD = 1 at the end of the loop; the RD = 1 before the loop is there to permit the initial test to take place.

I have done a little experimenting since posting the notice, and I can make the program run properly by adding a call to a dummy function, as shown:

code:
void nulltask(void) {;}


.
.
.
.
RD = 1;
while (EEDATA != CR) {
if (TXIF == 1) {
TXREG = EEDATA;
++SequenceAddress;
EEADR = SequenceAddress;
RD = 1;
}
OS_Yield(SequenceCharWait);
nulltask(); /* DUMMY FUNCTION */
}


But I don't understand why it's needed. In the original case, the optimiser appeared to have reason to believe that on return to SequenceCharWait, RP1 would still be correctly set, when it clearly isn't. Adding the function (apparently) forces the compiler to handle the page set bits properly.

Regards,

Colin

[This message has been edited by aek (edited December 04, 2001).]

cstocks
 
Posts: 7
Joined: Tue Oct 23, 2001 11:00 pm
Location: Crowborough, East Sussex, UK

Re: Incorrect RAM page settings on return after OS_Yield

Postby aek » Tue Dec 04, 2001 8:38 am

Hi Colin.

My original posting wasn't clear -- I have since re-edited it (see below).

In summary, you can't have "one-time setup" for a loop like this -- the setup for RD prior to the read of EEDATA needs to be in every loop iteration, not just the first one. Just fold the two RD = 1 statements into one, at the start of the loop, and you'll be fine (and the code will be smaller, too).

Regards

------------------

[This message has been edited by aek (edited December 04, 2001).]

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Incorrect RAM page settings on return after OS_Yield

Postby aek » Tue Dec 04, 2001 8:43 am

Hi Colin.

As to why it works with the nulltask(), I'm not really sure -- (while on the trail of an explanation / solution) I would have placed an RD = 1 where you put nulltask(), and that certainly would have fixed it because the program execution would resume after OS_Yield(), force RD to 1, and then read EEDATA and compare it against CR. But then I'd have three RD = 1 statements in the code, where only one is required -- then I'd use the solution below.

The PICC optimizer does quite a bit of loop optimization, and so it's hard sometimes to read the assembly list and / or figure out what it's doing. But it seems to be right all the time ...

------------------

[This message has been edited by aek (edited December 04, 2001).]

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Incorrect RAM page settings on return after OS_Yield

Postby cstocks » Tue Dec 04, 2001 8:50 am

Andrew,

This doesn't seem right. The loop condition is (EEDATA != CR), and all the program has to do is extract the value from the EEDATA register; the read operation does NOT have to be repeated (in this application) because nothing else disturbs the register between calls.

The code IS correctly trying to access EEDATA each time the loop is executed, but is NOT setting up the page select bits to do so correctly unless the dummy function is in there.

Or to put it another way, RD = 1 and (EEDATA != CR) are separate and distinct operations; there should be no correlation between the bank selection for one and the bank selection for the other. I could, in principle, legitimately execute the EEPROM read operation in an entirely separate part of the program, and still execute the test on EEDATA as shown.

Regards,

Colin

cstocks
 
Posts: 7
Joined: Tue Oct 23, 2001 11:00 pm
Location: Crowborough, East Sussex, UK

Re: Incorrect RAM page settings on return after OS_Yield

Postby aek » Tue Dec 04, 2001 9:11 am

Hi Colin.

I understand your point about RD.

The disassembled code has two reads of EEDATA in it -- the first, at 0773, and the second, at 077B. There is "in loop" setup (by the compiler) of RP1 for the second one, but not for the first. The question is: why isn't the compiler setting RP1 just prior to 0773?

The lack of in-loop setup for the first access (the while ( EEDATA != CR )) is the problem, agreed?

If you change OS_Yield() to a goto to the while() statement, does the failure to set RP1 remain? That would be a clear indication that it's a compiler error.

Looking at the disassembly, RP1 is clearly left at 0 just prior to OS_Yield(). Then it jumps up to 772, clears RP0, then tries to read a bank2 variable without setting RP1. That looks like a compiler bug, perhaps "tipped off" by the first RD = 1 statement.

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Incorrect RAM page settings on return after OS_Yield

Postby aek » Tue Dec 04, 2001 10:00 am

Hi Colin.

Yes, it is an odd one. And spooky. And it's not clear why this particular bit of code triggers it ... Matt @ HI-TECH is away for two weeks, so it may be a while before they address it.

One thing we (or you) could do is to add the dummy function to OS_Yield() in portpicc.h -- it should be optimized out, yielding unchanged code size, yet it should also fix this bug.

------------------

[This message has been edited by aek (edited December 04, 2001).]

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Incorrect RAM page settings on return after OS_Yield

Postby aek » Tue Dec 04, 2001 10:17 am

Hi Colin.

Congratulations -- you've found what appears to be a problem in PICC!

I used the following test program:

code:
#include <pic.h>

#define CR 0x0D

#define CAUSE_ERROR 1

unsigned char bank2 SequenceAddress;

void SimpleFn( unsigned int whatever )
{
whatever++;
}

void testfn ( void )
{
RD = 1;
while (EEDATA != CR) {
if (TXIF == 1) {
TXREG = EEDATA;
++SequenceAddress;
EEADR = SequenceAddress;
RD = 1;
}

#if CAUSE_ERROR
SimpleFn(0x1234);
#endif
asm(" return");

}

}

main()
{
testfn();
}


And here's the assembly listing for testfn() for CAUSE_ERROR = 1:

code:
07E2  1683  testfn            bsf    0x3,0x5                       
07E3 1703 bsf 0x3,0x6
07E4 140C bsf 0xC,0x0
07E5 2FF9 goto 0x7F9
07E6 1E0C btfss 0xC,0x4
07E7 2FF2 goto 0x7F2
07E8 1703 bsf 0x3,0x6
07E9 080C movf 0xC,W
07EA 1303 bcf 0x3,0x6
07EB 0099 movwf 0x19
07EC 1703 bsf 0x3,0x6
07ED 0A90 incf 0x10
07EE 0810 movf 0x10,W
07EF 008D movwf 0xD
07F0 1683 bsf 0x3,0x5
07F1 140C bsf 0xC,0x0
07F2 3034 movlw 0x34
07F3 1283 bcf 0x3,0x5
07F4 1303 bcf 0x3,0x6
07F5 00A6 movwf 0x26
07F6 3012 movlw 0x12
07F7 00A7 movwf 0x27
07F8 2FDE goto 0x7DE
07F9 1283 bcf 0x3,0x5
07FA 080C movf 0xC,W
07FB 3A0D xorlw 0xD
07FC 1303 bcf 0x3,0x6
07FD 1903 btfsc 0x3,0x2
07FE 0008 return
07FF 2FE6 goto 0x7E6

and here it is for testfn() for CAUSE_ERROR = 0:

code:
07E4  1683  testfn            bsf    0x3,0x5                       
07E5 1703 bsf 0x3,0x6
07E6 140C bsf 0xC,0x0
07E7 2FF5 goto 0x7F5
07E8 1E0C btfss 0xC,0x4
07E9 0008 return
07EA 1703 bsf 0x3,0x6
07EB 080C movf 0xC,W
07EC 1303 bcf 0x3,0x6
07ED 0099 movwf 0x19
07EE 1703 bsf 0x3,0x6
07EF 0A90 incf 0x10
07F0 0810 movf 0x10,W
07F1 008D movwf 0xD
07F2 1683 bsf 0x3,0x5
07F3 140C bsf 0xC,0x0
07F4 0008 return
07F5 1283 bcf 0x3,0x5
07F6 080C movf 0xC,W
07F7 3A0D xorlw 0xD
07F8 1303 bcf 0x3,0x6
07F9 1903 btfsc 0x3,0x2
07FA 0008 return
07FB 2FE8 goto 0x7E8

Note that in the latter, the read of EEDATA occurs at 07F6, RP1 is (still) set from 07EE, and all is well. But in the former, RP1 was cleared at 07F4, and remains cleared when EEDATA is read at 07FA.

The call to a function with 16-bit parameters followed by asm(" return") mimics the Salvo scheduler. I did some other tests, and it's apparently this combination that leads to a problem -- just testfn() or just asm( "return") still generates correct code.

I'll forward this to HI-TECH.

------------------

[This message has been edited by aek (edited December 04, 2001).]

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Next

Return to Coding

Who is online

Users browsing this forum: No registered users and 2 guests

cron