• 1
  • 9月

一个人的中秋,公司却发了两盒月饼。这可如何是好!

  • 24
  • 8月

IAR嵌汇编真是有些危险,尤其是关于堆栈的操作,经常就被“优化”了。

案例一:多中断程序的入口处有压栈保护操作,结果被优化生子程序来进行调用;

案例二:出口的压出栈操作不一样的,也被优化到一起去了。

IAR中要嵌汇编,千万要把优先级调低!

  • 17
  • 8月

在KeilC的选项中,C51这一项里有一项叫做“Don't use absolute register accesses”。我们已经因为这一项出了三次Bug了。

那么这一项有什么作用呢?

在KeilC默认中,这一项并没有选上,表示KeilC将使用寄存器的绝对定位来优化程序。什么意思呢?我们知道,51中有四组通用寄存器。在寄存器组0的时候,R0-R7实际上就映射到了0x01-0x07这段地址。也就是说有时候为了优化,KeilC将会使用0x01-0x07这样的绝对地址。举个简单的例子吧,比如说我们需要将寄存器R5的值存入R7,正常我们会这样写:
MOV A, R5
MOV R7, A
但是如果使用寄存器的绝对定位呢?我们就可以这样写了:
MOV R7, 0x05
节省了一条指令的执行时间!
当然,正常时候这样使用当然没有任何问题。然而,如果有一个中断的服务程序,我们使用了寄存器组1呢?这时候,R5就不再是0x05了,而是0x0D!因此,Bug就出来了。
当然,我们可以在这个中断服务程序上所调用的所有子程序中加在using 1的关键字来解决这个问题。不过这样还是带来了一些不便,更有一些时候,一些子函数是多处调用了。因此,有时我们一般都直接勾选了这个选项来取消KeilC的这项优化。

  • 12
  • 8月

在C51中,KeilC与IAR在函数参数的传递及返回值的处理上,有着较大的不同。本文主要小结不同,并稍稍发表Hanny个人对这些方式的优缺点的看法。

首先,我们对数据类型进行分类。根据数据类型的长度,我们可以将数据简单分为:bit, u8, u16, u32。其中,bit表示位变量;u8主要为char、signed char、unsigned char型变量;u16主要为short、usigned short、int、unsigned int、point型变量;u32主要为long、unsigned long、float型变量。

然后,先介绍一下函数参数的传入。
首先是bit,KeilC采用的是位寻址区的变量来进行bit型参数的传入。而IAR采用的是B寄存器来传入。
接着是u8,KeilC主要采用R7、R5、R3来进行参数的传入。也就是说:当函数的参数为一个时使用R7,两个时使用R7和R5,三个时就使用R7、R5及R3。同样的,IAR主要采用R1、R2、R3、R4、R5来进行u8型参数的传递。
紧接着是u16,KeilC主要采用R6:R7、R4:R5、R2:R3来进行传入,而IAR采用R3:R2、R5:R4来进行传入。
再接着就是u32,KeilC主要采用R4:R7来进行传入,IAR采用R5:R2来进行传入。
最后,KeilC还支持一种叫做通用数据指针的数据类型。主要采用R2:R1、R3来传入。其中,R2:R1存储指针地址,R3存储内存类型。

然后再说说返回值。
返回值为bit时,KeilC与IAR都用C来传出。
返回值为u8时,Keil采用R7,而IAR采用R1。
返回值为u16时,Keil采用R6:R7,而IAR采用R3:R2。
返回值为u32时,Keil采用R4:R7,而IAR采用R5:R2。

下面是Hanny的个人小结:
KeilC的函数传入传出都是秉承KeilC的大端思想,主要用到的寄存器为R7-R2;IAR的函数传入传出是秉承小端思想,主要用到的寄存器为R1-R5。
KeilC函数参数传递的优点是:在从u8向u16、u32扩展时,由于低位所处的寄存器位置不变,扩展时对代码的修改较小。
IAR的优点是:在传入的参数位数为u8时,更紧凑的方式能够传入更多的参数。

相比之下,Hanny更喜欢KeilC这种方式。

  • 14
  • 7月

上一篇中,主要介绍了Typecho插件的基本结构,这一篇,将以HelloWorld为例,来介绍一下插件的基本实现。

在看这个例子之前,我们还需要稍微了解一下几个小规则。

一个就是Typecho类的命名规规。Typecho类的命名是直接与类的存放位置相挂钩的,存放在var的目录下。比如说,Typecho_Plugin_Interface,就是存放在var/Typecho/Plugin目录下的Interface.php文件。再比如说:Typecho_Widget_Helper_Form_Element_Text 就是存放在var/Typecho/Widget/Helper/Form/Element/Text.php 中。明白了这一点,我们就可以通过参考其它插件,直接找到对应的源文件,来弄清里面的接口。

第二个需要弄明白的就是,明白Typecho哪里可以插,需要怎么插。Typecho的程序中预留了很多可以被插的接口。在Widget中,我们可以看到很多pluginHandle这样的地方;在admin下,我们可以看到Typecho_Plugin::factory这样的地方。这些,都是可以被插的。对这些函数指针重新赋值,则会在对应的位置被调用。

回到我们的HelloWorld插件,
Typecho_Plugin::factory('admin/menu.php')->navBar = array('HelloWorld_Plugin', 'render');

这句话告诉我们,在admin/menu.php目录下,有一个叫navBar的函数指针,将被定位到HelloWord_Plugin类的render函数下。而render函数又做了什么呢?我们接着看:
public static function render()
    {
        echo '<span class="message success">' . Typecho_Widget::widget('Widget_Options')->plugin('HelloWorld')->word . '</span>';
    }

Typecho_Widget::widget('Widget_Options')->plugin('HelloWorld')->word 是配置里填写的字段的内容。
先不理会这个Option的作用,我们可以看到,大概是输出了一段HTML,其实就是输出了在配置里真写的字段的内容。

我们再打开admin/menu.php这个文件
<p class="operate"><?php Typecho_Plugin::factory('admin/menu.php')->navBar(); _e('欢迎'); ?>, <a href="<?php $options->adminUrl('profile.php'); ?>" class="author important"><?php $user->screenName(); ?></a>
其实,就是管理页面右上角内容的输出。

如果这里的navBar被指到了render,也就是说,在输出欢迎之前,通过调用render输出了配置里填写的字段。

讲到这里,差不多也明白这个插件的用途了。