学习开发一个RISC-V上的操作系统(汪辰老师) — 01-helloRVOS程序讲解

news2025/2/26 23:04:14

前言

(1)此系列文章是跟着汪辰老师的RISC-V课程所记录的学习笔记。
(2)该课程相关代码gitee链接;
(3)PLCT实验室实习生长期招聘:招聘信息链接
(4)

start.S

(1)qemu模拟的板子有8个内核,为了让我们跟方便理解,汪辰老师只使用了一个内核。
(2)如下是进行判断,当前执行任务的是否是第一个内核。如果是的,往下执行,如果不是第一个内核,跳转到park任务中。

csrr	t0, mhartid		# read current hart id
mv	tp, t0			# keep CPU's hartid in its tp for later usage.
bnez	t0, park		# if we're not on the hart 0

(3)这里的wfi是让内核进入低功耗状态。如果没有这条语句,其他7个内核不进行任何操作,只是空转没必要,因此直接让他们进入休眠即可。这样省电。

park:
	wfi
	j	park

(4)这里主要是进行一些堆栈操作,最后的j,是跳转到c程序中。start_kernel你可以修改为任意名字,只要的c程序入口函数也修改为对应的函数名即可。

slli	t0, t0, 10		# shift left the hart id by 1024
la	sp, stacks + STACK_SIZE	# set the initial stack pointer
				# to the end of the first stack space
add	sp, sp, t0		# move the current hart stack pointer
				# to its place in the stack space

j	start_kernel		# hart 0 jump to c

kernel.c

(1)这里实际上就是在串口上打印一个Hello, RVOS!,之后进入空转状态。

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!
}

uart.c

宏定义

(1)因为qemu的串口0地址为0x10000000,所以这里以0x10000000为基地址进行偏移操作。这里建立一个宏的目的是为了后续方便操作。

/* --- 这个是在platform.h中 ---*/
#define UART0 0x10000000L
/* --- uart.c中 ---*/
#define UART_REG(reg) ((volatile uint8_t *)(UART0 + reg))

在这里插入图片描述

(2)这里的宏定义其实就是对照者如下表格来进行的宏定义的。这个时候肯定会有人有疑问,怎么偏移0地址和偏移1地址都是有多个寄存器的呢?
<1>对于偏移0地址而言,这个是串口的数据收发寄存器,一般来说,单片机的发送寄存器和接受寄存器都是同一个寄存器,这样可以保证资源的重复利用。那么单片机是如何知道这个寄存器的数据,到底是发送出去的,还是接受过来的呢?这个就是硬件层面的配置了对于写软件程序的我们,只需要知道,如果向这个寄存器写入数据,那么单片机就会发送数据。如果你要读取这个寄存器的数据,那么就是接收数据。 个人感觉这个可能和51单片机的IO准双向电路设计原理类似,感兴趣的可以去了解这部分电路设计。
<2>DLLDLM 又是什么呢?当LCR寄存器的bit7为1时候,偏移地址0和偏移地址1的两个寄存器就是被当成了波特率发生器寄存器,DLL就是波特率发生器的低8位,DLM就是高8位。(不理解的话,后面有更详细的介绍)

#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

在这里插入图片描述

(3)LSR寄存器的bit0是用于检测接受数据是否已经过来了,如果接收到了数据bit0 == 1LSR寄存器的bit5是用于判断串口数据是否发送出去,如果发送出去了bit5 == 0

#define LSR_RX_READY (1 << 0)
#define LSR_TX_IDLE  (1 << 5)

在这里插入图片描述
在这里插入图片描述

(4)上面说了,硬件上已经做好了处理,如果你写入数据,软件层面直接赋值。读取数据,直接获取这个寄存器数据即可。因此写法如下:

#define uart_read_reg(reg) (*(UART_REG(reg)))
#define uart_write_reg(reg, v) (*(UART_REG(reg)) = (v))

uart_init()

失能中断

(1)首先,我们对IER寄存器全部写入0,意思是关闭所有的中断。

IER BIT 7-4IER BIT-3IER BIT-2IER BIT-1IER BIT-0
全部置0modem状态寄存器中断接收中断发送完成中断接收就绪中断

在这里插入图片描述

// 失能所有中断
uart_write_reg(IER, 0x00);

波特率配置

(1)因为我们需要配置波特率,而配置波特率需要使用到DLLDLM寄存器。所以需要设置LCR寄存器的bit7为高电平。为了防止其他位被破坏,所以先读取LCR寄存器的值,再对bit7进行操作。

uint8_t lcr = uart_read_reg(LCR);

(2)使能内部波特率计数器锁存(DLAB),因为如果要配置波特率,需要先将这一位置为高电平。之后0地址和1地址的寄存器就变成了波特率设置寄存器。

uart_write_reg(LCR, lcr | (1 << 7));

(3)因为我们的仿真器是使用的1.8432MHZ的晶振进行的计算,最终需要生成的波特率是38.4K,就需要向DLL中写入3。至于为什么需要波特率是38.4K,这个我就不太清楚了。

uart_write_reg(DLL, 0x03);

在这里插入图片描述

(4)从上面的表我们可以看出,如果波特率为50,需要存入2304。而tb16550这款芯片的寄存器只有8位,明显是存放不下来的。因此IER寄存器在DLAB被使能的时候变成DLM,作为波特率生成器的高八位。因为我们需要写入的是3,所以DLM直接写0。

uart_write_reg(DLM, 0x00);

异步通讯格式配置

(1)这里就是设置有效数据为8位,停止位为1,不进行校验(当bit3为0时候,bit4--bit5都没有用)。因为不需要中断,所以bit6为0,波特率设置已经完成了,所以bit7为0。
(2)通过上面的分析,即可得出,LCR寄存器写入一个0000 0011即可。

lcr = 0;
uart_write_reg(LCR, lcr | (3 << 0));

在这里插入图片描述
在这里插入图片描述

uart_putc()

(1)这个函数就是用于发送一个字符数据的,如果玩过51单片机的同学都会知道,你进行串口发送数据的时候,都需要等待第一个数据发送完成,才可以开始第二个数据发送。否则就会出现,第一个数据还没有发送完,就被第二个数据覆盖了。因此第一个数据就无法成功的输出。
(2)通过查阅数据手册可知,当LSR寄存器的bit5 == 0时候,表示数据发送完成,因此这里需要进行一次while死循环。
(3)当LSR寄存器的bit5 == 0条件满足,退出while()循环,就可以发送数据了。

int uart_putc(char ch)
{
	while ((uart_read_reg(LSR) & LSR_TX_IDLE) == 0);
	return uart_write_reg(THR, ch);
}

在这里插入图片描述

uart_puts()

(1)因为我们需要发送一个字符串,而字符串的最后一位是'/0',所以写法如下。

void uart_puts(char *s)
{
	while (*s) {
		uart_putc(*s++);
	}
}

参考文章

(1)TECHNICAL DATA ON 16550;
(2)https://gitee.com/unicornx/riscv-operating-system-mooc/blob/main/code/os/01-helloRVOS/uart.c
(3)https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1087526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot项目入门: IDEA 创建SpringBoot项目

方式1:在线创建项目 https://start.spring.io/ 环境准备 &#xff08;1&#xff09;JDK 环境必须是 1.8 及以上&#xff0c;传送门&#xff1a;jdk1.8.191 下载&#xff08;2&#xff09;后面要使用到 Maven 管理工具 3.2.5 及以上版本&#xff08;3&#xff09;开发工具建议…

leetcode-279. 完全平方数

1. 题目链接 链接: 题目链接 2. 解答 #include <stdio.h> #include <stdlib.h> #include <stdbool.h>bool issquare(int n) {if (n 1 || n 4) return true;if (n 2 || n 3) return false;for (int i 3; i < n/2; i ) {if (n i*i) return true;}…

【HCIE】12.VXLAN

VXLAN&#xff0c;是一种IP VPN&#xff0c;每台设备几乎都支持IP&#xff0c;而MPLS会有很多设备不会支持&#xff0c;所以VXLAN是使用的较多。 采用MAC in UDP封装方式&#xff0c;MAC指的是原始数据的以太头部被封装到新的UDP头部里面。是基于三层的一个虚拟网络。 技术背…

13.SpringBoot项目之Service层

SpringBoot项目之Service层 JavaEE三层架构 为了项目维护方便&#xff0c;为了项目开发便利。三层架构功能控制器层&#xff1a;controller方便和前端数据进行交互业务层&#xff1a;service处理各种业务持久化层&#xff1a;mapper和数据库进行数据交互 抽取出service层 按…

华为汪涛:5.5G时代UBB目标网,跃升数字生产力

[阿联酋&#xff0c;迪拜&#xff0c;2023年10月12日] 在2023全球超宽带高峰论坛上&#xff0c;华为常务董事、ICT基础设施业务管理委员会主任汪涛发表了“5.5G时代UBB目标网&#xff0c;跃升数字生产力”的主题发言&#xff0c;分享了超宽带产业的最新思考与实践&#xff0c;探…

Ubuntu 23.10 Beta 镜像开放下载

导读Canonical放出了 Ubuntu 23.10 Beta 镜像&#xff0c;此外 Edubuntu、Kubuntu、Lubuntu、Ubuntu Budgie、Ubuntu Cinnamon、Ubuntu Kylin、Ubuntu MATE、Ubuntu Studio、Ubuntu Unity 和 Xubuntu 等风味版本也同步放出镜像。 近日消息&#xff0c;Canonical 放出了 Ubuntu …

【1++的Linux】之文件(二)

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的Linux】 文章目录 一&#xff0c;文件描述符二&#xff0c;重定向三&#xff0c;理解Linux下一切皆文件 一&#xff0c;文件描述符 我们先来看一段代码&#xff1a; #include<unistd.h&g…

什么是CDN内容分发网络?如何做到加速的?

这里写目录标题 CDN如何做到加速的&#xff1f; CDN content delivery network内容分发网络是建立并覆盖在承载网上&#xff0c;由遍布全球的边缘节点服务器群组成的分布式网络。 CDN将源站资源缓存在遍布全球的边缘加速节点服务器上&#xff0c;当客户需要访问和获取资源的时…

如何使用Net2FTP搭建免费web文件管理器打造个人网盘

文章目录 1.前言2. Net2FTP网站搭建2.1. Net2FTP下载和安装2.2. Net2FTP网页测试 3. cpolar内网穿透3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 文件传输可以说是互联网最主要的应用之一&#xff0c;特别是智能设备的大面积使用&#xff0c;无论是个人…

助力乡村教育 泰格智能AI英语开展捐赠实施线上培训

2023年10月11日晚8点至9点&#xff0c;泰格智能AI英语创始人李勤骞老师举行了一场为期一小时的线上培训&#xff0c;旨在详细解答泰格智能AI英语联合中国善网捐赠千词切APP训练账号的意义&#xff0c;探讨乡村教育、学习英语的现状和方法&#xff0c;以及项目的实施和落地要求。…

阿里健康携手15家药企发起“慢病减压计划”,为职场人的健康“减负”

近年来&#xff0c;慢性疾病患者的发病年龄正在逐年递减。一组来自阿里健康研究院内部分析数据印证了这一趋势。数据显示&#xff0c;当代80后职场人群中&#xff0c;三成用户购买过慢病药品。 30-39岁已经成为肝胆、心脑等相关疾病药品的购药主力人群 。35-39岁是高血压疾病药…

204、RabbitMQ 之 使用 topic 类型的 Exchange 实现通配符路由

目录 ★ 使用topic实现通配符路由代码演示topic通配符类型的Exchange代码演示:ConstantUtilConnectionUtilProducerConsumer01执行结果生产者消费者01消费者02 完整代码&#xff1a;ConstantUtilConnectionUtilProducerConsumer01Consumer02pom.xml ★ 使用topic实现通配符路由…

Linux系统移植框架简介

一、系统移植简介 系统移植就是给开发板安装一个linux系统。需要从官方下载u-boot源码&#xff0c;linux内核源码&#xff0c;根文件系统的源码&#xff0c;对源码进行配置和编译&#xff0c;生成对应的源码的镜像文件&#xff0c;将镜像文件部署到开发板中&#xff0c;使开发…

上海亚商投顾:沪指高开高走 锂电等新能源赛道大反攻

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日高开后强势震荡&#xff0c;创业板指盘中一度翻绿&#xff0c;随后探底回升再度走高。碳酸锂期货合约…

制药行业中的设备管理系统和CSV最佳实践

在制药行业&#xff0c;合规性和质量是关键要素&#xff0c;而设备管理和计算机化系统验证&#xff08;CSV&#xff09;是确保这些要素的关键。之前我们介绍过设备健康管理系统如何帮助制药企业实现CSV合规性>>PreMaint设备健康管理系统&#xff1a;实现制药企业的CSV合规…

Activiti 8.0.0 发布,业务流程管理与工作流系统

导读Activiti 8.0.0 现已发布。Activiti 是一个业务流程管理 (BPM) 和工作流系统&#xff0c;适用于开发人员和系统管理员。其核心是超快速、稳定的 BPMN2 流程引擎。Activiti 可以在任何 Java 应用程序、服务器、集群或云中运行&#xff0c;与 Spring 完美集成。 具体更新内容…

声音克隆,定制自己的声音,使用最新版Bert-VITS2的云端训练+推理记录

说明 本次训练服务器使用Google Colab T4 GPUBert-VITS2库为&#xff1a;https://github.com/fishaudio/Bert-VITS2&#xff0c;其更新较为频繁&#xff0c;使用其2023.10.12的commit版本&#xff1a;主要参考&#xff1a;B站诸多大佬视频&#xff0c;CSDN:https://blog.csdn.…

Visual Studio主题颜色及字体

一、打开VS上方的工具 二、选择“选项” 三、在“常规”中选择“颜色主题” 一共四个颜色供大家参考&#xff1a; ①深色 ②浅色 ③蓝色 ④蓝&#xff08;额外对比度&#xff09; 四、字体设置 左边环境中下划

【实训项目】“优品果园”-线上水果商城小程序

1.项目背景 随着现代人对消费水平的追求以及对食物安全的需要&#xff0c;无污染、产地直销的有机水果受到越来越多市民的喜欢。交易过程的简洁化是现代消费者的追求&#xff0c;产地直销也是近期流行的一种新型的交易模式。产地直销的交易模式使得交易过程更加简便快捷&#…