CW6.2 HC08 near pointers

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

CW6.2 HC08 near pointers

2,617 Views
kef
Specialist I

   int const * ptr2ci;   // a nonconst pointer to const object, right?

   int * const cptr2i;  // const pointer to nonconst object

 

If comments above are valid, then shouldn't near pointer to nonnear object be defined like this

 

  int * near nptr2i;

 

I think this ^^ should mean that ptr is to be placed to __SHORT_SEG and ptr should be able to address all 64k addresses.

 

And this pointer

 

  int near * ptr2ni;

 

could be placed anywhere and should be able to address only objects in __SHORT_SEG (addresses 0..0xFF).

 

 

 

But it looks like in reality it is reversed, ptr2ni behaves like nptr2i, and opposite.

 

   61:     *ptr2ni = 5;      
  0000 320000   [5]             LDHX  ptr2ni    <- pointer is 16bits wide
  0003 7f       [4]             CLR   ,X
  0004 a605     [2]             LDA   #5
  0006 e701     [3]             STA   1,X

   62:     ptr2ni = (void*)5;
  0008 ae05     [2]             LDX   #5
  000a 8c       [1]             CLRH 
  000b 960000   [5]             STHX  ptr2ni    <- pointer is 16bits wide

 


   61:     *nptr2i = 5;
  0000 ce0000   [4]             LDX   nptr2i   <- pointer is 8bits wide
  0003 8c       [1]             CLRH               <- widening X-> H:X
  0004 7f       [4]             CLR   ,X
  0005 a605     [2]             LDA   #5
  0007 e701     [3]             STA   1,X

   62:     nptr2i = (void*)5;
  0009 ae05     [2]             LDX   #5
  000b cf0000   [4]             STX   nptr2i

 

Is it normal?

 

CW help system is bit fuzzy, it gives following example

 

      int * __near i;     OK    __far pointer to int

 

I guess __far on the right is a typo. Also there's no int __near * i; case.

Labels (1)
Tags (1)
0 Kudos
7 Replies

657 Views
CompilerGuru
NXP Employee
NXP Employee

 

> If comments above are valid, then shouldn't near pointer to nonnear object be defined like this

 

The comments above are valid. But "near pointer" means that a pointer can only point

to near objects, therefore a "near pointer to nonnear object" does not exist.

 

There are 2 distinct things __near can define.

For a pointer type __near defines if the pointer type is a near

or far pointer. This defines if an object of that type is 1 byte or 2 bytes in size, it also defines what kind of objects can be reached with the pointer.

In this context __near is defining the type of the object.

In order to define the type of a pointer, the __near keyword must placed just after the star.

 

E.g.

int *__near p1;

int *__near* p2;


 

The type of p1 is  "int *__near", the type of p2 is "int *__near*".

In the case of p2 note that p2 itself is not a __near pointer, it just happens to point to one. So the size of p2 is 2 bytes (in the small memory model).

 

 

The second, independet topic is how the object itself is accessed.The compiler can either generate direct, 8 bit accesses or 16 bit externded addresses. This part is not specific to pointer, all kind of objects can have near access.

Also (and this is different from const) the __near access is not part of the type. It only aplies to the object.

For this use of __near, the keyword must be placed before the type, or for pointers it can also be listed after the type the pointer points to (if this is not itself a pointer).

E.g.

 

__near int in;

__near int* ip;

__near int** ip;

// Not recommended, easely confused with a near pointer type:

int __near * ip;

 

Here the near defines how the variables get accessed.

 

In real code using __near to define the access rarely is necessary. The __near object qualification on its own does not affect how the object gets allocated, so in order to be located in the zero page the object must also be allocated into a special section. By using a __DIRECT_SEG section qualifier, the __near object access gets the default for all object in such a section.

So using __near as an object qualifier is only necessary if the

default access to the section is not the right one. In practice that should rarely, if ever be the case.

So for variables to be placed into the zero page I would always write:

 

#pragma push

#pragma DATA_SEG __DIRECT_SEG ZERO_PAGE

int i;

int *__near pi = &i;

 

#pragma pop

 

The manual entry is obviously a copy paste bug.

 

Using __near (or const) after the int ("int __near i" or "int __near* ip") is equivalent to

using it before the int. But it is far more confusing in my opinion, so I'm always starting with the __near qualifier (for objects). Well as I said, code should rarely use __near for the object qualification anyway.

 

Daniel

 


 

 

 

0 Kudos

657 Views
kef
Specialist I

Thanks for your comments, Daniel. My 2nd attempt.

Const modifier used with pointers can apply 1) to pointer, 2) to object pointer points to, 3) to both, to pointer and to object pointer points to.

 

case1

   int * const ptr; // const pointer to regular object

 

case2

   const int *ptr;  // regular pointer to const object

  (^^ this is equivalent to  int const *ptr:smileywink:

 

case3

   const int * const ptr; // const pointer to const object

 

 

Now the same 3 cases should be available with near keyword.

case1

   int * near ptr; // near pointer to regular object. It means pointer should reside in zero page

 

case2

   int near * ptr; // regular pointer to near object. Means pointer can be placed anywhere, but can point only to zero page, addresses 0..ff

 

case3

   int near * near ptr; // near pointer to near object.

 

I see all 3 near cases working, but case1 and case2 are swapped. Compiler treats them as if Case1 was not a near pointer to regular object, but a regular pointer to near object. Case2 is alse reversed.

 

 


CompilerGuru wrote:

 

But "near pointer" means that a pointer can only point

to near objects, therefore a "near pointer to nonnear object" does not exist.


Why? I want to place most used pointer to zeropage, but pointer should be able to address whole 16bit address range. Compiler understands my needs, but it swaps the meaning of near pointer to regular with regular pointer to near.

 


int *__near* p2;


 

I'm not talking about pointers to pointers.


Also (and this is different from const) the __near access is not part of the type. It only aplies to the object.


To which object does it apply, to pointer, or to object pointer points to. I think rules should be the same like with const keyword. If keyword is closer to variable name than asterisk, then keyword applies to pointer (int * const ptr -- const pointer), else (int const * ptr or const int * ptr -- both pointers to const object). Obviously compiler uses different rules for near keyword.

 


In real code using __near to define the access rarely is necessary. The __near object qualification on its own does not affect how the object gets allocated,

Small memory model. Some variables near, some regular. I want to share some near variables and some regular variables among modules. I want all modules to use direct addressing with my zero page variables. Isn't it necessary to declare them with near keyword? How else compiler could decide extern variables can be accessed using direct addressing mode?


So for variables to be placed into the zero page I would always write:

 

#pragma push

#pragma DATA_SEG __DIRECT_SEG ZERO_PAGE

int i;

int *__near pi = &i;  // line 80 in my case

 

#pragma pop


I understand your pi as a near pointer to regular int. But compiler finds it problematic:

 

 

Warning : C1860: Pointer conversion: possible loss of data

main.c line 80  

Error   : C3400: Cannot initialize object (destination too small)

main.c line 80  

Error   : Compile failed

 

0 Kudos

657 Views
CompilerGuru
NXP Employee
NXP Employee

As I see it, the use of __near follows exactly the use of const for pointers.

int * const is a constant pointer, the pointer content is constant.

int * __near is a near pointer. The pointer content is 8 bit.

 

I see that the use of __near is different for objects (and I talk here about the object which gets qualified, not about the object refered to by a pointer) than for const, the reason is that __near in this case is not part of the type. So it follows how for example the static storage class is defined.

To make a variable static:

static int i;

static int* pi;

 

Note how this is different to how to make a variable const:

const int i = 0;

int * const pi = 0;


__near follows the static "model".

To access a variable with __near access:

__near int i;

__near int* pi;

 

So in this use case, __near does not change the type (as const does) it changes the way the variable is accessed. The type of a "__near int i" is int, just as it is int for "static int i".

By comparison the type of ci in "const int ci = 0" is const int.

 

In the end, when thinking about how to where to write __near the rule is simple.

It aplies to pointers only, and for those it is after the asterick.

This rule especially is valid for all kinds of pointers (pointers to pointers, function pointers, pinters to function pointers, not sure actually about pointers to members in C++, did not use those).

 

So while I can follow your reasoning, it's just different from what the compiler does. 

 

 

About the warning/error, hmm. I don't have any CW for MCU installed here (64 bit windows is not supported by the installer for 6.2....), so I cannot try. Must be a silly bug on my side.

But when using the proper qualifier for the section pragma the __near object qualifier is not needed for the typical use case.

Is the qualifier  __SHORT_SEG (and not as I guessed __DIRECT_SEG) ?

 

Daniel

0 Kudos

657 Views
kef
Specialist I

CompilerGuru wrote:

As I see it, the use of __near follows exactly the use of const for pointers.

int * const is a constant pointer, the pointer content is constant.

int * __near is a near pointer. The pointer content is 8 bit.


How near can follow const pointers, if code you suggested doesn't compile?

#pragma push

#pragma DATA_SEG __DIRECT_SEG ZERO_PAGE

int i;           

int *__near pi = &i;

#pragma pop

 

According to "const" rules, pi should be a near pointer to any object, not only near. pi should be 16bits wide. Extern declaration of pi should tell other source modules, that they can use direct addressing to access pi. This means pi has to be placed in direct addressing range 0..ff. But pi variable should be wider than 8bits!


I see that the use of __near is different for objects (and I talk here about the object which gets qualified, not about the object refered to by a pointer) than for const, the reason is that __near in this case is not part of the type. So it follows how for example the static storage class is defined.

To make a variable static:

static int i;

static int* pi;


If near follows static rules, then why this line compiles

 

  int * near p; 

 

and this doesn't compile

 

  int * static p;

 

Indeed something is very inconsistent.

 

And it makes a lot of sense for near to be a part of type. All these types make sense: near object in allocated in zero page, 8bits wide pointer to near object (pointer allocated in "far" memory), 16bits wide near pointer (allocated in zero page) to far object, near pointer to near object.


__near follows the static "model".


 

And I think near doesn't follow neither static nor const. 


To access a variable with __near access:

__near int i;

__near int* pi;


__near int * pi; doesn't compile! 


About the warning/error, hmm. I don't have any CW for MCU installed here (64 bit windows is not supported by the installer for 6.2....), so I cannot try. Must be a silly bug on my side.

But when using the proper qualifier for the section pragma the __near object qualifier is not needed for the typical use case.

Is the qualifier  __SHORT_SEG (and not as I guessed __DIRECT_SEG) ?


Yes, changing __DIRECT_SEG to __SHORT_SEG makes it compiling 

 

#pragma push

#pragma DATA_SEG __SHORT_SEG ZERO_PAGE

int i;           

int *__near pi = &i;

#pragma pop

 

 

But this 

 

int i;           

#pragma push

#pragma DATA_SEG __SHORT_SEG ZERO_PAGE

int *__near pi = &i;

#pragma pop

 

doesn't compile and I believe it should if near usage was similar to const usage.

 

Regards,

Edward

0 Kudos

657 Views
CompilerGuru
NXP Employee
NXP Employee

int i;           

#pragma push

#pragma DATA_SEG __SHORT_SEG ZERO_PAGE

int *__near pi = &i;

#pragma pop

 

>doesn't compile and I believe it should if near usage was similar to const usage.

 

Why should this compile? It clearly wont work properly. Well I probably would have defined it to be a serios warning, but in the end pointing with a near pointer to an 16 bit address is wrong.

 

Just because the syntax for __near pointers happens to have a similar syntax that const or volatile for pointers does not mean it has the same semantic or the same constraints.

const pointers can point to non constant objects, __near pointers cannot point to objects allocated non near.

 

0 Kudos

657 Views
kef
Specialist I

This example should work

 

int i;           

#pragma push

#pragma DATA_SEG __SHORT_SEG ZERO_PAGE

int *__near pi = &i;

#pragma pop

 

because like you said before (and I thought we agreed) that pi is a near pointer to int, not regular pointer to near int. Of course i isn't near.

 

BTW here what I see in manual for far keyword:

 

int __far *i;         OK          pointer to a __far object
int * __far i;        OK          __far pointer to int

 

Do you see the difference???? Compiler behaviour doesn't agree not only with "const model", but even with manual! Hope you won't say me __far keyword applies backwards compared to near.

 

Anyway thanks.

0 Kudos

657 Views
kef
Specialist I

More findings using extern declarations.

 

 extern char c;

   50:     c = 1;

  0000 a601     [2]             LDA   #1
  0002 c70000   [4]             STA   c    <-- extended addressing

 

extern near char nc;

   51:     nc = 5;
  0005 6e0500   [4]             MOV   #5,nc  <-- direct addressing

 

extern char      * near nptr2c;

    53:     *nptr2c = 17;
  0008 a611     [2]             LDA   #17
  000a ce0000   [4]             LDX   nptr2c  <-- pointer access extended

  000d 8c       [1]             CLRH               <-- pointer is 8bits wide
  000e f7       [2]             STA   ,X

 

 extern char near *      ptr2nc;

   54:     *ptr2nc = 15;
  000f a60f     [2]             LDA   #15
  0011 320000   [5]             LDHX  ptr2nc  <-- pointer access extended
  0014 f7       [2]             STA   ,X                 pointer is 16bits wide

 

 extern char near * near nptr2nc;

   55:     *nptr2nc = 20;  
  0015 a614     [2]             LDA   #20
  0017 ce0000   [4]             LDX   nptr2nc  <-- pointer access extended
  001a 8c       [1]             CLRH                <-- pointer is 8bits wide
  001b f7       [2]             STA   ,X

 

Now what is the difference between

   extern char      * near nptr2c;

and

   extern char near * near nptr2nc;

 

Looks like near to the left of * is USELESS.

 

Is the only way to make pointers accesses direct, to declare them between some DATA_SEG pragmas? Like this

 

#pragma push
#pragma DATA_SEG __SHORT_SEG ZERO_PAGE
extern char  *      ptr2nc; // near pointer to char
extern char  * near nptr2nc;  // actually near pointer to near char
#pragma pop

 

 

0 Kudos