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

华强商城公众号

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

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

华强商城M站

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

半导体行业观察第一站!

芯八哥公众号

半导体行业观察第一站!

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

华强微电子公众号

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

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

华强电子网公众号

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

讨论超越达拉斯半导体高速微控制器64kB限制的内存扩展概念

来源:analog 发布时间:2023-11-13

摘要: 本应用笔记检查高速微控制器片上存储器能力之外的存储器扩展的使用。在64kB内存映射之外检查银行切换。本文重点讨论了ROMless程序扩展、简单页面扩展和银行切换定时。添加了程序示例来澄清这些信息。

高速微控制器家族的所有成员都设计为直接处理高达64kB的程序和数据存储器。但是,有时候,应用程序需要的内存比芯片上可用的内存或通过使用64kB内存映射所需的内存更多。高速微控制器系列包括许多功能,使其易于处理大于64kb的程序和/或数据内存。位可寻址I/O端口允许单指令修改控制线,可用于银行切换或多个存储设备之间的页面。ROMSIZE功能可以方便地为带有片上存储器的设备调整内存大小。

本应用笔记讨论了程序和数据存储器的扩展。它被细分为三个主要类别:扩展非rom设备的程序内存超过64kB,使用ROMSIZE特性将片上程序内存扩展到或超过64kB,以及扩展数据内存。首先介绍银行交换和软件支持技术。

银行转换理论

超过64kB的扩展内存访问最常通过银行交换完成。这种技术使用一条或多条通用I/O线作为解码线来寻址更多的内存。如果使用单个大容量存储设备,则可以直接使用附加信号作为地址线。如果使用几个较小容量的存储设备,信号可以用作芯片选择。由解码逻辑切换的基本存储单元称为库或页。例如,如果使用I/O线在两个64kB eprom之间切换,则内存将由两个64kB页组成。

使用分页内存方案的最大障碍可能是中断向量表的位置。在大多数设备操作期间,软件可以在页面之间执行有序的切换。然而,当中断发生时,设备将立即跳转到适当的矢量地址,低于0070h。此时软件无法控制库配置,设备将尝试跳到当前库的低端寻找向量表。

有两种方法可以解决这个问题。最简单的方法是在每个页面的低端复制中断向量表。这样,中断向量表在任何时候都是可用的,而不管当前的内存配置如何。然而,这种方法也有一些缺点。由于中断向量表(大约120字节)和中断服务例程通常必须在每个页面上复制,因此对程序内存的使用效率很低。此外,一些编译器不直接支持跨页的数据复制,这使程序生成变得复杂。一种更有效的方法是保留一些较低的内存部分,其中包括中断向量表,这样它就不会被分页。这个“公共区域”可以直接从任何扩大的银行获得,而无需修改银行选择机制。每当处理器在该公共区域执行代码读取时,无论当前页面如何,硬件都会强制内存访问该区域。精心的设计会让之前的银行地址被保存下来,这样设备在公共存储器中的操作完成后会自动返回。中断服务程序的执行时间可以通过将它们与中断向量表一起放置在位于内存低端的公共区域中来减少。本应用笔记中的大多数示例将内存的较低区域指定为公共区域。

内存扩展的软件支持

要使分页内存方案工作,有必要将代码分割成页,并为软件提供在页之间切换的方法。在切换页面时必须小心,以免干扰指令流。主要有两种方法。第一种是“在飞行中”切换页面。下面的简单页面扩展示例演示了这一点。这种方法导致程序执行直接从一个展开页跳转到另一个展开页。必须谨慎操作,以使银行切换发生在与下一个银行的下一个指令开始对应的位置。如果不能正确对齐指令,可能会导致下一个操作码读取发生在多字节指令的中间,从而导致完全失去程序控制。

更好的方法是从不受更改影响的位置更改银行。这通常是内存中常见的或未分页的位置,例如中断向量表所在的保留位置。对低级内存的任何访问都由硬件自动切换到公共内存。这消除了上面简单的页扩展所带来的代码对齐困难,并且需要在每个内存页上复制中断向量和/或中断服务例程。

许多编译器和链接器直接支持银行切换,其中许多还包括用于页面切换的库函数。编译器附带的文档将提供有关其扩展内存支持的信息。下面的一些示例后面列出了汇编语言支持的简要示例。

如果将多个页面编程到单个EPROM中,则必须非常小心。许多EPROM程序员使用文件中指定的地址来计算程序偏移量,这可能导致代码错位。例如,假设分页方案涉及从8000h到FFFFh映射到程序空间的代码页。如果设计人员希望在EPROM中定位10000h的页面,他或她通常会在EPROM中选择10000h的偏移量,当将文件放入程序中时。十六进制文件中的所有地址都从8000h开始,但是,设备程序员会将其添加到10000h。这将不经意地将页面置于18000h,这不是预期的结果。各种设备编程器以不同的方式实现偏移,建议设计人员查阅设备编程器附带的文档以获得最佳解决方案。

无rom程序扩展

由于没有片上程序存储器,使得扩展DS80C320的程序存储器相对简单。本文介绍了三种扩展程序内存的方法。第一种方法是通过复制向量表和重叠页面来扩展相对较小的内存。第二个示例使用一个公共库来存储中断向量和中断服务例程,并使用几个通用I/O线来分页内存。最后一个示例使用一个锁存地址来寻址大量内存,而不使用额外的通用I/O行。


简单的页面扩展


这个例子展示了添加相对少量程序内存的最简单方法。单个通用I/O线用于提供高达128kB的程序内存。使用单个27C010 128k字节EPROM,并分为两个重叠的存储块。一条通用I/O线,在本例中是P1.0,用于提供银行开关控制。它由74F74锁存,时钟位于/PSEN\信号的上升沿上。这使银行交换机与内存周期同步。这种方法可以通过使用额外的I/O线来增加更多的内存。此示例的硬件配置如图1所示。


图1所示 简单的页面扩展硬件示例

然而,硬件的简单是以牺牲软件的复杂性为代价的。这个例子使用了两个银行,它们都在内存的较低部分包含中断向量表。这是必要的,因为当设备复位时,P1.0将很高,迫使复位向量地址为10000h。另外,在执行任一页的代码时可能会发生中断,因此中断向量必须在没有软件干预的情况下可用。中断向量表从位置00000h到00070h和10000h到10070h消耗大约115字节。如果需要在每个页面上重复中断服务例程,则可能需要额外的空间。


图2 简单的页面扩展示例内存映射。

当页面切换保持在最低限度时,即直接执行代码时,这种方法是最有效的。如果中断例程(不仅仅是向量)足够小,可以在每个页面上复制,那么代码效率将得到提高。使用MOVC指令访问的数据表或字符串应该位于与该指令相同的页面上。

这种方法直接修改页面而不修改程序计数器。这意味着新页面中的起始位置将与新页面中的银行切换例程结束时的位置相同。因此,页之间的指令位置是至关重要的。图3显示了MOV P1, a指令与银行选择信号的时序关系。在本例中,MOV指令位于位置5A10h,新页面上的第一条指令位于位置5A14h。

控制银行选择的端口引脚将在遵循MOV指令的第一个周期中改变。在执行第二个NOP期间,74F74锁存器使新的银行选择在预取时有效。新页面上的第一条指令必须位于第二个NOP后面的地址。

还有其他修改端口引脚的方法,该方案将适用于MOV direct、direct等2周期指令和SETB bit等1周期指令。银行切换指令只有两个要求。新页面上的第一条指令必须位于第二个NOP后面的地址。同时,执行MOV指令的指令不能是MOVX。由于拉伸周期的原因,MOVX指令的时间是可变的,并且可能会干扰指令流。


图3 银行切换时序图。

使用I/O进行公共页面扩展


下面的两个例子使用公共块方法来处理中断向量放置的问题。这允许更快的中断服务时间,并简化代码构造。这两个示例都采用了16页的分页方案,每个页面大小为32kB。第0页,在0000h映射到7FFFh,是公共区域,包含中断向量表和中断服务例程。地址行A15决定是公共块还是15个扩展页中的一个被寻址。

这个示例展示了如何使用端口1或3上的通用I/0线作为银行切换控件来寻址最多512kB的ROM。Bank 0是一个从0到7FFFh的32kB页面。这个公共区域将包含中断向量和常用的子程序。扩展内存将包含在15个32kB的页面中,从8000h映射到FFFFh。银行控制由4个通用I/O引脚提供。内存映射显示在图4。


图4 公共页扩展内存示例内存映射。

硬件配置如图5所示。银行控制由P1.0-3提供,由4个AND门解码,只需要一个IC封装。当A15较低时,设备被迫只访问较低的32kB内存。当访问低内存中的中断向量表时,这消除了软件干预的需要。本例使用27C040 512KB EPROM。


图5 DS80C320扩展内存硬件配置示例。

下面的软件示例展示了一个汇编语言例程,它使用图5所示的I/O行跳转到任何银行中的新位置。在调用银行交换机子程序之前,软件将新的地址和银行号码推入堆栈。然后,它调用一个子例程,从堆栈中弹出新的银行地址并将其放在P1.0-3上。然后修改堆栈,以便后续的RET指令返回到新的程序位置。这是在汇编代码中实现银行切换的许多可能方法之一的简单演示。


程序示例:使用I/O在银行之间跳转


;********************************************************************************; 程序BANKJMP1.ASM;;这个程序演示了一个可能的方式在一个共同的银行间跳——;页面内存扩展配置使用I / O。在P1.0-3的四个通用I/O引脚用于控制外部银行的选择,软件将新银行中的地址以及新银行地址推入堆栈。位于非分页地址的子例程BANKJUMP修改页面选择,然后将堆栈指针重新定位到先前压入堆栈的新地址。然后执行RET,从新页面中的新地址恢复操作。注意;BANKJUMP可以调用程序内存的任何领域 .;********************************************************************************; 0 f0h;等同tableBANKMASK装备P1.3-0用于银行的选择。子程序NEWSUB位于页面03h。NEWSUB equ 0F000h;子程序NEWSUB的地址。如果使用;编译器,它可以自动提供这个;;cseg at 0;复位向量。Start: MOV P1, #0F0h;默认为bank 0。MOV A, #low NEWSUB; NEWSUB地址的低字节。PUSH A mov A, #high NEWSUB; NEWSUB地址的高字节。PUSH A mov A, #NEWSUB_BANK;PUSH a ljmp BANKJUMP;调用子程序切换操作到新银行。这将转移执行;在银行NEWSUB_BANK NEWSUB位置 .;********************************************************************************; BANKJUMP——这个子程序把新和页面跳转地址从堆栈中。先修改P1.0-3,再修改堆栈指针为point;到新地址。然后返回到新的跳转位置。这个子程序必须放在一个常见,unpaged内存区域 .;******************************************************************************** BANKJUMP: CLR EA,禁用所有中断。从堆栈anl P1, #BANKMASK中获取新的页面地址,并仅将P1.0-3修改为新的银行orl P1, A;地址。重新启用中断。栈指针现在位于新的返回地址。程序将从新的银行开始执行。


使用锁存数据进行公共页面扩展


上述设计的一个缺点是它需要I/O线作为银行控制。一些I/O密集型应用程序可能无法为银行交换预留端口引脚。下面的示例使用Lattice Semiconductor GAL26V12可编程逻辑器件(PLD)来锁存银行选择信号,而不是使用专用I/O引脚。这种方法使用与前面示例相同的内存映射,唯一的例外是从FFE0h到FFFFh的数据内存不可访问。这32个字节是不可访问的,因为A5到A0没有解码,允许使用更小,成本更低的PLD。解码更多的地址行可以减少不可访问的数据内存,但需要更复杂的解码机制。

GAL26V12执行基于写入MOVX数据存储器的银行切换功能。从FFE0h到FFFFh对数据内存的任何写入都会被解码,并且写入该地址的数据的较低四位用于配置银行交换机选择线路。硬件配置如图6所示。

PLD的源文件如下图所示。它扫描选定范围内的任何地址,并将数据的较低部分锁存到存储设备的A15-A18上。80000h之间的寻址位置将暂时清除银行选择行,迫使EPROM从银行0 (0000h-7FFFh)读取。一旦下存储器操作完成,对存储器上半部分(8000h-FFFFh)的访问将自动返回到前一个银行,因为银行地址仍然锁存在PLD的注册输出中。

尽管各种各样的pld都适用于这种应用,但任何使用的设备都必须在上电时将其输出重置为0。这是必要的,因为在上电后,设备必须能够访问位于银行0 0000h的复位矢量。在选择PLD时,设计人员应该意识到许多标准的可编程逻辑器件被设计成在复位时输出高电平。


图6 DS80C320锁存地址存储器硬件示例。

下面的软件示例展示了一个汇编语言例程,该例程使用图6所示的锁存数据跳转到任何银行中的新位置。在调用银行交换机子程序之前,软件将新的地址和银行号码推入堆栈。然后,它调用一个子例程,从堆栈中弹出新的银行地址,并将其写入位置FFFFh,并将其作为新的银行地址锁存。然后修改堆栈,以便后续的RET指令返回到新的程序位置。


程序示例:使用锁存寻址在银行间跳转


这个程序演示了使用锁存寻址在公共页内存扩展配置中跳转银行的一种可能方法;软件将新银行地址以及新银行地址推入堆栈。位于非分页地址的子例程BANKJUMP修改页面选择,然后将堆栈指针重新定位到先前压入堆栈的新地址。然后执行RET,从新页面中的新地址恢复操作。注意;BANKJUMP可以调用程序内存的任何领域 .;***************************************************************************; 等同0 ffffh; tableLATCH_ADR装备的地址,银行选择门闩。子程序NEWSUB位于页面03h。NEWSUB equ 0F000h;子程序NEWSUB的地址。如果编译器是;使用时,它可以自动提供此复位向量。Start: MOV A, #low NEWSUB; NEWSUB地址的低字节。PUSH A mov A, #high NEWSUB; NEWSUB地址的高字节。PUSH A mov A, #NEWSUB_BANK;调用子程序切换操作;新银行 .;***************************************************************************; BANKJUMP——这个子程序把新和页面跳转地址从堆栈中。它将新的页面地址写入PLD,在PLD上锁存;作为新的页面地址。然后,RET对该地址执行;在调用此例程的函数中指定。这个子程序;必须放置在一个常见,unpaged内存区域 .;*************************************************************************** BANKJUMP: CLR EA,禁用所有中断。;指向页面地址。从堆栈中获取新的页地址。将页地址输出到锁存器。恢复中断。栈指针现在在new return;地址。程序将开始执行;新银行的。


本文给出了GAL26V12 PLD的源文件,以帮助设计人员开发自己的器件。该文件是用CUPL语言编写的,但是可以很容易地修改以与其他汇编程序一起工作。


程序示例:GAL程序文件


g26v12 MEM_EXP名称;设备 ;/********************************************************************//** 这个政法大学文件将程序GAL26V16作为银行* * / / * *锁切换到512 kb的程序内存地址。任何写到地址FFE0h到FFFFh的**//** MOVX将锁定D0 - D3 **//**作为新的银行选择。**//** **//**任何对程序内存中0000h到7FFFh的访问都将清除**//**银行选择行,仅用于该操作。这允许**//**设备在没有干预的情况下跳转到中断向量,并且**//**完成后返回到同一银行。**//********************************************************************//*/** 销的定义:这些定义了28销PLCC和浸* * / / * *输入插脚* * /销1 = CLKIN;GAL锁存器的时钟输入。引脚2 = a15;用于地址解码的微控制器地址行。销子3 = a14;销子4 = a13;销子5 = a12;销子6 = a11;销子8 = a10;销子9 = a9;销子10 = a8;销子11 = a7;销子12 = a6;销子13 = a5;销子14 = d3;微控制器数据线设置银行选择。引脚15 = d2;引脚16 = d1;引脚17 = d0;单片机写频闪/**输出引脚**/引脚20 = CLKOUT;合格的单片机写频闪。它被喂食;返回到gal26v12 CLK输入。这一切;信号必须分配到引脚20或22,因为;它需要12个乘积项。引脚18 = a18_latch;A18内存信号的临时锁存。引脚19 = a17_latch;A17内存信号的临时锁存。引脚22 = a16_latch;A16内存信号的临时锁存。引脚23 = a15_latch;A15内存信号的临时锁存。引脚24 = memadr_18;输出到存储器器件引脚A18。引脚25 = memadr_17;输出到存储器器件引脚A17。引脚26 = memadr_16;输出到存储器器件引脚A16。引脚27 = memadr_15;输出到存储器器件引脚A15;引脚7 = VCC;引脚21= GND/**合格写频闪检测有效的银行锁存器写。**/BANK_SEL = A15 &阿,首次购物,A12,A11,A10,A9,A8,A7和A6,A5CLKOUT = ! wr_频闪&Bank_sel /** bank select 0 generation **/ a15_latch。D = d0a15_latch。OEMUX = 0;禁止该信号的外部表达。Memadr_15 = a15_latch。问,A15/** bank选择1代**/ a16_latch。D = d1a16_latch。OEMUX = 0;禁止该信号的外部表达。Memadr_16 = a16_latch。问,A15/** bank选择2代**/ a17_latch。D = d2a17_latch。OEMUX = 0;禁止该信号的外部表达。Memadr_17 = a17_latch。问,A15/** bank选择3代**/ a18_latch。D = d3a18_latch。OEMUX = 0;禁止该信号的外部表达。Memadr_18 = a18_latch。问,A15

使用ROMSIZE特性

ROMSIZE特性允许软件动态地重新配置程序内存大小,允许程序内存的一部分在片内和片外之间切换。它提供了一种简单的方法将程序内存增加到64kB加上片上内存。此外,它简化了为外部可编程存储器(如FLASH、EEPROM或非易失性SRAM (NV SRAM))构建引导加载程序的任务。

使用ROMSIZE特性非常简单。位RMS2, RMS1, RMS0 (ROMSIZE.2-0)选择片上存储器的最大容量。ROMSIZE选择位是定时访问保护,以确保最大的软件可靠性。在ROMSIZE寄存器定义的范围之外的任何程序内存访问将自动通过端口0和2从外部获取。在具有ROMSIZE功能的设备上执行外部代码读取的方式与在高速微控制器系列的所有成员上执行的方式相同。设计者被提醒,如果端口0和2将被用于外部存储器访问,它们不应该被用作通用I/O端口。

在跳转到新的地址范围之前,对ROMSIZE寄存器的修改必须伴随着2个机器周期的延迟,例如执行2个NOP指令。在此操作期间必须禁用中断,因为在更改内存映射期间跳转到中断向量可能导致不稳定的结果。重新配置片上内存量的步骤如下:

  1. 跳转到程序内存中不受更改影响的位置

  2. 通过清除EA位(IE.7)禁用中断

  3. 将ah写入定时访问寄存器(TA;C7h)

  4. 将55h写入定时存取寄存器(TA;C7h)

  5. 修改ROM大小选择位(RMS2-0)

  6. 延迟2个机器周期(2个NOP指令)

  7. 通过设置EA位(IE.7)使能中断


在使用ROMSIZE特性在片内和片外内存之间切换时,有许多软件方面的考虑。ROM大小选择寄存器的修改必须从程序存储器位置进行,该位置将在片上存储器配置之前和之后都有效。在汇编或编译程序时必须小心,以便所有模块都位于正确的起始地址,包括中断向量表。

如果选择了0kB片上内存选项,则必须采取额外的预防措施。当将较低1kB的程序存储器从片内切换到片外时,有必要在片外存储器中复制中断向量表。通常,应用程序会发现将片上内存减少到不小于1kB是最有用的。这将最大化可寻址的外部存储器范围,同时保持芯片上的中断向量。当片上内存仅用作引导加载程序时,0kB选项最有用。

使用ROMSIZE特性扩展内存超过64kB

使用ROMSIZE特性对超过64kB的外部内存进行寻址的方法类似于无ROMless方法。主要区别在于ROMSIZE特性允许设计者使用片上程序存储器作为“公共”块。这简化了外部硬件的构造,因为不需要解码公共块存储信号(示例中的A15信号)。

利用ROMSIZE特性进行设计的关键是将片上内存以最有效的内存利用率和最简单的解码方法整合到内存映射中。有许多方法可以解决这个问题,但这里只介绍一种。本例使用16kB片上内存,加上位于27C040 512kB EPROM中的8个48kB扩展内存页。这提供了400kB的总程序内存。中断向量和服务例程包含在片上存储器中,以便快速访问。

图7显示了包含16kB片上EPROM的DS87C520使用的一种可能的内存映射。注意,每个外部页上从0000h到3FFFh的程序内存没有被使用。这大大简化了存储器解码的设计,不需要外部逻辑,也少了一条I/O线。图8显示了如何使用三条I/O线直接解码设备的上地址行。用于此配置的软件类似于前面示例中提供的软件。

也可以将ROMSIZE功能与MOVX总线上的锁定银行地址结合使用。与无ROMless示例类似,这种方法不需要用于银行切换的专用I/O引脚。由于片上程序存储器的使用允许更简单的解码电路,因此可以使用更便宜的pld。


图7 ROMSIZE公用页扩展内存映射。


图8 ROMSIZE common-page I/O扩展功能。

扩展微控制器使用的数据内存的数量是内存扩展的最简单形式。因为不存在干扰程序执行的可能性,所以时间就不那么重要了。通用I/O线可以直接连接到地址线或内存设备的芯片上。在内存操作之前,可以直接修改适当的端口引脚以访问正确的页面。如果应用程序需要所有可用的I/O行,那么可以使用上面示例中演示的锁存银行地址方案。



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

社群二维码

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

调查问卷

请问您是:

您希望看到什么内容: