1. hello rvos
用qemu模拟器模拟一块仿真的板子,然后通过模拟的串口线,在主机上打印hello
在qemu中,关于uart寄存器的内存映射如图(物理地址)
1. 源代码剖析
1. platform.h
用来定义开发板上的一些东西
#ifndef __PLATFORM_H__
#define __PLATFORM_H__
//这些宏用于防止重复包含头文件。#ifndef 检查宏 __PLATFORM_H__ 是否未定义,如果未定义,则定义它并继续包含文件内容。
#define MAXNUM_CPU 8 //定义系统中支持的最大 CPU 数量为 8 个
#define UART0 0x10000000L
//定义 UART0 的基地址为 0x10000000L。这个地址将用于访问 UART 控制寄存器
#endif /* __PLATFORM_H__ */
2. uart.c
整个uart.c包含uart初始化函数,读,写函数
uart初始化大概是设置分频寄存器从而设置波特率
读,写函数中的while循环都是寄存器不空闲而在等待
//整个uart寄存器被映射到内存中
#include "types.h"
#include "platform.h"
#define UART_REG(reg) ((volatile uint8_t *)(UART0 + reg))
//用于计算特定 UART 寄存器的地址
//uart0是基地址,reg对应的是第26行开始定义的那些寄存器。define RHR 0代表RHR寄存器偏移量为0
//定义了一组宏,用于访问不同的 UART 寄存器
#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
#define LSR_RX_READY (1 << 0)
#define LSR_TX_IDLE (1 << 5)
//uart_read_reg 和 uart_write_reg 用于读写寄存器
#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); //将中断使能寄存器 (IER) 设置为 0,禁用了所有 UART 中断
uint8_t lcr = uart_read_reg(LCR); //读取当前的 Line Control Register (LCR)。
uart_write_reg(LCR, lcr | (1 << 7)); //将 LCR 的 DLAB 位 (第 7 位) 置 1,以打开分频寄存器访问。
uart_write_reg(DLL, 0x03); //设置分频寄存器的低字节 (DLL) 和高字节 (DLM)
uart_write_reg(DLM, 0x00);
lcr = 0;
uart_write_reg(LCR, lcr | (3 << 0));
}
int uart_putc(char ch)
{
while ((uart_read_reg(LSR) & LSR_TX_IDLE) == 0); //若THR不空闲,则等待
return uart_write_reg(THR, ch);
}
void uart_puts(char *s)
{
while (*s) {
uart_putc(*s++);
}
}
// 读取一个字符
char uart_getc() {
while ((uart_read_reg(LSR) & LSR_RX_READY) == 0);
return uart_read_reg(RHR);
}
3. kernel.c
extern void uart_init(void);
extern void uart_puts(char *s);
void start_kernel(void)
{
uart_init();
uart_puts("Hello, RVOS!\n");
while (1) {}; // stop here!
}
2. exercise
在源代码基础上增加采用轮询方式读取控制台上输入的字符并回显在控制台上,另外用户按下回车后能够另起一行从头开始
extern void uart_init(void);
extern void uart_putc(char ch);
extern char uart_getc();
void start_kernel(void)
{
uart_init();
while(1)
{
char ch = uart_getc();
uart_putc(ch);
}
while (1) {}; // stop here!
}
这段代码我是本能写出来的,它也确实是对的。
但我不知道他为什么就实现了回车后能够另起一行从头开始
想了解这个估计要深入理解uart,但我现在还没有精力去了解它,所以就这样吧。