delay timer的wrap around
阅读原文时间:2023年07月15日阅读:2

span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }.cm-searching {background: #ffa; background: rgba(255, 255, 0, .4);}.cm-force-border { padding-right: .1px; }@media print { .CodeMirror div.CodeMirror-cursors {visibility: hidden;}}.cm-tab-wrap-hack:after { content: ""; }span.CodeMirror-selectedtext { background: none; }.CodeMirror-activeline-background, .CodeMirror-selected {transition: visibility 0ms 100ms;}.CodeMirror-blur .CodeMirror-activeline-background, .CodeMirror-blur .CodeMirror-selected {visibility:hidden;}.CodeMirror-blur .CodeMirror-matchingbracket {color:inherit !important;outline:none !important;text-decoration:none !important;}.CodeMirror-sizer {min-height:auto !important;}
-->
span::selection, .cm-s-base16-light .CodeMirror-line > span > span::selection { background: #e0e0e0; }.cm-s-base16-light .CodeMirror-line::-moz-selection, .cm-s-base16-light .CodeMirror-line > span::-moz-selection, .cm-s-base16-light .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; }.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; }.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; }.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; }.cm-s-base16-light .CodeMirror-linenumber { color: #b0b0b0; }.cm-s-base16-light .CodeMirror-cursor { border-left: 1px solid #505050; }.cm-s-base16-light span.cm-comment { color: #8f5536; }.cm-s-base16-light span.cm-atom { color: #aa759f; }.cm-s-base16-light span.cm-number { color: #aa759f; }.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #90a959; }.cm-s-base16-light span.cm-keyword { color: #ac4142; }.cm-s-base16-light span.cm-string { color: #f4bf75; }.cm-s-base16-light span.cm-variable { color: #90a959; }.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; }.cm-s-base16-light span.cm-def { color: #d28445; }.cm-s-base16-light span.cm-bracket { color: #202020; }.cm-s-base16-light span.cm-tag { color: #ac4142; }.cm-s-base16-light span.cm-link { color: #aa759f; }.cm-s-base16-light span.cm-error { background: #ac4142; color: #505050; }.cm-s-base16-light .CodeMirror-activeline-background { background: #DDDCDC; }.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }
-->
li {list-style-type:decimal;}.wiz-editor-body ol.wiz-list-level2 > li {list-style-type:lower-latin;}.wiz-editor-body ol.wiz-list-level3 > li {list-style-type:lower-roman;}.wiz-editor-body li.wiz-list-align-style {list-style-position: inside; margin-left: -1em;}.wiz-editor-body blockquote {padding: 0 12px;}.wiz-editor-body blockquote > :first-child {margin-top:0;}.wiz-editor-body blockquote > :last-child {margin-bottom:0;}.wiz-editor-body img {border:0;max-width:100%;height:auto !important;margin:2px 0;}.wiz-editor-body table {border-collapse:collapse;border:1px solid #bbbbbb;}.wiz-editor-body td,.wiz-editor-body th {padding:4px 8px;border-collapse:collapse;border:1px solid #bbbbbb;min-height:28px;word-break:break-word;box-sizing: border-box;}.wiz-editor-body td > div:first-child {margin-top:0;}.wiz-editor-body td > div:last-child {margin-bottom:0;}.wiz-editor-body img.wiz-svg-image {box-shadow:1px 1px 4px #E8E8E8;}.wiz-hide {display:none !important;}
-->

TF-A链接:

https://github.com/ARM-software/arm-trusted-firmware

在阅读TF-A源代码时,看到其udelay是实现如下:

https://github.com/ARM-software/arm-trusted-firmware/blob/master/drivers/delay_timer/delay_timer.c

/***********************************************************
* 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

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\\n", a, b, c);

    a = 0x00;  
    b = 0xE0;  
    c = a - b;  
    printf("a(0x%x) - b(0x%x) = %x\\n", a, b, c);

    a = 0x00;  
    b = 0x20;  
    c = a - b;  
    printf("a(0x%x) - b(0x%x) = %x\\n", a, b, c);

    a = 0xF0;  
    b = 0x10;  
    c = a - b;  
    printf("a(0x%x) - b(0x%x) = %x\\n", a, b, c);

    return ;  

}

下面是运行结果:

a(0x20) - b(0x0) =
a(0x0) - b(0xe0) =
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是一回事。

完。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器