I am using the 5.1 Codewarrier compiler for the 9S12XDP512. I want to be able to make the compiler generate a call that includes the page register. In the code I have:
void (*__far OD_func)(PLONG p) = pDict->obj->p.pFunc;
In the data structure I've declared a union that includes
void (* __far pFunc)(PLONG p)
From the S12CPUV2.pdf document:
CALL oprx16,xysp, page and the opcode should be 4B xb ee ff pg
where xb identifies which index format and which register is used. Trouble is I can't see what xb should be, so that the pg value is included in the instruction. Here's what's generated by the compiler where fb is F3 which matches the index dscription table in the S12CPUV2.pdf document.
Currently the function is in the same page so it doesn't matter. Also this doesn't work. If I replace __far with __near it does work but generates a JSR instead of the call.
0035 4bf30002 CALL [2,SP]
How do I do a paged call using a function pointer?
解決済! 解決策の投稿を見る。
Hi John,
thanks for your reply.
can you please send me your project for this problem?
Best Regards,
Jennie Zhang
Hi John,
first you use 9S12XDP512 which is HCS12x core device, you need to refer S12XCPUV2.pdf instead.
I will attach it to this thread.
which memory model do you working with for your project?
if use banked memory model, functions is allocated by far by default. Can you please check your project memory model?
Have a great day,
Jennie Zhang
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
-CPUHCS12X -D__FAR_DATA -D__NO_FLOAT__ -Lasm=%n.lst -Lasmc=ehpvy -Mb -Onf -Onbf -Onca -Oncn -One -OnP -WmsgSd5909
I am running banked as shown with -Mb.
I've tried putting the called function in a different segment. In the code it now shows up at: OD_ReadTemperature FBA9F3 4 4 2 PAGE_E0
as expected.
But the compiler generates
1149: void (* OD_func)(PLONG p) = pDict->obj->p.pFunc;
000e ed00 LDY 0,X
0010 e64f LDAB 15,Y
0012 eee810 LDX 16,Y
0015 6e83 STX 3,SP
0017 6b82 STAB 2,SP
To get at the new page register which is FB it needs to do a LDAB 18,Y
Instead it's loading the 0x00 in front of the actual address which is 00 A9 F3 FB
15,Y is 00 if it's a byte. 16,Y is A9F3 which is where the function lives.
18,Y would be the page number FB.
Later in the code it calls with the page 00 and crashes.
I still question if the compiler is even generating the correct code.
The stack at that location has have A9 F3 FC. I think it should be A9 F3 FB
It doesn't matter if I use the debugger to change the location.
A CALL [0002,SP] results in 00A9 for the address and F3 for the page.
If I change the data on the stack, shifting the bytes left one byte, to A9 F3 FB where [0002,SP] is the A9F3 the function call works correctly.
Thanks
John
And another quick follow-up to prove the compiler is generating incorrect code with comments ';;'.
1145: DictObjectRead(DICT_PARAM * pDict) {
1146: PBYTE rptr;
1147: DICT_PARAM * pDictTemp = pDict; // Add this as a place to save the pointer passed in D.
0004 6c87 STD 7,SP
1148: // If the object is valid, control code must be something other than 0
1149: if (pDict->obj->ctl) { // Process any functionally defined objects
0006 b745 TFR D,X
0008 ed00 LDY 0,X
000a e64c LDAB 12,Y
000c c100 CMPB #0
000e 2776 BEQ *+120 ;abs = 0086
1150: void (* OD_func)(PLONG p) = pDict->obj->p.pFunc;
0010 ed00 LDY 0,X
0012 e64f LDAB 15,Y ;; Loads 0x00 rather than page register
0014 eee810 LDX 16,Y ;; Loads offset to function
0017 6e85 STX 5,SP ;; Stores offset to wrong location
0019 6b84 STAB 4,SP ;; because it thinks page has to be in front of offset.
1151: asm ;; Above code doesn't work so we do it in assembler instead.
1152: LDX 7,SP ; restore * pDict
001b ee87 LDX 7,SP ;; Previous code trashed X so we get the copy back
1153: LDY 0,X ; point into pDict
001d ed00 LDY 0,X
1154: LDAB 18,Y ; Get the page register
001f e6e812 LDAB 18,Y
1155: LDX 16,Y ; Get the offset into that page
0022 eee810 LDX 16,Y
1156: STX 4,SP ; Store the offset
0025 6e84 STX 4,SP
1157: STAB 6,SP ; followed by the page register
0027 6b86 STAB 6,SP
1158: } Working assembler code completed
Now let's look at how it's used. This code as generated by the compiler works now.
1163: OD_func((PLONG)pDict->obj->pReqBuf); // pass result register.
0041 ee80 LDX 0,SP ;; Get our parameter to pass.
0043 ed00 LDY 0,X
0045 ec43 LDD 3,Y ;; Pass the parameter in the D register
0047 4bf30004 CALL [4,SP] ;; The opcode is correct and the call is to the function offset which is followed by the page value
Hi John,
thanks for your reply.
can you please send me your project for this problem?
Best Regards,
Jennie Zhang
Update on this after further research and testing.
The data structure that holds the pointer can be declared as (* pFunc)(long * p) or as (* __far pFunc)(long * p).
But everything else must be declared as __near. The compiler then generates a JSR instead of a CALL using the correct address for the function. The function must also be declared as __near so an RTS is used to get back. Forget that and it does an RTC.
It looks like the compiler thinks the page register is at the front of the address like 0xFC9317 when in memory it's organized as 0x9317FC. Since it does a LDAB to get the 0x93 at 15,Y and then LDX at 16,Y (brings in the 17FC) which is then stored 2 away from the SP. The CALL generated [0002,SP] and the program blows up.
As mentioned previously there doesn't seem to be a CALL instruction that loads the Page register along with the PC from registers although the compiler seems to think the B register has the page and it's placed on the stack just before the address.
1145: void (* __far OD_func)(PLONG p) = pDict->obj->p.pFunc;
000e ed00 LDY 0,X
0010 e64f LDAB 15,Y
0012 6b82 STAB 2,SP
0014 ece810 LDD 16,Y
0017 6c83 STD 3,SP
And here's the call to the function.
1150: OD_func((PLONG)pDict->obj->pReqBuf); // pass result register.
002f ee80 LDX 0,SP
0031 ed00 LDY 0,X
0033 ec43 LDD 3,Y
0035 4bf30002 CALL [2,SP]
Note the 4B F3 0002 instruction is correct for the CALL [2,SP] and that's a CALL that isn't supposed to have a page value after the 0002.
What I probably should be seeing is 4B F2 00 02 FC which is a 16 bit offset from the SP and should include the page register.
So is the compiler broken or am I doing something wrong?