zoukankan      html  css  js  c++  java
  • delay timer的wrap around

    TF-A链接:
     
    在阅读TF-A源代码时,看到其udelay是实现如下:
     
    /***********************************************************
     * Delay for the given number of microseconds. The driver must
     * be initialized before calling this function.
     ***********************************************************/
    void udelay(uint32_t usec)
    {
        assert((timer_ops != NULL) &&
            (timer_ops->clk_mult != 0U) &&
            (timer_ops->clk_div != 0U) &&
            (timer_ops->get_timer_value != NULL));
    
        uint32_t start, delta, total_delta;
    
        assert(usec < (UINT32_MAX / timer_ops->clk_div));
    
        start = timer_ops->get_timer_value();
    
        /* Add an extra tick to avoid delaying less than requested. */
        total_delta =
            div_round_up(usec * timer_ops->clk_div,
                            timer_ops->clk_mult) + 1U;
    
        do {
            /*
             * If the timer value wraps around, the subtraction will
             * overflow and it will still give the correct result.
             */
            delta = start - timer_ops->get_timer_value(); /* Decreasing counter */
    
        } while (delta < total_delta);
    }
     
    第16行的get_timer_value返回的是一个从0xFFFFFFFF到0的递减的数,减到0后,再往下减的话,会重新变成0xFFFFFFFF。
    其中第25到26行注释说即使发生了wraps around,也可以保证delta的值是正确的。下面我们看看是什么原理。
    为此,下面是一个简单的模拟程序,看看发生wraps around后,两个数字相减的结果,假设下面的a,b,c的范围都是从0到0xFF,a表示第一次读到的数,b表示第二次读到的数。
     
    #include <stdio.h>
    
    int main(int argc, const char *argv[])
    {
            unsigned char a, b, c;
    
            a = 0x20;
            b = 0x00;
            c = a - b;
            printf("a(0x%x) - b(0x%x) = %x
    ", a, b, c);
    
            a = 0x00;
            b = 0xE0;
            c = a - b;
            printf("a(0x%x) - b(0x%x) = %x
    ", a, b, c);
    
            a = 0x00;
            b = 0x20;
            c = a - b;
            printf("a(0x%x) - b(0x%x) = %x
    ", a, b, c);
    
            a = 0xF0;
            b = 0x10;
            c = a - b;
            printf("a(0x%x) - b(0x%x) = %x
    ", a, b, c);
    
            return 0;
    }
     
    下面是运行结果:
    a(0x20) - b(0x0) = 20
    a(0x0) - b(0xe0) = 20
    a(0x0) - b(0x20) = e0
    a(0xf0) - b(0x10) = e0

    可以看到,如果是以无符号数输出的话,上面的大数减小数和小数减大数的结果是一样的。

    原因是负数在计算机中是以补码的形式存放,关于补码的介绍可以参考:https://baike.baidu.com/item/%E8%A1%A5%E7%A0%81/6854613?fr=aladdin
     
    可以直观的理解,在模为10的情况下,一个数加上A,跟减去(10-A)的结果一样:比如 (3 + 8)%10 = 1,而(3-(10-8))%10 = 1,二者一样。
     
    或者可以手动计算一下:0 - 0xe0,理论上应该等于-0xe0,那么这个数字在计算机中如何表示呢?也就是-0xe0的补码是多少?根据负数求补码的方法,其绝对值各位取反然后再加1:
    -0xe0 --> 0xe(绝对值) --> 0b11100000(二进制表示) --> 0b00011111(取反) --> 0b00100000(加一) --> 0x20,即在模为0x100的情况下,-0xe0跟0x20是一回事。
     
    完。
  • 相关阅读:
    安装python包的两种方法
    Oracle 查询当前用户下的所有表
    Oracle SQL存储过程结构、异常处理示例
    Oracle IF-ELSE条件判断结构
    Oracle 组函数count()
    从svn下载项目后出现 Error:java: Compilation failed: internaljava compiler error 解决办法
    当学习失去方向,开始荒废时光时
    给自己一个目标
    汇编环境搭建在Linux下
    汇编学习总结
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/10990747.html
Copyright © 2011-2022 走看看