8051 Code Banking

2024-01-14 09:30
文章标签 code 8051 banking

本文主要是介绍8051 Code Banking,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://blog.sina.com.cn/s/blog_61500ed601012cgf.html


刚写完8051内存模型,今天我和大家一起来看看8051的代码分页机制(code banking)。如有疑问,请与我商榷。

Contiki支持的flash大小主要分为两种,一种是256KB(cc253x)或者128KB(snsinode)。如前篇文章所讲8051 memory spaces,flash主要映射到code存储空间,宽度为16bit,寻址范围可达到64kb。

首先我想问一个问题,为何要进行code banking??通俗点说一个标准的8051器件能寻址64KB的代码空间。对于超过64KB的代码,单片机系统通常采用代码分页(CODE BANKING)的方式来扩展程序空间。代码分页的机理就是将地址空间分成小于或等于64KB的不同的代码段,通过片选的方式实现程序在不同代码空间的跳转.

这篇文章当然描述的是一些基础性的东西,并且只针对contiki支持的soc。如果想详细参考,请看最后的reference list

(支持原创,如需转载,请注明地址:http://blog.sina.com.cn/litianping0709 作者:叶雨荫城(阿雨))

 

How does it Work

什么叫做banks?flash被分解成的小于或者等于64KB的代码段称之为banks。不同设备的banks数量不一定相同,但是技术是一样的。每个bank的大小为32KB,因此cc2430有4个banks,而cc2530有8个banks。

由于flash的大小超过64KB,我们不得不利用三个字节来进行寻址。举个例子,cc2530的物理地址范围为ox000000到0x03ffff。

 

Common Segment

flash的低地址位的32KB(物理地址0x000000到0x007fff),一般称之为common segment(HOME 或者 BANKO),总是由code存储空间的低32KB进行寻址(0x0000-0x7fff)。

 

Switched Segments

而code的高32KB地址空间(0x8000-0xffff)主要用来寻址剩下的N-1代码段。在任何给定的时间内只能指向一个segment。通过一个特殊的寄存器来告诉芯片现在只想的bank是哪个,寄存器一般称之为PSBANK或者FMAP.

 

Physical and Virtual Addresses

下面的表格显示了物理地址(on flash),code存储空间的地址及相应FMAP寄存器之间的值。

Mapping between physical and virtual addresses and the value of FMAP
SegmentPhysical AddressVirtual AddressFMAPAddress in CODE
HOME 0x000000 - 0x007FFF 0x000000 - 0x007FFF 0x00 0x0000 - 0x7FFF
BANK1 0x008000 - 0x00FFFF 0x018000 - 0x01FFFF 0x01 0x8000 - 0xFFFF
BANK2 0x010000 - 0x017FFF 0x028000 - 0x02FFFF 0x02 0x8000 - 0xFFFF
BANK3 0x018000 - 0x01FFFF 0x038000 - 0x03FFFF 0x03 0x8000 - 0xFFFF
...
BANK7 0x038000 - 0x03FFFF 0x078000 - 0x07FFFF 0x07 0x8000 - 0xFFFF

 

The Problem

到目前为止,上述机制听起来比较简单,但是不知道大家有没有注意到一个问题,在x bank里的代码希望调用y bank里代码时该怎么办??如果在转换bank之前调用相应的代码将会出现错误。而如果在调用之前转到了相应的bank,那么调用者已经被转换,调用也是不可能的。

 

Writing Banked Software with SDCC

为了解决这个问题,SDCC使用了一项称之为trampoline的技术banked函数调用的实现通过位于common segment中的一小块intermediate代码段来实现。为了讲述简单,流程如下:

  • caller:
    • 在RO、R1、R2中写入希望调用函数的地址,同时包括bank号
    • Invokes the trampoline (banked call)
  • The trampoline:
    • 将当前bank的信息写入到stack中
    • 加载新的 bank
    • 调用函数 
  • The callee:
    • Runs (and possibly makes more banked calls)
    • Returns to the trampoline (banked return)
  • The trampoline:
    • Loads the original bank (which is read from stack)
    • Returns to the caller

Normal vs Banked Calls

很明显,上述的调用对stack和调用的开销都会加大,但是我们知道banked调用相对是比较少的。

 

SDCC Memory Models

如之前文章所讨论到的8051 memory spaces,SDCC利用其中的模型之一来构建可运行程序。

 

Small, Medium and Large - Explicit Banking  

对于small,medium或者large来说,开发者必须显式的调用banked函数。

  • 函数声明必须有__banked关键字
  • 函数原型也需要__banked关键字

例子:

void foo() __banked; void bar() __banked
{
foo();
 
}

Huge - Implicit Banking   

而对于huge模型来说,所有的函数调用/返回都会调用trampoline。看例子。

void foo();

void bar()

{

 

   foo();

 / * This automatically becomes a banked return */

}

Here be Dragons

当然上述特性是SDCC不成文的特性,取决你自己怎么使用。

为了减少代码空间和提高性能,开发这可以利用__nonbanked关键字来阻止SDCC产生banked调用/返回。

为安全起见,最好遵循以下规则:

  • 确保使用__nonbanked关键字的函数存在于common segment中。
  • 对于存在于switched segment中的函数来说,如果只在相同的segment中进行调用,最好声明有__nonbanked关键字。

Bank Allocations

在利用sdcc开发程序时,开发者必须指定每个代码段存在于哪个segment。这个可以利用#pragma directive或者命令行指定。这里主要强调的是链接器不会检查bank溢出。如果你在一个相同的segment里分配了过多的文件并且超过32KB的大小,这样就会出现问题。

 

Banking in Contiki's 8051-based Ports

contiki的编译系统是banking-aware的,可以看看examples/cc2530dk或者examples/sensinode下的makefile文件,可以看到这一行:HAVE_BANKING=1;

HAVE_BANKING选项主要告诉编译器是否产生bankable的镜像

  • 如果HAVE_BANKING没有定义,并且支持uIPv6,那么HAVE_BANKING将会置为1,否则将会置0.
  • 如果指定需要banking,系统将会利用huge模式编译整个系统
  • 如果没有指定banking,系统利用large模式编译整个系统

当编译结束,可以看到一些信息输出,这些信息可以帮助你检查分配情况,以防有错误发生。

 

Code Segment Sizes and memory footprint

最后输出的信息会类似于如下所示。

8051 <wbr>Code <wbr>Banking

 

看看上面的信息可以判断出是否有bank溢出或者其他问题:

  • Decimal下列出的值的大小必须低于32768
  • 对于sensinode设备,BANK3的值必须低于30720

Automatic Bank Allocation

将利用sdcc banking进行编译时,分配器将会自动满足segment的大小,你只需要做一件事,就是在写新的中断服务程序时,告诉分配器这个程序必须位于HOME bank中。有两种方法:

  • 将文件以intr.c结尾,如foo_intr.c或者bar-intr.c。分配器碰到以intr.c结尾的文件时,将会自动将其他分配到HOME bank空间中
  • 但是如果你不想改变文件名如foo.c(不希望以intr.c结尾),那么在cpu文件夹下的segment.rules文件中加入一行:HOME foo.c即可

但是如果你不想写新的ISRs,那么你不用担心任何东西。

在编译的最后阶段,当分配器运行后,会产生如下信息:

 8051 <wbr>Code <wbr>Banking

Preallocations开始的一行后面列出了不能或者没有被移出的字节数目。例如,包含ISRs的标准库或者文件必须停留在HOME segment中。

Segment - max - alloc 相对来说比较重要,最后一列将会列出在编译结束后在每个segement中的字节数大小。这里列出的值的大小必须等需Decimal下列出的值的大小,

 

reference list

  1. The SDCC manual. Look for the section entitled 'Bankswitching'.
  2. Section 2.2.2 'CPU Memory Space' of the 'CC253x/4x User Guide (Rev. C)' (Literature Number: SWRU191C April 2009–Revised January 2012)
  3. Section 11.2.2 'CPU Memory Space' of the 'CC2430 Data Sheet (rev. 2.1)' (Literature Number: SWRS036F)

这篇关于8051 Code Banking的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/604700

相关文章

Debugging Lua Project created in Cocos Code IDE creates “Waiting for debugger to connect” in Win-7

转自 I Installed Cocos Code IDE and created a new Lua Project. When Debugging the Project(F11) the game window pops up and gives me the message waiting for debugger to connect and then freezes. Also a

LLVM入门2:如何基于自己的代码生成IR-LLVM IR code generation实例介绍

概述 本节将通过一个简单的例子来介绍如何生成llvm IR,以Kaleidoscope IR中的例子为例,我们基于LLVM接口构建一个简单的编译器,实现简单的语句解析并转化为LLVM IR,生成对应的LLVM IR部分,代码如下,文件名为toy.cpp,先给出代码,后面会详细介绍每一步分代码: #include "llvm/ADT/APFloat.h"#include "llvm/ADT/S

VS Code 调试go程序的相关配置说明

用 VS code 调试Go程序需要在.vscode/launch.json文件中增加如下配置:  // launch.json{// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information,

code: 400, msg: Required request body is missing 错误解决

引起这个错误的原因是,请求参数按照get方式给。 应该给json字符串才对 补充: 1. @RequestBody String resource 加@RequestBody必须给json字符串,否则会报错400,记如标题错误。 不加这个的进行请求的话,其实post和get就没有什么区别了。 2. List<String> indexCodes=(List<String>)json.

iOS项目发布提交出现invalid code signing entitlements错误。

1、进入开发者账号,选择App IDs,找到自己项目对应的AppId,点击进去编辑, 2、看下错误提示出现  --Specifically, value "CVYZ6723728.*" for key "com.apple.developer.ubiquity-container-identifiers" in XX is not supported.-- 这样的错误提示 将ubiquity

解决服务器VS Code中Jupyter突然崩溃的问题

问题 本来在服务器Anaconda的Python环境里装其他的包,装完了想在Jupyter里写代码验证一下有没有装好,一运行发现Jupyter崩溃了!?报错如下所示 Failed to start the Kernel. ImportError: /home/hujh/anaconda3/envs/mia/lib/python3.12/lib-dynload/_sqlite3.cpython-

Behind the Code:与 Rakic 和 Todorovic 对话 OriginTrail 如何实现 AI 去中心化

原文:https://www.youtube.com/watch?v=ZMuLyLCtE3s&list=PLtyd7v_I7PGnko80O0LCwQQsvhwAMu9cv&index=12 作者:The Kusamarian 编译:OneBlock+ 随着人工智能技术的飞速发展,一系列前所未有的挑战随之而来:模型的衰退与互联网的潜在威胁愈发明显。AI 的增长曲线可能因训练过程中的瓶颈而趋于平

冒泡排序和鸡尾酒排序(code)

昨天回顾了下冒泡排序和鸡尾酒排序,用面向对象的方式写了一下,并且优化了代码,记录一下~ 一、冒泡排序 # 冒泡排序class BubbleSort(object):def __init__(self, data_list):self.data_list = data_listself.length = len(data_list)# 简单粗暴的排序方式def b_sort(self):d

编译时出现错误 -- clang: error: linker command failed with exit code 1 (use -v to see invocation)

出现这个错误的原因有多种,常见的是因为某些文件的缺失或者是文件的重复导致的。 这类错误查看的关键在于其上一行的文字。 对于文件缺少而导致错误的情况: 例如上图中的示例,其上一行文字为 ld:library not found for -lrxl,可以看出是缺失了某一文件而导致的错误,这行文字中的最后“ -lrxl ”:-l 代表着其前缀是“lib”,连着后面的 rxl,其名称为 libr

GCDAsyncUdpSocket 使用时出现错误 Domain=NSPOSIXErrorDomain Code=13 Permission denied

完整的错误描述为: Domain=NSPOSIXErrorDomain Code=13 "Permission denied" UserInfo={NSLocalizedDescription=Permission denied, NSLocalizedFailureReason=Error in send() function.} 原始代码是这样的: clientBroadcast