Friday, May 01, 2009

悼念

从未想到在我认识的人里有走得这么早的,惊闻一师兄杨志高在学校自杀,不由得悗惜。你让老师们如此钟爱,你的论文又让我们那样地景仰,你的人生为何却又如此短暂。
曾有一句话很认同,完美主义者等于失败者,真的没有事情可以做到完美。
愿你一路走好。

Thursday, January 01, 2009

知识管理的原则

寻找PKM时,看到这样一个贴子,感觉有一些原则比较有启发作用,其实重要的是方法,其次是合适的工具。所谓原则,对不同人来说也不是绝对,适合自己的就好。

个人知识管理的29个原则(转)
1、持续的学习成为个人生存和发展的基础。持续学习不一定能带来成功,但不学习一定失败; 
2、信息和知识爆炸,在一段时间和时期内,学习的内容必须聚焦。起码要在一个领域内成为专家。 
3、你应该学习的内容取决于你的价值观、特长、个性和目标。 
4、你必须学会如何有效的评估信息和知识,所以你必须根据你的价值观、特长、个性和目标确立自己对信息和知识的“过滤器”; 
5、人是知识获取的重要渠道,所以你应该知道谁最擅长什么?遇到问题时知道可以向谁学习和请教; 
6、你牛了你的朋友也一定牛,建立人际资源的基础是自己的知识基础、个性和激情、自己优势的合理展示和帮助别人的意愿; 
7、人际关系需要维护;捷径是找到那些愿意共享自己朋友资源的人,你也应该做这样的人; 
8、信息如果不经过处理,不能称为知识。所以你存储的知识起码你应该简单看过、知道是在讲什么; 
9、信息和知识存储前应该尽可能做规范化的工作,例如你做的摘要、感触、觉得最有价值的部分、将来能做什么用等等; 
10、建立自己的分类字典,而不是每次想起什么就建立什么样的文件夹或者标签。分类字典,持之以恒坚持,适当调整; 
11、知识存储中分类不宜过宽,过宽则等于没有分类;分类不宜过深,过深后你就不会再去看; 
12、充分利用各种工具,尤其是web2.0工具做知识存储和获取工作; 
13、知识存储时适当共享,听取和收集别人的意见和建议; 
14、有意识的做知识显性化的工作,既方便知识传播也促进知识学习和建立人际网络; 
15、知识传播中必须考虑传播的方式和效率; 
16、不能用简单朴素的语言表述的知识证明你还没有深入理解; 
17、多用举例子、讲故事的方法传播你的知识、见解。这个过程是你对知识的再深化过程; 
18、你的知识传播的越广,你的影响力越大; 
19、你的目的决定了你知识利用的方式。如果目的是要写论文,则你的知识就是明确、简洁的表达;如果是想要在市场上销售,就必须产品化、规范化或者专利化; 
20、知识本身没有价值,只有被利用时才能展现其价值; 
21、知识必须跟任务、项目结合起来才能发挥作用; 
22、单独的一个主题的知识很难被很好的利用,所以你必须将你的知识融入团队中或者找到自己的合作伙伴; 
23、知识创新最简单的方法是总结和分析; 
24、知识创新是一种习惯; 
25、学习或者实践---总结----将总结出来的内容投入实践检验和请行家批评—继续总结和实践; 
26、不能光做,还要思考; 
27、个人竞争力的源泉不是你现在知道的或者掌握的,而是你选择方向和快速学习的能力,是你能够将知识用足用好的能力; 
28、环境造就人,太安逸的环境对个人的发展弊大于利。如果不能找到好的环境,那就自己给自己压力; 
29、既要会做,也要会展示自己做的,要有树立个人品牌的意识。

Wednesday, October 22, 2008

VxWorks对中断的处理

我们平时使用intConnect调用挂接中断向量实际是将中断处理函数连接到vxworks内部的一个中断向量表,以MIPS为例,这个表为excBsrTbl,前几项与MIPS处理器的定义相同,但在后面保留了许多向量作为扩展使用。

intConnect为用户提供的回调函数与指针分配一小块内存(通过intHandlerCreate),并调用intVecSet将它设置到excBsrTbl中去。
intHandlerCreate用4条指令包装了用户函数,为原本不支持参数的中断处理函数提供了参数传递的功能。
FUNCPTR intHandlerCreate
(
FUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
FAST UINT * pCode; /* pointer to newly synthesized code */

pCode = (UINT *) malloc (sizeof (intConnectCode));

if (pCode != NULL)
{
/* copy intConnectCode into new code area */

bcopy ((char *)intConnectCode, (char *)pCode, sizeof (intConnectCode));

/* set the addresses & instructions */

pCode [0] |= HI_WORD (routine);
pCode [1] |= HI_WORD (parameter);
pCode [2] |= LO_WORD (routine);
pCode [4] |= LO_WORD (parameter);
}

/*
* Flush the cache so we don't get instruction
* cache hits to wrong vector
*/

CACHE_TEXT_UPDATE ((void *) pCode, sizeof (intConnectCode));

return ((FUNCPTR)pCode);
}

封装代码与体系结构相关,下面是MIPS的代码,从注释中容易得知其作用,实现利用了指令的二进制编码形式,是一个较为巧妙的思想。
LOCAL UINT intConnectCode [] = /* intConnect stub */
{
/*
* 0x0: 3c08xxxx lui t0,xxxx * msh routine address
* 0x4: 3c04yyyy lui a0,yyyy * msh parameter load
* 0x8: 3508zzzz ori t0,t0,zzzz * lsh routine address
* 0xc: 01000008 jr t0 * jump to routine
* 0x10: 3484pppp ori a0,a0,pppp * lsh load in BD slot
*/
0x3c080000, /* msh routine address runtime load */
0x3c040000, /* msh parameter load runtime load */
0x35080000, /* lsh routine address runtime load */
0x01000008, /* jump to routine */
0x34840000, /* lsh load in BD slot runtime load */
};

然而MIPS异常0代表中断,又如何支持多个中断?这是由于vxworks提供了一个excIntStub中断处理函数作为异常0处理函数,然后根据中断位来分发中断。
这里涉及到两个表:sysHashOrder, IntPrioTable。sysHashOrder表是一个哈希表实现,在多个中断Pending情况下,两个表联合确定最高优先级的中断及该中断的信息。

vxworks提供了两个默认的哈希表,ffsMsbTbl和ffsLsbTbl,它们分别代表高位高先级和高位低先级,对于XLR,我们使用ffsMsbTbl,请看定义:
UINT8 ffsMsbTbl [256] =
{
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
};
MIPS一共有8个中断位。当多个中断来临时,假定最高位为N,那么2^N范围内的中断都取第N个中断为下一个处理的中断,按这种方式便可以将该表定义出来。
数组的值是对IntPrioTable的索引,在XLR中,定义如下:
PRIO_TABLE intPrioTable[8] =
{
{CAUSE_SW1,(ULONG) IV_XLR(IV_SW0), 0x0100, 0}, /* sw trap 0 */
{CAUSE_SW2,(ULONG) IV_XLR(IV_SW1), 0x0200, 0}, /* sw trap 1 */
{CAUSE_IP3,(ULONG) IV_XLR(IV_HW0), 0x0400, 0}, /* Uart0 */
{CAUSE_IP4,(ULONG) IV_XLR(IV_HW1), 0x0800, 0}, /* Hardware int 1 */
{CAUSE_IP5,(ULONG) IV_XLR(IV_HW2), 0x1000, 0}, /* PCIX */
{CAUSE_IP6,(ULONG) IV_XLR(IV_HW3), 0x2000, 0}, /* Demultiplex */
{CAUSE_IP7,(ULONG) IV_XLR(IV_HW4), 0x4000, 0}, /* Hardware int 4 */
{CAUSE_IP8,(ULONG) IV_XLR(IV_HW5), 0x8000, 0} /* Compare(Timer 0) */
};
IntPrioTable表提供了异常向量,中断向量,掩码等信息,有了中断向量,vxworks便可以通过excBsrTbl表找到中断回调并调用。

container_of

Linux常用container_of宏从成员变量提取整个结构体的首地针,这个宏的定义如下:

#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

typeof是gcc的一个扩展,用于确定一个变量的类型,有点像C++的RTTI,常用于表达式内的语句,在定义宏时,如果需要临时变量,可以这样做:
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
它可以保证我们定义的变量_a/_b与宏传入的变量a/b类型匹配,而不会产生编译器告警。

因此container_of的第一行就是定义一个与member类型匹配的变量__mptr,赋值后,__mptr为宏参数中的待转换指针,因为只是类型转换,不涉及数据读写,((type*)0)是没有任何副作用的。

第二行用__mptr减去member变量在type中的偏移,这样便可实际访问到ptr相同偏移,也即type的实际首地址了。offsetof有两种定义:

#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

__compiler_offsetof即__builtin_offsetof,__builtin_offsetof可能是gcc內建的支持(见gcc源码c-parser.c),
从后一种实现方式可以明显看到这一技巧,假定一个从0地址开始的结构体,取其成员member的地址正是结构体内的偏移。

Sunday, August 24, 2008

低谷

近段时间,小猪的身体不好,连续好几个周末游走于各个医院,两人的心情也坏到了极点。现在的小猪已俨然成为一个药罐子,不再提当年之勇。这个周末又发起烧来,像一滩烂泥似地躺在床上,真是祸不单行。
而我呢,由于前任离职的缘故,现在出奇地忙,每天就像打仗似地,压得人喘不过气来,工作与家庭,真有些夹缝中求生存的感觉,两头都要兼顾,我想这一次我们是真的走到一个低谷了吧。
希望这一切都会过去,一切都能圆满地解决。

Saturday, December 29, 2007

JTAG链路快速扫描方法

充分利用现有标准作为基础,是保证方案稳定而有效的一个原则。本文分析了IEEE1149.1协议,在与标准兼容的基础上,提供了一种快速扫描JTAG链路的方法。

根据IEEE1149.1-2001,存在如下规则:

  1. Test-Logic-Reset状态下,测试逻辑被禁用,器件正常工作。TAP在下列条件下会进入Test-Logic-Reset状态:(a)上电,(bTRST置低电平,(c)通过TMSTCK迁跃状态。不论TAP当前的状态如何,在连续5TCK的上升沿将TMS保持为高,即可使TAP进入Test-Logic-Reset状态。

  2. 每个设备都必须提供BYPASS指令,如果提供设备标志寄存器,则必须同时提供IDCODE指令。

  3. TAP的驱动下,进入Test-Logic-Reset状态后,IDCODE指令必须在TCK下降沿被锁存到指令寄存器(如果设备不提供IDCODE指令,则锁存BYPASS指令)。所有TAP状态的切换必须在TCK的上升沿发生。

  4. BYPASS数据寄存器长度为1,在Capture-DR状态下TCK上升沿,移位寄存器必须被设为0IDCODE数据寄存器长度为32,在Capture-DR状态下TCK上升沿,移位寄存器被设为设备标志码。设备ID数据寄存器最低位为1

  1. Manufacturer Identity不可能为全1。根据Rules 12.2.111位的厂商代码分为两个部分:7-1位来自EIA/JEP106定义的代码的低7位(最高位为校验位),11-8位为连接码符总数目与16的模。目前尚不清楚厂商代码如何计算连接码,但是连接码定义为7F,因此7-1不可能为全1,进而厂商代码不可能为全1

  2. 00001111111为无效的厂商代码,任何与IEEE1149兼容的设备都不使用该代码。

根据上述事实,JTAG链扫描的方案设计如下:
  1. 连续产生5TCK,并保持TMS为高,使TAP进入Test-Logic-Reset状态。

  2. TDI移入1位’1’,读取TDO。如果TDO0转至第3步,如果TDO1转至第4步。

  3. TDO0表明设备连通了BYPASS寄存器,将设备识别状态置为UNKNOWN并转至第2步。

  4. 如果为1表明设备连通了设备ID寄存器,再向TDI移入31个’1’,从TDO读取31个位,已读取的32位即为设备ID。首先检查厂商代码是否为00001111111,如匹配则表明提示链中有不兼容设备存在,直接返回,否则继续。检查设备ID是否为321,如果是321表明扫描结束,转至第5步,否则将32位设备ID与已知设备ID进行匹配,匹配成功的显示设备信息,匹配不成功的显示UNKNOWN及设备ID,转至第2步。

  5. 更新信息,结束。

上述方法有一个前提:JTAG链正常,信号不存在不连通的情况。

当然,在实际情况中,这个前提通常不能满足,软件要考虑JTAG链断链或者器件故障等情况造成信号不通的异常情况,必须在流程上予以保证。标准没有对JTAG链上设备的最大数目作限制,但我们可以根据现有硬件的条件设定一个最大设备数(如10个),当已识别出的设备数超出该最大值时,可以认为链路故障。只要强加上述条件,在发生故障时,不论TDO信号恒为0,恒为1或者不断变化,都可以保证软件不会进入死循环。而只要链路正常,一定可以扫描到321。

Saturday, December 15, 2007

终于可以喘口气了

连续数月的生活主题除了房子还是房子,今天签了正式合同,总算是可以喘口气了。
昨日阅读合同范本至深夜,不料今日全无用场,kfs已经将所有条款定死,完全没有商量的余地,买方永远是弱势群体。
房价已经涨得如此离谱,有人说拐点即将到来,我们是不想再等下去了,一方面对zf已经完全死心,另一方面也不愿意这么无结果地等下去,虽然到09年9月才能交付,但有盼头却是完全不同的心情。
现在,回到家,总算可以轻松一下,打打游戏,看看blog,让房价、加息、楼盘都滚到一边去吧。