On long programs that have gone over the page boundary there is a problem where the page isn't restored correctly after a call to a sub that ends in a goto some other sub - the original call may be on the same page as the calling code so the compiler doesn't add a 'pagesel $' but if there is a goto some other sub at the end the actual return will be from whatever page that other sub is on.
I took a stab at writing a fix in the AddPageCommands sub of GCBASIC.BAS changing this section of code -
'Alter call to correct instruction/s
If ModePIC Then
If ChipFamily = 12 Or ChipFamily = 14 Or ChipFamily = 15 Then
CurrLine = LinkedListDelete(CurrLine)
If CalledSubPage = ThisSubPage Then
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
Else
CurrLine = LinkedListInsert(CurrLine, " pagesel " + CallTarget)
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
If RestorePage Then
CurrLine = LinkedListInsert(CurrLine, " pagesel $")
End If
End If
End If
ElseIf ModeZ8 Then
CurrLine = LinkedListDelete(CurrLine)
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
End If
to this -
'Alter call to correct instruction/s
If ModePIC Then
If ChipFamily = 12 Or ChipFamily = 14 Or ChipFamily = 15 Then
CurrLine = LinkedListDelete(CurrLine)
If CalledSubPage = ThisSubPage Then
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
Else
CurrLine = LinkedListInsert(CurrLine, " pagesel " + CallTarget)
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
End If
If RestorePage And (CalledSubPage <> ThisSubPage Or Subroutine(CalledSub)->NoReturn) Then
CurrLine = LinkedListInsert(CurrLine, " pagesel $")
End If
End If
ElseIf ModeZ8 Then
CurrLine = LinkedListDelete(CurrLine)
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
End If
It should stick a pagesel $ in the code if the next line isn't another call to a different page and either the called sub page is different from the current page or the called sub doesn't appear to have a return. It relies on the NoReturn flag being a good indicator that there is a goto some other sub rather than a return at the end which looks true enough for the program I'm working on.
Originally I wrote something more complicated that retrieved the name of the goto sub and looked at whether that ended in a return or a goto and looped around until it reached a return but then realised that if any of the chain of goto subs had an 'exit sub' instruction (or two or three) there would be other return points maybe from other pages so the final return page was no more useful than the called sub page. At that point subtlety was abandoned and the brute force and ignorance approach above looked much more appealing.
The modified compiler added 9 extra pagesel's to the 173 that were already there in the program I'd been working on and it started working properly again. I reckon 8 of those pagesels were needed to restore the page properly so the mod doesn't seem to add too many pointless pagesels although its probably program dependant.
Frank
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I took a stab at writing a fix in the AddPageCommands sub of GCBASIC.BAS changing this section of code -
'Alter call to correct instruction/s
If ModePIC Then
If ChipFamily = 12 Or ChipFamily = 14 Or ChipFamily = 15 Then
CurrLine = LinkedListDelete(CurrLine)
If CalledSubPage = ThisSubPage Then
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
Else
CurrLine = LinkedListInsert(CurrLine, " pagesel " + CallTarget)
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
If RestorePage Then
CurrLine = LinkedListInsert(CurrLine, " pagesel $")
End If
End If
End If
ElseIf ModeZ8 Then
CurrLine = LinkedListDelete(CurrLine)
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
End If
to this -
'Alter call to correct instruction/s
If ModePIC Then
If ChipFamily = 12 Or ChipFamily = 14 Or ChipFamily = 15 Then
CurrLine = LinkedListDelete(CurrLine)
If CalledSubPage = ThisSubPage Then
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
Else
CurrLine = LinkedListInsert(CurrLine, " pagesel " + CallTarget)
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
End If
If RestorePage And (CalledSubPage <> ThisSubPage Or Subroutine(CalledSub)->NoReturn) Then
CurrLine = LinkedListInsert(CurrLine, " pagesel $")
End If
End If
ElseIf ModeZ8 Then
CurrLine = LinkedListDelete(CurrLine)
CurrLine = LinkedListInsert(CurrLine, " call " + CallTarget)
End If
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Well spotted! Your fix is heading in the right direction, but can be made more efficient with some more tweaks.
NoReturn is also used for lookup table subs, and for interrupt handlers. A bit neater solution is to add another flag to the subroutine type (SubType), which is set by the code that replaces the last call with a goto (the AsmOptimiser function in assembly.bi). This was pretty easy to do, and also allows the target of the goto to be stored for later checking.
I've made a few other changes to the version of GCBASIC I have here. I've altered the AddPageCommands sub in a similar way, but have added a bit of code to set the RestorePage flag properly. This code works similarly to how you describe your initial code working - it follows the chain of gotos. If it gets to the end of the chain without finding any subs outside of the same page as the original caller, it doesn't restore the page. If it comes to a subroutine in another page, it stops searching and adds the pagesel $ to restore the page. This should get around any problems with exit subs - I think they can only make trouble if somewhere along the line there's a goto instruction?
The subroutine size measuring code will also need a tweak (the CalcLineSize function), otherwise the page allocation code won't take into account the added size of the program from the extra page restorations when allocating program memory, and will probably end up overfilling pages.
Could you please email me your program so that I can run it through the altered version of the compiler and check its behaviour? My w_cholmondeley at users dot sourceforge dot net account would be the best one. (If it's too hard to send, I can send you the altered compiler source, but it's barely tested at this stage!)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Would the above issue cause a failure of interrupts when the Compiler locates the Interrupt code in the 2nd page.
Having a problem with a big program that goes over the page boundary of a 16F88 which uses a very simple Interrupt using Timer1 to increment a counter every second.
Program runs fine when the Compiler locates the Interrupt code in the 1st page, but not when it gets located in the 2nd page.
The 2nd page also holds subroutines.
Getting the Compiler to put the interrupt code in the first page is tricky, but I can sometimes fool it by adding lines of code that dont do anything, like Nops thats simply change the programs size.
Program also runs fine if I disable the Interrupts altogether regardless of where anything is located.
Thanks
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
If you're interrupt code makes any calls to subs that end in a goto another sub then it could be.
Or alternatively it might be that the sub or subs that are forced to move into 2nd page when you move the interrupt code into the first page either end in a goto another sub or are the targets for subs that end in goto and the program works when they are in the 2nd page. That seems less likely as you say the program works alright if interrupts are disabled.
Hugh is working on a fix at the moment that looks promising.
You could look through the assembly for any of your own subs that are ending in a goto another sub and try to rearrange the gcbasic code or add a bit dummy code so that the final basic statement in the sub isn't another subroutine - that should get rid of the goto's and pin down whether it is the problem.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for responding.
interrupt code is very simple and just keeps time.
its this
Sub IncCounter
TMR1L = 0
TMR1H = 11
TMR1L = 219
'Increment the counter
QSeconds += 1
if Qseconds = 4 then
Qseconds=0
tickb += 1
tick2 += 1
second += 1
end if
end sub
There are however subs which do call other subs, and they get shuffled around a lot
depending on how big they are , as well as how big the main prog is .
Currently ive managed to get the compiler to put the interrupt code in the first page and all is working fine.
Ill examine carefully what is now in the 2nd page , and see what gets shifted around.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I moved my big program to a bigger Pic 16F886 to see if the page problems dissapeared and they didnt.
The I implemented you patch to Gcbasic and all problems solved.
Looks like the gotos in the subs are the issue.
Fantastic.
Thanks for the fix.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
On long programs that have gone over the page boundary there is a problem where the page isn't restored correctly after a call to a sub that ends in a goto some other sub - the original call may be on the same page as the calling code so the compiler doesn't add a 'pagesel $' but if there is a goto some other sub at the end the actual return will be from whatever page that other sub is on.
I took a stab at writing a fix in the AddPageCommands sub of GCBASIC.BAS changing this section of code -
to this -
It should stick a pagesel $ in the code if the next line isn't another call to a different page and either the called sub page is different from the current page or the called sub doesn't appear to have a return. It relies on the NoReturn flag being a good indicator that there is a goto some other sub rather than a return at the end which looks true enough for the program I'm working on.
Originally I wrote something more complicated that retrieved the name of the goto sub and looked at whether that ended in a return or a goto and looped around until it reached a return but then realised that if any of the chain of goto subs had an 'exit sub' instruction (or two or three) there would be other return points maybe from other pages so the final return page was no more useful than the called sub page. At that point subtlety was abandoned and the brute force and ignorance approach above looked much more appealing.
The modified compiler added 9 extra pagesel's to the 173 that were already there in the program I'd been working on and it started working properly again. I reckon 8 of those pagesels were needed to restore the page properly so the mod doesn't seem to add too many pointless pagesels although its probably program dependant.
Frank
Sorry - should have taken the tabs out
I took a stab at writing a fix in the AddPageCommands sub of GCBASIC.BAS changing this section of code -
to this -
Well spotted! Your fix is heading in the right direction, but can be made more efficient with some more tweaks.
NoReturn is also used for lookup table subs, and for interrupt handlers. A bit neater solution is to add another flag to the subroutine type (SubType), which is set by the code that replaces the last call with a goto (the AsmOptimiser function in assembly.bi). This was pretty easy to do, and also allows the target of the goto to be stored for later checking.
I've made a few other changes to the version of GCBASIC I have here. I've altered the AddPageCommands sub in a similar way, but have added a bit of code to set the RestorePage flag properly. This code works similarly to how you describe your initial code working - it follows the chain of gotos. If it gets to the end of the chain without finding any subs outside of the same page as the original caller, it doesn't restore the page. If it comes to a subroutine in another page, it stops searching and adds the pagesel $ to restore the page. This should get around any problems with exit subs - I think they can only make trouble if somewhere along the line there's a goto instruction?
The subroutine size measuring code will also need a tweak (the CalcLineSize function), otherwise the page allocation code won't take into account the added size of the program from the extra page restorations when allocating program memory, and will probably end up overfilling pages.
Could you please email me your program so that I can run it through the altered version of the compiler and check its behaviour? My w_cholmondeley at users dot sourceforge dot net account would be the best one. (If it's too hard to send, I can send you the altered compiler source, but it's barely tested at this stage!)
Hi Hugh,
I emailed the program to your sourceforge address - did you receive it ok?
Would the above issue cause a failure of interrupts when the Compiler locates the Interrupt code in the 2nd page.
Having a problem with a big program that goes over the page boundary of a 16F88 which uses a very simple Interrupt using Timer1 to increment a counter every second.
Program runs fine when the Compiler locates the Interrupt code in the 1st page, but not when it gets located in the 2nd page.
The 2nd page also holds subroutines.
Getting the Compiler to put the interrupt code in the first page is tricky, but I can sometimes fool it by adding lines of code that dont do anything, like Nops thats simply change the programs size.
Program also runs fine if I disable the Interrupts altogether regardless of where anything is located.
Thanks
If you're interrupt code makes any calls to subs that end in a goto another sub then it could be.
Or alternatively it might be that the sub or subs that are forced to move into 2nd page when you move the interrupt code into the first page either end in a goto another sub or are the targets for subs that end in goto and the program works when they are in the 2nd page. That seems less likely as you say the program works alright if interrupts are disabled.
Hugh is working on a fix at the moment that looks promising.
You could look through the assembly for any of your own subs that are ending in a goto another sub and try to rearrange the gcbasic code or add a bit dummy code so that the final basic statement in the sub isn't another subroutine - that should get rid of the goto's and pin down whether it is the problem.
Thanks for responding.
interrupt code is very simple and just keeps time.
its this
Sub IncCounter
TMR1L = 0
TMR1H = 11
TMR1L = 219
'Increment the counter
QSeconds += 1
if Qseconds = 4 then
Qseconds=0
tickb += 1
tick2 += 1
second += 1
end if
end sub
There are however subs which do call other subs, and they get shuffled around a lot
depending on how big they are , as well as how big the main prog is .
Currently ive managed to get the compiler to put the interrupt code in the first page and all is working fine.
Ill examine carefully what is now in the 2nd page , and see what gets shifted around.
I moved my big program to a bigger Pic 16F886 to see if the page problems dissapeared and they didnt.
The I implemented you patch to Gcbasic and all problems solved.
Looks like the gotos in the subs are the issue.
Fantastic.
Thanks for the fix.