1

How do you declare a pointer on a 16 bit Renesas RL78 microcontroller using IAR's EWB RL78 compiler to a register which has a 20 bit address?

Ex:

static int *ptr = (int *)0xF1000;

The above does not work because pointers are 16 bit addresses.

Clifford
  • 88,407
  • 13
  • 85
  • 165
kamikazze
  • 13
  • 4
  • Does your compiler allow 32-bit pointers? What's `sizeof(int*)`? – Ed King Oct 26 '17 at 08:31
  • 1
    IAR make compilers for multiple targets, and not all 16 bit targets are alike; perhaps you could be more explicit! – Clifford Oct 26 '17 at 09:23
  • 1
    @EdKing : It only needs to support 20 bit pointers, and `sizeof(int*)` on its own is insufficient, you also need to know the value of `CHAR_BIT` on the platform in question. – Clifford Oct 26 '17 at 09:35
  • Does the microcontroller in question use paging? (or a separate peripheral address space?) – Realtime Rik Oct 26 '17 at 12:31
  • 16 bit MCU which places registers on 20 bit addresses? Really? That sounds very weird. Which MCU is it? – Lundin Oct 26 '17 at 13:36
  • Also, the question cannot be answered without knowing how large the register is. Is it 8 bits? 16 bits? – Lundin Oct 26 '17 at 13:37
  • @Realtime Rik - no paging. – kamikazze Oct 27 '17 at 07:12
  • @Lundin - RL78, the register has 20 bit address but all pointers are on 16bit address, – kamikazze Oct 27 '17 at 07:15
  • @kamikazze : Only if you use the _near data model_. Fix the question - if it is not in the question it cannot reasonably be addressed in an answer. You cannot expect everyone to read the comments. The question and its answer are very closely tied to the specific processor architecture and compiler. – Clifford Oct 28 '17 at 14:27
  • Never mind - fixed the question for you, with all teh information you have previously placed in comments. – Clifford Oct 28 '17 at 14:37
  • Your use of the term "_register_" followed by and example using an RL78 memory address (i.e. _not_ a register) still makes the question ambiguous and complicates the answer if it is to address (no pun intended) both register and memory addressing. – Clifford Oct 28 '17 at 15:26

1 Answers1

5

If the register in question is an on-chip peripheral, then it is likely that your toolchain already includes a processor header with all registers declared, in which case you should use that. If for some reason you cannot or do not wish to do that, then you could at least look at that to see how it declares such registers.

In any event you should at least declare the address volatile since it is not a regular memory location and may change beyond the control and knowledge of your code as part of the normal peripheral behaviour. Moreover you should use explicit sized data types and it is unlikely that this register is signed.

#include <stdint.h>

...

static volatile uint16_t* ptr = (uint16_t*)0xF1000u ;

Added following clarification of target architecture:

The IAR RL78 compiler supports two data models - near and far. From the IAR compiler manual:

● The Near data model can access data in the highest 64 Kbytes of data memory

● The Far data model can address data in the entire 1 Mbytes of data memory.

The near model is the default. The far model may be set using the compiler option: --data_model=far; this will globally change the pointer type to allow 20 bit addressing (pointers are 3 bytes long in this case).

Even without specifying the data model globally it is possible to override the default pointer type by explicitly specifying the pointer type using the keywords __near and __far. So in the example in the question the correct declaration would be:

static volatile uint16_t __far* ptr = (uint16_t*)0xF1000u ;

Note the position of the __far keyword is critical. Its position can be used to declare a pointer to far memory, or a pointer in far memory (or you can even declare both to and in far memory).

On an RL78, 0xF1000 in fact refers to the start of data flash rather then a register as stated in the question. Typically a pointer to a register would not be subject to alteration (which would mean it referred to a different register), so might reasonably be declared const:

static volatile uint16_t __far* const ptr = (uint16_t*)0xF1000u ;

Similarly to __far the position of const is critical to the semantics. The above prevents ptr from being modified but allows what ptr refers to to be modified. Being flash memory, this may not always be desirable or possible, so it is possible that it could reasonably be declared a const pointer to a const value.

Note that for RL78 Special Function Registers (SFR) the IAR compiler has a keyword __sfr specifically for addressing registers in the area 0xFFF00-0xFFFFF:

Example:

#pragma location=0xFFF20
__no_init volatile uint8_t __sfr PORT1;  // PORT1 is located at address 0xFFF20

Alternative syntax using IAR specfic compiler extension:

__no_init volatile uint8_t __sfr PORT1 @ 0xFFF20 ;
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • The problem is with the size of the address (20 bit long). The pointer will cast it to 16 bits and will mess it. It's more about near/far pointers here. – kamikazze Oct 26 '17 at 13:05
  • Nothing in the question indicates that the register is 16 bits wide though. The `uint16_t` must correspond to the register size. In my experience, most registers on 16 bit MCUs are just 8 bit wide. – Lundin Oct 26 '17 at 13:39
  • @kamikazze: `far` & `near` pointers are extensions to C and the implementation is compiler and processor specific. – Gerhard Oct 26 '17 at 13:44
  • @kamikazze : It will cast the value to whatever the pointer size is on your target, and as I have already commented you have not divulged that information. It does not follow that a 16 bit target has 16 bit pointers, in fact that is unlikely. near and far pointers are architecture specific, for 8086 segmented addressing for example. The compiler manual is the place to look, but since you have not specified the architecture we could not even know which manual to consult. Moreover you have not commented on my point about toolchain or chip vendor provided headers. The answer is in your hands – Clifford Oct 26 '17 at 20:48
  • @Clifford - It's a Renesas RL78. Yes "cast" wasn't the best way to express my idea. So, all pointers to RAM are near pointers (16 bit address) and the register has 20 bit address. If i'll set the address 0xF1000 to a pointer, it will point to 0x1000, because it will fit it to 16 bits. – kamikazze Oct 27 '17 at 06:28
  • @kamikazze : You need to edit your question to add that information, if it is only in a comment, it is not in the question, and most viewers will not read it. SO is not a discussion forum; the question needs to stand-alone. – Clifford Oct 28 '17 at 13:26
  • OK, now _I_ have the information on the processor _and_ the compiler, _I_ have looked in the [compiler manual](http://ftp.iar.se/WWWfiles/rl78/EWRL78_DevelopmentGuide.ENU.pdf), and it is clearly stated in pages 62 to 67 on _Memory types_. However I cannot reasonably update my answer _until_ your question contains the necessary information - answers should not respond to comments, only the question. The address 0xF1000 is not in fact a register, but the start of _data flash memory_. The default pointers are 16 bit _only_ in the _near data model_. It is all in the manual. – Clifford Oct 28 '17 at 13:51
  • Note to @kamikazze about the extension to this answer: I don't know any more than you, but I did read the manual! Knowing the precise target architecture was essential, don't keep us in the dark unnecessarily in future - it takes much longer to get an answer that way. – Clifford Oct 28 '17 at 15:05
  • Thank you. That is what i found in the manual too. The address 0xF1000 was just an exemple, not the address of a register, because i wanted the ideea, not a particular solution. But thank you again, it seems that the far pointer is the only solution. – kamikazze Oct 30 '17 at 05:57
  • @kamikazze : it patently is _not_ the only solution, as I have explained above, and for _registers_ the answer differs in any case, so using a non-register as an example leads to a misleading answer. – Clifford Oct 30 '17 at 07:49