一站式电子元器件采购平台

华强商城公众号

一站式电子元器件采购平台

元器件移动商城,随时随地采购

华强商城M站

元器件移动商城,随时随地采购

半导体行业观察第一站!

芯八哥公众号

半导体行业观察第一站!

专注电子产业链,坚持深度原创

华强微电子公众号

专注电子产业链,
坚持深度原创

电子元器件原材料采购信息平台

华强电子网公众号

电子元器件原材料采购
信息平台

使用MAXQ的乘数模块的处置方案

来源:analog 发布时间:2024-01-22

摘要: 本应用笔记描述了乘数是如何操作的,以及如何在应用程序中为该模块编写代码以最大化数学性能。

硬件乘法器(以下称为乘法累加或MAC)模块是一个非常强大的工具,特别是对于需要大量计算的应用,例如,电表微控制器的固件。该乘法器能够在单个机器周期内对有符号或无符号操作数执行乘法、乘数-负、乘数-累加或乘数-减操作,在特殊情况下甚至更快。本文研究了硬件组织和功能,解释了如何为MAC编写代码,并提供了使用MAXQ硬件乘法器进行典型计算的简单示例。

开始

首先,我们需要关于MAXQ架构、寄存器映射和指令集的基本知识,这些信息可以从MAXQ系列用户指南或任何基于MAXQ的微控制器数据表(例如MAXQ2000)中获得。我们还需要参考MAC硬件描述,它在MAXQ系列用户指南文档中。假定您对汇编语言,特别是对MAXQ汇编程序有一定的熟悉程度。

乘数的概述

从编程的角度来看,MAC模块表现为8个特殊函数寄存器,映射到模块的空间中,从M0到M5。一个寄存器(MCNT)包含控制位,两个寄存器(MA, MB)指定用于输入操作数,三个寄存器(MC0, MC1, MC2视为一个长MC寄存器)保存输出结果,即乘积或累积,两个只读寄存器(MC0R,MC1R视为一个MCR寄存器,“R”代表“只读”)在特殊情况下用作输出寄存器。累加器MC是可配置的,通常为40位或48位宽。在任何配置中,都有两个16位寄存器MC0和MC1,而MC2寄存器被实现为8位、16位或其他。为了简单起见,我们假设累加器MC为48位宽,MAC寄存器映射到模块M3中:

#定义MCNT M3[0]#定义MA M3[1]#定义MB M3[2]#定义MC2 M3[3]#定义MC1 M3[4]#定义MC0 M3[5]#定义MC1R M3[6]#定义MC0R M3[7]


乘数随时可以进行数学运算,使用非常简单,由四个基本步骤组成:1)设置配置,2)加载操作数,3)等待,4)卸载结果。图1表示MAC寄存器和典型操作流程。实际计算在步骤2之后立即开始。当一个操作开始时,乘数计算操作数MA和MB的乘积,然后在步骤3结束时将其乘积放入或添加到累加器MC中。MCR寄存器作为内部工作记忆参与,我们通常不关心它。寄存器的工作方式乍一看是相当棘手和令人困惑的。建议初学者忽略MCR寄存器,特殊情况MCW=1除外。高级用户可以通过从MCR寄存器中窃取中间数据来享受更短更快的代码的好处,但是这样的用户必须完全理解它的工作方式。


图1所示。硬件乘法器寄存器结构和典型操作流程。

设置配置步骤(步骤1)意味着对控制寄存器MCNT进行简单的写操作。除了更新数据,它还隐式初始化硬件,即准备MAC接受新的操作数并执行新的操作。如果所需的配置已经在MCNT寄存器中设置,则可以跳过此步骤。当一个操作开始时,乘法器总是使用MCNT的当前内容。

一旦必要的操作数被加载到MAC(步骤2)中,实际的计算就开始了。数据输入操作数寄存器的速度或数据输入的顺序没有限制。不可见的操作数计数寄存器跟踪所有对MA和MB的写入,并相应地触发计算。例如,在双操作数模式中,第一个加载的操作数可以被多次重新加载,而无需开始计算。只有在加载第二个操作数时才开始计算。在单操作数模式中,当第一个操作数加载到MA或MB寄存器时触发计算。当计算开始或写入MCNT寄存器时,操作数计数由硬件初始化。

当期望从MC寄存器获得操作结果时,需要等待状态(步骤3)。把它想象成一个两阶段的过程:1)执行一个操作,例如计算乘积MA*MB, 2)更新累加器MC。第一阶段马上完成,但第二阶段相当于“移动”指令。MAC硬件执行此移动需要一个机器周期的时间。但是,当期望从MCR寄存器得到结果时,在特殊情况下MCW=1可以跳过等待状态,因为第一阶段的输出存储在那里。在等待状态中,可以输入任何有意义的指令而不是“no operation”,但写入MCNT会中断当前的乘法器操作。

倍增器配置选项

MCNT寄存器中控制位的含义很简单。

  • 位0:当SUS=1时,SUS将操作数MA, MB视为无符号16位数;当SUS=0时,将操作数MA, MB视为有符号的16位数字;

  • bit 1:当MMAC=1时,MMAC向累加器MC添加产品;当MMAC=0时,将产品放入累加器MC;

  • 位2:当MSUB=1时,MSUB使用(-MA)值代替MA;当MSUB=0时按原样使用MA操作数;

  • 位3:当OPSC=1时,OPSC长一个操作数触发计算;当OPSC=0时,长两个操作数将触发计算;

  • 第4位:当SQU=1(平方模式)时,一个操作数将把加载的值复制到另一个操作数寄存器中,并触发计算;当SQU=0时,正方形模式被禁用;

  • 位5:CLD当CLD=1时,所有数据寄存器(MA、MB、MC、操作数count)清零。该位由硬件自动清除。

  • 位6:当MCW=1时,MCW阻止乘法器将结果写入累加器MC。当MCW=0时,multiplier将结果写入累加器MC;

  • bit 7: OF只读位,表示当OF=1时发生错误(如溢出);如果OF=0,则没有错误;


操作数选择位OPSC开启单操作数模式。当OPSC=1时,乘法器将在删除第一个操作数后开始计算。SQU位转换为平方模式,在这种模式下,第一个加载的操作数被自动复制到另一个操作数寄存器,并触发操作。当SQU=1时,OPSC位没有任何意义。

MCW位是累加器MC的写保护标志。设置MCW=1允许在不干扰MC寄存器的情况下执行乘法运算。在这种特殊情况下,可以在没有等待状态延迟的情况下从MCR寄存器获得操作结果(准确地说,是结果的至少32位)。注意,写保护特性只影响乘法器操作。当MCW=1时,用户仍然可以直接写入MC寄存器,但MAC无法更新它。这就提供了一种非传统使用MAC作为额外存储的可能性。五个16位寄存器MA, MB, MC0, MC1, MC2可以临时存储数据,指针,计数器等,这对8位MAXQ10内核特别有用。通过设置MCW=1,我们可以确保累加器MC在写入MA或MB时不会意外更新。

当运行过程中发生严重错误时,乘数设置为只读状态位OF:

  • 无符号操作的MC寄存器溢出或下溢;

  • 有符号操作的MC寄存器溢出或下溢;

  • 尝试执行无符号乘反操作。


在所有其他情况下,OF位在操作后由硬件清除。对于唯乘和有符号反乘操作,没有设置OF位,该位被清除。注意,在溢出/下流事件的情况下,MC寄存器包含结果的正确低位。

如上所述,对MCNT的任何写入也隐式初始化操作数计数寄存器,并准备MAC开始新的操作。有关控制位的更多细节可以在下面的代码示例部分中找到。

乘数数据流

累加器MC和只读寄存器MCR的作用可以用下面的公式表示:


其中n为执行周期,MMAC为MCNT寄存器中的累积标志(0或1),MSUB为否定标志(0或1)。MCR寄存器只保留等式(2)右侧的32位低位,但它在执行周期n时立即更新。MC寄存器保留结果的完整长度,必要时扩展of位,但MC和of都在1个周期后更新。在操作期间,乘数器中的数据流如图2所示。


图2。乘数运算数据流。

代码示例

用相应的名称表示控制位是方便的,

#定义SUS 0x01#定义MMAC 0x02#定义MSUB 0x04#定义OPSC 0x08#定义SQU 0x10#定义CLD 0x20#定义MCW 0x40#定义OF 0x80


用那些名字而不是数字。例如,指令“move MCNT, #(SUS+MMAC+MSUB+SQU)”是“move M3[0], #23”的助记符。编写乘数需要将数据移动到MAC或从MAC移出,因此最常用的指令是“move dest,src”。本节中的每个示例都附有一个表,显示执行每条指令后乘数寄存器的结果变化。粗体表示寄存器被更新,即使值没有改变。表中所有数字都是十六进制,“xxxx”表项表示不重要的值。请注意MCR寄存器的行为:每当MA、MB或MC的内容发生变化时,它都会更新。例1-7演示了MAC在单个操作中的简单使用,例8-12展示了更复杂的配置,例如如何避免连续计算的等待状态。例13演示了乘数如何加快平方根计算的速度。

  1. 无符号乘法。

    计算3*5的乘积,并将其放入寄存器A[0]。

    移动mcnt, #(SUS+CLD);unsigned, multiple -only, clear datmove ma, #3;加载第一个操作数到内存中,#5;将第二个操作数装入mb;产品在MCR注册中;等待MAC更新mcmove a [0], mc0;卸载产品


    寄存器A[0]包含乘积3*5 = 15 (0x000F)。

    指令MCNTMBMC2MC0受体MC0R
    移动MCNT # (SUS + CLD)010000000000000000000000000000
    移动MA, 3号010003000000000000000000000000
    移动MB, #501000300050000000000000000华氏000度
    nop010003000500000000华氏000度0000华氏000度
    移动[0],MC0010003000500000000华氏000度0000华氏000度


    高级用户可以通过从MCR('移动a [0],MC0R'而不是'nop')中删除来节省一个周期。

  2. 签署了乘法。

    计算乘积3*(-5)并将其放入寄存器A[0]。

    移动mcnt, #(CLD);signed, multiple -only, clear data registersmove ma, #3;加载第一个操作数到内存,#(-5);将第二个操作数装入mb;产品在MCR注册中;等待MAC更新mcmove a [0], mc0;卸载产品


    寄存器A[0]包含乘积3*(-5)= -15 (0xFFF1)。

    指令MCNTMBMC2MC0受体MC0R
    移动MCNT # (CLD)000000000000000000000000000000
    移动MA, 3号000003000000000000000000000000
    移动MB, #(-5)000003FFFB000000000000飞行符FFF1
    nop000003FFFB飞行符飞行符FFF1飞行符FFF1
    移动[0],MC0000003FFFB飞行符飞行符FFF1飞行符FFF1


    高级用户可以通过从MCR('移动a [0],MC0R'而不是'nop')中删除来节省一个周期。

  3. 有符号乘-反运算。

    计算3和(-5)的负积,将其放入寄存器A[0]。

    移动mcnt, #(MSUB+CLD);签名,多重否定,明确数据寄存器移动ma, #3;加载第一个操作数到内存,#(-5);将第二个操作数装入mb;结果在MCR寄存器中;等待MAC更新mcmove a [0], mc0;卸载结果


    寄存器A[0]包含结果-(3*(-5))= 15 (0x000F)。

    指令MCNTMBMC2MC0受体MC0R
    移动MCNT # (MSUB + CLD)040000000000000000000000000000
    移动MA, 3号040003000000000000000000000000
    移动MB, #(-5)040003FFFB0000000000000000华氏000度
    nop040003FFFB00000000华氏000度0000华氏000度
    移动[0],MC0040003FFFB00000000华氏000度0000华氏000度


    高级用户可以通过从MCR('移动a [0],MC0R'而不是'nop')中删除来节省一个周期。

  4. 无符号乘法累加操作。

    计算表达式2+3*5并将其放入寄存器A[0]。

    移动mcnt, #(SUS+MMAC);无符号,乘法累加;没有设置CLD,数据寄存器保存其内容移动mc0, #2;预载蓄电池移动mc1, #0;预载蓄电池移动mc2, #0;预载蓄能器移动ma, #3;加载第一个操作数到内存中,#5;将第二个操作数装入mb;结果是在MCR寄存器!nop;等待MAC更新mc;MCR改为MC+MA*MB!移动a [0], mc0;卸载结果


    寄存器A[0]包含结果2+3*5 = 17 (0x0011)。

    指令MCNTMBMC2MC0受体MC0R
    移动MCNT # (SUS + MMAC)03xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    移动MC0, 2号03xxxxxxxxxxxxxxxx0002xxxxxxxx
    移动MC1, #003xxxxxxxxxxxx00000002xxxxxxxx
    移动MC2, 0号03xxxxxxxx000000000002xxxxxxxx
    移动MA, 3号030003xxxx000000000002xxxxxxxx
    移动MB, #5030003000500000000000200000011
    nop030003000500000000001100000020
    移动[0],MC0030003000500000000001100000020


    注意MCR寄存器的行为。它遵循上面的公式(2),即总是反映MA, MB和MC的当前状态。在这个例子中,MCR寄存器在等待状态期间只保存一个机器周期的32位结果,然后改变其值,因为MC寄存器在等待状态后更新,新值为MCR = 0x0020 = 32 = 17+3*5 = MC+MA*MB。

    高级用户可以通过从MCR('移动a [0],MC0R'而不是'nop')中删除来节省一个周期。但是必须记住两件事:i) MCR只能提供32位低比特的结果,ii)即使这32位在有限的时间内可用,在这个示例配置中只有一个机器周期。

  5. 有符号乘法累加操作。

    计算表达式(-2)+3*(-5)并将其放入寄存器A[0]。

    移动mcnt, #(MMAC);sign, multiple -accumulatemove mc0, # 0fffeh;预加载蓄电池移动mc1, # 0ffffh;预载蓄能器移动mc2、mc1;预载蓄能器移动ma, #3;加载第一个操作数到内存,#(-5);将第二个操作数装入mb;结果是在MCR寄存器!nop;等待MAC更新mc;MCR改为MC+MA*MB!移动a [0], mc0;卸载结果


    寄存器A[0]包含结果(-2)+3*(-5)= -17 (0xFFEF)。

    指令MCNTMBMC2MC0受体MC0R
    移动MCNT # (MMAC)02xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    移动MC0, #0FFFEh02xxxxxxxxxxxxxxxxFFFExxxxxxxx
    移动MC1, #0FFFFh02xxxxxxxxxxxx飞行符FFFExxxxxxxx
    移动MC2, MC102xxxxxxxx飞行符飞行符FFFExxxxxxxx
    移动MA, 3号020003xxxx飞行符飞行符FFFExxxxxxxx
    移动MB, #(-5)020003FFFB飞行符飞行符FFFE飞行符FFEF
    nop020003FFFB飞行符飞行符FFEF飞行符FFE0
    移动A[0], mc0 02 0003 fffb ffff ffff ffff ffff ffe0








    在上面的例子4中,高级用户可以在寄存器被更新为新值MCR = 0xFFFF FFE0 = -32 = -17+3*(-5) = MC+MA*MB之前,通过从MCR ('move a [0],MC0R'而不是'nop')中删除来节省一个周期。

  6. 无符号乘法-减法操作。

    计算表达式17-3*5并将其放入寄存器A[0]。假设操作数存储在寄存器A[1]=3和A[2]=5中。

    移动mcnt, #(SUS+MMAC+MSUB);unsigned, multiply- subtmove mc0, #17;预载蓄电池移动mc1, #0;预载蓄电池移动mc2, #0;预载蓄能器移动ma, A[1];加载第一个操作数到mamove mb, A[2];将第二个操作数装入mb;结果是在MCR寄存器!nop;等待MAC更新mc;MCR改为MC-MA*MB!移动a [0], mc0;卸载结果


    寄存器A[0]包含结果17-3*5 = 2 (0x0002)。

    指令MCNTMBMC2MC0受体MC0R
    移动MCNT # (SUS + MMAC + MSUB)07xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    移动MC0, 17号07xxxxxxxxxxxxxxxx0011xxxxxxxx
    移动MC1, #007xxxxxxxxxxxx00000011xxxxxxxx
    移动MC2, 0号07xxxxxxxx000000000011xxxxxxxx
    移动MA, A[1]070003xxxx000000000011xxxxxxxx
    移动MB, A[2]070003000500000000001100000002
    nop0700030005000000000002飞行符FFF3
    移动[0],MC00700030005000000000002飞行符FFF3


    在上面的例子4中,高级用户可以在寄存器更新为新值MCR = 0xFFFF FFF3 = -13 = 2-3*5 = MC-MA*MB之前,通过从MCR ('move a [0],MC0R'而不是'nop')中删除来节省一个周期。

  7. 有符号的乘减运算。

    计算表达式(_2)-3*(-5)并将其放入寄存器A[0]。假设操作数存储在寄存器A[1]=3和A[2]= -5中。

    移动mcnt, #(MMAC+MSUB);sign, multiply- subtmove mc0, # 0fffeh;预加载蓄电池移动mc1, # 0ffffh;预加载累加器移动mc2, # 0ffffh;预载蓄能器移动ma, A[1];加载第一个操作数到mamove mb, A[2];将第二个操作数装入mb;结果是在MCR寄存器!nop;等待MAC更新mc;MCR改为MC-MA*MB!移动a [0], mc0;卸载结果


    寄存器A[0]包含结果(-2)-3*(-5)= 13 (0x000D)。

    指令MCNTMBMC2MC0受体MC0R
    移动MCNT # (SUS + MMAC + MSUB)06xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    移动MC0, #0FFFEh06xxxxxxxxxxxxxxxxFFFExxxxxxxx
    移动MC1, #0FFFFh06xxxxxxxxxxxx飞行符FFFExxxxxxxx
    移动MC2, #0FFFFh06xxxxxxxx飞行符飞行符FFFExxxxxxxx
    移动MA, A[1]060003xxxx飞行符飞行符FFFExxxxxxxx
    移动MB, A[2]060003FFFB飞行符飞行符FFFE0000000 d
    nop060003FFFB00000000000 d0000001 c
    移动[0],MC0060003FFFB00000000000 d0000001 c


    在上面的例子4中,高级用户可以通过从MCR('移动a [0],MC0R'而不是'nop')中删除来节省一个周期,然后这个寄存器被更新为新的值MCR = 0x001C = 28 = 13-3*(-5) = MC-MA*MB。

  8. One-operand模式。

    当应用程序需要多次使用相同的常量执行操作时,此模式非常有用。因为其中一个操作数没有改变,所以不需要每次都加载它。只需加载一次常量操作数,并将乘数切换到单操作数模式。然后,每次写入另一个操作数寄存器都会触发计算。

    例如,假设数字转换硬件在称为ADC的寄存器中反复返回16位电压值,最低有效位按1/8 V比例调整,微控制器应用程序必须重新计算每个电压值到mV单位并将其存储在数据RAM中。重新计算可以通过将行数据乘以系数1000/8=125 (0x7D)来完成。下面的代码将完成这项工作。

    ;初始配置乘数(此代码执行一次)移动ma, #125;将常数因子加载到MA中。移动mcnt, #(OPSC);有符号,只乘,单操作数模式......;此代码重复执行,每个新的ADC值移动mb, ADC;将操作数装入mb;结果是在MCR寄存器!移动dp [0],#8;设置地址=0x0008,同时等待MAC更新mcmove @ dp [0], mc0;将结果存储在地址0x0008......的数据内存中


    顺便说一下,这个例子展示了如何使用等待状态来设置地址,而不是用nop来浪费时间。假设三个连续的原始电压分别为5.0V, 1.5V, -2.5V (0x0028, 0x000C, 0xFFEC),则软件流程如下表所示。

    指令MCNTMBMC2MC0受体MC0R
    移动MA, 125号xxxx007 dxxxxxxxxxxxxxxxxxxxxxxxx
    移动MCNT # (OPSC)08007 dxxxxxxxxxxxxxxxxxxxxxxxx








    移动MB, ADC08007 d0028xxxxxxxxxxxx00001388
    移动DP[0], #808007 d002800000000138800001388
    移动@DP[0], MC008007 d002800000000138800001388
    数据存储器[8]= 0x1388 (= 5000mv)






    移动MB, ADC08007 d000 cxxxxxxxxxxxx000005年直流
    移动DP[0], #808007 d000年,一个0000000005年直流000005年直流
    移动@DP[0], MC008007 d000年,一个0000000005年直流000005年直流
    数据存储器[8]= 0x05DC (= 1500mv)






    移动MB, ADC08007 dFFECxxxxxxxxxxxx飞行符F63C
    移动DP[0], #808007 dFFEC飞行符飞行符F63C飞行符F63C
    移动@DP[0], MC008007 dFFEC飞行符飞行符F63C飞行符F63C
    数据存储器[8]= 0xF63C (= - 2500mv)







    同样,高级用户可以通过从MCR中删除重复代码来保存一个周期:

    ;初始配置乘数(此代码执行一次)移动dp [0],#8;set address=0x0008move ma, #125;将常数因子加载到MA中。移动mcnt, #(OPSC);有符号,只乘,单操作数模式......;此代码重复执行,每个新的ADC值移动mb, ADC;将操作数装入mb;结果是在MCR寄存器!移动@ dp [0], MC0R;将结果存储在地址0x0008......的数据内存中


    但请记住限制:只有32低比特从MCR可用,其内容可能会在不通知的情况下更改!

  9. 广场模式。

    在这种模式下,只需输入一个操作数就可以计算出一个平方。例如,微控制器应用程序必须计算电压的均方根值。计算的一部分是样本的平方和,这个和可以很容易地通过MAC的平方模式来完成。假设电压样本是16位有符号值,单位为mV,并(重复地)存储在地址0x0008的数据RAM中。代码可能如下所示。

    ;初始配置乘数(此代码执行一次)移动dp [0],#8;set address=0x0008move mcnt,#(MMAC+SQU+CLD);签名,方累积,明确寄存器......;对于每个新的samplemove ma, @DP[0],重复执行此代码;将操作数装入MA(假设DP[0]为活动数据ptr);结果是在MCR寄存器!nop;等待MAC更新mc;MCR改为MC+MA*MB!......


    平方和正在MC寄存器中累积。假设前三个连续的原始电压分别为5.0V、1.5V、-2.5V (0x1388、0x05DC、0xF63C),则软件流程可以用下表表示。

    指令MCNTMBMC2MC0受体MC0R
    移动DP[0], #8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    移动MCNT # (MMAC +汉堡+ CLD)120000000000000000000000000000

    移动MA, @DP[0]1213881388000000000000017 d7840
    nop12138813880000017 d784002年足总F080
    MC = 0x017D 7840 (= 25 000 000 mV2)
    移动MA, @DP[0]1205年直流05年直流0000017 d7840华氏019度CD50
    nop1205年直流05年直流0000华氏019度CD5001 c22260
    MC = 0x019F CD50 (= 25 000 000 + 2 250 000 mV2)
    移动MA, @DP[0]12F63CF63C0000华氏019度CD5001 ff2 b60
    nop12F63CF63C000001 ff2 b60025 e8970
    MC = 0x01FF 2B60 (= 25 000 000 + 2 25 000 + 6 25 000 mV2)


  10. 累加器写保护功能。

    这个特性(MCW控制位)允许不累加的乘法,即累加器的内容不被乘数操作更新。如果应用程序需要并行执行两个不同的任务,一个涉及累加,另一个只是进行数字相乘,则可能有用。然后,乘数可以在这些任务之间来回切换,而无需保存/恢复其累加器。比如说,我们可以结合上面的例子8和9,通过使用MCW控制位并行地积累平方和,并转换为毫伏。

    ;初始化MAC(此代码执行一次)移动dp [0],#8;set address=0x0008move mcnt,#(CLD);清楚寄存器……;每个新的ADC值都会重复执行此代码;mcnt, #(MCW);signed, multiple -only, mcw -protectmove ma, #125;加载常数因子到mamove mb, adc;将原始样本装入mb;结果是在MCR寄存器!;特殊情况MCW=1,这里不需要等待状态!移动@ dp [0], mc0r;将结果存储在地址为0x0008的数据内存中;mcmove mcnt, #(MMAC+SQU);签名,方形累积,清除mcw -保护移动ma, mc0r;将操作数装入ma;结果是在MCR寄存器!nop;等待MAC更新mc;MCR改为MC+MA*MB!......


    平方和在MC寄存器中累积,乘法结果(转换为mV)通过MCR寄存器访问。注意,乘法运算不需要等待状态。假设前三个连续的原始电压分别为5.0V, 1.5V, -2.5V (0x0028, 0x000C, 0xFFEC),则软件流程如下表所示。

    指令MCNTMBMC2MC0受体MC0R
    移动DP[0], #8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    移动MCNT # (CLD)000000000000000000000000000000

    移动MCNT, #(MCW)40xxxxxxxx000000000000xxxxxxxx
    移动MA, 125号40007 dxxxx000000000000xxxxxxxx
    移动MB, ADC40007 d002800000000000000001388
    移动@DP[0], MC0R40007 d002800000000000000001388
    移动MCNT, #(MMAC+SQU)12007 d002800000000000000001388
    移动MA, MC0R1213881388000000000000017 d7840
    nop12138813880000017 d784002年足总F080
    数据存储器[8]= 0x1388 (= 5000 mV)MC = 0x017D 7840 (= 25 000 000 mV2)
    移动MCNT, #(MCW)40xxxxxxxx0000017 d7840xxxxxxxx
    移动MA, 125号40007 dxxxx0000017 d7840xxxxxxxx
    移动MB, ADC40007 d000 c0000017 d7840000005年直流
    移动@DP[0], MC0R40007 d000 c0000017 d7840000005年直流
    移动MCNT, #(MMAC+SQU)12007 d000 c0000017 d7840000005年直流
    移动MA, MC0R1205年直流05年直流0000017 d7840华氏019度CD50
    nop1205年直流05年直流0000华氏019度CD5001 c22260
    数据存储器[8]= 0x05DC (= 1500 mV)MC = 0x019F CD50 (= 25 000 000 + 2 250 000 mV2)
    移动MCNT, #(MCW)40xxxxxxxx0000华氏019度CD50xxxxxxxx
    移动MA, 125号40007 dxxxx0000华氏019度CD50xxxxxxxx
    移动MB, ADC40007 dFFEC0000华氏019度CD50飞行符F63C
    移动@DP[0], MC0R40007 dFFEC0000华氏019度CD50飞行符F63C
    移动MCNT, #(MMAC+SQU)12007 dFFEC0000华氏019度CD50飞行符F63C
    移动MA, MC0R12F63CF63C0000华氏019度CD5001 ff2 b60
    nop1205年直流05年直流000001 ff2 b60025 e8970
    数据存储器[8]= 0xF63C (= -2500 mV)MC = 0x01FF 2B60 (= 25 000 000 + 2 250 000 + 6 250 000 mV2)

  11. 连续(背靠背)计算。

    等待状态可以在不中断当前操作的情况下为下一个操作保留一个操作数。例如,如果要计算和S=1*2+3*4+5*6+7*8+9*10,则可以通过以下代码完成。

    移动mcnt,#(MMAC+CLD);签名,多重累积,清除寄存器移动ma, #1;加载操作数mb, #2;加载操作数MB,触发1*2move ma, #3;加载操作数MA,同时等待MAC完成1*2move mb, #4;加载操作数MB,触发3*4move ma, #5;加载操作数MA,同时等待MAC完成3*4move mb, #6;加载操作数MB,触发5*6move ma, #7;加载操作数MA,等待MAC完成5*6move mb, #8;加载操作数MB,触发7*8move ma, #9;加载操作数MA,等待MAC完成7*8move mb, #10;加载操作数MB,触发9*10nop;等待MAC更新MC


    和S=190 (0xBE)是在MC寄存器。注意,在本例中,除了最后一个之外的所有等待状态都没有被浪费,而是用于长操作数。

    指令MCNTMBMC2MC0受体MC0R
    移动MCNT, #(MMAC+CLD)020000000000000000000000000000
    移动MA, #1020001000000000000000000000000
    移动MB, 2号020001000200000000000000000002
    移动MA, 3号020003000200000000000200000008
    移动MB, #402000300040000000000020000000 e
    移动MA, 5号020005000400000000000 e00000022
    移动MB, #6020005000600000000000 e0000002 c
    移动MA, 7号020007000600000000002 c00000056
    移动MB, #8020007000800000000002 c00000064
    移动MA, 9号0200090008000000000064000000交流
    移动MB, #10020009000年,一个000000000064000000是
    nop020009000年,一个0000000000是00000118


    类似的技术也可用于单操作数或平方模式。例如,如果要计算和S=1(2)+2(2)+3(2)+4(2)+5(2)+6(2)+7(2),可以使用以下代码完成。

    移动mcnt,#(MMAC+SQU+CLD);sign, square-accumulate, clear registrsmove ma, #1;将操作数装入MA,触发1*1move MA, #2;将操作数装入MA,等待移动MA时触发2*2,#3;将操作数装入MA,等待移动MA时触发3*3;将操作数装入MA,等待移动MA时触发4*4,#5;将操作数装入MA,等待移动MA时触发5*5,#6;将操作数装入MA,等待移动MA时触发6*6,#7;将操作数装入MA,等待nop时触发7*7;等待MAC更新MC


    和S=140 (0x8C)在MC寄存器中。请注意,除了最后一个等待状态外,所有等待状态都没有浪费,而是用于长操作数。

    指令MCNTMBMC2MC0受体MC0R
    移动MCNT, #(MMAC+SQU+CLD)120000000000000000000000000000
    移动MA, #1120001000100000000000000000001
    移动MA, 2号120002000200000000000100000005
    移动MA, 3号12000300030000000000050000000 e
    移动MA, 4号120004000400000000000 e0000001 e
    移动MA, 5号120005000500000000001 e00000037
    移动MA, 6号12000600060000000000370000005 b
    移动MA, 7号120007000700000000005 b0000008 c
    nop120007000700000000008 c000000 bd

  12. 溢出。

    在溢出/下流事件的情况下,MC寄存器包含结果的正确低位,因此of标志可以用作乘法器的进位/借位来实现比MC更长的累加器。例如,64位累加器可以由16位寄存器a[0]和48位MC寄存器组成。然后64位乘法累加操作可以通过以下代码完成。

    移动mcnt, #(SUS+MMAC);unsigned, multiple -accumulatemove ma, #32768;加载操作数到内存,#16384;将操作数装入mbnop;等待MAC更新mc;设置OF标志(如有必要)移动c, mcnt .7;拷贝bit到进位;A[0]+=0+进位(假设A[0]是活动MAXQ的累加器)


    临时的64位累加器加32768*16384。假设初始值为0x1234 FFFF F000 4321,则软件流程如下表所示,新值为0x1235 0000 1000 4321 =旧值+ 0x2000 0000。

    指令MCNTMB携带一个[0]MC2MC0
    移动MCNT # (SUS + MMAC)03xxxxxxxxxxxx1234飞行符4321
    移动MA, #32768038000xxxxxxxx1234飞行符F0004321
    移动MB, #163840380004000xxxx1234飞行符F0004321
    nop8380004000xxxx1234000010004321
    7 .选C838000400011234000010004321
    addc # 0838000400001235000010004321

  13. 平方根子程序。

    MAC模块可以帮助加快各种数学计算,而不仅仅是乘法和累加。例如,检查一个计算无符号32位数a的平方根的子例程。该子例程通过命中或不命中方法找到结果,即一个无符号16位数X,使X(2)≤a <(X+1)(2)。从X(0)=0x0000开始,它连续地将部分结果Xn的每个位从0切换到1,从最高有效位开始。如果X(n)(2)≤A,则比特位置保持1 (hit),否则比特位置为0 (miss)。这种方法的效率来自于乘法器可以在几个周期内计算出(a - x (n)(2))。整个过程在n=16次迭代中完成,大约需要200个机器周期。很容易看出,没有MAC模块的计算平方根将花费更长的时间为MAXQ20处理器。

    ;========================================;为MAXQ20 SQRT32MAC子例程 ;========================================;输入:A[3:2] =操作数,无符号32位;输出:A[0] = sqrt(操作数),无符号16位;使用(修改)资源:美联社、APC, 1:0, MAC寄存器 ;======================================== sqrt32mac_MAXQ20:;本地数据图:;A[0] = x;A[1] = A[0],#0;init X=0x0000move A[1],#08000h;init mask=0x8000move MCNT,#(SUS+MMAC+MSUB+SQU);无符号,square-subtractsqrt32mac_MAXQ20_loop:;启动迭代移动APC,#080h;设置Acc为A[0],不自动输入A[1];X |= mask(设置尝试位);get MC = AA-X^2move MC2,#0;预加载MC,A[3:2]移动MC1,A[3]移动MC0,A[2]移动MA,A[0];加载操作数MA <- xnop;等待MAC更新MC;现在MC = AA-X ^ 2;检查是否(AA-X^2) ><0?移动C, mc2.0;进位><- sign(AA-X^2)跳转NC, sqrt32mac_maxq20_update;如果没有Carry (hit),就跳;撤销掩码位(miss)xor A[1];X ^= mask (clear try bit)sqrt32mac_MAXQ20_update_mask:移动AP,#01;设Acc为A[1]sr;A[1] >>= 1(右移掩模,LSb ->sjump NC, sqrt32mac_maxq20_loop;如果没有进位,下一次迭代;全部16位完成,退出;返回;结束SQRT32MAC MAXQ20子例程 ;========================================


    下表展示了A=0x00AA 63CB的最后几个迭代。这个数字来自上面的例子9,表示电压均方值(=0x01FF 2B60/3)。这个数的平方根就是有效值电压,单位是毫伏。星号(*)表示有源MAXQ的累加器A[0]或A[1]。结果X=0x0D0D (=3341 mV)最后在A[0]寄存器中。

    指令一个[0](X)[1](面具)MCNTMBMC2MC0
    ……







    ;迭代14:







    移动APC, #080h* 0 d080004170 d080 d0800000000938 b
    或者一个[1]* 0 d0c0004170 d080 d0800000000938 b
    移动MC2, 0号* 0 d0c0004170 d080 d0800000000938 b
    移动MC1, A[3]* 0 d0c0004170 d080 d08000000 aa938 b
    移动MC0, A[2]* 0 d0c0004170 d080 d080000000063年cb
    移动MA, A[0]* 0 d0c0004170 d0c0 d0c0000000063年cb
    nop* 0 d0c0004170 d0c0 d0c000000002 b3b
    移动C, MC2.0进位= 0
    sjump数控& lt;……比;跳(打击)
    美联社,# 010 d0c* 0004170 d0c0 d0c000000002 b3b
    0 d0c* 0002进位= 0
    跳数控,& lt;……比;跳到下一个迭代
    ;迭代15:







    移动APC, #080h* 0 d0c0002170 d0c0 d0c000000002 b3b
    或者一个[1]* 0 d0e0002170 d0c0 d0c000000002 b3b
    移动MC2, 0号* 0 d0e0002170 d0c0 d0c000000002 b3b
    移动MC1, A[3]* 0 d0e0002170 d0c0 d0c000000 aa2 b3b
    移动MC0, A[2]* 0 d0e0002170 d0c0 d0c0000000063年cb
    移动MA, A[0]* 0 d0e0002170 d0e0 d0e0000000063年cb
    nop* 0 d0e0002170 d0e0 d0e飞行符飞行符F707
    移动C, MC2.0进位= 1
    跳数控,& lt;……比;不跳(错过)
    xOr一[1]* 0 d0c0002170 d0e0 d0e飞行符飞行符F707
    美联社,# 010 d0c* 0002170 d0e0 d0e飞行符飞行符F707
    0 d0c* 0001进位= 0
    sjump数控& lt;……比;跳到下一个迭代
    ;迭代16:







    移动APC, #080h* 0 d0c0001170 d0e0 d0e飞行符飞行符F707
    或者一个[1]* 0 d0d0001170 d0e0 d0e飞行符飞行符F707
    移动MC2, 0号* 0 d0d0001170 d0e0 d0e0000飞行符F707
    移动MC1, A[3]* 0 d0d0001170 d0e0 d0e000000 aaF707
    移动MC0, A[2]* 0 d0d0001170 d0e0 d0e0000000063年cb
    移动MA, A[0]* 0 d0d0001170 d0d0 d0d0000000063年cb
    nop* 0 d0d0001170 d0d0 d0d000000001122
    移动C, MC2.0进位= 0
    跳数控,& lt;……比;跳(打击)
    美联社,# 010 d0d* 0001170 d0d0 d0d000000001122
    0 d0d* 0000进位= 1
    sjump数控& lt;……比;不跳转到下一个迭代
    受潮湿腐烂返回A[0]= sqrt(A[3:2])



声明:本文观点仅代表作者本人,不代表华强商城的观点和立场。如有侵权或者其他问题,请联系本站修改或删除。

社群二维码

关注“华强商城“微信公众号

调查问卷

请问您是:

您希望看到什么内容: