-
Notifications
You must be signed in to change notification settings - Fork 1
/
Reg.hpp
232 lines (192 loc) · 7.61 KB
/
Reg.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#pragma once
//Register (SFR) R/W
//kseg1/0 address <-> physical address
#include <cstdint>
/* |-kseg = 1, phys = 0
SFR - kseg0 no SFR available in kseg0 <-kseg0 = 0
kseg1 0xBF800000-0xBF8FFFFF bit<31:29> 0b101<-kseg1 = 1
phys 0x1F800000-0x1F8FFFFF bit<31:29> 0b000
access sfr's via kseg1 addresses
retval name args- address(32bit), bitmask, (bool- set=1, clear=0)
-----------------------------------------------------------------------------
setbit (address, bitmask, bool) -set or clr bit(s)
setbit (address, bitmask) -set bit(s)
clrbit (address, bitmask) -clr bit(s)
flipbit (address, bitmask) -invert bit(s)
anybit (address, bitmask) -any bit(s) set?
allbit (address, bitmask) -all bit(s) set?
anybit0 (address, bitmask) -any bit(s) clr?
allbit0 (address, bitmask) -all bit(s) clr?
uint32_t val (address) -read 32bit value
value16 val16 (address) -read 16bit value
value8 val8 (address) -read 8bit value
val (address, value8|16|32) -set 8|16|32bit value
uint32_t p2kseg1 (address) -phys addr->kseg1
uint32_t p2kseg0 (address) -phys addr->kseg0
uint32_t k2phys (address) -ksegx addr->phys
address arguments are mostly enums, but can also be uint32_t or pointer
type, and value arguments are also mostly enums, but can be 8/16/32bit
values also, the templates work to get the underlying size of the value,
then set the address argument to a volatile pointer of that type, allowing
byte/half-word/word access to a register-
val(T r, V v) -> *(volatile V*)r = v -> type deduced by type passed in
address- caller makes sure is 32bit number, also be aware of addition on
the address, if enum- additions are byte, if pointer- addition is word
value- type will determine address type of pointer, if value needs to be
something other than its type (size), it will need to be cast-
val(ENUM_REG+3, ENUM_VAL) - if ENUM_VAL is 32bit, need to cast to 8bit
in this case in order to access third byte of ENUM_REG
(unaligned access will cause exception :) )
*/
//some typdefs for general use
using vu32ptr = volatile uint32_t*;
using vu16ptr = volatile uint16_t*;
using vu8ptr = volatile uint8_t*;
//helper templates- get size in bytes of V type
//also provide atomic register offsets
template<int> struct Vsiz {
using type = void;
};
template <> struct Vsiz<1> {
using type = uint8_t;
static const uint8_t CLR = 4;
static const uint8_t SET = 8;
static const uint8_t INV = 12;
};
template <> struct Vsiz<2> {
using type = uint16_t;
static const uint8_t CLR = 2;
static const uint8_t SET = 4;
static const uint8_t INV = 6;
};
template <> struct Vsiz<4> {
using type = uint32_t;
static const uint8_t CLR = 1;
static const uint8_t SET = 2;
static const uint8_t INV = 3;
};
template<typename T> struct getVsiz {
using type = typename Vsiz<sizeof(T)>::type;
};
struct Reg {
//T = address, V = value (V will become uint8/16/32_t)
//T will become volatile V*, so can access register by
//byte, half-word, or word, determined by size of V
//set bitmask bit(s) in register to specified level 0/1
template <typename T, typename V> static void setbit(T, V, bool);
//set bitmask bit(s) in register to 1
template <typename T, typename V> static void setbit(T, V);
//clear bitmask bit(s) in register to 0
template <typename T, typename V> static void clrbit(T, V);
//flip bitmask bit(s) in register
template <typename T, typename V> static void flipbit (T, V);
//test if any bitmask bit(s) in the register are set
template <typename T, typename V> static bool anybit(T, V);
//test if any bitmask bit(s) in the register are clear
template <typename T, typename V> static bool anybit0(T, V);
//test if all bitmask bit(s) in the register are set
template <typename T, typename V> static bool allbit(T, V);
//test if all bitmask bit(s) in the register are clear
template <typename T, typename V> static bool allbit0(T, V);
//return val from register- 32bit
template <typename T> static uint32_t val(T);
//return val from register- 16bit
template <typename T> static uint16_t val16(T);
//return val from register- 8bit
template <typename T> static uint8_t val8(T);
//val(address, val)-> *(V*)address = (V)val
template <typename T, typename V> static void val(T r, V v);
//physical to kseg1 addr
template <typename T> static uint32_t p2kseg1 (T);
//physical to kseg0 addr
template <typename T> static uint32_t p2kseg0 (T);
//kseg to physical addr
template <typename T> static uint32_t k2phys (T);
};
//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// functions inline
//setbit, specify 1 or 0
template <typename T, typename V>
void Reg::setbit(T r, V v, bool sc){
using vtype = typename getVsiz<V>::type;
*((volatile vtype*)r+Vsiz<sizeof(V)>::CLR+(sc*Vsiz<sizeof(V)>::CLR)) = v;
//if(sc) setbit(r,v); else clrbit(r,v); //this is 4bytes more code per use
}
//setbit
template <typename T, typename V>
void Reg::setbit(T r, V v){
using vtype = typename getVsiz<V>::type;
//((volatile vtype*)r)[Vsiz<sizeof(V)>::SET] = v; //same thing
*((volatile vtype*)r+Vsiz<sizeof(V)>::SET) = v;
}
//clrbit
template <typename T, typename V>
void Reg::clrbit(T r, V v){
using vtype = typename getVsiz<V>::type;
*((volatile vtype*)r+Vsiz<sizeof(V)>::CLR) = v;
}
//flipbit
template <typename T, typename V>
void Reg::flipbit(T r, V v){
using vtype = typename getVsiz<V>::type;
*((volatile vtype*)r+Vsiz<sizeof(V)>::INV) = v;
}
//anybit
template <typename T, typename V>
bool Reg::anybit(T r, V v){
using vtype = typename getVsiz<V>::type;
return *(volatile vtype*)r bitand v;
}
//anybit0
template <typename T, typename V>
bool Reg::anybit0(T r, V v){
using vtype = typename getVsiz<V>::type;
return (compl *(volatile vtype*)r) bitand v;
}
//allbit
template <typename T, typename V>
bool Reg::allbit(T r, V v){
using vtype = typename getVsiz<V>::type;
return *(volatile vtype*)r bitand v == v;
}
//allbit0
template <typename T, typename V>
bool Reg::allbit0(T r, V v){
using vtype = typename getVsiz<V>::type;
return (compl *(volatile vtype*)r) bitand v == v;
}
//return uint32_t value of register r
template <typename T>
uint32_t Reg::val(T r){
return *(volatile uint32_t*)r;
}
//return uint16_t value of register r
template <typename T>
uint16_t Reg::val16(T r){
return *(volatile uint16_t*)r;
}
//return uint8_t value of register r
template <typename T>
uint8_t Reg::val8(T r){
return *(volatile uint8_t*)r;
}
//set uint32_t/uint16_t/uint8_t value to register r
//(determined by size of V type)
template <typename T, typename V>
void Reg::val(T r, V v){
using vtype = typename getVsiz<V>::type;
*(volatile vtype*)r = v;
}
//physical to kseg0/1 addr, kseg to physical addr
template <typename T>
uint32_t Reg::p2kseg1(T r){
return (uint32_t)r bitor 0xA0000000; //A0=0b1010_0000
}
template <typename T>
uint32_t Reg::p2kseg0(T r){
return (uint32_t)r bitor 0x80000000; //80=0b1000_0000
}
template <typename T>
uint32_t Reg::k2phys(T r){
return (uint32_t)r bitand 0x1FFFFFFF; //1F=0b0001_1111
}