# LoongArch 内存模型与栅障

1.内存模型

1.1 访存类型

龙芯架构下支持三种存储访问类型,分别是:一致可缓存(Coherent Cached,简称CC)、强序非缓存(Strongly-ordered UnCached,简称SUC)和弱序非缓存(Weakly-ordered UnCached,简称WUC)。存储访问类型与访存虚拟地址绑定,通过页表项中的MAT(Memory Access Type)域决定。MAT域的值域存储访问类型的对应关系是:0–强序非缓存,1–一致可缓存,2–弱序非缓存,3–一保留。存储访问类型的设置过程对于应用软件是透明的。

采用一致可缓存访问类型访问时,所访问的对象既可以是最终存储对象也可以是处理器中维护有缓存一致性的缓存。通常采用这种访问类型访问内存以获得高性能。
采用强序非缓存或弱序非缓存类型访问时,只能直接访问最终存储对象。两者的区别在于:强序非缓存访问满足顺序一致性,即所有访问严格按照程序中的次序执行且当前访存操作彻底完成前不能开始执行下一个访存操作;而弱序非缓存的读访问允许推测执行,弱序非缓存的写数据可以在处理器核内部合并至更大的规模(如一个Cache行)后以突发(Burst)方式写出,合并过程中后面的写数据可以覆盖前面写数据。

龙芯架构下只要求强序非缓存类型的访存指令不能有副作用(Side Effect),即此类指令不可推测的执行。软件可以利用这一特性通过强序非缓存类型的访存指令来访问系统中的I/O设备。但是,龙芯架构允许强序非缓存类型的取指操作具有副作用。这是指,访问类型是强序非缓存类型的取指操作,即使它源自转移预测的结果,也允许执行。为避免此类推测执行所产生的核外访存操作误入非法的物理地址空间,需要在片上网络中过滤掉存在风险的访问。

弱序非缓存类型的访问通常用于加速非缓存的内存数据的访问,如显存数据。

1.1.1 指令Cache 的缓存一致性维护

某个处理器核的指令Cache与其它处理器核内的Cache或缓存一致输入输出主设备(Cache Coherent I/O Master)之间的缓存一致性必须由硬件维护
处理器核内部指令Cache与数据Cache之间的缓存一致性维护可以实现为硬件维护。这意味着对于自修改代码,软件不需要通过Cache维护指令来保证同一个核内部指令Cache与数据Cache之间的缓存一致性。不过,由于流水线结构和推测取指行为的存在,软件仍需要使用IBAR指令来确保取指一定能够看到store指令的执行效果。

1.2 非对齐存储访问

所有取指操作的访存地址必须4字节边界对齐,否则将触发取指地址错例外(ADEF)。
除了原子访存指令、整数边界检查访存指令和浮点数边界检查访存指令外,其余的load/store访存指令可以实现为允许访存地址不对齐。不过,在一个允许访存地址不对齐的实现中,系统态软件可以通过配置CSR.MISC中的ALCLOALCL3控制位,在PLVOPLV3特权等级下,对这些load/store访存指令也进行也址对齐检查。对于需要进行地址对齐检查的访存指令,如果其访问的地址不是自然对齐的,将触发地址非对齐例外(ALE)。

1.3 存储一致性模型

龙芯架构的存储一致性模型采用弱一致性(Weakly Consistency,简称WC)模型。本小节仅对架构所采用的弱一致性模型做一个简要描述。
在弱一致性模型中,同步操作和普通访存需要区分开来,程序员必须用架构所定义的同步操作把对于写共享单元的访问保护起来,以保证多个处理器核对于写共享单元的访问是互斥的。对访存事件发生次序做如下限制:
1.同步操作的执行满足顺序一致性条件。即同步操作在所有处理器核中都严格按照其在程序中出现的次序执行,且在当前同步操作彻底完成之前不能开始执行下一个同步操作。
2.在任一普通访存操作允许被执行之前,所有在同一处理器核中先于这一访存操作的同步操作都已经完成;
3.在任一同步操作允许被执行之前,所有在同一处理机中先于这一同步操作的普通访存操作都已完成。

龙芯架构中能够产生同步操作的指令有DBARIBAR、带有DBAR功能的AM原子访存指令以及LL-SC指令对。

2. 栅障指令

2.1 dbar

指令格式: dbar hint

hint 值默认为 0

用途:dbar 用于完成load/store 访存操作之间的栅障功能。其携带的立即数hint 用于指示该栅障的同步对象和同步程度。

只有等到之前所以load/store 访存操作彻底执行完毕后,dbar 0指令才开始执行;且只有dbar 0执行完成后,其后所有load/store访存操作才能开始执行。

代码应用示例(代码取自linux内核):

#define __sync()	__asm__ __volatile__("dbar 0" : : : "memory")

#define fast_wmb()	__sync()
#define fast_rmb()	__sync()
#define fast_mb()	__sync()
#define fast_iob()	__sync()
#define wbflush()	__sync()

#define wmb()		fast_wmb()
#define rmb()		fast_rmb()
#define mb()		fast_mb()
#define iob()		fast_iob()

#define __smp_mb()	__asm__ __volatile__("dbar 0" : : : "memory")
#define __smp_rmb()	__asm__ __volatile__("dbar 0" : : : "memory")
#define __smp_wmb()	__asm__ __volatile__("dbar 0" : : : "memory")

#ifdef CONFIG_SMP
#define __WEAK_LLSC_MB		"	dbar 0  \n"
#else
#define __WEAK_LLSC_MB		"		\n"
#endif

2.2 ibar

指令格式: ibar hint

hint 值默认为 0

用途:ibar 用于完成单个处理器核内部store 操作与取指操作之间的同步。其携带的立即数hint 用于指示该栅障的同步对象和同步程度。

它能够确保ibar 0指令之后的取指一定能够观察到ibar 0指令之前所以store操作的执行效果。

3. 参考资料

龙芯架构参考手册-卷一基础架构

你可能感兴趣的:(龙芯,loongarch,LoongArch,内存栅障)