openhwgroup / cva6

The CORE-V CVA6 is an Application class 6-stage RISC-V CPU capable of booting Linux
https://docs.openhwgroup.org/projects/cva6-user-manual/
Other
2.23k stars 676 forks source link

[UART] UART using bare metal assembly ? #1924

Closed 0BAB1 closed 6 months ago

0BAB1 commented 6 months ago

Is there an existing CVA6 bug for this?

Bug Description

I tried making a UART assembly hello world but i can't seem to figure out how to make it display anything even though i translated your perfectly working C program from the 2024 contest.

So i used :

// uart.h

#define UART_BASE 0x10000000

#define UART_RBR UART_BASE + 0
#define UART_THR UART_BASE + 0
#define UART_INTERRUPT_ENABLE UART_BASE + 4
#define UART_INTERRUPT_IDENT UART_BASE + 8
#define UART_FIFO_CONTROL UART_BASE + 8
#define UART_LINE_CONTROL UART_BASE + 12
#define UART_MODEM_CONTROL UART_BASE + 16
#define UART_LINE_STATUS UART_BASE + 20
#define UART_MODEM_STATUS UART_BASE + 24
#define UART_DLAB_LSB UART_BASE + 0
#define UART_DLAB_MSB UART_BASE + 4

void init_uart();

void print_uart(const char* str);

void print_uart_int(uint32_t addr);

void print_uart_addr(uint64_t addr);

void print_uart_byte(uint8_t byte);

and :

//uart .c

void init_uart(uint32_t freq, uint32_t baud)
{
    uint32_t divisor = freq / (baud << 4);

    write_reg_u8(UART_INTERRUPT_ENABLE, 0x00); // Disable all interrupts
    write_reg_u8(UART_LINE_CONTROL, 0x80);     // Enable DLAB (set baud rate divisor)
    write_reg_u8(UART_DLAB_LSB, divisor);         // divisor (lo byte)
    write_reg_u8(UART_DLAB_MSB, (divisor >> 8) & 0xFF);  // divisor (hi byte)
    write_reg_u8(UART_LINE_CONTROL, 0x03);     // 8 bits, no parity, one stop bit
    write_reg_u8(UART_FIFO_CONTROL, 0xC7);     // Enable FIFO, clear them, with 14-byte threshold
    write_reg_u8(UART_MODEM_CONTROL, 0x20);    // Autoflow mode
}

void write_serial(char a)
{
    while (is_transmit_empty() == 0) {};

    write_reg_u8(UART_THR, a);
}

void write_reg_u8(uintptr_t addr, uint8_t value)
{
    volatile uint8_t *loc_addr = (volatile uint8_t *)addr;
    *loc_addr = value;
}

and also : https://static.dev.sifive.com/FU540-C000-v1.0.pdf (the doc mentionned this datasheet)

And came up with :

.section .data
uart_base: .word 0x10000000
hello:  .asciz "MOM GET THE CAMERA!\n"

.section .text
.globl _start
_start:

    # init UART
    la a1, hello
    la a2, uart_base
    li t0, 0x00
    sb t0, 0x4(a2)      #disable interupt
    li t0, 0x80
    sb t0, 0xC(a2)      #Enable DLAB (set baud rate divisor)
    li t0, 0x00
    li t1, 0x1b
    sb t0, 0x0(a2)      #divisor (lo byte)
    sb t1, 0x4(a2)      #divisor (hi byte)
    li t0, 0x03
    sb t0, 0xC(a2)      # 8 bits, no parity, one stop bit
    li t0, 0xC7
    sb t0, 0x8(a2)      #Enable FIFO, clear them, with 14-byte threshold
    li t0, 0x20
    sb t0, 0x10(a2)     #Autoflow mode

    #go print
    j write_loop

write_loop:
    # Write to uart
    lbu a0, 0(a1)
    beqz a0, done 
    sb a0, 0(a2)
    addi a1,a1,1
    j write_loop

done:
    j done

=> I copied your init sequence and write my string byte by byte in UART memory base until end of line.

But it does not work, no matter what i try. Is there a way to use UART in bare metal on CVA6 ?

jquevremont commented 6 months ago

Hi @0BAB1, the contest uses the Zybo Z7-20 board while this repository uses Genesys 2 as the reference board. BSP are not the same. We do not support Zybo here.