Using pointers to __far function.

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Using pointers to __far function.

Jump to solution
1,338 Views
jcdammeyer
Contributor III

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?

Labels (1)
0 Kudos
1 Solution
1,052 Views
ZhangJennie
NXP TechSupport
NXP TechSupport

Hi John,

thanks for your reply.

can you please send me your project for this problem?

Best Regards,

Jennie Zhang

View solution in original post

0 Kudos
6 Replies
1,052 Views
ZhangJennie
NXP TechSupport
NXP TechSupport

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!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,052 Views
jcdammeyer
Contributor III

-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

0 Kudos
1,052 Views
jcdammeyer
Contributor III

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

0 Kudos
1,053 Views
ZhangJennie
NXP TechSupport
NXP TechSupport

Hi John,

thanks for your reply.

can you please send me your project for this problem?

Best Regards,

Jennie Zhang

0 Kudos
1,051 Views
jcdammeyer
Contributor III

Thanks

Here is the Project File.

John

0 Kudos
1,051 Views
jcdammeyer
Contributor III

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?

0 Kudos