Improper access to an on-chip peripheral register in Renesas RX port layer

Hello,

The following issues about FreeRTOS source code were reported to the Renesas’s Japanese user forum of RX MCU. With respect to this kind of these issues, I think that fixing it at the FreeRTOS master source code is better than fixing it at user’s local source code. Can I ask FreeRTOS maintainers to fix it at the FreeRTOS master source code? If possible, what should I do to ask them to fix it?

  1. In Renesas RX port layer, the SWINTR on-chip peripheral register (byte-size (8-bits width)) is written as byte-size, but it is read back as long-size (32-bits width). The register has to be read back as byte-size.

  2. Renesas RX MCU pipeline is so smart that only simple reading back from the SWINTR is not enough to wait for the completion of writing to the SWINTR. The operation using the value read has to be executed.

These issues were reported to the following Japanese thread which was started by hirakuni45. And the modified code which was proposed by him in his another post to another site was cited by me to this thread. (Reported code was for the CC-RX compiler but proposed code was for the GNURX compiler.)

Question about FreeRTOS code (Please note that original title and all contents are Japanese.)
https://japan.renesasrulz.com/cafe_rene/f/forum5/5878/freertos/

The code of FreeRTOS Kernel V10.3.1 and our proposal are the following, for example, regarding to the portable/Renesas/RX600v2/portmacro.h file which is one of many Renesas RX’s portmacro.h files. And a screen copy of two pages of RX64M Group User’s Manual is attached.

FreeRTOS Kernel V10.3.1

#pragma inline_asm vPortYield
static void vPortYield( void )
{
    /* Save clobbered register - may not actually be necessary if inline asm
    functions are considered to use the same rules as function calls by the
    compiler. */
    PUSH.L R5
    /* Set ITU SWINTR. */
    MOV.L #553696, R5                   ----> 553696 = 872E0H
    MOV.B #1, [R5]
    /* Read back to ensure the value is taken before proceeding. */
    MOV.L [R5], R5                      <---- HERE!
    /* Restore clobbered register to its previous value. */
    POP R5
}

Proposal

#pragma inline_asm vPortYield
static void vPortYield( void )
{
    /* Save clobbered register - may not actually be necessary if inline asm
    functions are considered to use the same rules as function calls by the
    compiler. */
    PUSH.L R5
    /* Set ITU SWINTR. */
    MOV.L #553696, R5
    MOV.B #1, [R5]
    /* Read back to ensure the value is taken before proceeding. */
    CMP [R5].UB, R5                     <---- HERE!
    /* Restore clobbered register to its previous value. */
    POP R5
}

RX64M Group User’s Manual: Hardware
https://www.renesas.com/us/en/search/keyword-search.html#genre=document&q=r01uh0377
r01uh0377ej0110-rx64m.pdf

Thank you for reporting. I will look into these right away and, assuming we agree with the report, ensure the code is updated for the next release. For your information you can also create pull requests for us to review and upstream here: https://github.com/FreeRTOS/FreeRTOS-Kernel

Thank you for your quick reply. If you find something that you disagree with, please let me know.

We are going to make this update in four Renesas compiler ports (RX100, 200, 600 and 600v2) and three IAR ports (RX100, 600 and 600v2).

[addition, just in case you are not aware, if you have future feedback you are able to report it here or directly create a pull request here to get updates upstreamed https://github.com/FreeRTOS/FreeRTOS-Kernel]

Hello Richard,

I notice that ICCRX needs the clobber list in the following code at least using strong optimization compile option. (I noticed it when I debugged my code for RXv3 DPFPU port layer.) I think that not only ICCRX but also GNURX has a possibility which causes the same issue of “inline assembly code”. On the other hand, CC-RX does not need such specification because the syntax used by CC-RX is not “inline assembly code” but “inline assembly code function”. CC-RX applies the same rule of normal function to “inline assembly code function” regarding to keeping/not keeping registers and keeping PSW is not required in the both function type.

ICCRX (and probably GNURX) needs the followig clobber list in the portYIELD()'s inline assembly code:

#define portYIELD()                         \
    __asm volatile                          \
    (                                       \
        "PUSH.L R10                 \n"     \
        "MOV.L  #0x872E0, R10       \n"     \
        "MOV.B  #0x1, [R10]         \n"     \
        "CMP    [R10].UB, R10       \n"     \
        "POP    R10                 \n"     \
        ::: "cc"                            \        <---- HERE!
    )

Ack.

[apparently I need 20 character to post - ignore this just getting the character count up!]