MAXQ内核是一个功能强大的单周期、传输触发CPU。本文通过展示整个指令集如何围绕简单的 MOVE 操作构建来演示这种功能。
MAXQ处理器系列是功能强大的8位、16位和32位单周期微控制器,在一个时钟周期内执行多个操作。本文将探讨MAXQ20内核的内部工作原理,并展示其强大的功能。
程序员模型
MAXQ20内核为16位CPU,这意味着所有累加器和大多数工作寄存器(堆栈、数据指针、计数器)的长度均为16位。MAXQ20可以寻址64k字的代码空间(即64kB指令)和64k字(128kB)的数据空间(图1)。
注意,对于基于MAXQ20内核的处理器,大部分内存空间将处于空置状态。此外,由于实用程序ROM和数据RAM位于代码空间的上部32kB,因此访问此区域中的用户代码需要内核中的特殊功能,这些功能超出了本文的范围。
图1.MAXQ20内核的编程模型由16个通用累加器、两个环路计数器和一组数据指针组成。
蓄电池
16个寄存器称为“累加器”,形成一个通用寄存器阵列。累加器指针寄存器 (AP) 指向的寄存器被指定为“活动累加器”,它是算术和逻辑运算的目标。因此,通过更改AP寄存器中的值,可以将2个累加器中的任何一个指定为算术逻辑单元(ALU)操作的目标。累加器指针控制寄存器 (APC) 使 AP 在访问活动累加器时自动递增或递减,从而使多精度算术变得简单。在图 0 中,A[1] 是有源累加器,但任何累加器访问都可以使 A[15] 或 A[<>] 成为有源累加器,具体取决于 APC 寄存器的值。
图2.活动累加器由AP寄存器指定,AP寄存器本身可以通过累加器访问指令进行修改。
遗传资源注册
通用寄存器(GR)有助于从16位字中提取单个字节。程序员可以使用GR将字节组装成一个字:将低字节加载到GRL(通用寄存器-低字节)中,将高字节加载到GRH(通用寄存器-高字节)中,并在GR中读取组装好的字。加载到 GR 中的单词可以在 GRS(通用寄存器-交换)中以字节交换格式读取。最后,加载到GRL寄存器的字节可以通过读取GRXL(通用寄存器低字节)来符号扩展为一个字。参见图 3。
图3.GR 寄存器支持字节提取、字节交换和 16 位符号扩展。
循环计数器
有两个环路计数器:环路计数器 0 (LC[0]) 和环路计数器 1 (LC[1])。这些寄存器可用作通用寄存器,但如果计数器为非零 (DJNZ) 指令,则用作递减和跳转的循环计数器。
叠
MAXQ20内核具有专用的16电平内部堆栈。堆栈指针指示要使用的下一个堆栈位置,或指示 PUSH 或 CALL 操作。
数据存储指针
MAXQ微控制器具有三个用于访问数据存储器的指针。两个,DP[0] 和 DP[1],是简单的 16 位指针。第三个指针是通过将基址指针 (BP) 添加到 8 位无符号偏移量 (OFFS) 来形成的。
请注意,由三个数据指针之一寻址的数据存储器与由指令指针寻址的代码存储器不同。虽然所有MAXQ处理器都包含一个存储器管理单元(MMU),允许将任何存储器段视为代码或数据,但代码和数据总线是分开的。代码和数据获取操作的总线分离是MAXQ20技术的基本要素,允许在单个时钟周期内同时访问代码和数据。
传输触发架构
通过检查程序员的模型,可以得出结论,有一个传统的指令获取-解码单元,它加载指令,解码它,然后激活CPU的某些元素。然而,这将是一种误解。MAXQ架构与其他传统CPU的不同之处在于MAXQ内核的传输触发特性。
传输触发是一种允许简单的 MOVE 指令执行 CPU 中可用的每个功能的技术。虽然MAXQ汇编器支持30多种指令操作码,但MAXQ指令集中的每条指令都可以编码为:
move Ma[b], Mc[d] or move Ma[b], #immediate_value
其中名称 Ma[b] 描述寄存器模块 a 和寄存器子解码 b。简单地说:每条指令——ADD、位操作、对外部存储器的引用——都被编码为两个寄存器之间的移动或将即时值移动到寄存器中。
当执行MAXQ指令时,目标寄存器加载源寄存器的内容或即时值。此外,这种数据传输可以触发其他事件,例如递增或递减指针、设置某些状态位或其他函数。因此,该架构是传输触发的。为了支持这种架构,需要一个大的寄存器补充。在MAXQ20内核中,共有512个寄存器地址,分为两大部分:外设寄存器空间和系统寄存器空间(图4)。
前六个寄存器模块(模块 0 到 5)专用于外设寄存器;最后九个模块(模块7至F)被分配为系统寄存器。(模块 6 是保留的。当外设寄存器模块从一种类型的MAXQ处理器变为另一种类型的MAXQ处理器时,所有MAXQ处理器的系统寄存器保持不变(图5)。
图4.MAXQ20内核中的寄存器分配分为两个区域:寄存器组0至5为外设寄存器,可以从MAXQ器件切换到另一个MAXQ器件;组7至15是系统寄存器,在所有MAXQ部件上保持相对固定。
图5.MAXQ系统寄存器映射由所有基于MAXQ20的处理器中的寄存器和用于实现指令集的附加解码组成。
解码MAXQ指令
因为每条MAXQ指令实际上都是一个MOVE,所以每条指令可以分解为三个字段:一个SOURCE字段,它指定数据从哪里移动;指定数据移动到何处的“目标”字段;以及一个格式位,指示源是即时值(FORMAT == 0)还是寄存器指示符(FORMAT == 1)(图6)。
图6.MAXQ指令由三部分组成:源指示符、目标指示符和源格式位,用于确定源是直接操作数还是寄存器操作数。
以指令操作码0x0923为例。在此指令中,FORMAT位是明确的,指示源指示符(23)应被视为8位即时值。目标模块是模块 9,即累加器阵列。该数组中的寄存器 0 是累加器 A[0]。因此,指令的作用是将0x0023的值加载到寄存器 A[0] 中。在这种情况下,没有与源或目标指示符相关的副作用。
对于第二个示例,请考虑0xBF09。在此指令中,设置了FORMAT位,这意味着源指示符应解释为寄存器。模块 9 寄存器 0 已在上面介绍:它是累加器 A[0]。在目标端,模块 F 是数据指针模块,寄存器 3(指令中的位 14:12)表示数据指针 DP[0]。因此,此指令将 A[0] 的内容移动到 DP[0]。
请注意,在某些情况下,寄存器模块内的各个位置可能引用实际寄存器,也可能不引用实际寄存器。或者,它们可以引用实际的寄存器,但在访问该寄存器子解码时会导致一些副作用。例如,让我们用0xAF09稍微修改前面的示例。只有目标子解码已更改。现在,指令不是加载寄存器 DP[0],而是递减 DP[0],然后开始对 DP[0] 指向的新内存位置进行存储操作。也就是说,指令在递减指针上执行间接存储。在MAXQ汇编器中,它被编码为移动@DP[0],A[0],但它可以像移动M15[2],M9[0]一样容易编码。
前缀寄存器
每个模块有 32 个寄存器,但只有 11 位用于选择源寄存器,只有 <> 位用于指定目标寄存器。乍一看,这意味着无法读取一半的寄存器子解码,并且无法写入整整四分之三的寄存器子解码。幸运的是,MAXQ架构设计可以解决这个问题。每个MAXQ处理器提供一个前缀寄存器,以提供这些额外的寄存器地址位,并提供字范围移动的高字节。有关详细信息,请参阅模块 <> - 前缀部分。
一次创建一个模块的MAXQ指令集
以下各节详细介绍了系统寄存器模块以及它们如何交互以创建所有记录和未记录的指令。我们首先研究MAXQ20内核的核心:累加器阵列。
模块 9 - 蓄能器
MAXQ架构最多支持32个累加器,尽管大多数型号只支持16个。累加器可通过模块 9 直接访问。此模块中的每个子解码代表一个累加器。模块 9 在概念上是最简单的模块,但还有两个模块会影响累加器阵列。
模块 8 - 系统控制
该模块包含许多寄存器,用于管理系统操作的各个方面,例如中断控制和程序状态标志。其中许多寄存器超出了本文的范围,因此有关详细信息,请参阅器件规格。表1列出了其中一些寄存器模块。
表 1.模块 8 函数
子 | 功能 | S/D | 描述 |
0 | 累加器指针寄存器 | S/D | 指定活动累加器,即用作 ALU 操作目标的累加器。 |
1 | 累加器指针控制寄存器 | S/D | 告诉 AP 如何表现。对于此讨论,它是一个通用的8位寄存器。 |
4 | 程序状态标志寄存器 | S/D | 包含用户可能希望在主程序中监视的标志(携带、零、等于)。寄存器通常用作源,但也可以用作目标。请注意,某些位是只读的(例如,Z 标志是活动累加器中所有位的逻辑 NOR)。 |
5 | 中断控制寄存器 | S/D | 管理中断子系统。 |
6 | 中断掩码寄存器 | S/D | 通常包含在模块级别屏蔽中断的位。 |
7 | 比较器寄存器 | DO | 只写子解码。不是真正的寄存器,因为它后面没有实际的内存。写入此子解码时,如果源操作数与当前累加器的内容匹配,则在 PSF 中设置等于位;否则,将清除等于位。 |
8 | 系统控制寄存器 | S/D | 包含控制系统操作(读/写)方面的位。 |
11 | 中断识别寄存器 | SO | 包含标识中断源的位集合。 |
14 | 时钟控制寄存器 | S/D | 包含与系统时钟相关的位。特别是,控制主时钟分频比,以及时钟源(如果特定微控制器中存在多个源)。 |
15 | 看门狗控制寄存器 | S/D | 控制看门狗定时器的操作。大多数MAXQ器件都包含一个看门狗定时器,如果处理器卡在程序循环中,该定时器可以复位。 |
AP和APC登记册值得特别注意。AP 寄存器确定哪个累加器寄存器是活动累加器;也就是说,它指定算术、逻辑和按位运算的目标。它可以指向数组中的任何累加器。
APC 寄存器包含一组位,用于定义在任何累加器操作后如何修改 AP 寄存器。因此,AP寄存器可以递增或递减,计数在可选择的2次幂模数上滚动,使多精度运算变得简单。
模块 10 - 累加器功能
模块 10 是完成累加器大部分实际工作的地方。它提供对传统 ALU 函数的访问和对有源累加器的位级访问。模块 10 是唯一的;它的行为有所不同,具体取决于它是用作源、目标还是同时用作源和目标(表 2)。
表 2.模块 10 作为源
子 | 功能 | 描述 |
0 | 有源蓄能器 | 活动累加器的内容将移动到目标,并且 AP 将根据 APC 进行更改。 |
1 | 有源蓄能器 | 活动累加器的内容将移动到目标,并且 AP 保持不变。 |
如果源是模块 10,并且目标是模块 10 以外的任何模块,则累加器的内容将移动到目标。如果子解码为零,则根据APC寄存器中的位修改AP寄存器。如果子解码为 1,则不会修改 AP 寄存器。
请注意,当前版本的宏汇编器不支持子解码 1。这是因为没有助记符或修饰符来指定子解码 1。因此,指令移动 A[1],ACC 将始终0x990A生成操作码,并且永远不会0x991A(表 3)。
表 3.模块 10 作为目的地
子 | 功能 | 描述 |
0 | MOVE | 源将移动到累加器。 |
1 | AND | 源的内容在逻辑上与累加器一起进行。 |
2 | OR | 源的内容与累加器进行逻辑 OR 运算。 |
3 | XOR | 源的内容在逻辑上与累加器进行 OR。 |
4 | ADD | 源的内容以算术方式添加到累加器中。从 MSB 溢出设置进位。 |
5 | SUB | 源的内容从累加器算术上减去。底流设置进位。 |
6 | ADDC | 源和进位的内容被添加到累加器中。 |
7 | SUBB | 源和进位的内容从累加器中减去。 |
当模块 10 被指定为目标并且源是即时值或模块 10 以外的任何模块时,源通过 ALU 路由;目标取自 ALU 的输出,而不是直接取自源。这就是算术和逻辑指令的实现方式。
请注意,对可用作源寄存器的内容没有限制。它可以是即时值、间接存储器位置,甚至是堆栈或外设寄存器上的值(表 4)。
表 4.模块 10 同时作为源和目标
德斯特亚 | SRC 子 | 功能 | 描述 |
0 | 0 | MOVE | 累加器的内容被移动到累加器;从逻辑上讲,一个NOP。但是,可以更改 AP 寄存器。 |
1 | .CPL | 累加器按位补充。 | |
2 | SLA | 累加器向左移动一位;低阶位设置为零。高阶位被复制到进位。 | |
3 | SLA2 | 累加器向左移动两位;低阶两位设置为零。位 14 被复制到携带。 | |
4 | RL | 蓄能器向左旋转一位,将位 15 复制到位 0。位 15 也被复制到携带。 | |
5 | RLC | 蓄能器向左旋转一位,将位 15 复制到进位,进位复制到位 0。 | |
6 | SLA4 | 蓄能器向左移动四位;低阶四位设置为零。位 12 被复制到携带。 | |
7 | XCHN | 累加器每个字节中的半字节被颠倒;0x1234变得0x2143。 | |
8 | XCH | 累加器的字节是相反的;0x1234变得0x3412。 | |
9 | NEG | 累加器在算术上被否定。 | |
10 | SR | 累加器向右移动一位。位 15 加载零。位 0 被移动到携带。 | |
11 | SRA4 | 累加器向右移动四位;高阶四位设置为零。位 3 被复制到携带。 | |
12 | RR | 蓄能器向右旋转一位,位 0 复制到位 15。位 0 也被复制到携带。 | |
13 | RRC | 蓄能器向右旋转一位,位 0 复制到进位,进位复制到位 15。 | |
14 | SRA2 | 累加器向右移动两位;高阶两位设置为零。位 1 复制到携带。 | |
15 | SRA | 累加器向右移动一位;高阶位设置为零。低阶位复制到进位。 | |
1 | 位 | 和 C | 进位与累加器中的指定位在逻辑上与 AND 运算。 |
2 | 位 | 或 C | 进位与累加器中的指定位在逻辑上是 OR 运算的。 |
3 | 位 | 异或 C | 进位与累加器中的指定位进行逻辑异或运算。 |
5 | 0 | C ← 0 | 进位设置为零。 |
1 | C ← 1 | 进位设置为 1。 | |
2 | C ← C | 进位是补充的。 | |
3 | NOP | 保证无价 | |
6 | 位 | C ← ACC | 蓄能器中的指定位被加载到进位中。 |
7 | 位 | ACC ← C | 进位被加载到累加器中的指定位中。 |
当源和目标指定都是模块 10 时,它要么是仅累加器指令,要么是涉及进位的位操作。在所有情况下,源子解码和目标子解码都用于指定操作。
目标子解码 0 是仅累加器指令的主页,包括补码、否定和所有移位、旋转和交换指令。目标子解码 1、2、3、6 和 7 涉及按位加载和使用进位的操作。最后,目标子解码 5 具有仅进位操作:加载 0 和 1 以及补码。
请注意,目标子解码 5 的一个源子解码是指定的 NOP 指令。虽然任何既没有副作用又解决空寄存器位置的操作都可以作为NOP,但MOVE M10[5]、M10[3]特别保证在当前或未来的MAXQ器件中不执行任何操作。这是在 NOP 助记符的所有当前汇编程序中生成的操作代码 (0xDA3A)。
模块 12 — 指令指针
模块 12 是唯一的,因为它包含许多条件加载操作。如果将模块 12 用作源模块,则只需将 IP 复制到目标指示符。但是,如果模块 12 是目标,则除非满足指定的条件,否则不会执行任何操作(表 5)。
表 5.模块 12 子解码
子 | 描述 |
0 | 如果源,则从 IP 加载目标。如果是目标,请从源加载 IP。 |
1 | 如果源,则从 IP 加载目标。如果是目标,则仅在 ACC == 0 时从源加载 IP。 |
2 | 如果源,则从 IP 加载目标。如果是目标,则仅在 C == 1 时从源加载 IP。 |
3 | 如果源,则从 IP 加载目标。如果是目标,则仅当最新的 CMP 指令设置 EQ 标志时,才从源加载 IP。 |
4 | 如果源,则从 IP 加载目标。如果是目标,则仅在设置了累加器的高阶位时从源加载 IP。 |
5 | 如果源,则从 IP 加载目标。如果是目标,则仅在 ACC == 0 时从源加载 IP。 |
6 | 如果源,则从 IP 加载目标。如果是目标,则仅在 C == 0 时从源加载 IP。 |
7 | 如果源,则从 IP 加载目标。如果是目标,则仅当最新的 CMP 指令清除了 EQ 标志时,才从源加载 IP。 |
模块 12 也是唯一的,因为当从 8 位即时源加载时,源值被解释为有符号整数,并添加到指令指针的先前预递增内容中。这种添加有助于相对短的跳跃,从而显着节省代码大小。这也意味着任何短跳或跳远指令都可以是有条件的。
请注意,此模块仅支持指令指针寄存器 (IP) 的简单加载和存储。CALL 指令被视为也加载 IP 的堆栈指令,而不是推送到堆栈的 IP 指令。因此,CALL 指令的传输在堆栈指针模块(模块 13)中。此外,没有明确的 RET 指令;这被强制转换为 POP IP。
模块 13 — 堆栈指针
模块 13 不仅包含与堆栈指针相关的寄存器,还包含循环计数器和中断向量。请注意,多个子解码仅作为目标有效,一个(子解码 8)仅作为源有效(表 6)。
表 6.模块 13 子解码
子 | 功能 | S/D | 描述 |
0 | 推/爆 | S/D | 如果是目标,则递增堆栈指针并将源操作数存储在堆栈上。如果是源,则将堆栈上的值加载到目标并递减堆栈指针。 |
1 | 堆栈指针 | S/D | 指向内部专用堆栈上最近使用的位置。 |
2 | 中断向量 | S/D | 指向程序内存中中断服务例程所在的位置。 |
3 | CALL | DO | 将当前 IP 推送到堆栈,然后从源操作数加载 IP。如果用作源操作数,将导致不可预知的结果。 |
4 | DJNZ LC[0] | DO | 递减 LC[0] 并使用源 IF LC[0] != 0 加载 IP。如果用作源操作数,将导致不可预知的结果。 |
5 | DJNZ LC[1] | DO | 递减 LC[1] 并使用源 IF LC[1] != 0 加载 IP。如果用作源操作数,将导致不可预知的结果。 |
6 | LC[0] | S/D | 数据移入/移出循环计数器 0。 |
7 | LC[1] | S/D | 数据移入/移出循环计数器 1。 |
8 | SO | 堆栈上的值将复制到目标,堆栈点递减,并清除 IN SERVICE 位。主要用于实现 RETI 操作。 |
子解码 3、4 和 5 用作 IP 寄存器的代理。Subdecode 3在递增的指令指针被推送到堆栈后加载指令指针,从而实现传统的CALL指令。子解码 4 和 5 将指定循环计数器的前置版本加载回循环计数器,如果前递减循环计数器不为零,则还会使用源操作数加载指令指针。要加载到此目标子解码中的源可以是任何内容;指令 DJNZ LC[0], A[1] 是完全有效的。在这种情况下,如果递减操作的结果不为零,则指令将递减 LC[0] 并跳转到 A[1] 中的地址。
模块 14 - GR、BP 和 DPC
模块14包含DPC寄存器、GR寄存器以及与基极指针和偏移寄存器相关的所有寄存器(表7)。
表 7.模块 14 子解码
子 | 功能 | S/D | 描述 | |
0 | @BP[offs] | S/D | 读取或写入 BP+off 指向的数据存储器位置 | |
1 |
|
S/D | 如果为 source,则读取 BP+off 指向的数据存储器位置,然后递增 off。如果为 target,则递增,然后将源数据存储在 BP+offs 处。 | |
2 | @BP[offs--] | S/D | 如果为 source,则读取 BP+off 指向的数据存储器位置,然后递减。如果是目标,则递减,然后将源数据存储在 BP+offs。 | |
3 | offs | S/D | 8位失调寄存器 | |
4 | DPC | S/D | 数据指针控制寄存器定义哪个数据指针是当前源指针以及每个数据指针的字/字节状态。 | |
5 | GR | S/D | 16位通用寄存器 | |
6 | GRL | S/D | 16位通用寄存器的低阶字节 | |
7 | BP | S/D | 16 位基本内存指针 | |
8 | GRS | 所以 | 遗传资源的字节交换版本 | |
9 | GRH | S/D | 16位通用寄存器的高阶字节 | |
10 | GRXL | 所以 | GR 的符号扩展低字节 | |
11 | BP[offs] | 所以 | 基指针和偏移量的总和 |
数据指针控制寄存器 (DPC) 描述数据指针的行为方式。特别是,它包含每个数据指针的位,用于定义该指针是在字模式还是字节模式下运行。它还包含一个字段,用于定义哪个指针是当前源指针。这是必需的,因为在加载源指针时访问源,并且只有一条总线用于操作数数据。
当 16 位数据需要字节访问时,GR 寄存器很方便。一旦GR加载了16位数据,就可以分别通过GRL和GRH寄存器检索低阶和高阶字节。GRS 寄存器包含 GR 的字节交换版本;GRXL 寄存器与 GRL 寄存器相同,不同之处在于高字节是低位字节的符号扩展。
基极指针寄存器(BP)是MAXQ架构中三个数据存储器指针寄存器之一,也是唯一支持失调寄存器的寄存器。BP 通常指向数据结构的基底,8 位无符号偏移寄存器指向结构内的数据元素。请注意,此寄存器的递增和递减版本仅修改偏移寄存器,而不会修改基寄存器。
模块 15 - 数据指针
模块15包含MAXQ架构中三个数据指针中的两个。根据子解码,对此模块的访问将执行直接或间接加载或存储,并可能在间接访问后增加或减少数据指针。这些寄存器子解码可用作源寄存器或目标寄存器(表8)。
表 8.模块 15 子解码
子 | 功能 | 描述 |
0 | @DP[0] | 读取或写入 DP[0] 指向的数据存储器位置。 |
1 | @DP[0]++ | 如果是 source,则读取 DP[0] 指向的数据存储器位置,然后递增 DP[0]。如果为 target,则递增 DP[0],然后将源数据存储在 DP[0]。 |
2 | @DP[0]-- | 如果为 source,则读取 DP[0] 指向的数据存储器位置,然后递减 DP[0]。如果为 target,则递减 DP[0],然后将源数据存储在 DP[0]。 |
3 | DP[0] | 数据指针 0 |
4 | @DP[1] | 读取或写入 DP[1] 指向的数据存储器位置 |
5 | @DP[1]++ | 如果是 source,则读取 DP[1] 指向的数据存储器位置,然后递增 DP[1]。如果为 target,则递增 DP[1],然后将源数据存储在 DP[1]。 |
6 | @DP[1]-- | 如果是 source,则读取 DP[1] 指向的数据存储器位置,然后递减 DP[1]。如果为目的地,则递减 DP[1]。然后将源数据存储在DP[1]。 |
7 | DP[1] | 数据指针 1 |
模块 7 - 布尔变量操作
布尔变量操作(BVM)模块(模块7)允许在典型的MAXQ处理器中对许多寄存器进行位提取和位设置/清除(图7)。请注意,并非所有模块都连接到 BVM 计算机。通常,只有外围模块连接到 BVM;系统寄存器没有。因此,在BVM和系统寄存器之间移动数据可能会导致不可预测的后果。
图7.模块7的子解码指定要提取或替换的位,如果是源指示符,则指定即时位值。
作为目的地指示符,BVM 充当进位的代理。提取源的一个位并将其复制到进位。如果 BVM 是源指示符,则子解码的第 3 位(完整源指示符的第 7 位)中给出的值将复制到目标的指定位。
请注意,BVM 仅适用于外设寄存器的 0 到 7 位。这对于大多数外设寄存器来说是可以接受的,因为许多寄存器(特别是I/O端口)的长度仅为8位。但是,当访问16位外设寄存器时,只有低阶8位可用。
模块 11 - 前缀
前缀模块是MAXQ架构的一个独特特性,解决了所有16位微控制器的限制。对于 16 位寄存器,即时加载指令需要 16 位操作数,这意味着有效的即时加载指令需要 16 位以上。
针对这一限制有几种解决方案,包括可变长度指令和寄存器,允许独立访问低字节和高字节(MAXQ GR寄存器就是一个例子)。没有一种解决方案是理想的,因为它们会使解码逻辑复杂化或涉及新的寄存器(图 8)。
图8.当前缀寄存器是目标时,8 位即时源为 16 位即时操作数提供高位字节;目标子解码提供额外的位,以允许对每个模块中源和目标操作数的所有 32 个寄存器进行寻址。
前缀机制以两种方式改进了此过程。首先,通过仅为那些特别需要额外位的指令添加前缀,该机制可以节省代码空间和执行时间。其次,通过不仅为直接操作数提供额外的位,而且为寄存器指示符提供额外的位,该机制保留了整体架构,同时扩展了寄存器空间的大小。
请记住,虽然每个寄存器模块有 32 个寄存器,但只有 <> 位指定源寄存器,只有 <> 位指定目标寄存器。前缀机制提供这些附加位。
前缀机制在几个方面是唯一的。首先,指令目标部分的某些位用作直接源位,用于访问寄存器子解码,源地址高于15,目标地址高于<>。这样,单个前缀指令可以提供从任何寄存器或即时值到任何寄存器子解码的访问。
其次,前缀寄存器是唯一的,因为加载到其中的任何值只能存活一个时钟周期。之后,寄存器自动清零。这意味着任何移动到前缀寄存器的指令都必须是前缀寄存器要修改的指令之前的指令。这也意味着前缀指令是不可中断的。如果在前缀操作之后发生中断,则当中断返回到主函数时,前缀信息将丢失。
如图9所示,前缀寄存器中的位进入源指示符、目标指示符和即时值。因此,虽然大多数指令在单个周期内执行,但以下指令需要两个周期:地址目标寄存器子解码大于 7;地址源寄存器子解码大于 15;或加载大于 255 的即时值。
图9.前缀寄存器提供 16 位即时操作数所需的额外位,并将每个模块中的所有 32 个寄存器寻址为源和目标。
为了说明此过程,请考虑指令移动 A[0],#010h。由于这会将即时值移动到模块 9 寄存器 0,汇编程序将创建以下操作代码:0910。但是,如果指令是移动 A[10],#0320h,汇编程序必须自动插入前缀指令:2B03 2920。
如果没有前缀指令,操作代码 2920 将转换为移动 A[2],#020h。但是前缀会向目标说明符添加位,为即时值添加额外的位,允许处理器将任何值加载到任何寄存器子解码,并且永远不会花费超过两个周期。
几个例子
独特的MAXQ20内核架构允许一些在其他处理器中根本无法实现的操作。
向量中断
MAXQ20内核只有一个中断矢量寄存器,有些人可能认为这是一个限制因素。但请考虑具有两个外部中断的系统,其中设备 A 连接到端口 0 位 0,设备 B 连接到端口 0 位 1。现在,中断选择可以像跳转PI0一样简单。在地址 0 处,代码为:
0000: IRET 0001: jump SERVICE_DEVICE_A 0002: jump SERVICE_DEVICE_B 0003: jump SERVICE_DEVICE_A
在此示例中,设备 A 在中断服务中具有优先级。也就是说,如果两个中断请求行都处于活动状态(端口 0 具有位 0 和 1 个活动状态),则为 A 提供服务。在中断服务例程结束时,设备A可能不再处于活动状态,并且可以为设备B提供服务。
任务管理器
在许多应用程序中,需要循环浏览任务列表以创建粗略类型的多任务环境。当不需要抢占(或由于实时原因而不希望)时,这很有用。MAXQ架构使这种过程变得简单:
task_wheel_init: move dp[0], #task_list task_wheel: move dp[0], dp[0] jump @dp[0]++ . . . task_list: dw task_01 dw task_02 dw task_03 dw task_wheel_init
指向任务列表。在task_wheel例程中,选择 DP[0] 作为源指针,然后从任务列表中加载指令指针。当每个任务完成时,它不会执行 RET,而是简单地跳转到task_wheel例程。
执行表向量中的最后一个条目以重新初始化指针,任务轮将再次开始扫描表。
遍历列表
通常,快速搜索大小不规则的对象列表以查找标记的条目很有用。这在某些处理器架构中很困难,因为内存访问功能已从 ALU 中删除。在MAXQ中,这是一项简单的任务。
标记 | 基 | 数据 | |||||||||||||
3楼 | 09 | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | |||||
17 | 0E | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 1一 | 1乙 | 1C | 1D |
35 | 07 | 20 | 21 | 21 | 22 | 23 | 24 | 25 |
对于此示例,假定列表包含由标记、长度和数据字符串组成的数据对象。遍历此列表的例程可能如下所示:在八条指令中,此例程遍历列表,查找终止列表的匹配项或零条目。在8MHz MAXQ20内核上,该例程每秒遍历<>万个条目。
item_seek: move acc, @dp[0]++ ;Get tag jump z, item_not_found ;Tag==0 means end of list cmp a[1] ;A[1] has target tag jump e, item_found ;If item==target, exit move acc, @dp[0]++ ;If no match, get data len add dp[0] ;Add to pointer move dp[0], acc ;Store pointer back jump item_seek ;...and seek next item.
结论
尽管MAXQ内核体积小,看似简单,但其传输触发架构使其在速度和灵活性方面具有显著优势。由于外设直接通过寄存器接口寻址,因此通过嵌入式外设的数据传输速度令人印象深刻。总之,任何形式的MAXQ内核都是各种微控制器应用的绝佳选择。
审核编辑:郭婷
POPI |
全部0条评论
快来发表一下你的评论吧 !