Add uart software lib.

This commit is contained in:
Colin 2025-03-30 00:21:49 +08:00
parent 393499537d
commit d2942fe094
2 changed files with 257 additions and 0 deletions

115
test/sim/common/uart.h Normal file
View File

@ -0,0 +1,115 @@
#ifndef _UART_H_
#define _UART_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define UART_BASE 0x40004000
#ifndef __ASSEMBLER__
#include <stdint.h>
#define DECL_REG(addr, name) \
volatile uint32_t *const(name) = (volatile uint32_t *)(addr)
#define __time_critical __attribute__((section(".time_critical")))
typedef volatile uint32_t io_rw_32;
#endif
// #include "addressmap.h"
#include "uart_regs.h"
DECL_REG(UART_BASE + UART_CSR_OFFS, UART_CSR);
DECL_REG(UART_BASE + UART_DIV_OFFS, UART_DIV);
DECL_REG(UART_BASE + UART_FSTAT_OFFS, UART_FSTAT);
DECL_REG(UART_BASE + UART_TX_OFFS, UART_TX);
DECL_REG(UART_BASE + UART_RX_OFFS, UART_RX);
static inline void uart_enable(bool en) {
*UART_CSR = *UART_CSR & ~UART_CSR_EN_MASK | (!!en << UART_CSR_EN_LSB);
}
// 10.4 fixed point format.
// Encodes number of clock cycles per clock enable.
// Each baud period is 16 clock enables (default modparam)
static inline void uart_clkdiv(uint32_t div) { *UART_DIV = div; }
// Use constant arguments:
#define uart_clkdiv_baud(clk_mhz, baud) \
uart_clkdiv((uint32_t)((clk_mhz) * 1e6 * (16.0 / 8.0) / (float)(baud)))
static inline bool uart_tx_full() {
return !!(*UART_FSTAT & UART_FSTAT_TXFULL_MASK);
}
static inline bool uart_tx_empty() {
return !!(*UART_FSTAT & UART_FSTAT_TXEMPTY_MASK);
}
static inline size_t uart_tx_level() {
return (*UART_FSTAT & UART_FSTAT_TXLEVEL_MASK) >> UART_FSTAT_TXLEVEL_LSB;
}
static inline bool uart_rx_full() {
return !!(*UART_FSTAT & UART_FSTAT_RXFULL_MASK);
}
static inline bool uart_rx_empty() {
return !!(*UART_FSTAT & UART_FSTAT_RXEMPTY_MASK);
}
static inline size_t uart_rx_level() {
return (*UART_FSTAT & UART_FSTAT_RXLEVEL_MASK) >> UART_FSTAT_RXLEVEL_LSB;
}
static inline void uart_put(uint8_t x) {
while (uart_tx_full());
*(volatile uint8_t *const)UART_TX = x;
}
static inline uint8_t uart_get() {
while (uart_rx_empty());
return *(volatile uint8_t *const)UART_RX;
}
static inline void uart_puts(const char *s) {
while (*s) {
if (*s == '\n') uart_put('\r');
uart_put((uint8_t)(*s++));
}
}
// Have you seen how big printf is?
static const char hextable[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
static inline void uart_putint(uint32_t x) {
for (int i = 0; i < 8; ++i) {
uart_put((uint8_t)(hextable[x >> 28]));
x <<= 4;
}
}
static inline void uart_putbyte(uint8_t x) {
uart_put((uint8_t)(hextable[x >> 4]));
uart_put((uint8_t)(hextable[x & 0xf]));
}
static inline void uart_wait_done() { while (*UART_CSR & UART_CSR_BUSY_MASK); }
static inline void uart_init() {
*UART_CSR = 0;
while (*UART_CSR & UART_CSR_BUSY_MASK);
while (!uart_rx_empty()) (void)uart_get();
uart_enable(true);
}
static inline void uart_enable_cts(bool en) {
*UART_CSR = *UART_CSR & ~UART_CSR_CTSEN_MASK | (!!en << UART_CSR_CTSEN_LSB);
}
#endif // _UART_H_

142
test/sim/common/uart_regs.h Normal file
View File

@ -0,0 +1,142 @@
/*******************************************************************************
* AUTOGENERATED BY REGBLOCK *
* Do not edit manually. *
* Edit the source file (or regblock utility) and regenerate. *
*******************************************************************************/
#ifndef _UART_REGS_H_
#define _UART_REGS_H_
// Block name : uart
// Bus type : apb
// Bus data width : 32
// Bus address width : 16
#define UART_CSR_OFFS 0
#define UART_DIV_OFFS 4
#define UART_FSTAT_OFFS 8
#define UART_TX_OFFS 12
#define UART_RX_OFFS 16
/*******************************************************************************
* CSR *
*******************************************************************************/
// Control and status register
// Field: CSR_EN Access: RW
// UART runs when en is high. Synchronous reset (excluding FIFOs) when low.
#define UART_CSR_EN_LSB 0
#define UART_CSR_EN_BITS 1
#define UART_CSR_EN_MASK 0x1
// Field: CSR_BUSY Access: ROV
// UART TX is still sending data
#define UART_CSR_BUSY_LSB 1
#define UART_CSR_BUSY_BITS 1
#define UART_CSR_BUSY_MASK 0x2
// Field: CSR_TXIE Access: RW
// Enable TX FIFO interrupt
#define UART_CSR_TXIE_LSB 2
#define UART_CSR_TXIE_BITS 1
#define UART_CSR_TXIE_MASK 0x4
// Field: CSR_RXIE Access: RW
// Enable RX FIFO interrupt
#define UART_CSR_RXIE_LSB 3
#define UART_CSR_RXIE_BITS 1
#define UART_CSR_RXIE_MASK 0x8
// Field: CSR_CTSEN Access: RW
// Enable pausing of TX while CTS is not asserted
#define UART_CSR_CTSEN_LSB 4
#define UART_CSR_CTSEN_BITS 1
#define UART_CSR_CTSEN_MASK 0x10
// Field: CSR_LOOPBACK Access: RW
// Connect TX -> RX and RTS -> CTS internally (for testing).
#define UART_CSR_LOOPBACK_LSB 8
#define UART_CSR_LOOPBACK_BITS 1
#define UART_CSR_LOOPBACK_MASK 0x100
/*******************************************************************************
* DIV *
*******************************************************************************/
// Clock divider control fields
// Field: DIV_INT Access: WO
#define UART_DIV_INT_LSB 4
#define UART_DIV_INT_BITS 10
#define UART_DIV_INT_MASK 0x3ff0
// Field: DIV_FRAC Access: WO
#define UART_DIV_FRAC_LSB 0
#define UART_DIV_FRAC_BITS 4
#define UART_DIV_FRAC_MASK 0xf
/*******************************************************************************
* FSTAT *
*******************************************************************************/
// FIFO status register
// Field: FSTAT_TXLEVEL Access: ROV
#define UART_FSTAT_TXLEVEL_LSB 0
#define UART_FSTAT_TXLEVEL_BITS 8
#define UART_FSTAT_TXLEVEL_MASK 0xff
// Field: FSTAT_TXFULL Access: ROV
#define UART_FSTAT_TXFULL_LSB 8
#define UART_FSTAT_TXFULL_BITS 1
#define UART_FSTAT_TXFULL_MASK 0x100
// Field: FSTAT_TXEMPTY Access: ROV
#define UART_FSTAT_TXEMPTY_LSB 9
#define UART_FSTAT_TXEMPTY_BITS 1
#define UART_FSTAT_TXEMPTY_MASK 0x200
// Field: FSTAT_TXOVER Access: W1C
#define UART_FSTAT_TXOVER_LSB 10
#define UART_FSTAT_TXOVER_BITS 1
#define UART_FSTAT_TXOVER_MASK 0x400
// Field: FSTAT_TXUNDER Access: W1C
#define UART_FSTAT_TXUNDER_LSB 11
#define UART_FSTAT_TXUNDER_BITS 1
#define UART_FSTAT_TXUNDER_MASK 0x800
// Field: FSTAT_RXLEVEL Access: ROV
#define UART_FSTAT_RXLEVEL_LSB 16
#define UART_FSTAT_RXLEVEL_BITS 8
#define UART_FSTAT_RXLEVEL_MASK 0xff0000
// Field: FSTAT_RXFULL Access: ROV
#define UART_FSTAT_RXFULL_LSB 24
#define UART_FSTAT_RXFULL_BITS 1
#define UART_FSTAT_RXFULL_MASK 0x1000000
// Field: FSTAT_RXEMPTY Access: ROV
#define UART_FSTAT_RXEMPTY_LSB 25
#define UART_FSTAT_RXEMPTY_BITS 1
#define UART_FSTAT_RXEMPTY_MASK 0x2000000
// Field: FSTAT_RXOVER Access: W1C
#define UART_FSTAT_RXOVER_LSB 26
#define UART_FSTAT_RXOVER_BITS 1
#define UART_FSTAT_RXOVER_MASK 0x4000000
// Field: FSTAT_RXUNDER Access: W1C
#define UART_FSTAT_RXUNDER_LSB 27
#define UART_FSTAT_RXUNDER_BITS 1
#define UART_FSTAT_RXUNDER_MASK 0x8000000
/*******************************************************************************
* TX *
*******************************************************************************/
// TX data FIFO
// Field: TX Access: WF
#define UART_TX_LSB 0
#define UART_TX_BITS 8
#define UART_TX_MASK 0xff
/*******************************************************************************
* RX *
*******************************************************************************/
// RX data FIFO
// Field: RX Access: RF
#define UART_RX_LSB 0
#define UART_RX_BITS 8
#define UART_RX_MASK 0xff
#endif // _UART_REGS_H_