2024-08-23 16:06:21 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2024, Barcelona Supercomputing Center (BSC)
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
*
|
|
|
|
* RBOOTROM v1.0
|
|
|
|
* Modified by Rodrigo Arias Mallo <rodrigo.arias@bsc.es>
|
|
|
|
*
|
|
|
|
* This is a custom bootrom that prints some information to the UART when
|
|
|
|
* starting, as well as when it hangs. It assumes the UART is at UART_BASE and
|
|
|
|
* it will jump to DRAM_BASE to continue the boot.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define DRAM_BASE 0x80000000
|
|
|
|
#define UART_BASE 0x40001000
|
2024-08-23 17:42:55 +02:00
|
|
|
#define UART_BAUDRATE 115200
|
|
|
|
#define UART_CLOCK 50000000
|
|
|
|
|
|
|
|
#define UART_BDIV ((UART_CLOCK + 8 * UART_BAUDRATE) / (16 * UART_BAUDRATE))
|
|
|
|
#define UART_SHIFT 2
|
|
|
|
|
|
|
|
#define UART_RBR_OFFSET (0<<UART_SHIFT) /* In: Recieve Buffer Register */
|
|
|
|
#define UART_THR_OFFSET (0<<UART_SHIFT) /* Out: Transmitter Holding Register */
|
|
|
|
#define UART_DLL_OFFSET (0<<UART_SHIFT) /* Out: Divisor Latch Low */
|
|
|
|
#define UART_IER_OFFSET (1<<UART_SHIFT) /* I/O: Interrupt Enable Register */
|
|
|
|
#define UART_DLM_OFFSET (1<<UART_SHIFT) /* Out: Divisor Latch High */
|
|
|
|
#define UART_FCR_OFFSET (2<<UART_SHIFT) /* Out: FIFO Control Register */
|
|
|
|
#define UART_IIR_OFFSET (2<<UART_SHIFT) /* I/O: Interrupt Identification Register */
|
|
|
|
#define UART_LCR_OFFSET (3<<UART_SHIFT) /* Out: Line Control Register */
|
|
|
|
#define UART_MCR_OFFSET (4<<UART_SHIFT) /* Out: Modem Control Register */
|
|
|
|
#define UART_LSR_OFFSET (5<<UART_SHIFT) /* In: Line Status Register */
|
|
|
|
#define UART_MSR_OFFSET (6<<UART_SHIFT) /* In: Modem Status Register */
|
|
|
|
#define UART_SCR_OFFSET (7<<UART_SHIFT) /* I/O: Scratch Register */
|
|
|
|
#define UART_MDR1_OFFSET (8<<UART_SHIFT) /* I/O: Mode Register */
|
|
|
|
|
|
|
|
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
|
|
|
|
#define UART_LSR_DR 0x01 /* Receiver data ready */
|
2024-08-23 16:06:21 +02:00
|
|
|
|
|
|
|
.macro PUTC, ch
|
|
|
|
li a0, \ch
|
|
|
|
jal putchar
|
|
|
|
.endm
|
|
|
|
|
|
|
|
.section .text.start, "ax", @progbits
|
|
|
|
.globl _start
|
|
|
|
_start:
|
2024-08-23 17:42:55 +02:00
|
|
|
jal uart_init // Initialize console
|
2024-08-23 16:06:21 +02:00
|
|
|
jal print_hello // Print initial message on HART 0 only
|
2024-08-23 16:46:40 +02:00
|
|
|
|
|
|
|
la t0, _hang
|
|
|
|
csrw mtvec, t0 // Set the machine trap vector
|
|
|
|
|
2024-08-23 16:06:21 +02:00
|
|
|
csrr a0, mhartid // Load HART ID into a0
|
|
|
|
li s0, DRAM_BASE // Load next address into s0
|
|
|
|
jr s0 // Jump to s0
|
|
|
|
|
|
|
|
.section .text.hang, "ax", @progbits
|
|
|
|
.globl _hang
|
|
|
|
_hang:
|
|
|
|
|
|
|
|
PUTC '\n'
|
|
|
|
PUTC '\r'
|
|
|
|
PUTC 'R'
|
|
|
|
PUTC 'B'
|
|
|
|
PUTC 'O'
|
|
|
|
PUTC 'O'
|
|
|
|
PUTC 'T'
|
|
|
|
PUTC 'R'
|
|
|
|
PUTC 'O'
|
|
|
|
PUTC 'M'
|
|
|
|
PUTC ' '
|
|
|
|
PUTC 'H'
|
|
|
|
PUTC 'A'
|
|
|
|
PUTC 'N'
|
|
|
|
PUTC 'G'
|
|
|
|
PUTC '\n'
|
|
|
|
PUTC '\r'
|
|
|
|
|
|
|
|
/* Hang */
|
|
|
|
csrr a0, mhartid
|
|
|
|
1:
|
|
|
|
wfi
|
|
|
|
j 1b
|
|
|
|
|
|
|
|
.section .text, "ax", @progbits
|
|
|
|
|
|
|
|
putchar:
|
2024-08-23 17:42:55 +02:00
|
|
|
/* Wait until ready to transmit */
|
|
|
|
|
|
|
|
la t0, UART_BASE // Load UART base address
|
2024-08-23 16:06:21 +02:00
|
|
|
1:
|
2024-08-23 17:42:55 +02:00
|
|
|
lb t1, UART_LSR_OFFSET(t0) // Read Line Status Register
|
|
|
|
andi t1, t1, UART_LSR_THRE // Transmitter Holding Register Empty
|
|
|
|
beqz t1, 1b // Repeat if zero (not empty)
|
|
|
|
|
|
|
|
/* Write the character now */
|
|
|
|
sb a0, UART_THR_OFFSET(t0) // Transmit character
|
|
|
|
ret
|
|
|
|
|
|
|
|
uart_init:
|
|
|
|
/* Assume reg_shift = 2 and reg_width = 2 */
|
|
|
|
|
|
|
|
la t0, UART_BASE // Load UART base address
|
|
|
|
|
|
|
|
/* From OpenSBI v1.5 lib/utils/serial/uart8250.c */
|
|
|
|
|
|
|
|
la t1, 0x00 // Disable all interrupts
|
|
|
|
sb t1, UART_IER_OFFSET(t0)
|
|
|
|
la t1, 0x80 // Enable DLAB
|
|
|
|
sb t1, UART_LCR_OFFSET(t0)
|
|
|
|
|
|
|
|
la t1, UART_BDIV & 0xff // Set divisor low byte
|
|
|
|
sb t1, UART_DLL_OFFSET(t0)
|
|
|
|
la t1, (UART_BDIV >> 8) & 0xff // Set divisor high byte
|
|
|
|
sb t1, UART_DLM_OFFSET(t0)
|
|
|
|
|
|
|
|
la t1, 0x03 // 8 bits, no parity, one stop bit
|
|
|
|
sb t1, UART_LCR_OFFSET(t0)
|
|
|
|
la t1, 0x01 // Enable FIFO
|
|
|
|
sb t1, UART_FCR_OFFSET(t0)
|
|
|
|
la t1, 0x00 // No modem control DTR RTS
|
|
|
|
sb t1, UART_MCR_OFFSET(t0)
|
|
|
|
|
|
|
|
/* TODO: Clear line status */
|
|
|
|
/* TODO: Read receive buffer */
|
|
|
|
|
|
|
|
la t1, 0x00 // Set scratchpad to 0
|
|
|
|
sb t1, UART_SCR_OFFSET(t0)
|
2024-08-23 16:06:21 +02:00
|
|
|
|
|
|
|
ret
|
|
|
|
|
|
|
|
print_hello:
|
|
|
|
csrr t0, mhartid // Load HART ID into a0
|
|
|
|
beq t0, zero, 1f // Print message on HART 0 only
|
|
|
|
ret
|
|
|
|
1:
|
2024-08-23 16:45:03 +02:00
|
|
|
mv s0, ra // Save return address
|
|
|
|
PUTC '\n' // Identify bootroom
|
2024-08-23 16:06:21 +02:00
|
|
|
PUTC '\r'
|
|
|
|
PUTC 'R'
|
|
|
|
PUTC 'B'
|
|
|
|
PUTC 'O'
|
|
|
|
PUTC 'O'
|
|
|
|
PUTC 'T'
|
|
|
|
PUTC 'R'
|
|
|
|
PUTC 'O'
|
|
|
|
PUTC 'M'
|
|
|
|
PUTC ' '
|
|
|
|
PUTC 'v'
|
|
|
|
PUTC '1'
|
|
|
|
PUTC '.'
|
|
|
|
PUTC '0'
|
2024-08-23 16:45:03 +02:00
|
|
|
PUTC ' '
|
|
|
|
PUTC ':'
|
|
|
|
PUTC '^'
|
|
|
|
PUTC ')'
|
|
|
|
PUTC '\n'
|
|
|
|
PUTC '\r'
|
|
|
|
|
|
|
|
// Print jumping address
|
|
|
|
PUTC 'J'
|
|
|
|
PUTC 'u'
|
|
|
|
PUTC 'm'
|
|
|
|
PUTC 'p'
|
|
|
|
PUTC 'i'
|
|
|
|
PUTC 'n'
|
|
|
|
PUTC 'g'
|
|
|
|
PUTC ' '
|
|
|
|
PUTC 't'
|
|
|
|
PUTC 'o'
|
|
|
|
PUTC ' '
|
|
|
|
PUTC '0' // TODO: Compute from DRAM_BASE
|
|
|
|
PUTC 'x'
|
|
|
|
PUTC '8'
|
|
|
|
PUTC '0'
|
|
|
|
PUTC '0'
|
|
|
|
PUTC '0'
|
|
|
|
PUTC '_'
|
|
|
|
PUTC '0'
|
|
|
|
PUTC '0'
|
|
|
|
PUTC '0'
|
|
|
|
PUTC '0'
|
|
|
|
PUTC '.'
|
|
|
|
PUTC '.'
|
|
|
|
PUTC '.'
|
2024-08-23 16:06:21 +02:00
|
|
|
PUTC '\n'
|
|
|
|
PUTC '\r'
|
2024-08-23 16:45:03 +02:00
|
|
|
|
|
|
|
mv ra, s0 // Restore return address
|
2024-08-23 16:06:21 +02:00
|
|
|
ret
|