FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

LiteXのUART書き込みのフローについて

LiteXにおけるUARTの書き込みについて、そのフローを確認しておく。

  • litex/litex/soc/software/libc/stdio.c
static int
litex_putc(char c, FILE *file)
{
    (void) file; /* Not used in this function */
#ifdef CSR_UART_BASE
    uart_write(c);
    if (c == '\n')
        litex_putc('\r', NULL);
#endif
    return c;
}

uart_write()を呼び出す。

  • litex/litex/soc/software/libbase/uart.c

ポイントは、IRQにおけるUART_INTERRUPTをDisableにして、tx_bufに文字を書き込んでいく。 書き込んだ後に、irqmaskを書き込み直して、割り込みを発生させる。 書き込みバッファにすでに値が入ってれば、バッファを更新する。そうでなければ、uart_rxtx_write(c)を直接書き込む。

void uart_write(char c)
{
    unsigned int oldmask;
    unsigned int tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;

    if(irq_getie()) {
        while(tx_produce_next == tx_consume);
    } else if(tx_produce_next == tx_consume) {
        return;
    }

    oldmask = irq_getmask();
    irq_setmask(oldmask & ~(1 << UART_INTERRUPT));
    if((tx_consume != tx_produce) || uart_txfull_read()) {
        tx_buf[tx_produce] = c;
        tx_produce = tx_produce_next;
    } else {
        uart_rxtx_write(c);
    }
    irq_setmask(oldmask);
}

このuart_rxtx_write()が実際にUARTのモジュールに書き込みを行う。

static inline void uart_rxtx_write(uint32_t v) {
    csr_write_simple(v, (CSR_BASE + 0x3000L));
}