Using CW 4.7 (with patch 4.7.1), target: 9S12XDT512
Application is TCP-IP stack implemented as a ROM library installed in processor memory, prior to installing an application program. ROM library is located in a far code segment and banked model is being used to construct the library as a project in its own right. Customised application programs will be built as separate projects that can call functions from the common firmware library.
I have written most functions for a module called UDPIP, based loosely on Freescale AN2304. This module covers Layer 3 of the OSI protocol stack: Ethernet driver below it, a TCP module above it, and an HTTP module above that. The 'middle layer' primarily implements IP, but with UDP and ICMP thrown in.
So far I have written and (mostly) tested and debugged the following functions:
Sending:
UDP_Write() : invoked by higher layer when UDP protocol req'd - mainly for DHCP client
IP_Write() : invoked by UDP_Write() and - when I get to it - TCP_Write()
Receiving:
IP_Receive() : invoked as a callback from lower layer
ICMP_Receive() : invoked by IP_Receive() if protocol is ICMP - generates Echo Reply to a Ping
UDP_Handler() : invoked by IP_Receive() if protocol is ICMP
- others to follow
Problem:
The compiler INSISTS on treating UDP_Write() as the subject of a near function call - assembly code shows RTS at the end, whereas all others show RTC. I've tried the following:
- naming the code segment with and without the __FAR qualifier
- including and not including the __far prefix with the UDP_Write() prototype (and with the function name in the source code)
- messing about with linker segments and placements
- looking through past 12 months of posts on this board
- tearing hair out
- etc
The only difference between UDP_Write() and other functions in this module is that it has a dependency (IP_Write()) in the same module; this situation may change in due course, as more of the module and other modules are written.
UDP_Write() calls IP_Write() using a far call, as you'd expect with the banked model and without pragmas to override. But UDP_Write() in general would be called from another module, and possibly from another page of code memory. It is essential that, in general, this function be called using a far call. But the compiler insists it is a near function, while all the others are allowed to be far functions.
What could be special about a function in a far segment that makes the compiler treat it as a near 'callee', and put an RTS at the end instead of RTC?
Solved! Go to Solution.
- Make sure you do not have an imlicit parameter declaration (header not included or prototype not visible for whatever reason).
-A RTS can also occur for calls internal to the function. Hmm. Given your description, this may really be your issue. The compiler does build subfunctions inside of functions for repeated code patterns and those are called with JSR and end with RTS. For those cases the function call and the call target are inside of the same function only and therefore never cross a page boundary.
Using -onf switches of the optimization (should not be necessary, just to verify that this is the origin of the RTS).
- Note that the final return for a function does not have to be at the end. The "real" RTC maybe somewhere in the middle before the internal subfunctions.
Daniel
- Make sure you do not have an imlicit parameter declaration (header not included or prototype not visible for whatever reason).
-A RTS can also occur for calls internal to the function. Hmm. Given your description, this may really be your issue. The compiler does build subfunctions inside of functions for repeated code patterns and those are called with JSR and end with RTS. For those cases the function call and the call target are inside of the same function only and therefore never cross a page boundary.
Using -onf switches of the optimization (should not be necessary, just to verify that this is the origin of the RTS).
- Note that the final return for a function does not have to be at the end. The "real" RTC maybe somewhere in the middle before the internal subfunctions.
Daniel
Daniel - you fully deserve the title 'CompilerGuru'!
The last point you made turns out to be the answer - the last few lines of the assembler listing are just a subroutine within a subroutine, the "real" RTC is, indeed, further back.
In this project there is also a low-level firmware library containing hardware dependent functions (eg to SPI ports with tricky interfaces to other sections of the board) and I wrote much of that library as assembly language routines. I'm a bit of an 'assembler buff' anyway (though I don't attempt to write Windows applications in assembly language, which I believe some freaks do). I don't normally put subroutines within subroutines, but I'm aware that a compiler will often do that, depending on the optimization rules it is using. It just didn't enter my head that that's what I was looking at in the assembler listing of the C function library.
Anyway, many thanks for your advice. It's a relief to know that the compiler isn't up the chute - only me!
Neil