Amoswap on uart.txdata register

Hi,

I’m writing some code that directly interfaces the UART. In the U540 documentation it mentions that:

A RISC‑V amoswap instruction
can be used to both read the full status and attempt to enqueue data, with a non-zero return
value indicating the character was not accepted.

When I try this approach I see some characters duplicated in the output.

Reading the FSBL source code I notice that rather than amoswap an amoor instruction is used. (https://github.com/sifive/freedom-u540-c000-bootloader/blob/master/uart/uart.c#L15). When I switch to using amoor rather than amoswap everything works as expected and I don’t get any duplicated characters.

I’m new to RISC-V so it’s very possible my code using amoswap is wrong in some way, so I’ve got two questions:

  1. Is it possible to use amoswap to write to txdata while checking the full bit?
  2. Why does the FSBL source use amoor rather than amoswap

Note: I’m seeing this behavior on the Unleashed platform (haven’t tried on any simulator).

amoswap source code
.equ UART_BASE_ADDRESS, 0x10010000

.text

.globl _start
_start:
        csrrs   t0, mhartid, x0         /* get hartid */
        bnez    t0, busy_loop           /* got to busy loop if not hart0 */

        la      t0, message             /* load pointer to hello world message */
        li      t1, UART_BASE_ADDRESS   /* load address of UART txdata register */

next_byte:
        lbu     t2, (t0)                /* load byte from message */
        beqz    t2, busy_loop           /* null terminated, so finish */
        addi    t0, t0, 1               /* increment message pointer */
retry:
        amoswap.w t3, t2, (t1)          /* atomically read txdata into t3 and write t2 (message char) to txdata */
        bnez    t3, retry               /* if t3 != 0 then full bit was set, so have to retry */
        j       next_byte               /* current byte successfully written to FIFO, get next byte */

busy_loop:
        j       busy_loop


.data
message:
        .asciz "Hello World\r\n"

amowap output:

SiFive FSBL:       2018-03-20
HiFive-U serial #: 00000313
Helllo  Woorlld

Note: the actual duplicated characters are not deterministic

amoor source code
.equ UART_BASE_ADDRESS, 0x10010000

.text

.globl _start
_start:
        csrrs   t0, mhartid, x0         /* get hartid */
        bnez    t0, busy_loop           /* got to busy loop if not hart0 */

        la      t0, message             /* load pointer to hello world message */
        li      t1, UART_BASE_ADDRESS   /* load address of UART txdata register */

next_byte:
        lbu     t2, (t0)                /* load byte from message */
        beqz    t2, busy_loop           /* null terminated, so finish */
        addi    t0, t0, 1               /* increment message pointer */
retry:
        amoor.w t3, t2, (t1)            /* atomically read txdata into t3 and write t3 | t2 to tx data*/
        bnez    t3, retry               /* if t3 != 0 then full bit was set, so have to retry */
        j       next_byte               /* current byte successfully written to FIFO, get next byte */

busy_loop:
        j       busy_loop


.data
message:
        .asciz "Hello World\r\n"

amoor output:

SiFive FSBL:       2018-03-20
HiFive-U serial #: 00000313
Hello World

Thanks,

Ben

I did some more research into this. Reading the sifive-blocks code I came across this commit:

It looks like writes to the txdata register with the txfull bit set will quash the sending of the byte (effectively making it so that write is ignored by the device).

(At least that’s my assumption, I don’t really know the language that the blocks are written in, and I’m not a hardware guy).

I have to assume that the atomics working on IO registers are not atomic with respect to operations within the device (such as consuming bytes from the FIFO), but I assume they are atomic with respect to other bus masters writing to the registers.

I think in this case it means that the documentation is incorrect and should be updated to make it clear that an amoor instruction is required and that writing to the txdata register with txfull bit set will result in the write being ignored by the device.

Is this accurate? Is the documentation source available? If so, I’ll write a patch.

The docs are not in a public tree. I filed an internal issue against them. The uart source is in a public tree, you could always try filing an issue there.

The doc sources have been updated to mention amoor.w instead of amoswap. I don’t know if any old docs will be regenerated, but at least new docs will match the source.

Thanks Jim! Appreciate your time looking in to it. I feel a bit more confident in understanding how the system works now.

hi benno,

I am trying with UART stuff for Freedom U540- board, if want to do so what is the standard procedure that i need to follow to test UART ,in the board is any code available.