Hexagon的程序执行顺序(一)

概述

Hexagon处理器支持如下的程序流程机制

 

  • l  条件指令
  • l  硬件循环
  • l  软件分支
  • l  暂停
  • l  异常

 

软件分支包括了跳转(jump),调用(call)以及返回(return)。Hexagon一共支持四种不同的跳转(jump):

 

  • l  推理跳转
  • l  比较跳转
  • l  寄存器转移跳转
  • l  双跳转

条件指令

很多Hexagon内部的处理器可以被选择性的执行。例如:

 

if (P0) R0 = memw(R2) // conditionally loadword if P0
if (!P1) jump label // conditionally jumpif not P1


  • l  如下的指令可以被指定为条件执行:
  • l  跳转与调用
  • l  大部分的load与store指令
  • l  逻辑指令(包括AND/OR/XOR)
  • l  半字移位
  • l  32位的寄存器或立即数加/减
  • l  有符号与零扩展
  • l  寄存器立即转移等

 

更多的指令可以去看我的文章

硬件循环

Hexagon处理器包括了硬件循环指令。硬件循环指令可以实现循环分支,例如:

 

     loop0(start,#3) // loop 3 times
start:
            { R0 = mpyi(R0,R0) } :endloop0

loop0和loop1提供了两系列的循环指令,两个循环可以将硬件循环形成一级嵌套。例如:

 

// Sum the rows of a 100x200 matrix.
     loop1(outer_start,#100)
outer_start:
     R0 = #0
     loop0(inner_start,#200)
inner_start:
     R3 = memw(R1++#4)
     { R0 = add(R0,R3) }:endloop0
{ memw(R2++#4) = R0 }:endloop1

硬件指令主要的应用场景如下:


  • 对于非嵌套循环,可以使用loop0来实现
  • 对于嵌套循环,loop0用于套内循环,loop1用于套外循环

 

每个硬件循环与一对特定的循环寄存器相关:

 

  • l  loop start address寄存器SAn被设定为循环中第一条指令的地址(通常该代码以汇编指令表示)
  • l  loop count寄存器LCn是32位的无符号值,用于确定循环的迭代次数。但程序计数器达到了循环的地步,LCn会被检查是否循环需要重复或者是退出

 

硬件循环设置指令可以一次性设置两个寄存器的值,既然如此我们就没必要分开两次来设置他们。但是,因为循环寄存器需要单独的设置循环状态,他的值可以被保存并且存储(既可以通过中断也可以通过软件执行),这使得循环寄存器可以被重新导入并正常继续。

 

Hexagon处理器为两个硬件循环提供了两列循环寄存器:

  • l  SA0以及LC0用于loop0
  • l  SA1以及LC1用于loop1

 

下图列出了硬件循环的指令:

Hexagon的程序执行顺序(一)_第1张图片


循环的设置

为了设置一个硬件循环,循环寄存器SAn与LCn必须被设置为相应的值。我们可以通过两种方法来实现:

 

一个loopN指令

向SAn以及LCn的寄存器转移指令

 

loopN指令可实现所有设置SAn和LCn的工作。例如:

 

     loop0(start,#3) // SA0=&start, LC0=3
start:
     { R0 = mpyi(R0,R0) } :endloop0


在这个案例中,硬件循环被执行了三次。loop0指令设置寄存器SA0的职位start的地址,设置LC0为3.

 

如果将循环数设置为立即数,则循环数的范围为0-1023。如果期望的循环次数比这个值大,那么我们必须用寄存器的值来定义它。例如:

 

使用loopN

     R0 = #20000;
     loop0(start,R0) // LC0=20000, SA0=&start
start:
     { R0 = mpyi(R0,R0) } :endloop0

使用寄存器转移:

R0 = #20000
LC0 = R0 // LC0=20000
R0 = #start
SA0 = R0 // SA0=&start
start:
{ R0 = mpyi(R0,R0) } :endloop0

如果一个loopN指令与他的循环开始地址距离太远,那么程序寄存器相对移位的值也许会超出指令起始操作数的最大范围。在这种情况下,要么把loopN的指令搬到离地址更近的地方,要么以一个32位的常数值来定义。例如:

 

     R0 = #20000;
     loop0(##start,R0) // LC0=20000, SA0=&start
     ...

循环的终止

嵌套硬件循环可以将同样的指令指定为内部或外部循环的终止。例如:

 

// Sum the rows of a 100x200 matrix.
// Software pipeline the outer loop.
     p0 = cmp.gt(R0,R0) // p0 = false
     loop1(outer_start,#100)
outer_start:
     { if (p0) memw(R2++#4) = R0
           p0 = cmp.eq(R0,R0) // p0 = true
           R0 = #0
loop0(inner_start,#200) }
inner_start:
     R3 = memw(R1++#4)
     { R0 = add(R0,R3) }:endloop0:endloop1
     memw(R2++#4) = R0

虽然endloopN表现的像一个常用的指令,但请注意他不会在任何堆中执行,并且不会在指令包中计数。因此一个单一指令包可以实现超过六个指令,其中包括:

 

l  四个常规指令

l  endloop0指令

l  endloop1指令

循环的执行

当我们为Hexagon DSP设置好硬件循环后,循环主体最起码会被执行一次,无论是否定义了循环次数(因为循环次数在执行后才会被检测)。因此,如果一个循环需要选择性的执行0次,那么必须用一个特殊而清晰的条件分支来定义,例如:

     loop0(start,R1)
     P0 = cmp.eq(R1,#0)
     if (P0) jump skip
start:
     { R1 = add(R1,#1) } :endloop0
skip:

在这个案例中,我们在R1寄存器中设置好了一个硬件循环,但是如果R1中的值为1,那么软件分支会直接跳过这个循环主体。

 

循环结束指令后,Hexagon处理器将检查相应的循环技术寄存器中的值:

 

l  如果值大于1,那么处理器将循环计数的值建议并实现一个跳转至start地址

l  如果值小于1,那么处理器将会立即继续程序的执行。


循环的限制

l  loopN中的循环设置指令包不能包含间接跳转,新值比较跳转或者dealloc_return指令

l  循环中的最后一个包不能包括任何程序流程指令(包括跳转和调用)

l  loop0中的循环终止包不能包含任何改变寄存器SA0或LC0的指令。同样的,loop1中的循环终止包不包含任何改变寄存器SA1或LC1的指令。

l  spNloop0的循环终止包不能包含任何改变P3寄存器的指令

你可能感兴趣的:(嵌入式,hexagon)