misc: Update NO_COLOR define switch
[simavr] / simavr / sim / fifo_declare.h
1 /*
2         fifo_declare.h
3
4         Copyright 2008, 2012 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 /* Licensed to Vidiactive by Michel Pollet under the terms of the VECL */
23
24 /*
25  * FIFO helpers, aka circular buffers
26  *
27  * these macros define accessories for FIFOs of any name, type and
28  * any (power of two) size
29  */
30
31 #ifndef __FIFO_DECLARE__
32 #define __FIFO_DECLARE__
33
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37
38 /*
39         doing a :
40         DECLARE_FIFO(uint8_t, myfifo, 128);
41
42         will declare :
43         enum : myfifo_overflow_f
44         type : myfifo_t
45         functions:
46                 // write a byte into the fifo, return 1 if there was room, 0 if there wasn't
47                 int myfifo_write(myfifo_t *c, uint8_t b);
48                 // reads a byte from the fifo, return 0 if empty. Use myfifo_isempty() to check beforehand
49                 uint8_t myfifo_read(myfifo_t *c);
50                 int myfifo_isfull(myfifo_t *c);
51                 int myfifo_isempty(myfifo_t *c);
52                 // returns number of items to read now
53                 uint16_t myfifo_get_read_size(myfifo_t *c);
54                 // read item at offset o from read cursor, no cursor advance
55                 uint8_t myfifo_read_at(myfifo_t *c, uint16_t o);
56                 // write b at offset o compared to current write cursor, no cursor advance
57                 void myfifo_write_at(myfifo_t *c, uint16_t o, uint8_t b);
58
59         In your .c you need to 'implement' the fifo:
60         DEFINE_FIFO(uint8_t, myfifo)
61
62         To use the fifo, you must declare at least one :
63         myfifo_t fifo = FIFO_NULL;
64
65         while (!myfifo_isfull(&fifo))
66                 myfifo_write(&fifo, 0xaa);
67         ....
68         while (!myfifo_isempty(&fifo))
69                 b = myfifo_read(&fifo);
70  */
71
72 #include <stdint.h>
73
74 #if __AVR__
75 #define FIFO_CURSOR_TYPE        uint8_t
76 #define FIFO_BOOL_TYPE  char
77 #define FIFO_INLINE
78 #endif
79 #ifndef FIFO_CURSOR_TYPE
80 #define FIFO_CURSOR_TYPE        uint16_t
81 #endif
82 #ifndef FIFO_BOOL_TYPE
83 #define FIFO_BOOL_TYPE  int
84 #endif
85 #ifndef FIFO_INLINE
86 #define FIFO_INLINE     inline
87 #endif
88
89 #ifndef FIFO_ZERO_INIT
90 #define FIFO_ZERO_INIT {0}
91 #endif
92 #define FIFO_NULL { FIFO_ZERO_INIT, 0, 0, 0 }
93
94 #define DECLARE_FIFO(__type, __name, __size) \
95 enum { __name##_overflow_f = (1 << 0) }; \
96 enum { __name##_fifo_size = (__size) }; \
97 typedef struct __name##_t {                     \
98         __type          buffer[__name##_fifo_size];             \
99         volatile FIFO_CURSOR_TYPE       read;           \
100         volatile FIFO_CURSOR_TYPE       write;          \
101         volatile uint8_t        flags;          \
102 } __name##_t
103
104 #define DEFINE_FIFO(__type, __name) \
105 static FIFO_INLINE FIFO_BOOL_TYPE __name##_write(__name##_t * c, __type b)\
106 {\
107         FIFO_CURSOR_TYPE now = c->write;\
108         FIFO_CURSOR_TYPE next = (now + 1) & (__name##_fifo_size-1);\
109         if (c->read != next) {  \
110                 c->buffer[now] = b;\
111                 c->write = next;\
112                 return 1;\
113         }\
114         return 0;\
115 }\
116 static FIFO_INLINE FIFO_BOOL_TYPE __name##_isfull(__name##_t *c)\
117 {\
118         FIFO_CURSOR_TYPE next = (c->write + 1) & (__name##_fifo_size-1);\
119         return c->read == next;\
120 }\
121 static FIFO_INLINE FIFO_BOOL_TYPE __name##_isempty(__name##_t * c)\
122 {\
123         return c->read == c->write;\
124 }\
125 static FIFO_INLINE __type __name##_read(__name##_t * c)\
126 {\
127         __type res = FIFO_ZERO_INIT; \
128         if (c->read == c->write)\
129                 return res;\
130         FIFO_CURSOR_TYPE read = c->read;\
131         res = c->buffer[read];\
132         c->read = (read + 1) & (__name##_fifo_size-1);\
133         return res;\
134 }\
135 static FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_read_size(__name##_t *c)\
136 {\
137         return c->write > c->read ? c->write - c->read : __name##_fifo_size - 1 - c->read + c->write;\
138 }\
139 static FIFO_INLINE void __name##_read_offset(__name##_t *c, FIFO_CURSOR_TYPE o)\
140 {\
141         c->read = (c->read + o) & (__name##_fifo_size-1);\
142 }\
143 static FIFO_INLINE __type __name##_read_at(__name##_t *c, FIFO_CURSOR_TYPE o)\
144 {\
145         return c->buffer[(c->read + o) & (__name##_fifo_size-1)];\
146 }\
147 static FIFO_INLINE void __name##_write_at(__name##_t *c, FIFO_CURSOR_TYPE o, __type b)\
148 {\
149         c->buffer[(c->write + o) & (__name##_fifo_size-1)] = b;\
150 }\
151 static FIFO_INLINE void __name##_write_offset(__name##_t *c, FIFO_CURSOR_TYPE o)\
152 {\
153         c->write = (c->write + o) & (__name##_fifo_size-1);\
154 }\
155 static FIFO_INLINE void __name##_reset(__name##_t *c)\
156 {\
157         c->read = c->write = c->flags = 0;\
158 }\
159 struct __name##_t
160
161 #ifdef __cplusplus
162 };
163 #endif
164
165 #endif