0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

在MAXQ2000数据存储器中实现软堆栈

星星科技指导员 来源:ADI 作者:ADI 2023-02-14 18:20 次阅读

MAXQ2000微控制器MaximRISC微控制器系列MAXQ器件一样,都是基于MAXQ20内核。基于MAXQ20的微控制器通常可实现一个16位宽硬堆栈,其深度固定不变(MAXQ2000为16),存储在与数据和程序空间分开的专用内部存储器中。通过子程序调用和中断,这一硬堆栈可用于保存和恢复微控制器的操作状态。

虽然非常适合紧凑型应用,但是在规模较大的汇编应用中,使用深度嵌套的子程序(或者使用了在堆栈中保存和恢复多个工作寄存器的子程序),硬堆栈会很快耗尽空间。利用数据存储器中的“软堆栈”,以C编程语言(使用IAR的Embedded Workbench®等编译器)或者Rowley Associates的Crossworks for MAXQ编写应用程序可避免这一问题。这一软堆栈存储子程序的调用/返回地址以及本地工作变量。然而,MAXQ20内核没有内置机制来定位数据存储器中的堆栈,这些数据存储器只用在汇编应用中。

本应用笔记介绍了汇编应用中在数据存储器中实现软堆栈的简单方法。应用笔记中的代码可以用于MAXQ2000和其他基于MAXQ20的微控制器。采用了MAX-IDE的宏预处理特性,在Maxim的MAXQ系列工程应用开发和调试环境中编写了实例代码。

可以免费下载MAX-IDE环境最新的安装包和文档:

MAX-IDE安装(ZIP)

MAXQ内核汇编指南(PDF)

开发工具指南(PDF)

MAXQ20内核中的硬堆栈工作

MAXQ20内核使用了两种不同类型的堆栈工作模式:

PUSH工作(它包括操作代码PUSH、LCALL和SCALL)被用于在堆栈中存储数据。这些操作将堆栈指针SP预增1,然后,把数据存储在SP指针(@SP)指向的堆栈位置。

POP工作(它包括操作代码POP、POPI、RET和RETI)被用于从堆栈中恢复数据。这些操作从SP指向的堆栈位置恢复数据,然后,将堆栈指针减1。

硬堆栈的一项主要功能是在调用子程序时保存并恢复地址,因此,堆栈含有16位(字)位置。这一位宽支持在一次push或者pop操作中保存或者恢复16位指令指针(IP)寄存器。尽管可以使用PUSH或者POP在堆栈中保存或者恢复8位寄存器(例如,AP),但每一堆栈操作总是使用整个16位字。

除了利用堆栈的各种操作代码之外,还有两种其他的情况,在这些情况下,微控制器自动使用硬堆栈:

当处理中断时,开始执行中断服务程序(中断矢量寄存器IV所指)之前,当前程序执行点被推入堆栈。

当调用某些调试命令(例如,读寄存器和写数据存储器)时,需要执行完程序ROM中的代码,在控制被传送给程序ROM之前,当前的执行点被推入堆栈。一旦执行完程序ROM中的调试程序,执行点从堆栈中弹出,恢复处理器以前的状态。

找到中断服务程序或者执行调试器命令总是需要使用硬堆栈。由于这一行为嵌入在硬件中,因此,无法避开这一问题。然而,对于更常用的PUSH/POP和CALL/RET指令对,可以采用软堆栈。

注意,当以下任一堆栈错误状态出现时,MAXQ2000 (和其他的基于MAXQ20内核的器件一样)并不支持任何错误探测或者报警:

堆栈上溢:将数值推入已经满的堆栈时发生。这一错误导致堆栈中最早的数值被覆写。

堆栈下溢:从空堆栈中弹出数值时发生。这一错误导致返回无效数据值。例如,如果堆栈空时执行RET,执行后将返回一个不正确的(有可能是随机的)地址。

在数据存储器中建立一个软堆栈

在数据存储器中建立一个软堆栈的第一步是定义要使用数据存储器的哪一部分。然后,必须定义跟踪堆栈顶当前位置的数据存储器指针(DP[0]、DP[1]或者BP[Offs])。注意:应用软件不会出于其他目的使用堆栈专用数据存储器(例如,变量或者缓冲)。

定义并初始化这类软堆栈的一种简单方法涉及到BP[Offs]寄存器对和一个公式。

SS_BASE  equ  0100h

ss_init:
   move    DPC,  #1Ch        ; Set all pointers to word mode   
   move    BP,   #SS_BASE    ; Set base pointer to stack base location
   move    Offs, #0          ; Set stack to start
   ret

如果基指针(BP)寄存器被设置在SS_BASE位置,那么,可以采用Offs寄存器指向堆栈的当前顶部。由于Offs寄存器只有8位宽,硬件会自动把堆栈限制在数据存储器的范围内(BP .. (BP+255))。如果当Offs等于255 (上溢)时出现推入,或者Offs等于0 (下溢)时出现弹出,那么,Offs寄存器只会限制在堆栈的另一端。这一行为模仿硬堆栈工作方式,支持简单的软堆栈实现;它不探测下溢和上溢状态。

在使用软堆栈前,主程序必须调用ss_init例程。它将BP[Offs]指针设置为字模式,由于软堆栈以16位宽堆栈实现,因此,必须完成这一步。它还将BP[Offs]寄存器对指向堆栈开始。

软堆栈工作

不能重新定义使用堆栈的内置操作代码(PUSH、POP、CALL、RET等)以使用软堆栈,这是因为这些代码意味着MAXQ汇编器的硬线连接。而且,还有可能需要在应用程序中的某些部分使用标准硬堆栈,例如,中断服务例程等。出于这些原因,由复制标准操作代码的宏来访问软堆栈。

mpush  MACRO  Reg
   move    @BP[++Offs], Reg  ; Push value to soft stack
endm

mpop   MACRO  Reg
   move    Reg, @BP[Offs--]  ; Pop value from soft stack
endm

mcall  MACRO  Addr
LOCAL  return
   move    @BP[++Offs], #return   ; Push return destination to soft stack
   jump    Addr
return:
endm

mret   MACRO
   jump    @BP[Offs--]       ; Jump to popped destination from soft stack
endm

下面将讨论这些宏是怎样工作的。

mpush

该宏的使用方式和PUSH操作代码相同。它支持将8位或者16位寄存器,或者将立即值推入堆栈。

 mpush   A[0]              ; Save the value of the A[0] register
   mpush   A[1]              ; Save A[1]
   mpush   A[2]              ; Save A[2]

   ...                       ; code which destroys A[0]-A[2]

   mpop    A[2]              ; Restore the value of A[2] (pop in reverse order)
   mpop    A[1]              ; Restore A[1]
   mpop    A[0]              ; Restore A[0]

mpop

该宏的使用方式和POP操作代码相同。它支持从堆栈中装入8位或者16位寄存器,如上所示。注意,如果推入了一个16位值,该值弹入到一个8位寄存器中,那么,只有低位字节被存储在寄存器中。高位字节丢失。这与内置硬堆栈的方式一致。

subroutine:
   mpush   A[0]              ; Save the current value of A[0]
   
   ...                       ; Code which destroys A[0]

   mpop    A[1]              ; Restore A[0]
   mret

mcall
mret

mcall宏的使用方式和CALL操作代码执行子程序相同。一旦执行完成,子程序必须使用mret宏(而不是标准RET操作代码)才能返回。

 mcall   mySub

   ...

mySub:
   mpush   A[0]              ; Save A[0]
   mpush   A[1]              ; Save A[1]
   ...                       ; Perform calculations, etc.
   mpop    A[1]
   mpop    A[0]
   mret

扩展软堆栈的大小

某些应用程序需要大于256级的软堆栈。使用其他数据指针(DP[0]或者DP[1])之一可以实现任意大小的堆栈(最大达到数据存储器的上限)。

SS_BASE  equ  0000h
SS_TOP   equ  01FFh

ss_init:
   move    DPC,   #1Ch       ; Set all data pointers to word mode
   move    DP[0], #SS_BASE   ; Set pointer to stack base location
   ret

上面的代码存储在数据存储器的0000h至01FFh,因此,产生的堆栈可以保持511级。(没有使用堆栈存储器空间中的某一位置;这样可以更有效,以更短的代码实现

只改变数据指针,而代码中的其他部分保持不变可以扩展堆栈。虽然如此,由于DP[0]并没有限制在数据存储器的一定范围内,因此,没有措施来防止推入或者弹出操作使DP[0]增加或者减小导致超出所指定的软堆栈边界。为避免这一点,可以加入简单的下溢/上溢检查。

加入下溢和上溢检查

为保持宏(每次使用时扩展为代码)尽量短,在子程序中完成下溢和上溢检查,使用硬堆栈,由宏调用子程序。

mpush  MACRO  Reg
   call    ss_check_over     ; Check for possible overflow
   move    @++DP[0], Reg     ; Push value to soft stack
endm

mpop   MACRO  Reg
   call    ss_check_under    ; Check for possible underflow
   move    Reg, @DP[0]--     ; Pop value from soft stack
endm

mcall  MACRO  Addr
LOCAL  return
   call    ss_check_over     ; Check for possible overflow
   move    @++DP[0], #return ; Push return destination to soft stack
   jump    Addr
return:
endm

mret   MACRO
   call    ss_check_under    ; Check for possible underflow
   jump    @DP[0]--          ; Jump to popped destination from soft stack
endm

ss_check_under:
   push    A[0]
   push    AP
   push    APC
   push    PSF   

   move    APC, #80h         ; Set Acc to A[0], standard mode, no auto inc/dec
   move    Acc, DP[0]        ; Get current value of stack pointer
   cmp     #SS_BASE
   jump    NE, ss_check_under_ok
   nop                       ; < Error handler should be implemented here >
ss_check_under_ok:
   pop     PSF
   pop     APC
   pop     AP
   pop     A[0]
   ret

ss_check_over:
   push    A[0]
   push    AP
   push    APC
   push    PSF   

   move    APC, #80h         ; Set Acc to A[0], standard mode, no auto inc/dec
   move    Acc, DP[0]        ; Get current value of stack pointer
   cmp     #SS_TOP
   jump    NE, ss_check_over_ok
   nop                       ; < Error handler should be implemented here >
ss_check_over_ok:
   pop     PSF
   pop     APC
   pop     AP
   pop     A[0]
   ret

上面的代码导致在推入或者弹出(或者call,或者ret)操作之前检查当前的堆栈位置。如果探测到下溢或者上溢错误,不同的应用程序有不同的响应。一般情况下,这类错误只会出现在应用程序开发阶段;如果代码编写正确,不会出现这类错误。如果的确出现了错误,一般将其考虑为重大错误,就像使用硬堆栈时出现下溢/上溢错误。对这类错误可能的响应包括暂停,发送错误消息,或者闪烁LED。在开发阶段,一个好的方法是两个程序中的每一个都在MAX-IDE中设置断点(例如,在“Error handler should be implemented here”行中),如果出现下溢或者上溢,立即发出反馈。

但是,应用程序有时候也可以从堆栈下溢或者上溢中恢复(例如,重新装入和从头重新启动应用程序子任务)。在这种情况下,需要简单地设置一个标志,指示出现了堆栈错误。可选的这类标志包括位于PSF寄存器中的两个通用标志(GPF0和GPF1)。由于有两个位标志,因此,其中一个可以用于指示上溢,另一个用于指示下溢。

结论

MAX-IDE强大的宏预处理功能实现了MAXQ2000以及其他MAXQ20微控制器数据存储器软堆栈的直接替换。这一软堆栈使子程序更加模块化,可重复使用,有助于大规模汇编应用程序的开发。堆栈还支持堆栈错误的探测。

审核编辑:郭婷

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 微控制器
    +关注

    关注

    48

    文章

    6811

    浏览量

    147646
  • 存储器
    +关注

    关注

    38

    文章

    7151

    浏览量

    161998
收藏 人收藏

    评论

    相关推荐

    MAXQ2000 SPI模块与MAX6951/MAX6950怎么配合使用?

    本应用笔记提供了MAXQ®汇编程序范例,说明MAXQ2000 SPI模块与MAX6951/MAX6950的配合使用。
    发表于 05-31 06:08

    MAXQ2000微控制与MAX4397是如何连接的?

    MAX4397是什么?MAXQ2000微控制与MAX4397是如何连接的?
    发表于 06-04 06:15

    使用MAXQ2000评估板的应用实例

    摘要:本文介绍了利用MAXQ系列微控制器开发一个产品的具体技术。MAXQ2000评估板被用来开发一个特殊处理器外设,给出了LCD控制、SPI通信、通过串口传输数据、定时器使用和响应中
    发表于 04-23 17:33 34次下载

    采用MAXQ2000进行音频滤波

    集成了乘累加单元(MAC)和单周期内核的MAXQ2000非常适合用作通用微控制器。MAXQ2000所具有的性能和I/O外设适合多种应用:如闹钟、手持医疗设备、数字读取器等需要低功耗、高性能
    发表于 12-25 23:24 34次下载

    MAXQ2000 业内最高MIPS/mA的16位、RISC微

    MAXQ2000 业内最高MIPS/mA的16位、RISC微控制器、低功耗LCD微控制器 MAXQ2000 概述
    发表于 02-06 13:35 665次阅读

    MAXQ2000数据存储器实现堆栈

    摘要:本应用笔记介绍了汇编应用中在数据存储器实现堆栈的简单方法。该方法使用了MAXQ2000和其他基于
    发表于 04-23 16:04 900次阅读

    利用MAXQ2000设计电压表

    摘要:本应用笔记演示了如何配置MAXQ2000微控制器实现简单的电压表设计。该应用采用MAXQ2000评估板,其中包括4½位段式LCD显示器和MAX1407数据采集系统(
    发表于 04-23 16:07 784次阅读
    利用<b class='flag-5'>MAXQ2000</b>设计电压表

    利用SD存储介质扩展MAXQ2000的非易失性数据存储空间

    摘要:本文讨论如何使用安全数字(SD)媒体格式扩展MAXQ2000的非易失数据存储器。 低功耗、低噪声的MAXQ2000微控制器适合于多种应用。MA
    发表于 04-23 16:25 1095次阅读
    利用SD<b class='flag-5'>存储</b>介质扩展<b class='flag-5'>MAXQ2000</b>的非易失性<b class='flag-5'>数据</b><b class='flag-5'>存储</b>空间

    采用MAXQ2000进行音频滤波

    摘要:集成了乘累加单元(MAC)和单周期内核的MAXQ2000非常适合用作通用微控制器(µC) 。MAXQ2000所具有的性能和I/O外设适合多种应用:如闹钟、手持医疗设备、数字读取器等需要低功
    发表于 04-23 17:27 904次阅读
    采用<b class='flag-5'>MAXQ2000</b>进行音频滤波

    采用MAXQ2000实现与MAX1169的高速I²C接口

    本应用笔记使用了MAX1169评估(EV)板和MAXQ2000评估板。MAX1169评估板包含MAX1169、所需的全部无源器件以及经过验证的PCB布板。评估板电路如图1所示。MAX1169评估
    发表于 04-06 15:34 5次下载
    采用<b class='flag-5'>MAXQ2000</b><b class='flag-5'>实现</b>与MAX1169的高速I²C接口

    利用SD存储介质扩展MAXQ2000数据存储空间

    本文讨论如何使用安全数字(SD)媒体格式打“展MAXQ2000的非易失数据存储器
    发表于 04-08 09:59 4次下载

    MAXQ2000数据存储器实现堆栈

    本应用笔记演示了一种在数据存储器实现堆栈的简单方法,用于基于汇编的应用。该方法使用MAXQ2000和其他基于
    的头像 发表于 01-11 11:20 483次阅读

    使用MAXQ2000进行音频滤波

    乘法累加单元(MAC)和单周期内核的组合使MAXQ2000成为多功能微控制器(μC)。MAXQ2000具有性能和I/O外设,非常适合许多应用:闹钟、手持医疗设备、数字读数——任何需要低功耗、高性能和大量I/O的应用。通过集成MAC,MA
    的头像 发表于 03-02 14:13 589次阅读
    使用<b class='flag-5'>MAXQ2000</b>进行音频滤波

    使用MAXQ2000微控制器进行基于温度的风扇控制

    用笔记描述了如何使用MAXQ2000驱动风扇,并通过PWM实时改变风扇速度。该过程需要使用Maxim的另一种产品,即MAX1407多通道数据采集系统(DAS)。利用SPI,MAXQ2000可以
    的头像 发表于 03-02 14:36 703次阅读
    使用<b class='flag-5'>MAXQ2000</b>微控制器进行基于温度的风扇控制

    如何将MAXQ2000用作电压表

    本应用笔记演示如何为简单的电压表应用配置MAXQ2000微控制器。应用使用MAXQ2000评估板,该评估板包括一个4/1407段LCD显示屏和一个MAX2000数据采集系统(DAS),
    的头像 发表于 03-03 14:27 549次阅读
    如何将<b class='flag-5'>MAXQ2000</b>用作电压表