以统一格式使用指令有什么好处?

 沫小兮 发布于 2023-01-30 10:29

许多处理器具有统一格式和宽度的指令,例如ARM,其中所有指令都是32位长.其他处理器具有多个宽度的指令,例如长度为2,3或4个字节,例如8086.

    使所有指令具有相同宽度和统一格式的优点是什么?

    使用多个宽度的指令有什么好处?

Paul A. Clay.. 33

固定长度指令权衡

具有相对统一格式的固定长度指令的优点是获取和解析指令基本上更简单.

对于每个周期获取单个指令的实现,固定大小的单个对齐的存储器(高速缓存)访问保证提供一个(且仅一个)指令,因此不需要缓冲或移位.也不用担心在单个指令中跨越高速缓存行或页面边界.

指令指针增加固定量(执行控制流指令时除外 - 跳转和分支),与指令类型无关,因此下一个顺序指令的位置可以在最少的额外工作的情况下提前获得(与必须在至少部分解码指令).这也使得每个周期获取和解析多于一个指令相对简单.

对每条指令采用统一格式允许将指令简单地解析为其组件(立即值,操作码,源寄存器名称,目标寄存器名称).解析源寄存器名称是最重要的时序; 如果这些处于固定位置,则可以在确定指令类型之前开始读取寄存器值.(这个寄存器读数是推测性的,因为操作可能实际上并没有使用这些值,但这种猜测在错误推测的情况下不需要任何特殊的恢复,但确实需要额外的能量.)在MIPS R2000的经典5级流水线中,这允许读取指令提取后立即启动的寄存器值,提供半个周期来比较寄存器值并解析分支的方向; 使用(填充的)分支延迟槽,这避免了没有分支预测的停顿.

(解析操作码通常比源寄存器名称的时序要小一些,但提取操作码的时间越早,执行就越早开始.简单地解析目标寄存器名称可以更简单地检测指令之间的依赖关系;这可能主要是有帮助的当每个周期尝试执行多个指令时.)

除了更快地提供解析之外,更简单的编码使得解析工作更少(能量使用和晶体管逻辑).

与典型的可变长度编码相比,固定长度指令的一个小优点是指令地址(和分支偏移)使用较少的位.在一些ISA中已经利用这一点来为模式信息提供少量额外存储.(具有讽刺意味的是,在像MIPS/MIPS16这样的情况下,表示具有较小或可变长度指令的模式.)

固定长度指令编码和统一格式确实有缺点.最明显的缺点是代码密度相对较低.无法根据使用频率或需要多少不同信息来设置指令长度.严格的统一格式化也倾向于排除隐式操作数(尽管MIPS使用链接寄存器的隐式目标寄存器名称)和可变大小的操作数(大多数RISC可变长度编码具有只能访问总数的子集的短指令)寄存器).

(在面向RISC的ISA中,这还有一个小问题,即不允许将更多工作捆绑到指令中以均衡指令所需的信息量.)

固定长度指令也使得使用大的immediates(指令中包含的常量操作数)更加困难.经典RISC将立即长度限制为16位.如果常量较大,则必须将其作为数据加载(这意味着额外的加载指令及其地址计算开销,寄存器使用,地址转换,标记检查等)或第二条指令必须提供其余的常量.(MIPS提供了一个高负载立即指令,部分假设大常量主要用于加载地址,后者将用于访问内存中的数据.PowerPC使用高立即数提供若干操作,允许例如添加32在两条指令中立即执行.)使用两条指令显然比使用单条指令的开销更大(尽管聪明的实现可能会融合前端的两条指令[英特尔称之为宏操作融合]).

固定长度指令还使得扩展指令集更加困难,同时保持二进制兼容性(并且不需要额外的操作模式).即使严格统一的格式化也会妨碍指令集的扩展,特别是对于增加可用寄存器的数量.

富士通的SPARC64 VIIIfx就是一个有趣的例子.它使用一个两位操作码(在其32位指令中)来指示加载一个特殊寄存器,其中有两个15位指令扩展用于接下来的两条指令.这些扩展提供额外的寄存器位和SIMD操作的指示(即,扩展应用扩展的指令的操作码空间).这意味着指令的完整寄存器名称不仅不完全处于固定位置,甚至不在同一"指令"中.(可能会注意到与x86的REX前缀相似 - 它提供了扩展在指令主要部分中编码的寄存器名称的位).

(固定长度编码的一个方面是两个幂的暴政.虽然可以使用非幂的两个指令长度[Tensilica的XTensa现在已经将固定的24位指令作为其基本ISA - 具有16位简短的指令支持是一个扩展,以前它们是基础ISA的一部分; IBM有一个带有40位指令的实验性ISA.],这样​​增加了一点复杂性.如果一个大小,例如32位,有点太短,下一个可用的大小,例如64位,可能太长,牺牲了太多的代码密度.)

对于具有深度流水线的实现,解析指令所需的额外时间不太重要.硬件完成的额外动态工作和额外的设计复杂性对于高性能实现而言意义重大,这些实现增加了复杂的分支预测,无序执行和其他功能.

可变长度指令权衡

对于可变长度指令,权衡取舍基本相反.

更高的代码密度是最明显的优势.更高的代码密度可以改善静态代码大小(给定程序所需的存储量).这对于某些嵌入式系统尤其是微控制器尤其重要,因为它可能占系统成本的很大一部分并影响系统的物理尺寸(这会影响系统的适用性和制造成本).

改进动态代码大小减少了用于获取指令的带宽量(来自内存和缓存).这可以降低成本和能源使用,并可以提高性能.较小的动态代码大小也减小了给定命中率所需的缓存大小; 较小的高速缓存可以使用更少的能量和更少的芯片面积,并且可以降低访问延迟.

(在具有窄存储器接口的非流水线实现或最小流水线实现中,在某些情况下仅在一个周期中获取指令的一部分不会像在更少流水线设计中那样损害性能,而不受获取带宽的限制.)

对于可变长度指令,可以在指令中使用大常量,而不需要所有指令都很大.使用立即而不是从数据存储器加载常量会利用空间局部性,在管道中提供较早的值,避免额外的指令,并删除数据缓存访问.(更宽的访问比相同总大小的多次访问更简单.)

考虑到对可变长度指令的支持,扩展指令集通常也更容易.可以通过使用超长指令来包括添加信息.(在某些编码技术的情况下 - 特别是使用前缀 - ,也可以向现有指令添加提示信息,允许向后兼容其他新信息.x86利用它不仅提供分支提示[主要是未使用的]而且还有硬件锁Elision扩展.对于固定长度编码,很难提前选择哪些操作应该有额外的操作码,以备将来可能添加提示信息.)

可变长度编码显然使得查找下一个顺序指令的开始更加困难.对于每个周期仅解码一个指令的实现来说,这不是一个问题,但即使在这种情况下,它也为硬件增加了额外的工作(这可以增加周期时间或流水线长度以及使用更多的能量).对于更宽的解码,可以使用几个技巧来降低从指令存储器块中解析出单个指令的成本.

一种主要用于微体系结构的技术(即,不包括在暴露于软件但仅包括实现技术的接口中)是使用标记位来指示指令的开始或结束.将为每个指令编码设置这样的标记位并将其存储在指令高速缓存中.这样就延迟了指令高速缓存未命中的这种信息的可用性,但是与填充高速缓存未命中的普通延迟相比,这种延迟通常较小.额外(预)解码工作仅在高速缓存未命中时需要,因此在高速缓存命中的常见情况下节省了时间和能量(以一些额外存储和带宽为代价,其具有一些能量成本).

(一些AMD x86实现使用了标记位技术.)

或者,标记位可以包括在指令编码中.这对操作码分配和放置设置了一些约束,因为标记位实际上成为操作码的一部分.

IBM zSeries(S/360和后代)使用的另一种技术是在第一个包中的操作码中以简单的方式对指令长度进行编码.zSeries使用两个位来编码三个不同的指令长度(16,32和48位),其中两个编码用于16位长度.通过将其置于固定位置,可以相对容易地快速确定下一个顺序指令的开始位置.

(更积极的预编码也是可能的.奔腾4使用包含固定长度微操作的跟踪缓存,而最近的英特尔处理器使用微操作缓存,可能是[固定]固定长度的微操作.)

显然,可变长度编码需要以小块的粒度进行寻址,该粒度通常小于固定长度ISA的指令.这意味着分支偏移要么丢失一些范围,要么必须使用更多位.这可以通过支持更多不同的即时尺寸来补偿.

同样,获取单个指令可能更复杂,因为指令的开始可能不会与更大的2的幂对齐.缓冲指令获取减少了这种影响,但增加了(微不足道的)延迟和复杂性.

对于可变长度指令,具有统一编码也更加困难.这意味着在开始指令的基本解析之前,必须经常解码部分操作码.这往往会延迟寄存器名称和其他不太重要的信息的可用性.仍然可以获得显着的均匀性,但它需要更仔细的设计和权衡权衡(这可能会在ISA的整个生命周期内发生变化).

如前所述,随着更复杂的实现(更深的流水线,无序执行等),处理可变长度指令的额外相对复杂性降低.在指令解码之后,具有可变长度指令的ISA的复杂实现往往看起来非常类似于具有固定长度指令的ISA之一.

还可以注意到,可变长度指令的大部分设计复杂性是一次性成本; 一旦组织学会了处理怪癖的技术(包括开发验证软件),这种复杂性的成本对于以后的实现来说就会降低.

由于许多嵌入式系统的代码密度问题,一些RISC ISA提供可变长度编码(例如,microMIPS,Thumb2).这些通常只有两个指令长度,因此额外的复杂性受到限制.

捆绑作为妥协设计

为某些ISA选择的一种(中间的)替代方案是使用具有不同长度指令的固定长度的指令束.通过在包中包含指令,每个包具有固定长度指令的优点,并且每个包中的第一指令具有固定的对齐的起始位置.CDC 6600使用60位捆绑包,具有15位和30位操作.M32R使用带有16位和32位指令的32位软件包.

(Itanium使用固定长度的两个功率组来支持两个[41位]指令的非功率,并且在一些情况下,两个"指令"被连接以允许64位立即数.Heidi Pan的[学术]负责人和尾部编码使用固定长度的束来从左到右编码固定长度的基本指令部分,从右到左编码可变长度的块.)

一些VLIW指令集使用固定大小的指令字,但字内的各个操作时隙可以是不同的(但对于特定时隙固定)长度.因为不同的操作类型(对应于插槽)具有不同的信息要求,所以对于不同的插槽使用不同的尺寸是合理的.这提供了具有一定代码密度益处的固定大小指令的优点.(此外,可以分配一个插槽,以便可选地为指令字中的一个操作提供立即数.)

1 个回答
  • 固定长度指令权衡

    具有相对统一格式的固定长度指令的优点是获取和解析指令基本上更简单.

    对于每个周期获取单个指令的实现,固定大小的单个对齐的存储器(高速缓存)访问保证提供一个(且仅一个)指令,因此不需要缓冲或移位.也不用担心在单个指令中跨越高速缓存行或页面边界.

    指令指针增加固定量(执行控制流指令时除外 - 跳转和分支),与指令类型无关,因此下一个顺序指令的位置可以在最少的额外工作的情况下提前获得(与必须在至少部分解码指令).这也使得每个周期获取和解析多于一个指令相对简单.

    对每条指令采用统一格式允许将指令简单地解析为其组件(立即值,操作码,源寄存器名称,目标寄存器名称).解析源寄存器名称是最重要的时序; 如果这些处于固定位置,则可以在确定指令类型之前开始读取寄存器值.(这个寄存器读数是推测性的,因为操作可能实际上并没有使用这些值,但这种猜测在错误推测的情况下不需要任何特殊的恢复,但确实需要额外的能量.)在MIPS R2000的经典5级流水线中,这允许读取指令提取后立即启动的寄存器值,提供半个周期来比较寄存器值并解析分支的方向; 使用(填充的)分支延迟槽,这避免了没有分支预测的停顿.

    (解析操作码通常比源寄存器名称的时序要小一些,但提取操作码的时间越早,执行就越早开始.简单地解析目标寄存器名称可以更简单地检测指令之间的依赖关系;这可能主要是有帮助的当每个周期尝试执行多个指令时.)

    除了更快地提供解析之外,更简单的编码使得解析工作更少(能量使用和晶体管逻辑).

    与典型的可变长度编码相比,固定长度指令的一个小优点是指令地址(和分支偏移)使用较少的位.在一些ISA中已经利用这一点来为模式信息提供少量额外存储.(具有讽刺意味的是,在像MIPS/MIPS16这样的情况下,表示具有较小或可变长度指令的模式.)

    固定长度指令编码和统一格式确实有缺点.最明显的缺点是代码密度相对较低.无法根据使用频率或需要多少不同信息来设置指令长度.严格的统一格式化也倾向于排除隐式操作数(尽管MIPS使用链接寄存器的隐式目标寄存器名称)和可变大小的操作数(大多数RISC可变长度编码具有只能访问总数的子集的短指令)寄存器).

    (在面向RISC的ISA中,这还有一个小问题,即不允许将更多工作捆绑到指令中以均衡指令所需的信息量.)

    固定长度指令也使得使用大的immediates(指令中包含的常量操作数)更加困难.经典RISC将立即长度限制为16位.如果常量较大,则必须将其作为数据加载(这意味着额外的加载指令及其地址计算开销,寄存器使用,地址转换,标记检查等)或第二条指令必须提供其余的常量.(MIPS提供了一个高负载立即指令,部分假设大常量主要用于加载地址,后者将用于访问内存中的数据.PowerPC使用高立即数提供若干操作,允许例如添加32在两条指令中立即执行.)使用两条指令显然比使用单条指令的开销更大(尽管聪明的实现可能会融合前端的两条指令[英特尔称之为宏操作融合]).

    固定长度指令还使得扩展指令集更加困难,同时保持二进制兼容性(并且不需要额外的操作模式).即使严格统一的格式化也会妨碍指令集的扩展,特别是对于增加可用寄存器的数量.

    富士通的SPARC64 VIIIfx就是一个有趣的例子.它使用一个两位操作码(在其32位指令中)来指示加载一个特殊寄存器,其中有两个15位指令扩展用于接下来的两条指令.这些扩展提供额外的寄存器位和SIMD操作的指示(即,扩展应用扩展的指令的操作码空间).这意味着指令的完整寄存器名称不仅不完全处于固定位置,甚至不在同一"指令"中.(可能会注意到与x86的REX前缀相似 - 它提供了扩展在指令主要部分中编码的寄存器名称的位).

    (固定长度编码的一个方面是两个幂的暴政.虽然可以使用非幂的两个指令长度[Tensilica的XTensa现在已经将固定的24位指令作为其基本ISA - 具有16位简短的指令支持是一个扩展,以前它们是基础ISA的一部分; IBM有一个带有40位指令的实验性ISA.],这样​​增加了一点复杂性.如果一个大小,例如32位,有点太短,下一个可用的大小,例如64位,可能太长,牺牲了太多的代码密度.)

    对于具有深度流水线的实现,解析指令所需的额外时间不太重要.硬件完成的额外动态工作和额外的设计复杂性对于高性能实现而言意义重大,这些实现增加了复杂的分支预测,无序执行和其他功能.

    可变长度指令权衡

    对于可变长度指令,权衡取舍基本相反.

    更高的代码密度是最明显的优势.更高的代码密度可以改善静态代码大小(给定程序所需的存储量).这对于某些嵌入式系统尤其是微控制器尤其重要,因为它可能占系统成本的很大一部分并影响系统的物理尺寸(这会影响系统的适用性和制造成本).

    改进动态代码大小减少了用于获取指令的带宽量(来自内存和缓存).这可以降低成本和能源使用,并可以提高性能.较小的动态代码大小也减小了给定命中率所需的缓存大小; 较小的高速缓存可以使用更少的能量和更少的芯片面积,并且可以降低访问延迟.

    (在具有窄存储器接口的非流水线实现或最小流水线实现中,在某些情况下仅在一个周期中获取指令的一部分不会像在更少流水线设计中那样损害性能,而不受获取带宽的限制.)

    对于可变长度指令,可以在指令中使用大常量,而不需要所有指令都很大.使用立即而不是从数据存储器加载常量会利用空间局部性,在管道中提供较早的值,避免额外的指令,并删除数据缓存访问.(更宽的访问比相同总大小的多次访问更简单.)

    考虑到对可变长度指令的支持,扩展指令集通常也更容易.可以通过使用超长指令来包括添加信息.(在某些编码技术的情况下 - 特别是使用前缀 - ,也可以向现有指令添加提示信息,允许向后兼容其他新信息.x86利用它不仅提供分支提示[主要是未使用的]而且还有硬件锁Elision扩展.对于固定长度编码,很难提前选择哪些操作应该有额外的操作码,以备将来可能添加提示信息.)

    可变长度编码显然使得查找下一个顺序指令的开始更加困难.对于每个周期仅解码一个指令的实现来说,这不是一个问题,但即使在这种情况下,它也为硬件增加了额外的工作(这可以增加周期时间或流水线长度以及使用更多的能量).对于更宽的解码,可以使用几个技巧来降低从指令存储器块中解析出单个指令的成本.

    一种主要用于微体系结构的技术(即,不包括在暴露于软件但仅包括实现技术的接口中)是使用标记位来指示指令的开始或结束.将为每个指令编码设置这样的标记位并将其存储在指令高速缓存中.这样就延迟了指令高速缓存未命中的这种信息的可用性,但是与填充高速缓存未命中的普通延迟相比,这种延迟通常较小.额外(预)解码工作仅在高速缓存未命中时需要,因此在高速缓存命中的常见情况下节省了时间和能量(以一些额外存储和带宽为代价,其具有一些能量成本).

    (一些AMD x86实现使用了标记位技术.)

    或者,标记位可以包括在指令编码中.这对操作码分配和放置设置了一些约束,因为标记位实际上成为操作码的一部分.

    IBM zSeries(S/360和后代)使用的另一种技术是在第一个包中的操作码中以简单的方式对指令长度进行编码.zSeries使用两个位来编码三个不同的指令长度(16,32和48位),其中两个编码用于16位长度.通过将其置于固定位置,可以相对容易地快速确定下一个顺序指令的开始位置.

    (更积极的预编码也是可能的.奔腾4使用包含固定长度微操作的跟踪缓存,而最近的英特尔处理器使用微操作缓存,可能是[固定]固定长度的微操作.)

    显然,可变长度编码需要以小块的粒度进行寻址,该粒度通常小于固定长度ISA的指令.这意味着分支偏移要么丢失一些范围,要么必须使用更多位.这可以通过支持更多不同的即时尺寸来补偿.

    同样,获取单个指令可能更复杂,因为指令的开始可能不会与更大的2的幂对齐.缓冲指令获取减少了这种影响,但增加了(微不足道的)延迟和复杂性.

    对于可变长度指令,具有统一编码也更加困难.这意味着在开始指令的基本解析之前,必须经常解码部分操作码.这往往会延迟寄存器名称和其他不太重要的信息的可用性.仍然可以获得显着的均匀性,但它需要更仔细的设计和权衡权衡(这可能会在ISA的整个生命周期内发生变化).

    如前所述,随着更复杂的实现(更深的流水线,无序执行等),处理可变长度指令的额外相对复杂性降低.在指令解码之后,具有可变长度指令的ISA的复杂实现往往看起来非常类似于具有固定长度指令的ISA之一.

    还可以注意到,可变长度指令的大部分设计复杂性是一次性成本; 一旦组织学会了处理怪癖的技术(包括开发验证软件),这种复杂性的成本对于以后的实现来说就会降低.

    由于许多嵌入式系统的代码密度问题,一些RISC ISA提供可变长度编码(例如,microMIPS,Thumb2).这些通常只有两个指令长度,因此额外的复杂性受到限制.

    捆绑作为妥协设计

    为某些ISA选择的一种(中间的)替代方案是使用具有不同长度指令的固定长度的指令束.通过在包中包含指令,每个包具有固定长度指令的优点,并且每个包中的第一指令具有固定的对齐的起始位置.CDC 6600使用60位捆绑包,具有15位和30位操作.M32R使用带有16位和32位指令的32位软件包.

    (Itanium使用固定长度的两个功率组来支持两个[41位]指令的非功率,并且在一些情况下,两个"指令"被连接以允许64位立即数.Heidi Pan的[学术]负责人和尾部编码使用固定长度的束来从左到右编码固定长度的基本指令部分,从右到左编码可变长度的块.)

    一些VLIW指令集使用固定大小的指令字,但字内的各个操作时隙可以是不同的(但对于特定时隙固定)长度.因为不同的操作类型(对应于插槽)具有不同的信息要求,所以对于不同的插槽使用不同的尺寸是合理的.这提供了具有一定代码密度益处的固定大小指令的优点.(此外,可以分配一个插槽,以便可选地为指令字中的一个操作提供立即数.)

    2023-01-30 10:31 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有