C8051F12X中多bank的分区跳转处理

发布者:chi32最新更新时间:2007-12-04 来源: 单片机及嵌入式系统应用关键字:地址  调用  变量  寄存 手机看文章 扫描二维码
随时随地手机看文章
在8051核单片机庞大的家族中,C8051F系列作为其中的后起之秀,是目前功能最全、速度最快的8051衍生单片机之一,正得到越来越广泛的应用。它集成了嵌入式系统的许多先进技术,有丰富的模拟和数字资源.是一个完全意义上的SoC产品。

C805IFl2X作为该系列中的高端部分,具有最快100MIPS的峰值速度,集成了最多的片上资源。其128 KB的片上Flash和8 KB的片上RAM足以满足绝大多数应用的需求。使用C8051F12X,只需外加为数不多的驱动和接口,就可构成较大型的完整系统。只是其中128 KB的Flash存储器不可避免地要处理bank分区问题。

幸运的是Keil C51开发环境对C8051F系列有良好的支持,包括一般的跨bank分区的程序跳转和调用。作为数据存储器使用时,Flash的分区读写完全是编程者要考虑的事情,与开发环境无关。本文只针对特殊的强制转移和μC/OS—II在多bank分区中的移植问题展开讨论。

1 C8051F12X在Keil C51中的多bank分区转移机制

Keil C51的连接定位器支持分组连接,允许生成代码长度大于64 KB的8051目标程序_1_。一般的8051系统只提供16根地址线,需要附加地址线来实现代码分组切换,而编译器产生bank切换代码时受到配置文件L51_BANK.A51的支持,所以用户必须根据自己的硬件结构来修改这个配置文件。

C8051F12X系列不用考虑硬件部分,也不存在地址线的扩展问题,因为128 KB的4个bank区全部都在CPU内部,所以作为常规跨bank的跳转和调用,不需要处理1.5l_BANK.A51配置文件。但在特殊情况下就必须考虑该问题,否则程序将无法工作。下面以C8051F120为例先讨论代码的透明分组切换过程。

C805IFl20在Keil C51的项目配置中被划分为4个bank,每个32 KB。公共bank地址从0~0x7fff,其余bank从0x8000h~0xffff。在对应的配置文件L51_BANK.A51中,涉及到特殊功能寄存器PSBANK(SFR地址:0B1H)、SWITCHn宏、B_BANKn、B_SWITCHn分组信息保存和切换代码,以及B_CURENTBANK变量。

PSBANK为C8051F120内的特殊功能寄存器,128KB Flash的分bank访问就是通过它来实现的。要想转移到新的bank中去,必须赋予PSBANK正确的值,然后再转向bank区内地址即可。

SWITCHn宏共有4个,分别是SwITCH0、SWlTCH1、SWITCH2和SWITCH3,对应切换到4个bank中。其中SWITCH0对应的语句为:

MOV PSBANK.#00h ;把00h用1Ih、22h和33h替换,

;就是其他三个宏

它将插入到B_SWITCHn代码中,用来切换新的bank和恢复到原来的bank。

所有4组B_BANKn和B_SWlTCHn代码也都是用宏实现的,对应4个bank处理。它们汇集在BANK SWITCH代码段中,整个bank切换及恢复机制非常巧妙,可以实现任意bank之间函数的相互调用及嵌套。下面以bank3区中的main函数调用bankl区的Delay_noOS()延时函数为例说明该机制。

  void main(void){
MCUInit(); //初始化CPU
Delay_n00s(10); //延时lO ms
Lcmlnition();

  bank3中被调用的函数Delay_noOS(10)对应的汇编语句为:

  LCALL C:5049

  公共段(即Common段,对应bank0)中C:5049处的汇编语句如下:

  MOV dptr,#Delay_noOS

  AJMP B_BANKl

这里的B_BANKl就是宏B_BANK&N中N为1的例程。现在进入问题的核心:全部的跨bank区程序切换及恢复过程依靠公共段中BANK SWITCH代码段里的以下汇编代码实现,对应的N为0、1、2和3。BANK SWlTCH SEGMENT CODE PAGE

  ;
B_BANK&N:
PUSH B_CURRENTBANK (1)
MOV A,#HIGH BANK SWITCH (2)
PUSH ACC (3)
PUSH DPL (4)
PUSH DPH (5)
B_SWITCH&N:
MOV B_CURRENTBANK,#LOW B_SWITCH&N
(6)
SWlTCH&N (7)
RET (8)

Delay_noOS(10)函数的返回地址,即函数LcmIni-tion()的入口地址(也在bank3中),其高低位字节表示为ADDH和ADDL。程序进入main()后的B_CURRENTBANK变量初值是B_SWITCH3的低8位,其意义稍后叙述。AJMP B_BANKl后程序执行?B_BANKl和?B_SWITCHl的(1)~(8),执行到(5)时的堆栈结构如图1所示。

继续执行B_SWITCHl到(7)时,PSBANK变为指向bankl,B_CURRENTBANK变为B_SWITCHl的低8位。执行(8)后,从堆栈结构可以看出,堆栈弹出①作为新的PC值,程序进入Delay_noOS(10)函数,延时功能完成后,函数最后一条RET指令开始返回。这是Keil C51处理bank机制的关键,此时的返回地址为堆栈中的②,此地址即B_SWITCH&H代码的入口,这里对应main()函数所在的bank3分组,也就是B_SWITCH3的人口。

因为所有B_SWITCH&N的高8位地址,即BANK SWITCH代码段的高8位都一样,由语句(2)中的操作符HIGH BANK SWITCH确定;低8位保存在已经压栈的B_CURRENTBANK变量中,此时堆栈中的?B_CURRENTBANK压栈值是B_SWITCH3的低8位,这样②的地址就是B_SWITCH3。

程序继续执行B_SWITCH3,在执行?B_SWITCH3的(6)语句之前,B_CURRENTBANK还是前面执行?B_SWITCHl时的值,即B_SWITCHl的低8位。执行语句(6)后,B_CURRENTBANK恢复为B_SWITCH3的低8位,为返回main函数做准备。然后PSBANK置为33h,即指向bank3,接着执行RET语句,堆栈③成为RET的返回地址,程序回到了main()中Delay_noOS(10)的下一条语句继续执行,B_CURRENTBANK也已恢复。

这个调用过程中,用了6个堆栈字节,3条RET指令,关键内容就是B_CURRENTBANK变量,它保存了可以恢复调用前bank环境代码的地址低位。从被调用函数返回 到这个地址后,就能恢复调用前的bank环境,即赋予PSBANK正确的值。

不采用直接保存PSBANK值然后再恢复,而是用压栈的方式保存了相关地址(语句(1)~(3)),是为了实现跨bank区的嵌套调用。例如,在Delay_noOS(10)函数中,如果再次跨bank去调用新函数,会再次重复上述过程,堆栈从②往上再长6个字节。Delay_noOS(10)函数之前执行B_SWITCHI产生的B_CURRENTBANK值(B_SWITCHI的低8位)也会进栈,为调用完新函数后返回到bankl继续执行Delay_noOS(10)提供保证。

2 无操作系统bank分区间的强制跳转

通过上面的分析得知,如果要处理跨bank区的跳转、调用和返回,关键是能正确处理好PSBANK中的内容。当程序没有操作系统用于任务切换,而又需要强制退出某一函数进入到另一函数的某一地址时,比如说在中断发生后,结束原来的工作转入到另一工作去,就需要处理好PSBANK。

如果不考虑bank,可以在转入新地址之前执行一段代码,保存该地址处的环境变量[2],包括堆栈指针sP和需要的入口地址。然后在中断返回之前,恢复此环境变量,执行中断返回指令进入该新地址。这个思路和C51库函数setjump和longjump比较相近,但比它们灵活,因为环境变量可以自己处理。

考虑bank后的情况稍微复杂些,环境变量中需增加bank的处理信息,那么只处理PSBANK行不行呢?

如果仅保存和恢复PSBANK,则很简单,在保存环境变量的程序中加入:

JMPEnv[envl][3]=PSBANK;

在恢复环境变量的程序中加入:

PSBANK=JMPEnv[envl][3];

这里环境变量是二维数组JMPEnv,envl代表一个环境变量,即一个返回点。第二维是变量中的参数个数。因此可以保存多个环境变量以供使用。

初看起来这样处理是没有问题的,可实际上不行。因为进入返回点后,虽然PSBANK正确了,但是B_CUR-RENTBANK可能已经被修改,不能和返回点程序的bank区匹配,如果再次出现跨bank调用的话将不能正确返回。

处理方法是有点技巧的,因为C语言不支持汇编变量B_CURRENTBANK的写法,所以在L51_bank.A51中要加上声明:

PUBLIC BLCURRENTBANK

和伪指令:
B_CURRENTBANK EQU B_CURRENTBANK

这样就可以在C程序中使用B_CURRENTBANK了,先声明B_CURRENTBANK:

extern Uchar data B_CURRENTBANK;

然后在保存环境变量程序中加入:

JMPEnv[envl][3]=PSBANK;

JMPEnv[envl][4]=B_CURRENTBANK;

恢复环境变量程序中加入:

PSBANK=JMPEnv[envl][3];

B_CURRENTBANK=JMPEnv[envl][4];

这样恢复环境变量进入到新程序后,也将恢复该程序对应的正确?B_cuRRENTBANK值,问题得到解决。

3 no/0S-ll移植中的bank分区处理

μC/OS-II的51版本已经很成熟,但是所有移植版本均未处理bank问题,需要增加该内容,否则不能在包括C8051F12X系列及其他多bank程序中使用。

如前所述,Keil C51提供对跨bank调用的透明切换支持,但在使用操作系统时,这种透明切换机制还需要提供对任务切换的支持。因为任务的切换,程序可能需要到别的代码分组中去运行,而此时PSBANK和B_CUR-RENTBANK还停留在原来代码分组中的状态,将导致程序崩溃。显然,无论由于什么情况导致的任务切换完成之前,都需要保存和恢复PSBANK和B_CURRENT-BANK的值。解决的办法是在每次任务切换前将PS-BANK和B_CURRENTBANK压入用户任务栈。

按照μC/OS-II的要求,在任务创建时,任务栈必须初始化成像运行中的任务刚刚发生过中断一样嘲。B_CURRENTBANK的初始值取决于该任务所在分组对应的切换代码段的低8位地址。所以,任务堆栈的初始化函数OSTaskStkInit需要加入一个参数INT8U bank,指明该任务位于哪个代码分组中。又由于任务堆栈的初始化函数是被任务创建函数OSTaskCreate调用的,所以该函数一样需要加入参数INT8U bank。

在压栈,出栈宏中需要加入:

PUSH PSBANK
PUSH B_CURRENTBANK

POP B_CURRENTBANK
POP PSBANK
在任务堆栈的初始化函数OSTaskStkInit中需要加入:
*stk++=17; //堆栈长度增加2个到17

if(bank==0x22:){ //bank2
*stk++=bank;
*stk++=CurrentBank2();
else if(bank==0x33){ //bank3
*stk++=bank;
*stk++=CurrentBank3();
}
else{ //bankl和common
*stk++=0xll; //PSBANK
*stk++=CurrentBankl();
)

其中,bank0用任何的PSBANK值均没有问题,所以简化了PSBANK取值0x00的情况。

函数INT8U CurrentBankl(void),INT8U Current-Bank2(void)和INT8U CurrentBank3(void)是用汇编语言实现的,返回值通过R7传递,目的是获得该任务所在分组对应切换代码段(SWITCHn)的低8位地址。不用C语言编写的原因同样是B_SWITCH&N不被C支持。

CurrentBankl(void)代码如下,其他两个类同。
RSEG PR CurrentBankl Os_CPU_A
CurrentBankl:
MOV DPTR,#B_SWITCHl
MOV R7.DPL
RET

结 语

本文介绍了Keil C51实现大于64 KB程序的bank分组代码切换机制的原理,提出了没有操作系统情况下非正常转移时bank的处理方法以及μc/os—II操作系统在多bank分区程序移植中应采取的措施,在开发实例中均得到了很好的应用。

关键字:地址  调用  变量  寄存 引用地址:C8051F12X中多bank的分区跳转处理

上一篇:Atmel 推低成本CAP可定制微控制器入门级开发工具包
下一篇:用PIC16F87X单片机实现高分辨率频率计的一种方法

推荐阅读最新更新时间:2024-03-16 12:22

汇编语言 数据寄存器AX、BX、CX、DX
8086内部有4个16位的数据寄存器AX、BX、CX和DX,用来存放16位数据信息或地址信息;也可分成8个8位寄存器来使用,低8位寄存器位AL、BL、CL和DL,高8位为AH、BH、CH和DH,它们只能用来存放8位数据,不能用来存放地址信息。这些通用寄存器也可以有专门的用途。 AX为累加器:它是编程中用得最多、最频繁的寄存器。AX、AH和AL在乘、除法等操作中有专门的用途。 BX为基址寄存器:可以用来存放偏移地址。 CX为计数寄存器:在循环操作时作计数器用,用于控制循环程序的执行次数。 DX为数据寄存器:在乘、除法及I/O端口操作时有专门用途。 通过汇编指令来修改寄存器中的内容,从而来控制CPU,寄存器是CPU中保存地址信息和
[单片机]
汇编语言 数据<font color='red'>寄存</font>器AX、BX、CX、DX
DS4830的多地址I2C总线从机模块设计
引言     经过十几年不懈努力,我国已经成为光纤、光缆、光器件和光收发模块的制造大国,特别是在光收发模块领域取得了长足的发展。目前,光收发模块正朝着小型化、高速率、低功耗、长距离方向发展。特别是高速率方向,从最初的10 Mbps、100 Mbps、1 000 Mbps,到10 Gbps、40 Gbps、100 Gbps。其对内部使用的微控制器提出越来越高的要求。不仅仅对微处理器的处理速率有要求,而且对微处理器外围功能模块如ADC、DAC、TEC(Thermoeleetric Cooler)等处理性能的要求也越来越高。针对此,Maxim公司针对光通信行业特殊应用及功能要求,定制设计了一款采用低功耗、16位MAXQ20核的微控制器,
[单片机]
DS4830的多<font color='red'>地址</font>I2C总线从机模块设计
51单片机的串口通信详解-原理 寄存器 编程等
单片机的通信一般有并行通信和串行通信。并行通讯是数据的各位同时发送或接收,并行通信控制简单,传输速度快,传输线较多。 参看下图: 串行通讯传输线少,可利用电话网,但传送控制复杂。数据一位一位顺序发送或接收。 串行通讯中有一种是异步通信,即我们通常所说的串口通信。这是我们今天要分享的内容: 异步通讯用一个起始位表示字符的开始,用停止位表示字符的结束。其每帧的格式如下:在一帧格式中,先是一个起始位0,然后是8个数据位,规定低位在前,高位在后,接下来是奇偶校验位(可以省略),最后是停止位1。用这种格式表示字符,则字符可以一个接一个地传送。 一、在异步通讯中,CPU与外设之间必须有两项规定,即字符格式和波特
[单片机]
51单片机的串口通信详解-原理 <font color='red'>寄存</font>器 编程等
MSP430串口波特率寄存器的配置
在写串口通信时,经常因为时钟频率或波特率更改,需要重新配置波特率寄存器,以MSP430F5438A为例,记录一下寄存器配置方法: //============================= void Hal_Uart_Init(void) { P3SEL|=RXD+TXD; // P3.4,5 = USCI_A0 TXD/RXD UCA0CTL1 |= UCSWRST; // **Put state machine in reset** UCA0CTL1 |= UCSSEL__SMCLK; // CLK = UCSSEL__SMCLK ,8192000Hz UCA0B
[单片机]
一种高性能32位移位寄存器单元的设计
1 引言 随着CPU设计位数与性能的不断提高,对CPU 执行单元中专用硬件移位寄存器的要求也越来越高。CPU移位寄存器的性能直接影响到所设计CPU 对移位类指令的处理能力和执行速度。传统结构的CPU中,移位寄存器的设计一般采用矩阵结构和树状结构。当CPU的位数达到32位,速度达到100M以上时,要在一个指令周期内对32位的数据进行32 位内任意移位,以前的设计方法已经很难达到要求。曾经有过对32位桶形移位寄存器的行为级描述,但其只适用于RISC指令集,并且作为CPU中的专用硬件为了达到功耗、速度和面积上的最佳,通常硬件电路采用全定制设计。 本文给出了一种可用于32位以上CPU执行单元的移位寄存器电路,并针对CISC指令集IN
[单片机]
一种高性能32位移位<font color='red'>寄存</font>器单元的设计
内部低128B、SFP区的地址分布、访问方式
  MCS-51 内部有 128 个字节的数据存储器 RAM ,它们可以作为数据缓冲器、堆栈、工作寄存器和软件标志等使用。 CPU 对内部 RAM 有丰富的操作指令。在编程时经常用到它们,内部 RAM 地址为 00H ~ 7FH ,不同的地址区域内,规定的功能不完全相同。128 字节地址空间的 RAM 中不同的地址区域功能分配为:工作寄存器区(00H-1FH)、位地址区(20H-2FH)、堆栈和缓冲区(30H-7FH )、特殊功能寄存器 SFR 区(80H ~ FFH),下面分别说明。   ① 工作寄存器区   单片机的内部工作寄存器以 RAM 形式组成,即工作寄存器包含在内部数据存储器中。地址为 00H ~ 1FH 单元,内部
[单片机]
基于FPGA的可变长度移位寄存器优化设计
本文以最大可变长度为N、宽度为1bit的移位寄存器为模型,讨论如何从结构上优化可变长度移位寄存器和有效的FPGA实现。至于宽度不为1bit的情况,可以此类推。   1 可变长度移位寄存器的常用结构   通常可变长度移位寄存器的结构可分为两种:一种是输入分支型(结构A),如图1所示;另一种是输出分支型(结构B),如图2所示。      结构A与结构B有两个共同点:第一,都是由触发器链路加数据流向控制逻辑组成;第二,每级触发器的输入输出都是信号节点,因而各级都需要对本级节点的信号流向进行控制。结构A用n-to-2n译码器来控制信号流向,结构B则用2n:1多路复用器控制信号流向。对于基本逻辑单元为查找表(LUT)+
[工业控制]
基于FPGA的可变长度移位<font color='red'>寄存</font>器优化设计
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • ARM裸机篇--按键中断
    先看看GPOI的输入实验:按键电路图:GPF1管教的功能:EINT1要使用GPF1作为EINT1的功能时,只要将GPFCON的3:2位配置成10就可以了!GPF1先配 ...
  • 网上下的--ARM入门笔记
    简单的介绍打今天起菜鸟的ARM笔记算是开张了,也算给我的这些笔记找个存的地方。为什么要发布出来?也许是大家感兴趣的,其实这些笔记之所 ...
  • 学习ARM开发(23)
    三个任务准备与运行结果下来看看创建任务和任运的栈空间怎么样的,以及运行输出。Made in china by UCSDN(caijunsheng)Lichee 1 0 0 ...
  • 学习ARM开发(22)
    关闭中断与打开中断中断是一种高效的对话机制,但有时并不想程序运行的过程中中断运行,比如正在打印东西,但程序突然中断了,又让另外一个 ...
  • 学习ARM开发(21)
    先要声明任务指针,因为后面需要使用。 任务指针 volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • 学习ARM开发(20)
  • 学习ARM开发(19)
  • 学习ARM开发(14)
  • 学习ARM开发(15)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved