• 3
  • 11月

openrisc,或者说mips吧,跳转指令会有一个延迟槽。

首先,Hanny可能先需要解释一下什么是延迟槽。我们知道,CPU指令在执行跳转指令时,一般是会清空流水线的。这样,就会造成几个指令周期的浪费。具体浪费周期数取决于流水线的级数。

而延迟槽的作用呢,则是在执行完跳转指令,并执行跳转指令的下一条指令后,才会真正地跳转至目标PC。因此,延迟槽在一定程度上,能够提高CPU的效率。

有的时候,可能不想去利用延迟槽,在GCC的编译选项中增加

-fno-delayed-branch

这样,在编译过程中的跳转,都会在延迟槽中填入nop指令。缺点就是有点浪费程序空间了。

  • 3
  • 11月

最近使用GCC时,老是提示一个错误:
/cygdrive/xx/..\xxx/xxxx.c:118: multiple definition of `xxxx'<br />
xxx/xxxx.o:/cygdrive/xx/..\xxx/xxxx.c:118: first defined here


大概意思就是,有一个函数重定义了!
可是在整个程序中,我并没有去重定义这个函数啊!

最后,经过Hanny的一番查找,原来是斜杆和反斜杆惹的祸!

我们知道,Windows是比较喜欢用反斜杆的,而Linux却钟情于斜杆。

由于在GCC的Makefile中使用了反斜杆的路径,而在linker文件中却使用了斜杆路径,这样,链接器就认为是两个不同路径了。同一个文件也就链接了两次,造成了重定义的发生。

解决方法就是,统一使用斜杆或反斜杆就行了。而Hanny比较推荐斜杆。

  • 29
  • 9月

IAR对局部部变量,一般是采取虚拟寄存器的方式来进行访问。如果是外部堆栈的话,有时它会将SPH,SP的值赋至DPTR中,然后使用DPTR来对堆栈进行操作。

然而,除了将SPH和SP的值赋至DPTR外,它还会做一些动作。

ANL    A,#0x03         ; Maks out relevant ESP bits.<br />
ORL     A,#(HIGH(sfb(EXT_STACK)) & 0xFC)<br />
MOV    DPH,A


其实就是会将堆栈的高6BIT地址强制不可改。具体作用暂时不明。

不过,如果有做一些多BIN的工程时,可就要小心了,需要保证堆栈的高6BIT地址不变,否则可能出一些不可预料的错误。

  • 29
  • 6月

想用IAR的C语言来该问一下LONG型变量的4个Byte,版本是IAR720H的。

最初,按照最直观的写法,用这种方法来进行访问:
(unsigned char)(num)<br />
(unsigned char)(num>>8)<br />
(unsigned char)(num>>16)<br />
(unsigned char)(num>>24)


编译,查看lst文件。what??这是什么呀!!
居然出现了?UL_SHR。
你还真去右移了呢?

接下来,换用第二种方式:
((unsigned char *)&num)[0]<br />
((unsigned char *)&num)[1]<br />
((unsigned char *)&num)[2]<br />
((unsigned char *)&num)[3]


这下,问题更大了。
什么DPTR都来了。这个更夸张。

差点都想自己写汇编算了。

最后经过了许多实验,总算把方法试出来了。

可以定义以下的宏:
#define     BYTE0(n)            ((unsigned char)(n))<br />
#define     BYTE1(n)            ((unsigned char)((n)>>8))<br />
#define     BYTE2(n)            ((unsigned char)(((unsigned short)((n)>>8))>>8))<br />
#define     BYTE3(n)            ((unsigned char)(((unsigned short)((n)>>16))>>8))


以后就可以直接用BYTE0 ~ BYTE3来进行LONG型变量的按BYTE来访问了。

  • 11
  • 2月

USB在通信过程中,有DataToggle这么一个概念。

例如,在一次通信中,主机如果需要接收一个数据包,那么,主机会先发送一个IN的令牌包,然后从机发送数据包,然后主机再发送ACK握手包进行确认,这就完成了一次数据的接收。

假如出现通信错误,掉包的情况,那么又如何处理呢?

第一步,假如是令牌包IN发生了通信错误,那么主机则不会发送数据包。主机可以再次发送令牌包IN来让从机发送数据包。

第二步,假如是数据包发生了错误,那么主机收不到数据,则不会发出ACK信号,而再次发送IN;而从机由于没有收到ACK,则得知数据包出错,可以再次发送该数据包。

现在问题来了,假如是ACK信号出错,主机已经成功接收到数据,认为通信完成。由于从机并没有接收到ACK信号,还认为数据出错,继续准备上一包数据,此时岂不是要不同步了?

这个时候,DataToggle就派上用场了。DataToggle要求数据包前加DATA0和DATA1标识,并且要求每成功完成一次通信后,对DATA标识进行切换,这样,主机在下一次的IN包中,就可能通过DATA的标识来判断从机是否成功地完成上一次数据通信了。

DataToggle在USB Reset阶段是要清为0的,而今天就发现了一个错误,不幸在GetMaxLun和ClassReset这两条命令中对DataToggle进行了清零操作,造成了USB的通信过程中,发送这两条命令则有可能通信失败。

特记录一下:在A1 FE和21 FF这两条类命令中,是不需要对Bulk的DataToggle进行清零操作的。