QEMU仿真中串口的输入和输出
最近在QEMU上搭建CM33的仿真环境,目前QEMU支持的CM33的设备是musca-b1
等系列板卡,这个系列是ARM公司做的一个CM33的参考设计,也有相应的硬件开发板。因为我们主要就是关心仿真环境,所以只是关心系统的memory map和串口相关的资源.实际上对于MUSCA开发板, QEMU只是支持NVIC,串口和Systick这几个模块,其它诸如GPIO,timer等都是不支持的。
尽管QEMU支持的外设并不多,实际对于一般的软件层面的仿真已经足够了,这个实际也是QEMU的设计初衷,它的主要应用也是针对于软件的仿真,比如运行常见的操作系统,对于系统porting来说,实际就是中断和systick可以正常工作就可以了。
我们这里实际并没有引入操作系统,而是直接开发了一个bare metal的工程,实际也想试试QEMU对于TrustZone的支持,但是因为没能找到QEMU直接load多个elf的方法,或者合并elf的方法,暂时没能实现两个程序的同时下载,也就没能测试QEMU对于TrustZone是否支持。
QEMU对于外设的模拟和真实的硬件还是有一定区别的,比如模拟的串口并不需要进行开时钟,设置波特率等操作,需要发送数据就直接往DATA寄存器中写数据就可以了。并且是直接写直接发,单周期搞定,是不是很爽?所以对于模拟起来说,串口的输入输出可以直接通过下面的函数实现:
#define UART_TX_DATA_REG (*(volatile uint32_t *)0x40105000)
#define UART_FIFO_REG (*(volatile uint32_t *)0x40105018)
#define UART_FIFO_EMPTY_MASK (1 << 4U)
void env_put_char(char c)
{
UART_TX_DATA_REG = c;
}
char env_get_char()
{
while (UART_FIFO_REG & UART_FIFO_EMPTY_MASK)
{
}
return UART_TX_DATA_REG;
}
似乎还挺简单,跑个demo试试,输出完全没啥问题,但是输入嘛,似乎并不正常。比如我们调用一个inchar
函数,键盘敲了大半天也没反应,后面debug进去看看,奇了怪了,我只需要一个char,怎么到了函数里面就成了1024个?
原来这个是因为我使用的nano libc里面的输入和输出都是自带缓存的,所以我们从串口输入的时候实际上是系统从stdin
读取字符串,libc中这些外设都是模拟成一个文件的,所以读取的时候也就有缓存,比如默认的1K大小的缓存,所以我们调用inchar()
的时候,因为有缓存,默认的读取长度就变成了1K。为了修正这个问题,我们需要禁用stdin
和stdout
上的缓存,这个操作可以通过如下的方式实现:
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
里面的参数_IONBF
代表不使用缓存,后面的0是缓存大小,setvbuf的原型如下:
int setvbuf(FILE *stream, char *buffer, int mode, size_t size)
各个参数的定义:
- stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。
- buffer -- 这是分配给用户的缓冲。如果设置为 NULL,该函数会自动分配一个指定大小的缓冲。
- mode -- 这指定了文件缓冲的模式:
|模式|含义|
_IOFBF | 全缓冲:对于输出,数据在缓冲填满时被一次性写入。对于输入,缓冲会在请求输入且缓冲为空时被填充。 |
_IOLBF | 行缓冲:对于输出,数据在遇到换行符或者在缓冲填满时被写入,具体视情况而定。对于输入,缓冲会在请求输入且缓冲为空时被填充,直到遇到下一个换行符。 |
_IONBF | 无缓冲:不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略。 |
-size --这是缓冲的大小,以字节为单位。1
将缓冲区禁用之后,我们的串口输入和输出行为符合我们的预期。
顺便提一下,QEMU中所有的运行模式,包括while(1)都会消耗宿主CPU资源,一般会到100%,而STOP模式则不会消耗CPU,因此我们要在必要的时候调用asm("WFI");
进入STOP模式。
[1]https://www.runoob.com/cprogramming/c-function-setvbuf.html
- 1 ↩
最后更新于 2020-01-12 11:01:36 并被添加「ARM QEMU 仿真 cortex」标签,已有 11160 位童鞋阅读过。
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。
请问此bare metal的完整工程能否共享?
谢谢
请问你这个demo的完整工程能否发我一个,学习一下。
多谢!