SimAVR
AVR Simulator
fifo_declare.h
Go to the documentation of this file.
1 /*
2  * fido_declare.h
3  *
4  * Copyright (C) 2003-2012 Michel Pollet <buserror@gmail.com>
5  *
6  * This library is free software; you can redistribute it and/or modify it under the terms of the GNU
7  * Lesser General Public License as published by the Free Software Foundation; either version 2.1 of
8  * the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
11  * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License along with this library;
15  * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16  * 02110-1301 USA
17  */
18 
27 #ifndef __FIFO_DECLARE__
28 #define __FIFO_DECLARE__
29 
30 #ifdef __cplusplus
31 extern "C"
32 {
33 #endif
34 
35  /*
36  doing a :
37  DECLARE_FIFO(uint8_t, myfifo, 128);
38 
39  will declare :
40  enum : myfifo_overflow_f
41  type : myfifo_t
42  functions:
44  int myfifo_write(myfifo_t *c, uint8_t b);
46  uint8_t myfifo_read(myfifo_t *c);
47  int myfifo_isfull(myfifo_t *c);
48  int myfifo_isempty(myfifo_t *c);
50  uint16_t myfifo_get_read_size(myfifo_t *c);
52  uint8_t myfifo_read_at(myfifo_t *c, uint16_t o);
54  void myfifo_write_at(myfifo_t *c, uint16_t o, uint8_t b);
55 
56  In your .c you need to 'implement' the fifo:
57  DEFINE_FIFO(uint8_t, myfifo, 128)
58 
59  To use the fifo, you must declare at least one :
60  myfifo_t fifo = FIFO_NULL;
61 
62  while (!myfifo_isfull(&fifo))
63  myfifo_write(&fifo, 0xaa);
64  ....
65  while (!myfifo_isempty(&fifo))
66  b = myfifo_read(&fifo);
67  */
68 
69 #include <stdint.h>
70 
71 #if __AVR__
72 #define FIFO_CURSOR_TYPE uint8_t
73 #define FIFO_BOOL_TYPE char
74 #define FIFO_INLINE
75 #define FIFO_SYNC
76 #endif
77 
78 #ifndef FIFO_CURSOR_TYPE
79 #define FIFO_CURSOR_TYPE uint16_t
80 #endif
81 #ifndef FIFO_BOOL_TYPE
82 #define FIFO_BOOL_TYPE int
83 #endif
84 #ifndef FIFO_INLINE
85 #define FIFO_INLINE inline
86 #endif
87 
88  /* We should not need volatile */
89 #ifndef FIFO_VOLATILE
90 #define FIFO_VOLATILE
91 #endif
92 #ifndef FIFO_SYNC
93 #define FIFO_SYNC __sync_synchronize()
94 #endif
95 
96 #ifndef FIFO_ZERO_INIT
97 #define FIFO_ZERO_INIT {0}
98 #endif
99 #define FIFO_NULL { FIFO_ZERO_INIT, 0, 0, 0 }
100 
101  /* New compilers don't like unused static functions. However, we do like 'static inlines' for
102  * these small accessors, so we mark them as 'unused'. It stops it complaining */
103 #ifdef __GNUC__
104 #define FIFO_DECL static __attribute__ ((unused))
105 #else
106 #define FIFO_DECL static
107 #endif
108 
109 #define DECLARE_FIFO(__type, __name, __size) \
110  enum { __name##_overflow_f = (1 << 0) }; \
111  enum { __name##_fifo_size = (__size) }; \
112  typedef struct __name##_t { \
113  __type buffer[__name##_fifo_size]; \
114  FIFO_VOLATILE FIFO_CURSOR_TYPE read; \
115  FIFO_VOLATILE FIFO_CURSOR_TYPE write; \
116  FIFO_VOLATILE uint8_t flags; \
117  } __name##_t
118 
119 #define DEFINE_FIFO(__type, __name) \
120  FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_write(__name##_t * c, __type b) \
121  { \
122  FIFO_CURSOR_TYPE now = c->write; \
123  FIFO_CURSOR_TYPE next = (now + 1) & (__name##_fifo_size-1); \
124  if (c->read != next) { \
125  c->buffer[now] = b; \
126  FIFO_SYNC; \
127  c->write = next; \
128  return 1; \
129  } \
130  return 0; \
131  } \
132  FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_isfull(__name##_t *c) \
133  { \
134  FIFO_CURSOR_TYPE next = (c->write + 1) & (__name##_fifo_size-1); \
135  return c->read == next; \
136  } \
137  FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_isempty(__name##_t * c) \
138  { \
139  return c->read == c->write; \
140  } \
141  FIFO_DECL FIFO_INLINE __type __name##_read(__name##_t * c) \
142  { \
143  __type res = FIFO_ZERO_INIT; \
144  FIFO_CURSOR_TYPE read = c->read; \
145  if (read == c->write) \
146  return res; \
147  res = c->buffer[read]; \
148  FIFO_SYNC; \
149  c->read = (read + 1) & (__name##_fifo_size-1); \
150  return res; \
151  } \
152  FIFO_DECL FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_read_size(__name##_t *c) \
153  { \
154  return ((c->write + __name##_fifo_size) - c->read) & (__name##_fifo_size-1); \
155  } \
156  FIFO_DECL FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_write_size(__name##_t *c) \
157  { \
158  return (__name##_fifo_size-1) - __name##_get_read_size(c); \
159  } \
160  FIFO_DECL FIFO_INLINE void __name##_read_offset(__name##_t *c, FIFO_CURSOR_TYPE o) \
161  { \
162  FIFO_SYNC; \
163  c->read = (c->read + o) & (__name##_fifo_size-1); \
164  } \
165  FIFO_DECL FIFO_INLINE __type __name##_read_at(__name##_t *c, FIFO_CURSOR_TYPE o) \
166  { \
167  return c->buffer[(c->read + o) & (__name##_fifo_size-1)]; \
168  } \
169  FIFO_DECL FIFO_INLINE void __name##_write_at(__name##_t *c, FIFO_CURSOR_TYPE o, __type b) \
170  { \
171  c->buffer[(c->write + o) & (__name##_fifo_size-1)] = b; \
172  } \
173  FIFO_DECL FIFO_INLINE void __name##_write_offset(__name##_t *c, FIFO_CURSOR_TYPE o) \
174  { \
175  FIFO_SYNC; \
176  c->write = (c->write + o) & (__name##_fifo_size-1); \
177  } \
178  FIFO_DECL FIFO_INLINE void __name##_reset(__name##_t *c) \
179  { \
180  FIFO_SYNC; \
181  c->read = c->write = c->flags = 0; \
182  } \
183  struct __name##_t
184 
185 #ifdef __cplusplus
186 };
187 #endif
188 
189 #endif
190