数码之家

 找回密码
 立即注册
搜索
查看: 8198|回复: 5

[C51] 兼容keil C51 为 SDCC 添加个intrins.h 头文件

[复制链接]
发表于 2019-7-26 13:19:04 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 huaweiwx 于 2019-7-26 14:14 编辑

序:keil c51 intrins.h 头文件包含了两个函数
  void _push_ (unsigned char _sfrname);
  void _pop_  (unsigned char _sfrname);
  功能:通过压栈操作临时保存一个变量或寄存器的值,代码执行后,用出栈来恢复,如中断和寄存器页(page)值;优点是高效快速,缺点是必须成对使用,且避开了编译阶段的检查,这样存在严重的安全隐患;

1 应用场合:
   例如:执行到某个代码段时无论原有中断是否允许,都必须关闭中断, 安全无隐患的代码如下:
    uint8_t tmp;
   tmp = EA;  //保存 EA 在临时变量 tmp中
   EA = 0;
   {...}
   EA = tmp;  //恢复 EA 值

2 更快速高效的方法是不使用临时变量进行寻址/取值/存取,而以压栈出栈来代替,这在keil c51 intrins.h 提供了两个嵌入汇编宏,将变量值压入堆栈或从堆栈中弹出,这样生成的代码更短,运行更快但具有安全隐患,用这两个函数改写上述代码:
  _push_(EA); //保存 EA 在堆栈
  EA = 0;
  {...}
  _pop_(EA); //在堆栈中弹出EA
  但这种方法存在安全隐患:_push_ 和 _pop_ 必须成对出现,就像c语言的括号一样,但如果 _push_ 和 _pop_ 未成对出现,编译程序还无法检查出来,运行结果可想而知:直接崩溃!

3 还是要在这里吐槽下 STC 在 stc-isp 中提供的代码范例中,需要临时设置下寄存器值时 ,暂存的方法是采用了上述 2,而nuvoton/silicon等官方示例都是 1 ,2 优点是节约了几个机器周期和几个byte内存,缺点也是显而易见的,避开了编译系统的安全检查,另外也降低了系统的可移植性,如SDCC就未提供intrins.h头文件和相应的堆栈操作函数;

一、兼顾速度和安全的方法,让编译系统帮我们检查:
   我采用的方法是:
   建立两个新的宏定义来调用上述堆栈操作:

   #define pushSfr(x)  do{\
                                  _push_ (x)

   #define popSfr(x)      _pop_ (x);\
                             }while(0)

   原理是将 _push_ (x) 和 _pop_ (x) 及之间的代码用放到一个 do{}while(0)块中,这是一个C 中常用的做法,显然,使用顺序和非成对出现均会引起编译错误,从而规避上述风险;
   而do{}while(0),由于循环条件恒假,编译编译时会优化成只生成块内代码并运行一次,并不会生产条件跳转代码,因此不会增加执行代码的数量;

二、应用实例,改写前面有缺陷代码的如下:
  pushSfr(EA);
  EA = 0;
  {...}
  popSfr(EA);
  这样,就不用将STC范例修改成 前面1的方式了,即使不小心未配对,编译阶段就会出错让我们发现;这对初学者来说,只要将_push_  改为 pushSfr 及 _pop_ 改为popSfr 即可安全放心使用了;

三、SDCC 中应用:
  在SDCC中,没有提供intrins.h 头文件及相应栈操作函数,但我们可以很方便的仿照keil 中同名头文件来做一个,非常简单,代码如下:
  1. /*
  2.   keil c51 intrins.h 兼容头文件  for SDCC by huaweiwx@sina.com 2017.5.19
  3.   实现 void _push_ (unsigned char _sfr) / void _pop_ (unsigned char _sfr)
  4. */

  5. #ifndef _INTRINS_H_
  6. #define _INTRINS_H_

  7. /* warning: __push __pop 使用堆栈临时保存 sfr 数据,必需成对使用!  
  8.      __push(x);
  9.          ...  // 保护代码块
  10.          __pop(x);  //缺少无该语句编译不会出错,但运行错误!
  11. */
  12.         #define __push(x)      __asm push _##x  __endasm  /* void _push_ (unsigned char _sfr); */
  13.         #define __pop(x)       __asm pop  _##x  __endasm  /* void _pop_  (unsigned char _sfr); */

  14.         #define _push_        __push        /*兼容 keil c51*/
  15.         #define _pop_        __pop         /*兼容 keil c51*/
  16.         
  17. /*   安全使用保护宏:
  18.      pushSfr(x);
  19.          ...                 // 受保护代码块
  20.          popSfr(x);         // 缺少无该语句编译出错,确保生成正确代码。
  21. */
  22.     #define pushSfr(x)  do{\
  23.                                   __push(x)

  24.         #define  popSfr(x)     __pop(x);\
  25.                               }while(0)

  26. #endif //_INTRINS_H_
复制代码

说明: 14/15 行分别定义了 2 个嵌入汇编宏函数,名称为__push 和 __pop 没用单下划线是因为sdcc单下划线名称是汇编对应C无下划线名称,这不符合sdcc 的命名规则;           17/18 提供了兼容keil C51 的同名函数宏替换成我这里的实际名称 即 _push_ 替换成 __push 和  _pop_替换成 __pop;
           25~29 就是上述安全使用的宏定义;


四 、说明:以上内容已经包含在 arduino for  51 中;
  
    2年前我在旧坛上预告过这个消息,竟然引来多个不明就里坛友瞎喷,当时我改变主意不开源了,本来就是自己玩玩的;
    现在玩ardiuno的坛友也越来越多了,这次我错误估计1周时间可能超不过50个跟帖响应,因为坛上比较冷清估计也不会有多少人想在51上玩arduino,出乎我意料之外的是二三天就超过了50楼,反而我来不及整理发布了,天又太热!
    现在我得加快把一些简单的教程写好,敬请坛友耐心等待!

打赏

参与人数 4家元 +80 收起 理由
人艰不拆了 + 20
2545889167 + 20
2235880905 + 20 这么好的贴子居然瞎喷可恶
不长叶子的树 + 20 原創內容

查看全部打赏

发表于 2019-7-26 22:02:41 | 显示全部楼层
支持老大,arduino支持的芯片越多,arduino就更火

打赏

参与人数 1家元 +20 收起 理由
huaweiwx + 20 我很贊同

查看全部打赏

回复 支持 反对

使用道具 举报

发表于 2019-7-28 22:14:23 | 显示全部楼层
支持楼主(虽然现在不玩51了)但是这种好东西还是能大大方便大家的入门学习,必须支持

打赏

参与人数 1家元 +20 收起 理由
huaweiwx + 20 我也是,新唐一折买了个ML51板子,又拣起了.

查看全部打赏

回复 支持 2 反对 1

使用道具 举报

发表于 2021-2-28 09:13:05 | 显示全部楼层
谢谢分享  :lol:
回复 支持 反对

使用道具 举报

发表于 2021-5-28 07:33:57 | 显示全部楼层
51只有读书的时候学过,毕业后兼职搞了一段51开发,用的是PL/M语言,估计没多少人知道

现在玩stm32,这辈子都不可能再回到51了
回复 支持 反对

使用道具 举报

发表于 2021-5-28 22:03:20 | 显示全部楼层
这个做法似乎只适用于有公共出口的程序,对那些喜欢“if(a) return;“的就不适用了,一般中断服务程序是统一出口,主程序中就不一定了。



回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2024-4-20 07:14 , Processed in 0.405600 second(s), 21 queries , Redis On.

Powered by Discuz!

© 2006-2023 smzj.net

快速回复 返回顶部 返回列表