Timer QEMU ARM versatilepb平台上与SP804双定时器模块的IRQ频率不一致

Timer QEMU ARM versatilepb平台上与SP804双定时器模块的IRQ频率不一致,timer,arm,qemu,Timer,Arm,Qemu,我用QEMU在ARM平台上编写了一个裸机定时器程序。平台是versatilepb。计时器是自动的 SP804提供2个定时器模块。每个模块提供2个定时器。因此总共有4个计时器,即计时器0、1、2、3 计时器0/1共享IRQ 4 定时器2/3共享IRQ 5 我注意到,如果我启动一个单个计时器,或者从不同的计时器模块启动两个计时器,比如0/2或1/3。中断频率非常正常 但是如果我从相同的计时器模块启动两个计时器,比如0/1或2/3。中断频率要高得多 当我从同一个定时器模块启动两个定时器时,我启动的第一

我用QEMU在ARM平台上编写了一个裸机定时器程序。平台是
versatilepb
。计时器是自动的

SP804
提供2个定时器模块。每个模块提供2个定时器。因此总共有4个计时器,即
计时器0、1、2、3

计时器0/1共享IRQ 4

定时器2/3共享IRQ 5

我注意到,如果我启动一个单个计时器,或者从不同的计时器模块启动两个计时器,比如0/2或1/3。中断频率非常正常

但是如果我从相同的计时器模块启动两个计时器,比如0/1或2/3。中断频率要高得多

当我从同一个定时器模块启动两个定时器时,我启动的第一个定时器的IRQ频率比第二个定时器的IRQ频率高得多,而后者的IRQ频率似乎正常

下面是我的一些IRQ处理程序代码:

void IRQ_handler()
{
    u32 vicstatus = VIC_STATUS;

    // VIC status BITs: timer0,1=4, timer2,3=5
    if (vicstatus & (1<<4))
    {// bit4=1:timer0,1, handle timer 0 and 1 one by one
        if (*(timer[0].base + TVALUE) == 0) // timer 0
            timer_handler(0);
        if (*(timer[1].base + TVALUE) == 0) // timer 1
            timer_handler(1);
    }
    if (vicstatus & (1<<5))
    {// bit5=1:timer2,3, handle timer 2 and 3 one by one
        if (*(timer[2].base + TVALUE) == 0) // timer 2
            timer_handler(2);
        if (*(timer[3].base + TVALUE) == 0) // timer 3
            timer_handler(3);
    }
}



void timer_handler(u32 n)
{
    TIMER *t = &timer[n];
    t->tick++; // Assume 20 ticks per second. Need to calculate it for more accuracy.
    if (t->tick == 20)
    {
        t->tick = 0;
        t->ss++;
        if (t->ss == 60)
        {
            t->ss = 0;
            t->mm++;
            if (t->mm == 60)
            {
                t->mm = 0;
                t->hh++; // no 24 hour roll around
            }
        }
        t->clock[7] = '0' + (t->ss % 10);
        t->clock[6] = '0' + (t->ss / 10);
        t->clock[4] = '0' + (t->mm % 10);
        t->clock[3] = '0' + (t->mm / 10);
        t->clock[1] = '0' + (t->hh % 10);
        t->clock[0] = '0' + (t->hh / 10);

        kprintf("Timer [%d]: %s\n", n, (u8 *)&t->clock[0]);
    }
    timer_clearInterrupt(n); // clear timer interrupt
}
以下是从同一定时器模块启动定时器2/3的屏幕截图:


IRQ\u处理程序使用
当前值寄存器
来检测哪个计时器导致了中断,它看起来不正确。这里有一个
屏蔽中断状态寄存器
,显然就是为了这个,我建议改用它。除了检查IRQ源外,还必须保护通过写入
中断清除寄存器
来记录检查结果和清除IRQ,以防止重入,否则单定时器IRQ仍可能被计数多次


我的猜测是,观察到最初的问题是因为计时器IRQ是由其他东西触发的,或者当计时器计数器为零时,为其他IRQ调用IRQ\U处理程序。

我认为这些模拟器不应该是周期精确的,它们显然不能使处理器或存储/内存系统周期精确,我知道uart发送器不是周期精确的,我也不希望定时器是周期精确的。你检测哪个定时器是IRQ_处理器中断源的方法在我看来并不可靠。这里有一个屏蔽的中断状态寄存器,显然就是为了这个,我建议用它来代替。此外,代码不完整,因此不清楚如何设置计时器。如果您为这个问题提供了一个自给自足的复制机,那就容易多了。@jcmvbkbc谢谢。稍后我将提供更多详细信息。@jcmvbkbc它现在与
屏蔽中断状态寄存器一起工作。如果你将你的评论作为答案发表,我将荣幸地将其标记为答案。我仍然想知道为什么
当前值寄存器
不工作。虽然看起来很自然。。。
void IRQ_handler()
{
    u32 vicstatus = VIC_STATUS;

    //UART 0
    if (vicstatus & UART0_IRQ_VIC_BIT)
    {
        uart_handler(&uart[0]);
    }

    //UART 1
    if (vicstatus & UART1_IRQ_VIC_BIT)
    {
        uart_handler(&uart[1]);
    }

    // VIC status BITs: timer0,1=4, uart0=13, uart1=14
    if (vicstatus & TIMER01_IRQ_VIC_BIT)
    {// bit4=1:timer0,1, handle timer 0 and 1 one by one
        if (*(timer[0].base + TMIS) == 1) // timer 0 <===== HERE changed to use TMIS
            timer_handler(0);
        if (*(timer[1].base + TMIS) == 1) // timer 1 <===== HERE changed to use TMIS
            timer_handler(1);
    }
    if (vicstatus & TIMER23_IRQ_VIC_BIT)
    {// bit5=1:timer2,3, handle timer 2 and 3 one by one
        if (*(timer[2].base + TMIS) == 1) // timer 2 <===== HERE changed to use TMIS
            timer_handler(2);
        if (*(timer[3].base + TMIS) == 1) // timer 3 <===== HERE changed to use TMIS
            timer_handler(3);
    }
}