5.1. 64位屏障

CPC700 有一个 “特性”,该特性本应使某些内存访问使用 64 位宽度。这是一个问题,因为我们板上的一些测试和设置寄存器可能会被意外设置,因为我们试图读取低 16 位的内容。为了解决这种情况,我们将内存控制器设置为 64 位宽间隔。如果您尝试以其他方式(8 位或 16 位访问)访问这些区域,CPC700 会直接丢弃它们。我们必须能够读/写这些区域,因为重要的 “离散量”(由 Altera 设备控制)映射在那里。

为了访问这些区域,我们需要一个执行 64 位写入的函数。据我所知,在 PowerPC 上执行 64 位写入有两种方法:使用缓存行和使用浮点寄存器。浮点寄存器是一个 64 位大小的寄存器,因此当我们写入它时,整个 64 位都会被写入。问题是您不能在内核中执行浮点运算。由于内核在上下文切换期间不保存浮点寄存器,因此它不允许 FP,如果在内核中执行 FP 操作,则会抛出异常。

在尝试使用缓存行之后,我们决定采用 FP 方式,并添加了以下函数
void out64(__u32 addr, long long *pVal) {
	__u32 flags, tmp_msr;

	save_flags(flags);
	cli();
	tmp_msr = __get_MSR();
	tmp_msr |= MSR_FP;
	tmp_msr &= ~(MSR_FE0 | MSR_FE1);
	__put_MSR(tmp_msr);

	sysOut64(addr, pVal);
	__put_MSR(flags & ~(MSR_EE));
	restore_flags(flags);
}
该函数向 PowerPC MSR 寄存器添加一个浮点值,并确保执行 FP 操作不会产生任何异常。完成后,它使用汇编代码,如下文中的sysOut64()来执行实际的浮点运算。请注意,该函数会关闭中断,但这在这里是可以接受的,因为我们在极少情况下使用该函数。
_GLOBAL(sysOut64)
stwu    r1, -DEPTH(r1)
mflr    r0
stw     r31, FP_LOC(r1)
stw     r0,  LR_LOC(r1)
mr              r31, r1
stfd    fr0, FPR_SAVE(r31)      /* save floating point reg contents */

lfd     fr0,0(r4)
stfd  fr0,0(r3)
eieio

lfd     fr0, FPR_SAVE(r31)      /* restore floating point value */
lwz     r4, 0(r1)               /* now restore the stack frame  */
lwz     r0, 4(r4)
mtlr    r0
lwz     r31, -4(r4)
mr      r1, r4
blr