RISC-V 指令集

16 篇文章 0 订阅
2 篇文章 0 订阅

ISC-V 原子操作

RV32A有两种类型的原子操作

  • 内存原子操作(AMO)
  • 加载保留/条件存储(load reserved/store conditional)

RISC-V的原子指令中包含两部分,分别是LR/SC指令和AMO指令。

LR/SC指令必须成对使用,才能达到原子效果,在执行LR指令的同时,处理器会设置相应的标志位,用于监控其内存地址上有没有其它hart访问,有没有产生中断异常,有没有执行MRET指令。只要发生上述情况里的一种,就会导致SC指令执行失败。通过这样的规则,才能确保LR与SC指令之间的操作是原子的。

LR 指令是个缩写,全名是 Load Reserved,即保留加载;而 SC 指令的缩写展开是 Store Conditional,即条件存储

不过,有时候LR/SC指令用起来还是挺复杂的,所以AMO类指令(即原子内存操作)应运而生。RISC-V提供了一系列AMO类指令,它们是原子交换指令、原子加法指令、原子逻辑指令、原子取大小指令,这些指令相比LR、SC指令,使用起来更加方便。
AMO 是 Atomic Memory Operation 的缩写,即原子内存操作。AMO 指令又分为几类,分别是原子交换指令、原子加法指令、原子逻辑指令和原子取大小值指令。 

 在这里插入图片描述

Spinlock:
 

自旋锁(spin lock)的状态有两种:

  • 0: lock is unlocked/free/released 未加锁
  • 1: lock is locked/held/acquired 加锁

锁的结构体:

typedef struct {
	u32 locked;    ///< data inside atomic_t, is the lock held?
} atomic_t;

其中变量 locked 只有 0 或者 1,用于指示是否加锁。

在实际的实现中,RISC-V Architecture为我们提供了一个原子化的指令 atomic swap instruction ("AMOSWAP"),实现多个进程(Core)同时访问 shared memory locked 变量。

初始化锁:

static inline void spinlock_init(atomic_t *p)
{
	p->locked = 0;
}

获取锁:

// Acquire the lock.
// Loops (spins) until the lock is acquired.

static inline void spinlock_lock(atomic_t *p)
{
  // On RISC-V, sync_lock_test_and_set turns into an atomic swap:
  //   a5 = 1
  //   s1 = &p->locked
  //   amoswap.w.aq a5, a5, (s1)
  while(__sync_lock_test_and_set(&p->locked, 1) != 0);

  // Tell the C compiler and the processor to not move loads or stores
  // past this point, to ensure that the critical section's memory
  // references happen strictly after the lock is acquired.
  // On RISC-V, this emits a fence instruction.
  __sync_synchronize();
}

释放锁:

static inline void spinlock_unlock(atomic_t *p)
{
  // Tell the C compiler and the CPU to not move loads or stores
  // past this point, to ensure that all the stores in the critical
  // section are visible to other CPUs before the lock is released,
  // and that loads in the critical section occur strictly before
  // the lock is released.
  // On RISC-V, this emits a fence instruction.
	__sync_synchronize();

  // Release the lock, equivalent to lk->locked = 0.
  // This code doesn't use a C assignment, since the C standard
  // implies that an assignment might be implemented with
  // multiple store instructions.
  // On RISC-V, sync_lock_release turns into an atomic swap:
  //   s1 = &p->locked
  //   amoswap.w zero, zero, (s1)
	__sync_lock_release(&p->locked);
}

xv6源码阅读系列(3) 锁的实现 - 知乎 (zhihu.com)

xv6源码解读1:启动,xv6! - 知乎 (zhihu.com)

RISC-V 的栈也是向下扩展的,高地址为栈底,低地址为栈顶,所以sp = stack0 + (hartid * 4096),将高地址加载到sp寄存器中。

首先,在RISC-V计算机打开电源上电之后,它会初始化自己并运行一个在只读内存中的boot loader。Boot loader将xv6的内核加载到物理地址为0x80000000內存中,至于为什么不从0x0开始,那是因为在0x0~0x80000000的地址范围里包含了I/O设备。

然后在machine mode下,CPU从_entry(位于kernel/entry.S)开始运行xv6。我们来看看这段代码。

.section .text
.global _entry
_entry:
        # set up a stack for C.
        # stack0 is declared in start.c,
        # with a 4096-byte stack per CPU.
        # sp = stack0 + (hartid * 4096)
        la sp, stack0
        li a0, 1024*4
        csrr a1, mhartid
        addi a1, a1, 1
        mul a0, a0, a1
        add sp, sp, a0
        # jump to start() in start.c
        call start
spin:
        j spin

可以看到,这是一段汇编代码,会做一些必要的事情来启动xv6,比如,设置一个栈区,这样就xv6就可以运行C代码。关于初始栈 stack0 的空间声明,我们可以在 kernel/start.c 中找到代码。

__attribute__ ((aligned (16))) char stack0[4096 * NCPU];

在上面的汇编代码中,注释里有一个 hartid,事实上这是hart的编号。什么是 hart?RISC-V处理器对底层提供了一种抽象,叫Hardware Thread,简称hart,中文可以翻译为硬件线程。可以把hart理解为是真实CPU提供的一种模拟,关于 hart、core、CPU的一些区别并不是操作系统层面需要关心的,我们在这里可以简单地将三者视为同样的概念,把hartid看作是cpuid。

__sync_synchronize();

这个函数是一个内存屏障,告诉编译器和CPU不要越过屏障重排 load 和 store 指令,也就是说将这条语句之前和之后的读写指令分隔开。这么做是因为编译器在编译的过程中可能会做一些优化,导致代码的顺序发生一些变化,使用这条语句相当于加了一个锁。

Xv6操作系统导论(第一章)_唱丶跳和Rap的博客-CSDN博客

Xv6操作系统导论(第二章)_唱丶跳和Rap的博客-CSDN博客

Xv6操作系统导论(第三章)_唱丶跳和Rap的博客-CSDN博客

Xv6操作系统导论(第四章)_唱丶跳和Rap的博客-CSDN博客

Xv6操作系统导论(第五章)_唱丶跳和Rap的博客-CSDN博客

Xv6操作系统(第六章)_唱丶跳和Rap的博客-CSDN博客

Xv6操作系统导论(第七章)_唱丶跳和Rap的博客-CSDN博客

Xv6操作系统导论(第八章)_唱丶跳和Rap的博客-CSDN博客

GitHub - mit-pdos/xv6-riscv: Xv6 for RISC-V

6.S081 / Fall 2020 (mit.edu)

xv6: a simple, Unix-like teaching operating system (mit.edu)

1、RISC-V规范

了解RISC-V相关内容,RISC-V的规范是肯定要读的,这个是绕不过去的。

规范地址:Specifications – RISC-V International (riscv.org)

2、《计算机组成与设计——硬件/软件接口》 RISC-V版本

 中文版

3、《The RISC-V Reader: An Open Architecture Atlas》

这本书已经由包云岗等几位老师翻译成中文了,可以免费下载,地址:

The RISC-V Reader: An Open Architecture Atlas (riscvbook.com)

 

An Introduction to Assembly Programming with RISC-V

RISC-V Assembly Programming (riscv-programming.org)

RISC-V 官方文档请见:

指令集架构 (ISA) 定义了计算机指令集,包括但不限于指令的行为、它们的编码以及指令可能访问的资源,例如 CPU 寄存器。 为给定 ISA 生成的程序可以由任何实现兼容 ISA 的计算机执行。

ISA 往往会随着时间的推移而发展,但是,ISA 设计者试图使较新的 ISA 版本与以前的版本兼容,以便遗留代码,即为以前版本的 ISA 生成的代码,仍然可以由较新的 CPU 执行。 例如,为 80386 ISA 生成的程序可以由实现此或任何其他兼容 ISA(例如 80486 ISA)的任何处理器执行。

RV32I ISA 规定指令使用 32 位编码。 因此,假设系统有一个字节寻址内存 (byte addressable memory),每条指令占用四个内存字。 此外,它指定指令按顺序执行,与它们在主内存中出现的顺序相同。

RISC-V汇编语言入门(三)—编译、链接 - 知乎 (zhihu.com)

RISC-V汇编语言入门(四)—组成、规范 - 知乎 (zhihu.com)

RISC-V汇编语言入门(六) —RV32I指令集 - 知乎 (zhihu.com) 

RISC-V体系结构编程与实践

 

计算机体系结构简明教程(RISC-V版) 蒋本珊 PDF电子版

链接:https://pan.baidu.com/s/1s6kM6RqjxI1HUVp0NUzqFA?pwd=4dav 

提取码:4dav  作者:诗音碧霄 https://www.bilibili.com/read/cv23040111 出处:bilibili

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值