Archives

Archive for November, 2008

在u-boot中,采用函数udelay来进行延时。这是一个单纯等待的算法。在beagle board的u-boot中,udelay会不断去读OMAP general purpose timer的count值,然后根据general purpose timer的输入时钟来得到已经经过的时间。
在u-boot中,gp timer2的输入时钟为系统时钟,beagle board中为13MHZ。并且时钟经过了256分频。因此,每一秒钟的时间,gp timer2的count的值会增加1*(13MHZ/256)。
对于qemu来说,必须要保证当u-boot去读gptimer寄存器值的时候,返回的count值是正确的。也就是说,必须是实际经过的时间*13MHZ/256。
在qemu中,ticks_per_sec的值为1000000000。函数qemu_get_clock可以得到当前时间的ticks。因此,当u-boot来读gptimer寄存器值的时候,返回的count值应该为:

(qemu_get_clock/ticks_per_sec)*(13MHZ/256)

也就是

(qemu_get_clock*13MHZ)/(ticks_per_sec*256)

见函数omap_gp_timer_read

distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);

这里,timer->ticks_per_sec= ticks_per_sec*256。
可是问题的关键在于,函数muldiv64的原型为

/* compute with 96 bit intermediate result: (a*b)/c */
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)

也就是说,参数b和c都是32bit的。而timer->ticks_per_sec已经超过了32bit。导致distance的计算出错,后果是u-boot中的延时函数是不准的。
解决方法:
首先判断一下ticks_per_secis有没有超过32bit,然后根据情况分别计算。

/*if ticks_per_secis bigger than 32bit, we can not use muldiv64 anymore!*/
if (timer->ticks_per_sec>0xffffffff){
distance = distance/(ticks_per_sec/1000); /*distance ms*/
rate = timer->rate >> (timer->pre ? timer->ptv [...]

Nov 28th, 2008 | Filed under OMAP, emulation

经过几天的debug,在很多地方加入 判断是否有SIG pending的语句,结果都是没有信号pending。那么唯一的可能就根本没有产生SIGALRM信号! 继续追踪。Qemu中提供了很多中定时器的实现方法,见数组alarm_timers。

1: static struct qemu_alarm_timer alarm_timers[] = {

2: #ifndef _WIN32

3: #ifdef __linux__

4: {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer,

5: dynticks_stop_timer, dynticks_rearm_timer, NULL},

6: /* HPET - if available - is preferred */

7: {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL},

8: [...]

Nov 25th, 2008 | Filed under OMAP, emulation

那在qemu中,有一个gui timer会定时刷新gui的信息。现在gui的tile没有变化,就说明这个gui timer 根本没有被触发。
而在qemu中的定时器是通过函数host_alarm_handler来触发运行的,函数host_alarm_handler又是通过信号来进行触发的。那么问题的根源就是信号没有被发送或者被block(还没有查出具体原因)。
我尝试在终端中向qemu发生SIGALRM信号,果然,qemu接收到SIGALRM信号后,执行host_alarm_handler然后会执行所有注册了的定时器的超时函数(包括display_state.gui_timer)。
kill-bill: # ps aux | grep qemu
root      2945  101  3.2 196468  8404 pts/1    R+   09:36   0:14 ./qemu-system-arm -M beagle -mtdblock beagle-nand.bin
root      2947  0.0  0.2   2996   692 pts/0    R+   09:36   0:00 grep qemu
kill-bill: # kill -s SIGALRM 2945

多次发送SIGALRM信号后,qemu可以正常接受终端的输入。下面是qemu运行u-boot的截图。

接下来就需要查找为什么qemu没有收到SIGALRM!

Nov 18th, 2008 | Filed under OMAP, emulation

x-load 已经可以在qemu-omap3中运行起来。对x-load主要做了两个地方的修改:
1. 对判断外部输入时钟频率的部分,做了修改。x-load判断外部时钟频率的方法是先设置32KHZ的基准时钟,然后设置GP1的时钟源为SYS_CLK。然后读取GP1 Timer在20个cycle内的差值,进而判断时钟。这个方法在emulator中有的时候并不是很准。因为emulator除了执行指令外,还需要做其他事情。有的时候,emulator去读取GP1 Timer 的时候,实际上运行的时间已经不止ARM 20个cycle的时间,因此读取出来的counter值偏大。而x-load仍然认为刚才是跑了20个cycle。因此,得到的频率比实际的频率大。在 qemu-omap3中,目前认为外部时钟的频率是12MHZ13MHZ,因此,去掉了x-load中判断外部时钟频率的部分,在x-load中直接赋值外部时钟频率12MHZ13MHZ.
2. 去掉了nand flash中进入ECC检查的部分。也就是注释掉drivers/k9f1g08r0a.c中的宏ECC_CKECK_ENABLE

//57 #define ECC_CHECK_ENABLE

 

下面是x-load运行的信息:

 

# ./qemu-system-arm -M beagle -mtdblock beagle-nand.bin -serial stdio -nographic

Texas Instruments X-Loader 1.41

Starting OS Bootloader...

 

运行到u-boot的时候还有点问题。go on working.

Nov 15th, 2008 | Filed under OMAP, emulation

ARM和MIPS都是Load-store结构,也就是说CPU只处理寄存器中的数据,而不会直接去处理memory中的数据。要想处理memory中的数据,必须先把memory中的数据load到寄存器中。
那如何load一个32bit的立即数到寄存器中呢?我们知道,ARM和MIPS的指令长度都是32bit,也就是说,不可能用一条指令来直接load一个32bit数据到寄存器中(如果可以的话,数据占了32bit,指令该如何编码?)
ARM中采用了ldr指令来实现这个功能。

LDR {cond} <Rd>,<addressing mode>

ldr 指令将一个memory中的数据load到寄存器Rd中。因此,如果需要load一个32bit立即数的话,先在memory中存放这个数据,然后调用 ldr指令来load这个数据到寄存器中。参考下面的代码中Line3。为了load 0x49020000到r0中,先在地址0x40202428中存入这个立即数,然后在调用ldr将这个数load到寄存器中。

1: 40202418 <serial_getc>:

2: 40202418: e52de004 push {lr} ; (str lr, [sp, #-4]!)

3: 4020241c: e59f0004 ldr r0, [pc, #4] ; 40202428 <serial_getc+0x10>

4: 40202420: eb000042 bl 40202530 <NS16550_getc>

5: 40202424: e49df004 pop [...]

Nov 8th, 2008 | Filed under ARM/MIPS