mirror of
https://github.com/plctlab/riscv-operating-system-mooc.git
synced 2025-11-16 12:34:47 +00:00
121 lines
3.4 KiB
C
121 lines
3.4 KiB
C
#include "types.h"
|
||
#include "platform.h"
|
||
|
||
/*
|
||
* The UART control registers are memory-mapped at address UART0.
|
||
* This macro returns the address of one of the registers.
|
||
*/
|
||
#define UART_REG(reg) ((volatile uint8_t *)(UART0 + reg))
|
||
|
||
/*
|
||
* Reference
|
||
* [1]: TECHNICAL DATA ON 16550, http://byterunner.com/16550.html
|
||
*/
|
||
|
||
/*
|
||
* UART control registers map. see [1] "PROGRAMMING TABLE"
|
||
* note some are reused by multiple functions
|
||
* 0 (write mode): THR/DLL
|
||
* 1 (write mode): IER/DLM
|
||
*/
|
||
#define RHR 0 // Receive Holding Register (read mode)
|
||
#define THR 0 // Transmit Holding Register (write mode)
|
||
#define DLL 0 // LSB of Divisor Latch (write mode)
|
||
#define IER 1 // Interrupt Enable Register (write mode)
|
||
#define DLM 1 // MSB of Divisor Latch (write mode)
|
||
#define FCR 2 // FIFO Control Register (write mode)
|
||
#define ISR 2 // Interrupt Status Register (read mode)
|
||
#define LCR 3 // Line Control Register
|
||
#define MCR 4 // Modem Control Register
|
||
#define LSR 5 // Line Status Register
|
||
#define MSR 6 // Modem Status Register
|
||
#define SPR 7 // ScratchPad Register
|
||
|
||
/*
|
||
* POWER UP DEFAULTS
|
||
* IER = 0: TX/RX holding register interrupts are bith disabled
|
||
* ISR = 1: no interrupt penting
|
||
* LCR = 0
|
||
* MCR = 0
|
||
* LSR = 60 HEX
|
||
* MSR = BITS 0-3 = 0, BITS 4-7 = inputs
|
||
* FCR = 0
|
||
* TX = High
|
||
* OP1 = High
|
||
* OP2 = High
|
||
* RTS = High
|
||
* DTR = High
|
||
* RXRDY = High
|
||
* TXRDY = Low
|
||
* INT = Low
|
||
*/
|
||
|
||
/*
|
||
* LINE STATUS REGISTER (LSR)
|
||
* LSR BIT 0:
|
||
* 0 = no data in receive holding register or FIFO.
|
||
* 1 = data has been receive and saved in the receive holding register or FIFO.
|
||
* ......
|
||
* LSR BIT 5:
|
||
* 0 = transmit holding register is full. 16550 will not accept any data for transmission.
|
||
* 1 = transmitter hold register (or FIFO) is empty. CPU can load the next character.
|
||
* ......
|
||
*/
|
||
#define LSR_RX_READY (1 << 0)
|
||
#define LSR_TX_IDLE (1 << 5)
|
||
|
||
#define uart_read_reg(reg) (*(UART_REG(reg)))
|
||
#define uart_write_reg(reg, v) (*(UART_REG(reg)) = (v))
|
||
|
||
void uart_init()
|
||
{
|
||
/* disable interrupts. */
|
||
uart_write_reg(IER, 0x00);
|
||
|
||
/*
|
||
* Setting baud rate. Just a demo here if we care about the divisor,
|
||
* but for our purpose [QEMU-virt], this doesn't really do anything.
|
||
*
|
||
* Notice that the divisor register DLL (divisor latch least) and DLM (divisor
|
||
* latch most) have the same base address as the receiver/transmitter and the
|
||
* interrupt enable register. To change what the base address points to, we
|
||
* open the "divisor latch" by writing 1 into the Divisor Latch Access Bit
|
||
* (DLAB), which is bit index 7 of the Line Control Register (LCR).
|
||
*
|
||
* Regarding the baud rate value, see [1] "BAUD RATE GENERATOR PROGRAMMING TABLE".
|
||
* We use 38.4K when 1.8432 MHZ crystal, so the corresponding value is 3.
|
||
* And due to the divisor register is two bytes (16 bits), so we need to
|
||
* split the value of 3(0x0003) into two bytes, DLL stores the low byte,
|
||
* DLM stores the high byte.
|
||
*/
|
||
uint8_t lcr = uart_read_reg(LCR);
|
||
uart_write_reg(LCR, lcr | (1 << 7));
|
||
uart_write_reg(DLL, 0x03);
|
||
uart_write_reg(DLM, 0x00);
|
||
|
||
/*
|
||
* Continue setting the asynchronous data communication format.
|
||
* - number of the word length: 8 bits
|
||
* - number of stop bits:1 bit when word length is 8 bits
|
||
* - no parity
|
||
* - no break control
|
||
* - disabled baud latch
|
||
*/
|
||
lcr = 0;
|
||
uart_write_reg(LCR, lcr | (3 << 0));
|
||
}
|
||
|
||
int uart_putc(char ch)
|
||
{
|
||
while ((uart_read_reg(LSR) & LSR_TX_IDLE) == 0);
|
||
return uart_write_reg(THR, ch);
|
||
}
|
||
|
||
void uart_puts(char *s)
|
||
{
|
||
while (*s) {
|
||
uart_putc(*s++);
|
||
}
|
||
}
|
||
|