本帖最后由 xyz549040622 于 2011-12-28 09:01 编辑
20111223_.pdf
(285.8 KB)
John Lee(1513562323) 20:28:41
今天我们来讨论一下关于使用C++ 临时对象缓冲技术访问特殊功能寄存器方法的内部实现。
John Lee(1513562323) 20:29:34
首先我们需要了解SFR是如何定义的,我们选取UART的BAUD寄存器作为讨论的对象,
John Lee(1513562323) 20:29:57
这是因为BAUD寄存器中,不仅有单个位的位域,还有多个位的位域,相对其它只含有单个位域的寄存器,BAUD寄存器更能说明问题。
John Lee(1513562323) 20:30:38
下面是uart外设的结构定义,为了清晰起见,我们只保留BAUD寄存器的成员定义,略去了其它无关紧要的定义。
John Lee(1513562323) 20:31:05
struct uart_t {
...
volatile sfr_t<baud_t> BAUD;
...
};
日期:2011/12/23
John Lee(1513562323) 20:31:34
我们可以看到BAUD成员的类型是volatile sfr_t<baud_t>,其中有一个volatile修饰符,我们暂且不表。
John Lee(1513562323) 20:32:00
那么sft_t<baud_t>是什么东西?
John Lee(1513562323) 20:32:11
这只不过是 C++ 的模板类。大家不要晕,不要把模板想得很高深,把自己吓倒了。
John Lee(1513562323) 20:32:49
模板类,就像是带参数的宏定义,只不过普通的宏定义是由 C/C++ 预处理程序处理了,而模板,则是由编译器自己处理的。
John Lee(1513562323) 20:33:32
我们知道,预处理程序对宏的参数的语**确性不会做任何检查,只是简单地替换而已,最后的正确性是由编译器来检查的。
皇星客栈-Linux(769181464)20:34:11
恩恩
John Lee(1513562323) 20:34:16
而模板类的参数,就有一些语法要求了,参数只能有两种,第1种是“类型”,第2种是“常数值”。
John Lee(1513562323) 20:34:45
例如:
template<typename T, int N>
class foo { ... };
John Lee(1513562323) 20:35:26
其中的 T 就是一种类型,N 是一个常数,注意,这里的 T 和 N 都是“形参”,在模板类定义时,只具有抽象意义。
John Lee(1513562323) 20:36:18
当我们创建模板类的实例时,必须给出模板类的参数,就像使用宏一样要给出宏的参数。
John Lee(1513562323) 20:36:50
例如:
foo<char, 2> foo1;
雁塔菜农(1270688699)20:36:52
好
John Lee(1513562323) 20:37:30
char就是一个具体类型了,用来作为“实参”代替“形参”T,常数 2 也是用来代替 N 的。
John Lee(1513562323) 20:38:00
宏和模板的区别还有一点,模板允许递归,而宏不允许。
John Lee(1513562323) 20:40:09
通过给模板类不同的参数,我们就可以“生成”若干不同的新类型,这些类型都有类似的行为(成员函数)。
John Lee(1513562323) 20:41:02
模板就简单地介绍到这里了,大家可能还是觉得很抽象,下面我们就回过头继续讲寄存器的访问,
John Lee(1513562323) 20:41:49
里面涉及了一些模板的操作,我们在讲的过程中,大家就可以继续加深对模板的认识。
皇星客栈-Linux(769181464)20:43:05
恩恩
John Lee(1513562323) 20:43:30
我们先找到sfr_t模板类的定义:
template<typename SFR>
class sfr_t { // Special Function Register
public:
__INLINE operator decltype(SFR::val)() {return val; }
__INLINE sfr_t<SFR> operator =(SFR v){ val = v.val; return *this; }
__INLINE decltype(SFR::val) operator=(decltype(SFR::val) v) { val = v; return v; }
__INLINE SFR operator ()() { returnSFR(val); }
__INLINE SFR operator ()(decltype(SFR::val)v) { return SFR(val, v); }
volatile decltype(SFR::val) val;
};
我们也略去了其中不是关键的部分。
John Lee(1513562323) 20:44:52
当我们定义uart_t的成员BAUD时,使用了baud_t这个类型作为sfr_t模板的参数,
John Lee(1513562323) 20:45:47
我们可以把sfr_t的形参SFR,用手工替换成baud_t,得到如下结果:
John Lee(1513562323) 20:46:18
class sft_t<baud_t> { // SpecialFunction Register
public:
__INLINE operator decltype(baud_t::val)() {return val; }
__INLINE sfr_t<baud_t> operator=(baud_t v) { val = v.val; return *this; }
__INLINE decltype(baud_t::val) operator=(decltype(baud_t::val) v) { val = v; return v; }
__INLINE baud_t operator ()() { returnbaud_t(val); }
__INLINE baud_t operator()(decltype(baud_t::val) v) { return baud_t(val, v); }
volatile decltype(baud_t::val) val;
};
John Lee(1513562323) 20:47:13
在这里,我们第一个看不明白的地方可能是decltype(baud_t::val)。
murex(344582199) 20:47:27
嗯
寒雨(251539157)20:47:33
是的
John Lee(1513562323) 20:47:54
这仅仅是一个“类型”,只不过这个类型不是定死的,而是根据baud_t::val的类型来动态定义的一个类型,
John Lee(1513562323) 20:48:24
decltype是 C++11 的关键字,括号里是一个已存在的类型表达式,decltype可以取得其类型,然后用这个类型去定义新的变量等等。
murex(344582199) 20:49:04
这个不错,牛,还有这种用法
murex(344582199) 20:49:08
c++强悍
John Lee(1513562323) 20:49:25
baud_t::val,从字面意思可以看出,有一个名叫baud_t的类,里面有一个叫val的成员。
日期:2011/12/23
寒雨(251539157)20:49:45
哦
John Lee(1513562323) 20:50:19
如果baud_t::val的类型是char,那么:
__INLINE operator decltype(baud_t::val)() {return val; }
就变成了:
__INLINE operator char() { return val; }
John Lee(1513562323) 20:52:01
现在是不是清楚一些了?这实际上是一个“类型转换”函数。
murex(344582199) 20:52:11
嗯,清楚了
John Lee(1513562323) 20:53:27
可以通过这个operatorchar()函数,把sfr_t<baud_t>类对象,转换为char类型数据。
寒雨(251539157)20:53:52
哦
John Lee(1513562323) 20:54:18
如果没有定义这个函数,编译器就不知道如何转换。
murex(344582199) 20:54:49
那是的了
John Lee(1513562323) 20:55:47
例如:
sfr_t<baud_t> baud_data;
char ch_data = baud_data;
John Lee(1513562323) 20:57:09
C/C++的隐含转换规则,是没有用户类型转换的。
John Lee(1513562323) 20:58:09
我们定义了这样一个转换函数,就是为编译器定义了一个转换规则。
John Lee(1513562323) 20:59:06
下面,我们继续追踪,去看看baud_t是什么样的:
John Lee(1513562323) 20:59:22
union baud_t { // Baud Rate DividerRegister (UA_BAUD)
__SFR(baud_t, uint32_t, 0)
sfb_t<baud_t, uint32_t, 0, 16> BRD;
sfb_t<baud_t, uint32_t, 24, 4>DIVIDER_X;
sfb_t<baud_t, uint32_t, 28, 1>DIV_X_ONE;
sfb_t<baud_t, uint32_t, 29, 1>DIV_X_EN;
};
John Lee(1513562323) 20:59:48
baud_t是一个“union”类型,有一个宏__SFR,和4个成员。
John Lee(1513562323) 21:00:03
继续追踪__SFR。
John Lee(1513562323) 21:00:58
看代码就是要学会追踪,一步一步深入,但不要迷路,要做好路标,一旦某条路追到了底后,能找到回来的路。
皇星客栈-Linux(769181464)21:01:16
恩恩
John Lee(1513562323) 21:02:05
追踪代码,就像是钻迷宫,要一条路一条路的钻。
murex(344582199) 21:02:22
找到根为止
John Lee(1513562323) 21:03:13
__SFR宏是这样的:
#define __SFR(SFR, TYPE, WRITE) \
__INLINE SFR(TYPE volatile& r) :ref(r), val(r), changed(0) { } \
__INLINE SFR(TYPE volatile& r, TYPE v): ref(r), val(v), changed((TYPE)(-1)) { } \
__INLINE ~SFR() { apply(); } \
__INLINE SFR& apply() \
{ \
if (changed != 0) { \
ref = val; \
changed = 0; \
} \
return *this; \
} \
struct { \
volatile TYPE& ref; \
TYPE val; \
TYPE changed; \
};
John Lee(1513562323) 21:03:49
现在我们把它展开到unionbaud_t中:
John Lee(1513562323) 21:04:34
union baud_t { // Baud Rate Divider Register(UA_BAUD)
__INLINE baud_t(uint32_t volatile& r) :ref(r), val(r), changed(0) { } \
__INLINE baud_t(uint32_t volatile& r,uint32_t v) : ref(r), val(v), changed((uint32_t)(-1)) { } \
__INLINE ~baud_t() { apply(); } \
__INLINE baud_t& apply() \
{ \
if (changed != 0) { \
ref = val; \
changed = 0; \
} \
return *this; \
} \
struct { \
volatile uint32_t& ref; \
uint32_t val; \
uint32_t changed; \
};
sfb_t<baud_t, uint32_t, 0, 16> BRD;
sfb_t<baud_t, uint32_t, 24, 4>DIVIDER_X;
sfb_t<baud_t, uint32_t, 28, 1>DIV_X_ONE;
sfb_t<baud_t, uint32_t, 29, 1>DIV_X_EN;
};
John Lee(1513562323) 21:05:40
好了,我们终于看到了baud_t::val,它的类型是uint32_t,
murex(344582199) 21:05:53
嗯
John Lee(1513562323) 21:06:55
那么我们先回过头来,把sft_t<baud_t>类中的decltype(baud_t::val),全部替换为uint32_t,
John Lee(1513562323) 21:07:55
得到结果如下:
class sft_t<baud_t> { // SpecialFunction Register
public:
__INLINE operator uint32_t() { return val;}
__INLINE sfr_t<baud_t> operator=(baud_t v) { val = v.val; return *this; }
__INLINE uint32_t operator =(uint32_t v) {val = v; return v; }
__INLINE baud_t operator ()() { returnbaud_t(val); }
__INLINE baud_t operator ()(uint32_t v) {return baud_t(val, v); }
volatile uint32_t val;
};
John Lee(1513562323) 21:08:51
现在,sfr_t<baud_t>类就是最终的样子了。
John Lee(1513562323) 21:09:43
我简单讲解一下sfr_t<baud_t>类的成员。
murex(344582199) 21:09:55
好
John Lee(1513562323) 21:09:56
1、__INLINE operator uint32_t() { return val; }
日期:2011/12/23
John Lee(1513562323) 21:11:41
这是“类型转换”函数,可以把sfr_t<baud_t>类的对象,转换为uint32_t
寒雨(251539157)21:12:43
这函数好用
John Lee(1513562323) 21:13:23
现在提个问,sfr_t<baud_t>类的对象(也叫实例)是哪个?
John Lee(1513562323) 21:13:43
看谁先中奖。
murex(344582199) 21:14:31
_INLINE baud_t operator ()(uint32_t v) {return baud_t(val, v); }
John Lee(1513562323) 21:15:24
暂停5分钟,大家快找答案。5分钟后继续。
潜龙思瑞(373744463)21:16:26
__INLINE sfr_t<baud_t> operator=(baud_t v) { val = v.val; return *this; }
murex(344582199) 21:16:58
嗯,应该是这个的了
John Lee(1513562323) 21:17:24
错,继续找
难民人(95714627)21:18:44
难民人(95714627)21:18:49
z这个
难民人(95714627)21:18:53
类的对象
皇星客栈-Linux(769181464)21:19:22
__INLINEbaud_t operator ()(uint32_t v) { return baud_t(val, v); }
难民人(95714627)21:19:33
对吗? 李老师
John Lee(1513562323) 21:19:38
错
murex(344582199) 21:19:58
赶紧说啊,总共就没几个了
murex(344582199) 21:20:00
哈哈
寒雨(251539157)21:20:39
class sft_t<baud_t> { // SpecialFunction Register
潜龙思瑞(373744463)21:20:48
volatile decltype(baud_t::val) val;
consif(593049297) 21:20:53
union baud_t { // Baud Rate DividerRegister (UA_BAUD)
难民人(95714627)21:21:16
__INLINE operator uint32_t()
__INLINE baud_t operator ()()
__INLINE baud_t operator ()(uint32_t v)
难民人(95714627)21:21:22
这个就对了
John Lee(1513562323) 21:21:40
sfr_t<baud_t>类的对象!!显然是个数据嘛,咋个都去找函数?
难民人(95714627)21:21:53
寒雨(251539157)21:22:04
我对了一半
寒雨(251539157)21:22:06
呵呵
寒雨(251539157)21:22:17
sft_t<baud_t>
潜龙思瑞(373744463)21:22:49
实例不就是函数么
John Lee(1513562323) 21:23:08
sfr_t<baud_t>类!!!这个是“类型”,就像int,char等一样。 |
|