1. 简介

MCS-51是8根数据线,16根地址线,所以MCS-51最大只能访问64KB(2162^{16}216)的地址。很多较复杂的C51代码,其整个代码生成Bin文件可能大于64KB。针对这种情况,Keil C51提出了Code Banking机制来解决这个问题。

2. 基本原理

MCS-51内核的代码执行机制已经固定死了,代码运行的地址范围只能在0-64KB之间。一般情况下,我们编译生成的Bin文件,其代码执行地址和代码存储地址是一致。MCU执行到哪个地址,直接去ROM上取相应地址的内容然后执行即可。
MCU要访问超过64KB的地址范围,肯定需要增加地址线。增加4根地址线,则能够访问到2MB的地址范围。由于MCS-51只能执行64K范围的代码,Keil C51编译器相应也只会生成64K地址范围内的代码。
C51是采用分离编译,即单个文件独立编译,最后再链接成一个Bin文件。在链接的过程中,会有一个地址重定位的过程,会将每个obj文件中的代码映射成64K中的一个绝对地址。Keil链接器在链接时,可以将指定的多个Obj文件中的代码地址重定位到相同同地址空间去。如ObjA和ObB指定地址重定位到相同的地址范围内,并且各自的CodeSize为40KB。这样A.c和B.c的代码不能同时在MCU上执行,但是分两次加载,就可以在分别MCU上执行了。
MCS-51默认ROM片外存储器为64KB,存放A.bin。MCS-51再外接1个64KB的外置存储器ROM存放B.bin。什么时候读取ROMA,什么时候读取ROMB呢?还需要1个Pin用来选择。执行A.C中的函数时,选择读取ROMA,执行B.C中的函数时,选择读取ROMB。那么如何知道A.C中的函数会读取ROMA,B.C中的函数会读取ROMB呢?这是因为编译器会将A.C中的函数全部标记0,将B.C中的函数全部标记1。这个标记正好对应上面选择ROM的Pin。

3. Keil的实现

像Reset Vector、Interrupt Vectors、Interrupt Service Routines以及负责几个相同地址模块切换的代码,都是必须固定位置,不能随意变动,可能导致系统出问题。所以Keil C51提出了一个Common Area的概念,存放上述代码。然后针对重定位到相同地址的代码,则被称为Bank Area。

3.1. 具体设置

  1. Bank Area,选择指定有多少个相同地址范围的代码。

  2. 指定文件所属Bank号。
    可以将多个文件指定为相同Bank号,未指定Bank号的文件默认为Common Area。BX51链接器最多支持32个Bank号,LX51链接器最多支持64个Bank号。

  3. Bank分配基本原则。
    Common Bank因为是不需要重复加载的,所以效率最高。那些追求效率的代码,都可骗我在Common Bank中。如:Reset Vector、Interrupt Vector、Interruption Service Routines、String constants、Bank Switching Routines、Inter-Bank Jump Tables等等。
    Bank0放置一上电就需要调用,并且调用不是非常频率的代码。
    其他调用不频繁的代码放在其他Bank。

  4. 添加Bank调用代码,默认使用系统提供的(在Keil\C51\LIB\L51_BANK.A51)。
    B_NBANKS与前面配置的Bank数相同,B_MODE是Bank_Switching的方式。

;                         <i> For BL51 the maximum value for ?B_NBANKS is 32
;                         <i> For LX51 the maximum value for ?B_NBANKS is 64
?B_NBANKS       EQU  4    ; Define maximum Number of Banks
;                         ; following values are allowed: 2, 4, 8, 16, 32, 64
;                         ; for BL51 the maximum value for ?B_NBANKS is 32
;                         ; for LX51 the maximum value for ?B_NBANKS is 64
;
; <o> ?B_MODE: Bank Switching via
;                    <0=> 8051 Port
;                    <1=> XDATA Port
;                    <4=> User-provided bank switch code
?B_MODE         EQU  0    ; 0 for Bank-Switching via 8051 Port
;                         ; 1 for Bank-Switching via XDATA Port
;                         ; 4 for user-provided bank switch code

3.2. 链接器

Keil C51支持2种链接器,分别为BL51和LX51。

3.2.1. BL51链接器

BL51默认生成的Hex文件为Hex80,并且当前工程设置多少个Bank,则生成多少个Hex文件,每个Bank和相同的Common组成一个文件,如下图。每个Hex文件可以用Hex2Bin.exe转换成Bin文件。

3.2.2. LX51链接器

BL51是较早的链接器,LX51是在BL51基础上进行扩展的链接器,功能更强大,优化性能更好。一般情况下建议使用LX51。LX51会将多个Bank合并生成一个Hex文件。这个Hex文件中的代码地址空间是超过64KB的,Hex80格式不支持超过64KB的地址空间。针对这种情况,一种新的Hex描述格式产生了——Hex386。Hex386不仅支持多超过64KB地址范围,还支持指定偏移存储。

BL51链接器生成的Bin文件,如果Bank Area有多余空间,会以0填充。而LX51生成的Bin文件,如果Bank Rrea有多余空间,则会优先以Common代码填充。Offset默认为0,如果指定了,则将生成的代码放在Bin文件相应的偏移。下图为偏移为0。

3.3. Bank Switching方式

3.3.1. 8051Port

MSC-51操作64KROM的结构如下:

我们完全可以依据上述接口,连接多个ROM。然后通过P口来选通。

L51_BANK.A51中有下述代码,即指定P1口用来控制选择哪个ROM,也即代码执行到Bank1时,P1=1;执行到Bank2时,P1=2,依次类推。更详细的切换流程,可以查看汇编代码。

IF  ?B_MODE = 0;
;-----------------------------------------------------------------------------
; if ?BANK?MODE is 0 define the following values
; For Bank-Switching via 8051 Port define Port Address / Bits
;
;<h> Bank Switching via 8051 Port
;    <i> This is only used if ?B_MODE is 0
; <o> P1: 8051 Port address <0x0-0xFF>
P1              DATA    90H      ; I/O Port Address
;
?B_PORT         EQU     P1       ; default is P1
; <o> ?B_FIRSTBIT: Starting with Bit <0-7>
;     <i> Default is Bit 2
?B_FIRSTBIT     EQU     2        ; default is Bit 2
;</h>
;-----------------------------------------------------------------------------
ENDIF;

3.3.2. XData Port

查看L51_BANK.A51代码,变量B_XDATAPORT是参与切换的标识,默认设置为0xFFFF,可以根据需要修改。

IF  ?B_MODE = 1;
;-----------------------------------------------------------------------------
; if ?BANK?MODE is 1 define the following values
; For Bank-Switching via XDATA Port define XDATA Port Address / Bits
;
;<h> Bank Switching via XDATA Port Address
;    <i> This is only used if ?B_MODE is 1
; <o> P1: XDATA port address <0x0-0xFFFF>
?B_XDATAPORT    EQU     0FFFFH   ; default is XDATA Port Address 0FFFFH
; <o> ?B_FIRSTBIT: Starting with Bit <0-7>
;     <i> Default is Bit 0
?B_FIRSTBIT     EQU     0        ; default is Bit 0
;</h>
;-----------------------------------------------------------------------------
ENDIF;

配合分布外部存储器,如下图。PSD813F2可以0FFFFH地址为控制位,来分别切换不同的Bank对应不同的存储空间,达到和8051Port类似的效果。标准的ROM成本较高,使用此种方式,可以更方便地支持更多的Bank,成本也低。PSD813F2更详细的配置可以参考PSD813F2的DataSheet。

3.3.3. user-provided

以上两种方式,明显是8051Port更容易。所以用户定义也是基于这种方式。很多基于MSC-51内核的MCU,并未完整引出P1口,不能正确的使用方法1,此时可以自定义。见L51_BANK.A51代码。

P1              DATA    90H      ; I/O Port Addresses
P3              DATA    0B0H
;
SWITCH0         MACRO            ; Switch to Memory Bank #0CLR     P1.5     ; Clear Port 1 Bit 5CLR     P3.3     ; Clear Port 3 Bit 3ENDM
;
SWITCH1         MACRO            ; Switch to Memory Bank #1SETB    P1.5     ; Set   Port 1 Bit 5CLR     P3.3     ; Clear Port 3 Bit 3ENDM
;
SWITCH2         MACRO            ; Switch to Memory Bank #2CLR     P1.5     ; Clear Port 1 Bit 5SETB    P3.3     ; Set   Port 3 Bit 3ENDM
;
SWITCH3         MACRO            ; Switch to Memory Bank #3SETB    P1.5     ; Set   Port 1 Bit 5SETB    P3.3     ; Set   Port 3 Bit 3ENDM

默认是以P1.5和P3.3两个Pin为例。需要匹配相应的外置电路,见下图。编译器编译Bank1的函数,会在前面插入SWITCH1指令,相当于Bank1对应的EPROM。编译器编译Bank2的函数,会在前面插入SWITCH2指令,相当于Bank2对应的EPROM。更多详细信息,可以在Keil中仿真调试查看。

3.3.4. 注意

使用user-provided时,因为复位时,系统保持之前的状态,不会自动切换到Bank0,需要修改切换代码,见STARTUP.A51代码的最后,将if 0改为if 1。

; This code is required if you use L51_BANK.A51 with Banking Mode 4
;<h> Code Banking
; <q> Select Bank 0 for L51_BANK.A51 Mode 4
#if 0
;     <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4.
EXTRN CODE (?B_SWITCH0)CALL    ?B_SWITCH0      ; init bank mechanism to code bank 0
#endif

3.4. 自定义外部存储器

除了MSC-51直接总线支持的的ROM外部存储器外,还有一些设备可以作为外部存储器存储bin文件。如EEPROM、NorFlash,这两种设置,MSC-51一般没有直接提供总线访问,也就是说直接连接到MSC-51上,然后直接利用Keil提供的Bank Switching方法。那么针对这种情况,我们有办法吗?可以的。我们可以完全不用Keil提供的Switch方法,完全自己构建Switch方法。如在执行Bank0中的FunA时,接下来需要执行Bank1中的函数B,那么在执行FunB之前,先让代码运行至Common Bank中的SwitchFun。SwitchFun负责将Bank1中的Bin文件加载SRAM中覆盖原有的Bank0的代码。详见下面的伪代码。

// Common.c
void SwitchFun(int nOldBankNo, int nNewBankNo, PFun pFun)
{LoadBinToSRAM(nNewBankNo);pFun();LoadBinToSRAM(nNewBankNo);
}// Bank0.c
void FunA()
{// Call FunB of bank1SwitchFun(0, 1, FunB);// Do some stuff
}// Bank1.c
void FunB()
{// Do some stuff
}

LoadBinToSRAM完成加载指定Bank的Bin覆盖到指定的SRAM。
此种方法主要是利用Keil的Code Banking功能将指定文件生成相同的执行代码地址,加载切换的过程换成自己实现。这里依然要利用L51_BANK.A51文件,否则无法使用Bank功能。然后用user-provided模式,为了防止触发Keil提供的切换功能自动设置了相应的Pin,我们可以修改L51_BANK.A51中B_MODE = 4时时的代码,注释对相关Pin的设置。当我们调用Bank0的函数时,系统可能会调用SWITCHO函数,然后会设置对应的2个Pin,这会带来不可控影响。

P1              DATA    90H      ; I/O Port Addresses
P3              DATA    0B0H
;
SWITCH0         MACRO            ; Switch to Memory Bank #0
;                CLR     P1.5     ; Clear Port 1 Bit 5
;                CLR     P3.3     ; Clear Port 3 Bit 3ENDM
;
SWITCH1         MACRO            ; Switch to Memory Bank #1
;                SETB    P1.5     ; Set   Port 1 Bit 5
;                CLR     P3.3     ; Clear Port 3 Bit 3ENDM
;
SWITCH2         MACRO            ; Switch to Memory Bank #2
;                CLR     P1.5     ; Clear Port 1 Bit 5
;                SETB    P3.3     ; Set   Port 3 Bit 3ENDM
;
SWITCH3         MACRO            ; Switch to Memory Bank #3
;                SETB    P1.5     ; Set   Port 1 Bit 5
;                SETB    P3.3     ; Set   Port 3 Bit 3ENDM

3.5 注意

Hex386和Hex80的格式略有些差异,前者兼容后者,后者并不完全兼容前者。Demo中提供支持Hex386转成Bin的Hex2Bin.exe。
更多细节见附件。

Keil C51 Code Banking相关推荐

  1. Keil C51中code、data、bdata、idata、xdata、pdata的解释

    8051 结构提供给用户3 个不同的存储空间,程序存储器ROM,数据存储器RAM(内部RAM和外部RAM). Keil C51通过以下的关键字定义了不同的存储类型,从而确保用户能够访问到51架构的全部 ...

  2. c语言程序如何在keil中运行,keil c51中C程序的启动过程

    汇编是从org 0000h开始启动,那么keil c51是如何启动main()函数的?keil c51有一个启动程序startup.a51,它总是和c程序一起编译和链接.下面看看它和main()函数是 ...

  3. Keil C51详细设置

    一.target名更改        打开Keil后,左侧Project Workspace中的target可改,方法:右击Target--Manage Compnents--双击待修改项即可,若要添 ...

  4. c语言lst文件,Keil C51 之LST文件

    Keil C51编译器在编译程序时,会生成一个扩展名为LST的列表文件,也被称为listing file. 这个文件包含了有关编译过程的丰富信息,该文件由多个段组成,其中Symbol Listing ...

  5. Proteus和Keil C51联调仿真完整解析(附程序)

    背景:目前,还有不少人使用Proteus仿真诸如带有Firmware固件C51单片机时,先用Keil C51把C程序编译成.HEX文件,然后将.HEX文件导入Proteus项目中进行调试,调试发现软件 ...

  6. Keil C51教程

    第三课 C51数据类型 作者:    来源:本站原创    点击数: <script src="http://www.51hei.com/Article/GetHits.asp?ID= ...

  7. 根据c51程序改写汇编语言,Keil C51编译及连接技术

    主要介绍Keil C51的预处理方法如宏定义.常用的预处理指令及文件包含指令,C51编译库的选择及代码优化原理,C51与汇编混合编程的方法与实现以及超过64KB空间的地址分页方法的C51实现. 教学目 ...

  8. Keil C51程序设计

    转载地址:http://www.dwenzhao.cn/profession/mcu/mcu51keilc.html Keil C51是一种专为8051系列单片机设计的C编译器,支持符合ANSI标准的 ...

  9. Keil C51 V9.00/uVision 4基础

    Keil C51 V9.00 即09年发布的最新版本uVision 4,版本外观改变比较大 可以使用以前的注册文件 如果全新安装,在VISTA或者WIN 7系统下,请使用管理员方式运行,然后注册即可无 ...

  10. Keil C51编译/链接/优化

    Keil C51编译/链接/优化 一.C51编译库及代码优化技术 如下图所示:可以根据优化等级的需要选择相应的库文件. 通过Keil ->Target 下 Memory Model / code ...

最新文章

  1. OpenCV+Tensorflow实现实时人脸识别演示
  2. python学习3. 无重复字符的最长子串(滑动窗口)
  3. 【并发编程】 操作系统介绍
  4. jsp中php代码格式化,JSP 语法 - [ JSP参考手册 ] - 在线原生手册 - php中文网
  5. sbt启动机制、配置优化及与Intellij IDEA的集成
  6. 数据清理中,处理缺失值的方法
  7. 第二章、Zigbee模块参数(DRF1609H、DRF2657C)
  8. 洛谷P1005 [NOIP2007 提高组] 矩阵取数游戏题解
  9. EXCEL 批量插入指标批注
  10. Python 爬虫---百度首页
  11. java 实心圆,如何用css3实现实心圆
  12. 日光能和电池两用计算机,为什么太阳照射的光可以给太阳能转化为电,而我们的日光灯却不行?...
  13. 熵相似_南哲思享 | 张一兵:人类纪的“熵”、“负熵”和“熵增” ——张一兵对话贝尔纳斯蒂格勒...
  14. 高防服务器网站搭建专用死扛CC攻击有效处理高并发
  15. 送给1985年的朋友 ZT
  16. 7:1 error Expected indentation of 2 spaces but found 4 indent 11:35 error Newline requir
  17. 谷歌机器翻译Attention is All You Need
  18. 人体红外传感器简明教程
  19. 蚂蚁金服面试相关流程及关注核心技术方向收集
  20. 2018年新版超音速启动

热门文章

  1. AI实现矢量图片批量转dwg
  2. 软件工程毕业答辩常问的问题
  3. 数学建模与数学实验P48第2题解答
  4. Android App设计规范
  5. php下获取客户端IP
  6. mysql字段命名_数据库表及字段命名规范
  7. java猜成语,成语疯狂猜-疯狂猜成语下载-javaweb下载站
  8. 指定目录下创建TXT文件
  9. 应用 | 使用小O地图制作热力分布图
  10. 北京54坐标系转经纬度坐标系教程