【UCOSIII源码阅读笔记】第二篇

前言

本文主要分析ucosiii中管理优先级表的os_prio.c文件。
在这里插入图片描述

正文

优先级表中每一个bit表示一个优先级,优先级表中某一个bit置位表示该优先级有就绪态的任务等待运行。其定义如下:

CPU_DATA   OSPrioTbl[OS_PRIO_TBL_SIZE];

其中CPU_DATAunsigned int类型数据;OS_PRIO_TBL_SIZE定义为

#define  OS_PRIO_TBL_SIZE          ((OS_CFG_PRIO_MAX - 1u) / (DEF_INT_CPU_NBR_BITS) + 1u)

也就是1,所以优先级表翻译过来就是:

unsigned int OSPrioTbl[1];

一个32位无符号的变量,它表示32个优先级。
优先级表相关的函数都在os_prio.c文件中,包括:
OS_PrioInit()初始化优先级列表(把OSPrioTbl清零)。
OS_PrioInsert()把优先级表中的某一位置位。
OS_PrioRemove()把优先级表中的某一位清零。
OS_PrioGetHighest()根据优先级表查找最高优先级。

接下来重点分析OS_PrioGetHighest(),其代码内容为:

OS_PRIO  OS_PrioGetHighest (void)
{
    CPU_DATA  *p_tbl;
    OS_PRIO    prio;


    prio  = (OS_PRIO)0;
    p_tbl = &OSPrioTbl[0]; //获取优先级表的首地址
    while (*p_tbl == (CPU_DATA)0) {   //32位的遍历  找到不为0的32位    /* Search the bitmap table for the highest priority       */
        prio += DEF_INT_CPU_NBR_BITS;                       /* Compute the step of each CPU_DATA entry                */
        p_tbl++;
    }
    prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl);  //计算前导0,如果汇编没有   就用二分查找法            /* Find the position of the first bit set at the entry    */
    return (prio);
}

比如优先级表二进制形式为10000000 00000000 00000000 00000000b那么OS_PrioGetHighest()函数返回的优先级数为0,
10010100 01000000 00000000 00000000b返回也是0
01010100 01000000 00000000 00000000b返回1
也就是返回第一个被置位的bit的位置。
其中调用的CPU_CntLeadZeros()函数用于快速找出32位变量中第一个被置位的bit位置。
为了提高查询速度,CPU_CntLeadZeros()用到了二分查找法哈希表算法
其代码如下:

CPU_DATA  CPU_CntLeadZeros (CPU_INT32U  val)
{                                                                      
	if (val > 0x0000FFFFu) {
	    if (val > 0x00FFFFFFu) {                                                
	        ix             = (CPU_DATA)(val >> 24u);                            
	        nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix] +  0u);        
	
	    } else {                                                                
	        ix             = (CPU_DATA)(val >> 16u);                            
	        nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix] +  8u);      
	    }
	
	} else {
	    if (val > 0x000000FFu) {                                                
	        ix             = (CPU_DATA)(val >>  8u);                            
	        nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix] + 16u);         
	    } else {                                                                
	        ix             = (CPU_DATA)(val >>  0u);                            
	        nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix] + 24u);         
	    }
	}
	return (nbr_lead_zeros);
}

首先判断val是否大于0x0000FFFFu,如果大于,那么第一个被置位的bit一定在前16位,后16位就不用再找了;
然后再判断val是否大于0x00FFFFFFu,如果大于,那么第一个被置位的bit一定在前16位中的前8位,前16位中的后8位就不用再找了。
第一个被置位的bit的位置也叫前导零,。
通过这段代码,只需要两个if判断就确定下来第一个被置位的bit在32位中的哪8位,确定是哪8位之后,接下来用哈希表法判断这8位中第一个被置位的bit是哪一位,实现方法简单粗暴,因为8位数据中每一位01的排列组合一共就只有256中情况,而每种情况的前导零是固定的,所以UCOS中干脆用一个数据把他们列举了出来。如下:

static  const  CPU_INT08U  CPU_CntLeadZerosTbl[256] = {                             /* Data vals :                      */
/*   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F   */
    8u,  7u,  6u,  6u,  5u,  5u,  5u,  5u,  4u,  4u,  4u,  4u,  4u,  4u,  4u,  4u,  /*   0x00 to 0x0F                   */
    3u,  3u,  3u,  3u,  3u,  3u,  3u,  3u,  3u,  3u,  3u,  3u,  3u,  3u,  3u,  3u,  /*   0x10 to 0x1F                   */
    2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  /*   0x20 to 0x2F                   */
    2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  2u,  /*   0x30 to 0x3F                   */
    1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  /*   0x40 to 0x4F                   */
    1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  /*   0x50 to 0x5F                   */
    1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  /*   0x60 to 0x6F                   */
    1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  1u,  /*   0x70 to 0x7F                   */
    0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  /*   0x80 to 0x8F                   */
    0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  /*   0x90 to 0x9F                   */
    0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  /*   0xA0 to 0xAF                   */
    0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  /*   0xB0 to 0xBF                   */
    0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  /*   0xC0 to 0xCF                   */
    0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  /*   0xD0 to 0xDF                   */
    0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  /*   0xE0 to 0xEF                   */
    0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u   /*   0xF0 to 0xFF                   */
};

比如:如果想知道00000001b的前导零,00000001b1,CPU_CntLeadZerosTbl[1]为7,所以00000001b的前导零是7,
再比如:0x14二进制形式为00010100b,十进制为20,CPU_CntLeadZerosTbl[20]为3,所以0x14的前导零就是3。

通过以上方式,只需要两个if判断和一次数组调用就找到了32位变量中第一个被置位bit的位置。

后记

如果有对位图操作的需求,可以模仿os_prio.c文件中的内容进行代码编写。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值