软件和硬件的快慢

随着CPU越来越快,以及多级流水线的架构设计,在软件编程上有一些新的注意需要引起我们的重视。
最近正好碰到这个方面的问题,引发了一些讨论和思考,和大家分享一下。
首先说CPU和外设之间。因为总线上的一些delay,所以当我们对外设寄存器进行设置之后,外设按照最新的设置需要进行一些动作和变化。这些动作和变化需要一些时间,可是软件已经足够快了,在这些动作还没有开始之前,软件又要来访问了。
此时,看硬件是怎么做的。
1 硬件足够聪明。发现自己还没有生效呢,把软件的这次请求hold住,等生效了,再给生效后新的值。
2 硬件比较傻。软件请求就把没生效前的设置就傻乎乎的给拿走了。
3 硬件提供了一些手段供SW来用。比如提供一个状态寄存器的一个bit位来表示是否生效。

如以我遇到的问题为例:
下面是某外设的自动测试函数。单独的写操作和读操作都验证过OK。结果发现在这里读操作出现问题。
测试函数()
{
HW写操作;
HW读操作;
对比读写数据;
}
经过分析,发现只要中间有一点delay,读操作就OK。检查HW的手册,发现的确写操作需要占用一定的时间。幸好,该HW属于上述的类型3,我还是有手段可以得知HW是否准备好了。更改新的流程如下:
==>
测试函数()
{
HW写操作;
等待HW写操作ready
HW读操作;
对比读写数据;
}
当然,这样还不行。这里,实际上是写操作函数的事情没做到,所以还要把这个动作放到写函数后面去。
==>
HW写操作()
{
....
等待HW写操作ready
return;
}

如果万一是HW类型2,怎么办呢?我觉得SW还是可以不断polling该寄存器是否更改来做的啦。
----------------------------------------------------------------------------------
另外,现在的CPU内部都采用了X级流水线架构,你上面代码刚跑完,下面就马上开始跑。如果大家都是对RAM操作,没有问题。但是如果是对HW的话,由于HW天生的反应能力不同,可能在运行时的先后顺序与代码的顺序并不一致了。所以为了保证我们的HW能乖乖的按我们的代码顺序跑,还是需要做一些小技巧的改变。
常见的保证CPU内部寄存器数据一定读写的办法是,写完对该寄存器之后,需要再读它一下。如下面宏所示:
#define IT_MUST_BE_COMPLETED(reg)   \
{         \
 volatile unsigned U32 tmp; \
 tmp=*((unsigned U32*)(reg)); \
 tmp>1?1:0;      \
}

使用如下:
REG_XXX= 0xFFFF;
IT_MUST_BE_COMPLETED(REG_XXX);

如果是在汇编中,就是在str之后,要ldr一下。
str         r1,         [r0]
ldr         r1,         [r0]


posted on 2008-03-18 16:33  Titan  阅读(656)  评论(0编辑  收藏  举报

导航