微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 模拟电路设计 > Xtensa处理器窗寄存器函数调用机制与应用

Xtensa处理器窗寄存器函数调用机制与应用

时间:10-10 来源:互联网 点击:

口处ENTRY指令将首先进行Window重叠检测,条件满足的时候将触发相应的windows overflow异常,引导程序进行覆盖寄存器的入栈保护。

  正常模式下函数内部指令的寄存器引用,如xxx ar,as,at,处理器在非异常模式下将进行正常的window检测,否则产生非法指令异常。

  4.Windows寄存器检测方法

  寄存器覆盖检测通过如下硬件semantic实现:

  WindowCheck

  n ← if (wr ≠ 2'b00 or ws ≠ 2'b00 or wt ≠ 2'b00) and WindowStartWindowBase+1 then 2'b01

  else if (wr1 or ws1 or wt1) and WindowStartWindowBase+2 then 2'b10

  else if (wr = 2'b11 or ws = 2'b11 or wt = 2'b11) and WindowStartWindowBase+3 then 2'b11

  else 2'b00

  if CWOE = 1 and n ≠ 2'b00 then

  PS.OWB ← WindowBase

  m ← WindowBase + (2'b00||n)

  PS.EXCM ← 1

  EPC[1] ← PC

  nextPC ← if WindowStartm+1 then WindowOverflow4

  else if WindowStartm+2 then WindowOverflow8

  else WindowOverflow12

  WindowBase ← m(注:和Overflow跳转并行)

  endif

  通过深入解析如上原语,有如下注意要点:任何地方引用a0~a3不会产生windows异常,因此在用户的c或者汇编代码里可以任意使用,为什么呢? 因为在a0~a3引用的任意环境里,当前函数的逻辑窗里的物理寄存器,要么是无覆盖安全到达,要么是经过了函数调用entry指令触发windows overflow异常,在异常里,a0~a3的所在物理AR寄存器已经安全地压栈保存了。

  a15~a4之间的高位寄存器(比如a15)引用会触发低位寄存器(如a4)的寄存器覆盖检测,哪怕没有指令显式的应用低位寄存器,触发的顺序将是先进行overflow4,overflow8,至overflow12,从而最有效和最安全地保存活动寄存器。通过了解以上两点,读者可以深入理解Tensilica提供的高效XTOS代码,透彻体会相关代码的精妙之处。

  5. Windows寄存器下溢(underflow)问题

  当子函数返回时,RETW或者RETW.N指令执行,此时也仅此时处理器将进行上溢检查。如果当Windowbase所在位置的前3个window pane(4 registers组)的WindowStart比特都为零,则意味着返回后的父函数发生过 WindowOverflow,父函数的窗口寄存器曾经被压入栈,要先行通过相应的underflow弹出。

  如果不是全为零,则应该不为零的点和正常window返回的点对应,要正常返回,如果不同,则说明发生了不正常的调用,a0被破坏掉,要产生非法指令错误。关于这个方面的具体硬件原语,读者可以参考Xtensa的ISA手册,这里不再赘述。

Alloca异常问题

  C语言中函数中经常会发生从堆栈中分配临时空间的情况,在正常的不发生窗寄存器溢出的时候没有任何问题。但是,如果该函数的下级函数的嵌套调用曾导致过寄存器溢出,由于该函数的堆栈Frame底部存有溢出的basic area的寄存器,如果简单的偏移堆栈指针来分配临时空间,则这些保存过basic寄存器会被完全破坏掉。为有效解决这一问题,Xtensa架构引入一个特殊的Alloca异常来管理basic area寄存器的搬移和临时空间的分配。

  当函数内部进行局部stack的内存分配时,Xtensa编译器会生成一个MOVSP at,as指令,异常的检测通过这一指令来完成,该指令有如下原语:

  if WindowStartWindowBase-0011WindowBase-0001 = 03 then

  Exception (AllocaCause)

  elseAR[t] ← AR[s]

  endif

  类似于underflow,如果当前寄存器窗口前3个register pane的占用状态全为0(全部为自由使用状态),则说明其上一级函数一定发生过窗口溢出,当前函数栈下方一定保存有溢出的寄存器,简单的修改SP指针不再安全,需要触发Alloca异常来进行正确处理。需要说明的是,发生alloc异常的时候,过去的寄存器窗口调用已经循环一周,且发生溢出,溢出的充分必要条件必然是当前寄存器窗口的前3个register pane占用状态全为0(WindowStartWindowBase-0011WindowBase-0001 = 000),其次当前函数不可能是调用树的叶子节点,当前函数的前半部分曾经进入过,且过去进入的路径上发生过溢出,否则就没有产生异常的必要。alloca异常是为解决sp覆盖而引入的硬件机制。

  这里解释了alloc异常产生的基本原理,那么,什么样的代码会产生MOVsp指令,从而可能触发alloc异常呢? 有如下几种情况:

  调用alloc函数,如

  void foo(int array_size) {

  char * bar = alloca(array_size);

  …

  使用变长数组(GNU C 扩展语言),如

  void foo(int array_size) {

  char bar[array_size];

  …

  使用嵌套函数定义(GNU C 扩展语言),如

  void afunction(void) {

  …

int anotherfunc

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top