Skip to content

LA32R中的用户态整型指令

其它用户态指令

数据栅障指令

首先要说明一下,LA32R中的数据栅障指令虽然有“栅障(barrier)”的字眼,并不意味着单独用这个指令就能实现操作系统内核或各种支持多线程执行的库中的访存栅障(memory barrier)原语。访存栅障原语通常是针对一个多处理器系统的同步问题的,而数据栅障指令dbar只是用来对单个处理器核上load/store指令引发的访存操作定序的。这里定的“序”本质上是内存序(Memory Order),只不过为了方便读者理解,指令集手册里面还是用执行的角度来描述dbar指令的行为,但是手册中“彻底执行完毕”还是要在内存一致性(Memory Consistency)的概念体系下去解读。如果读者想彻底搞清楚为什么指令集要定义dbar指令,恐怕还是得把内存一致性基本了解一下。囿于篇幅,我们这里就对这方面的理论不展开讨论了,仅介绍两个最常见的会用到dbar指令的场景。

场景一、用汇编语言直接开发1的驱动涉及设备DMA和处理器核之间的数据交互。以处理器核写DMA读为例,当处理器核写完数据并用cacop指令2将缓存中的数据写回至内存,然后再通过非缓存访问属性的store指令写设备中的控制寄存器来通知其DMA开始从内存中读数据。软件如何保证DMA开始读内存的时候,之前从缓存中写回内存的数据一定都已经在内存中?就需要在cacop指令(序列)执行完之后加一个dbar 0指令,再执行非缓存访问属性的store指令。有的读者可能会想不明白,为什么DMA开始读内存的时候还有可能读不到缓存中写回内存。明白这个道理要从硬件角度来思考。虽然缓存数据写回内存的“写”操作和写设备中的控制寄存器的“写”操作在处理器核接口上是一先一后发出去的,但是前一个写操作的目的地是内存,后一个写操作的目的地是设备控制器,从处理器核到这两个不同目的地的写操作命令所走的路径可能不一样,又由于两条路径距离有远近以及路上拥塞情况不一样,就可能导致后发出的写操作比先发出的写操作先到达目的地,进而就有可能使得DMA从内存读回旧的错误的数据。

场景二、用汇编语言直接开发的用户程序中需要保证没有地址相关3的读写操作之间的顺序。由于有的处理器内部是允许访存操作乱序发射执行的,因此为了开发的程序适用于不同的硬件平台,程序员可以在需要确保执行顺序与预期一致的场景下使用dbar指令来避免乱序执行带来的不确定性。最典型的情况是,在store指令和load指令之间加dbar以避免load指令越过它前面的store指令提前执行。

访存取指栅障指令

LA32R中的ibar指令也是为了维护访存操作的序而定义的。它主要解决同一个处理器核上,前面的store指令的内存写操作与后面指令取指动作产生的内存读操作之间的顺序,不会因为处理器核内部的推测执行使得取指的内存读操作先于程序顺序在前的store指令的内存写操作发生。或许这样的描述还有点抽象,那么初学者只需记住自修改代码这个应用场景即可。所谓自修改代码场景,是指程序中生成了一段代码写入内存,然后在跳转到这段代码的入口处执行。切记,在跳转到自修改代码入口的跳转指令前加一条ibar指令。

预取指令

预取指令preld用于将指定地址处的数据取入到高速缓存中。那么为什么要单独定义它呢?preld addr_A是不是可以用ld.w $zero, addr_A来代替呢?这中间最关键的区别在于preld指令不会触发任何由访存地址引发的例外。这个特性带来的好处在于,当你在程序中使用preld指令时,无须额外的代码来判断该指令所用的地址落在合法的范围内。否则的话,使用预取指令引入的开销就有些大了,对于性能来说可能是得不偿失。

计时器读取指令

LA32R中定义了一个64比特的Counter,可以用rdcntvl.wrdcntvh.w指令读取它的计数值。定义这个Counter的目的是为了给用户程序提供一个低访问开销的高精度时钟源。64比特的位宽使得它几乎不会出现溢出的情况,但在32位架构下就不得不拆分为两条指令来读取。这时软件要注意执行过程中恰好发生低32位向高32位进位的场景,要进行特殊处理。严谨的代码可以采用如下的风格:

read_again:
    rdcntvh.w   $t1
    rdcntvl.w   $t0
    rdcntvh.w   $t2
    bne         $t1, $t2, read_again

LA32R中还定义了rdcntid指令来读取每个Counter对应的全局唯一ID号。在多核场景下,用户态程序可以用这个指令来高效率地判断当前执行所在的处理器核是否发生了变化。


  1. 如果是在一个操作系统下开发驱动,应尽量使用系统中提供的已经封装好的同步原语。 

  2. LA32R中设备DMA和处理器核之间的缓存一致性(Cache Coherency)由软件负责。这点与LA64并不相同。 

  3. 如果有地址相关的情况,处理器硬件必须保证它们之间的数据依赖不会因为执行顺序的不同而发生竞争冒险(Hazard)。