regbits: Added a "raw" variant to get/set
[simavr] / simavr / sim / sim_regbit.h
1 /*
2         sim_regbit.h
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #ifndef __SIM_REGBIT_H__
23 #define __SIM_REGBIT_H__
24
25 #include "sim_avr.h"
26
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30
31 #define ARRAY_SIZE(_aa) (sizeof(_aa) / sizeof((_aa)[0]))
32
33 /*
34  * this 'structure' is a packed representation of an IO register 'bit'
35  * (or consecutive bits). This allows a way to set/get/clear them.
36  * gcc is happy passing these as register value, so you don't need to
37  * use a pointer when passing them along to functions.
38  *
39  * 9 bits ought to be enough, as it's the maximum I've seen (atmega2560)
40  */
41 typedef struct avr_regbit_t {
42         unsigned long reg : 9, bit : 3, mask : 8;
43 } avr_regbit_t;
44
45 /*
46  * These accessors are inlined and are used to perform the operations on
47  * avr_regbit_t definitions. This is the "official" way to access bits into registers
48  * The small footprint costs brings much better versatility for functions/bits that are
49  * not always defined in the same place on real AVR cores
50  */
51 /*
52  * set/get/clear io register bits in one operation
53  */
54 static inline uint8_t avr_regbit_set(avr_t * avr, avr_regbit_t rb)
55 {
56         uint8_t a = rb.reg;
57         if (!a)
58                 return 0;
59         uint8_t m = rb.mask << rb.bit;
60         avr_core_watch_write(avr, a, avr->data[a] | m);
61         return (avr->data[a] >> rb.bit) & rb.mask;
62 }
63
64 static inline uint8_t avr_regbit_setto(avr_t * avr, avr_regbit_t rb, uint8_t v)
65 {
66         uint8_t a = rb.reg;
67         if (!a)
68                 return 0;
69         uint8_t m = rb.mask << rb.bit;
70         avr_core_watch_write(avr, a, (avr->data[a] & ~(m)) | ((v << rb.bit) & m));
71         return (avr->data[a] >> rb.bit) & rb.mask;
72 }
73
74 /*
75  * Set the 'raw' bits, if 'v' is the unshifted value of the bits
76  */
77 static inline uint8_t avr_regbit_setto_raw(avr_t * avr, avr_regbit_t rb, uint8_t v)
78 {
79         uint8_t a = rb.reg;
80         if (!a)
81                 return 0;
82         uint8_t m = rb.mask << rb.bit;
83         avr_core_watch_write(avr, a, (avr->data[a] & ~(m)) | ((v) & m));
84         return (avr->data[a]) & (rb.mask << rb.bit);
85 }
86
87 static inline uint8_t avr_regbit_get(avr_t * avr, avr_regbit_t rb)
88 {
89         uint8_t a = rb.reg;
90         if (!a)
91                 return 0;
92         //uint8_t m = rb.mask << rb.bit;
93         return (avr->data[a] >> rb.bit) & rb.mask;
94 }
95
96 /*
97  * Return the bit(s) 'in position' instead of zero based
98  */
99 static inline uint8_t avr_regbit_get_raw(avr_t * avr, avr_regbit_t rb)
100 {
101         uint8_t a = rb.reg;
102         if (!a)
103                 return 0;
104         //uint8_t m = rb.mask << rb.bit;
105         return (avr->data[a]) & (rb.mask << rb.bit);
106 }
107
108 static inline uint8_t avr_regbit_clear(avr_t * avr, avr_regbit_t rb)
109 {
110         uint8_t a = (rb.reg);
111         uint8_t m = rb.mask << rb.bit;
112         avr_core_watch_write(avr, a, avr->data[a] & ~m);
113         return avr->data[a];
114 }
115
116
117 /*
118  * This reads the bits for an array of avr_regbit_t, make up a "byte" with them.
119  * This allows reading bits like CS0, CS1, CS2 etc even if they are not in the same
120  * physical IO register.
121  */
122 static inline uint8_t avr_regbit_get_array(avr_t * avr, avr_regbit_t *rb, int count)
123 {
124         uint8_t res = 0;
125
126         for (int i = 0; i < count; i++, rb++) if (rb->reg) {
127                 uint8_t a = (rb->reg);
128                 res |= ((avr->data[a] >> rb->bit) & rb->mask) << i;
129         }
130         return res;
131 }
132
133 #define AVR_IO_REGBIT(_io, _bit) { . reg = (_io), .bit = (_bit), .mask = 1 }
134 #define AVR_IO_REGBITS(_io, _bit, _mask) { . reg = (_io), .bit = (_bit), .mask = (_mask) }
135
136 #ifdef __cplusplus
137 };
138 #endif
139
140 #endif /* __SIM_REGBIT_H__ */