minor reformatting in sim/common/sim-fpu.c.
[external/binutils.git] / sim / bfin / dv-bfin_gpio.c
1 /* Blackfin General Purpose Ports (GPIO) model
2
3    Copyright (C) 2010-2016 Free Software Foundation, Inc.
4    Contributed by Analog Devices, Inc.
5
6    This file is part of simulators.
7
8    This program 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    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21 #include "config.h"
22
23 #include "sim-main.h"
24 #include "devices.h"
25 #include "dv-bfin_gpio.h"
26
27 struct bfin_gpio
28 {
29   bu32 base;
30
31   bu16 int_state;
32
33   /* Order after here is important -- matches hardware MMR layout.  */
34   bu16 BFIN_MMR_16(data);
35   bu16 BFIN_MMR_16(clear);
36   bu16 BFIN_MMR_16(set);
37   bu16 BFIN_MMR_16(toggle);
38   bu16 BFIN_MMR_16(maska);
39   bu16 BFIN_MMR_16(maska_clear);
40   bu16 BFIN_MMR_16(maska_set);
41   bu16 BFIN_MMR_16(maska_toggle);
42   bu16 BFIN_MMR_16(maskb);
43   bu16 BFIN_MMR_16(maskb_clear);
44   bu16 BFIN_MMR_16(maskb_set);
45   bu16 BFIN_MMR_16(maskb_toggle);
46   bu16 BFIN_MMR_16(dir);
47   bu16 BFIN_MMR_16(polar);
48   bu16 BFIN_MMR_16(edge);
49   bu16 BFIN_MMR_16(both);
50   bu16 BFIN_MMR_16(inen);
51 };
52 #define mmr_base()      offsetof(struct bfin_gpio, data)
53 #define mmr_offset(mmr) (offsetof(struct bfin_gpio, mmr) - mmr_base())
54
55 static const char * const mmr_names[] =
56 {
57   "PORTIO", "PORTIO_CLEAR", "PORTIO_SET", "PORTIO_TOGGLE", "PORTIO_MASKA",
58   "PORTIO_MASKA_CLEAR", "PORTIO_MASKA_SET", "PORTIO_MASKA_TOGGLE",
59   "PORTIO_MASKB", "PORTIO_MASKB_CLEAR", "PORTIO_MASKB_SET",
60   "PORTIO_MASKB_TOGGLE", "PORTIO_DIR", "PORTIO_POLAR", "PORTIO_EDGE",
61   "PORTIO_BOTH", "PORTIO_INEN",
62 };
63 #define mmr_name(off) mmr_names[(off) / 4]
64
65 static void
66 bfin_gpio_forward_int (struct hw *me, struct bfin_gpio *port, bu32 mask,
67                        int dst_port)
68 {
69   HW_TRACE ((me, "resending levels on port %c", 'a' + dst_port));
70   hw_port_event (me, dst_port, !!(port->int_state & mask));
71 }
72 static void
73 bfin_gpio_forward_ints (struct hw *me, struct bfin_gpio *port)
74 {
75   bfin_gpio_forward_int (me, port, port->maska, 0);
76   bfin_gpio_forward_int (me, port, port->maskb, 1);
77 }
78
79 static void
80 bfin_gpio_forward_ouput (struct hw *me, struct bfin_gpio *port, bu32 odata)
81 {
82   int pin, value, ovalue, bit;
83
84   for (pin = 0; pin < 16; ++pin)
85     {
86       bit = 1 << pin;
87
88       /* Make sure this is an output pin.  */
89       if (!(port->dir & bit))
90         continue;
91
92       /* Only signal port if the pin changes value.  */
93       value = !!(port->data & bit);
94       ovalue = !!(odata & bit);
95       if (value == ovalue)
96         continue;
97
98       HW_TRACE ((me, "outputting gpio %i changed to %i", pin, value));
99       hw_port_event (me, pin, value);
100     }
101 }
102
103 static unsigned
104 bfin_gpio_io_write_buffer (struct hw *me, const void *source, int space,
105                            address_word addr, unsigned nr_bytes)
106 {
107   struct bfin_gpio *port = hw_data (me);
108   bu32 mmr_off;
109   bu16 value;
110   bu16 *valuep;
111   bu32 data = port->data;
112
113   /* Invalid access mode is higher priority than missing register.  */
114   if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
115     return 0;
116
117   value = dv_load_2 (source);
118   mmr_off = addr - port->base;
119   valuep = (void *)((unsigned long)port + mmr_base() + mmr_off);
120
121   HW_TRACE_WRITE ();
122
123   switch (mmr_off)
124     {
125     case mmr_offset(data):
126     case mmr_offset(maska):
127     case mmr_offset(maskb):
128     case mmr_offset(dir):
129     case mmr_offset(polar):
130     case mmr_offset(edge):
131     case mmr_offset(both):
132     case mmr_offset(inen):
133       *valuep = value;
134       break;
135     case mmr_offset(clear):
136     case mmr_offset(maska_clear):
137     case mmr_offset(maskb_clear):
138       /* We want to clear the related data MMR.  */
139       valuep -= 2;
140       dv_w1c_2 (valuep, value, -1);
141       break;
142     case mmr_offset(set):
143     case mmr_offset(maska_set):
144     case mmr_offset(maskb_set):
145       /* We want to set the related data MMR.  */
146       valuep -= 4;
147       *valuep |= value;
148       break;
149     case mmr_offset(toggle):
150     case mmr_offset(maska_toggle):
151     case mmr_offset(maskb_toggle):
152       /* We want to toggle the related data MMR.  */
153       valuep -= 6;
154       *valuep ^= value;
155       break;
156     default:
157       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
158       return 0;
159     }
160
161   /* If updating masks, make sure we send updated port info.  */
162   switch (mmr_off)
163     {
164     case mmr_offset(dir):
165     case mmr_offset(data) ... mmr_offset(toggle):
166       bfin_gpio_forward_ouput (me, port, data);
167       break;
168     case mmr_offset(maska) ... mmr_offset(maska_toggle):
169       bfin_gpio_forward_int (me, port, port->maska, 0);
170       break;
171     case mmr_offset(maskb) ... mmr_offset(maskb_toggle):
172       bfin_gpio_forward_int (me, port, port->maskb, 1);
173       break;
174     }
175
176   return nr_bytes;
177 }
178
179 static unsigned
180 bfin_gpio_io_read_buffer (struct hw *me, void *dest, int space,
181                           address_word addr, unsigned nr_bytes)
182 {
183   struct bfin_gpio *port = hw_data (me);
184   bu32 mmr_off;
185   bu16 *valuep;
186
187   /* Invalid access mode is higher priority than missing register.  */
188   if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
189     return 0;
190
191   mmr_off = addr - port->base;
192   valuep = (void *)((unsigned long)port + mmr_base() + mmr_off);
193
194   HW_TRACE_READ ();
195
196   switch (mmr_off)
197     {
198     case mmr_offset(data):
199     case mmr_offset(clear):
200     case mmr_offset(set):
201     case mmr_offset(toggle):
202       dv_store_2 (dest, port->data);
203       break;
204     case mmr_offset(maska):
205     case mmr_offset(maska_clear):
206     case mmr_offset(maska_set):
207     case mmr_offset(maska_toggle):
208       dv_store_2 (dest, port->maska);
209       break;
210     case mmr_offset(maskb):
211     case mmr_offset(maskb_clear):
212     case mmr_offset(maskb_set):
213     case mmr_offset(maskb_toggle):
214       dv_store_2 (dest, port->maskb);
215       break;
216     case mmr_offset(dir):
217     case mmr_offset(polar):
218     case mmr_offset(edge):
219     case mmr_offset(both):
220     case mmr_offset(inen):
221       dv_store_2 (dest, *valuep);
222       break;
223     default:
224       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
225       return 0;
226     }
227
228   return nr_bytes;
229 }
230
231 static const struct hw_port_descriptor bfin_gpio_ports[] =
232 {
233   { "mask_a", 0, 0, output_port, },
234   { "mask_b", 1, 0, output_port, },
235   { "p0",     0, 0, bidirect_port, },
236   { "p1",     1, 0, bidirect_port, },
237   { "p2",     2, 0, bidirect_port, },
238   { "p3",     3, 0, bidirect_port, },
239   { "p4",     4, 0, bidirect_port, },
240   { "p5",     5, 0, bidirect_port, },
241   { "p6",     6, 0, bidirect_port, },
242   { "p7",     7, 0, bidirect_port, },
243   { "p8",     8, 0, bidirect_port, },
244   { "p9",     9, 0, bidirect_port, },
245   { "p10",   10, 0, bidirect_port, },
246   { "p11",   11, 0, bidirect_port, },
247   { "p12",   12, 0, bidirect_port, },
248   { "p13",   13, 0, bidirect_port, },
249   { "p14",   14, 0, bidirect_port, },
250   { "p15",   15, 0, bidirect_port, },
251   { NULL, 0, 0, 0, },
252 };
253
254 static void
255 bfin_gpio_port_event (struct hw *me, int my_port, struct hw *source,
256                       int source_port, int level)
257 {
258   struct bfin_gpio *port = hw_data (me);
259   bool olvl, nlvl;
260   bu32 bit = (1 << my_port);
261
262   /* Normalize the level value.  A simulated device can send any value
263      it likes to us, but in reality we only care about 0 and 1.  This
264      lets us assume only those two values below.  */
265   level = !!level;
266
267   HW_TRACE ((me, "pin %i set to %i", my_port, level));
268
269   /* Only screw with state if this pin is set as an input, and the
270      input is actually enabled.  */
271   if ((port->dir & bit) || !(port->inen & bit))
272     {
273       HW_TRACE ((me, "ignoring level/int due to DIR=%i INEN=%i",
274                  !!(port->dir & bit), !!(port->inen & bit)));
275       return;
276     }
277
278   /* Get the old pin state for calculating an interrupt.  */
279   olvl = !!(port->data & bit);
280
281   /* Update the new pin state.  */
282   port->data = (port->data & ~bit) | (level << my_port);
283
284   /* See if this state transition will generate an interrupt.  */
285   nlvl = !!(port->data & bit);
286
287   if (port->edge & bit)
288     {
289       /* Pin is edge triggered.  */
290       if (port->both & bit)
291         {
292           /* Both edges.  */
293           if (olvl == nlvl)
294             {
295               HW_TRACE ((me, "ignoring int due to EDGE=%i BOTH=%i lvl=%i->%i",
296                          !!(port->edge & bit), !!(port->both & bit),
297                          olvl, nlvl));
298               return;
299             }
300         }
301       else
302         {
303           /* Just one edge.  */
304           if (!(((port->polar & bit) && olvl > nlvl)
305                 || (!(port->polar & bit) && olvl < nlvl)))
306             {
307               HW_TRACE ((me, "ignoring int due to EDGE=%i POLAR=%i lvl=%i->%i",
308                          !!(port->edge & bit), !!(port->polar & bit),
309                          olvl, nlvl));
310               return;
311             }
312         }
313
314       /* Send the signal up, and then fall through to clear it.  */
315       port->int_state |= bit;
316       bfin_gpio_forward_ints (me, port);
317       port->int_state &= ~bit;
318     }
319   else
320     {
321       /* Pin is level triggered.  */
322       if (nlvl == !!(port->polar & bit))
323         {
324           HW_TRACE ((me, "ignoring int due to EDGE=%i POLAR=%i lvl=%i",
325                      !!(port->edge & bit), !!(port->polar & bit), nlvl));
326           /* We still need to signal SIC to clear the int, so don't return.  */
327           port->int_state &= ~bit;
328         }
329       else
330         port->int_state |= bit;
331     }
332
333   bfin_gpio_forward_ints (me, port);
334 }
335
336 static void
337 attach_bfin_gpio_regs (struct hw *me, struct bfin_gpio *port)
338 {
339   address_word attach_address;
340   int attach_space;
341   unsigned attach_size;
342   reg_property_spec reg;
343
344   if (hw_find_property (me, "reg") == NULL)
345     hw_abort (me, "Missing \"reg\" property");
346
347   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
348     hw_abort (me, "\"reg\" property must contain three addr/size entries");
349
350   hw_unit_address_to_attach_address (hw_parent (me),
351                                      &reg.address,
352                                      &attach_space, &attach_address, me);
353   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
354
355   if (attach_size != BFIN_MMR_GPIO_SIZE)
356     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_GPIO_SIZE);
357
358   hw_attach_address (hw_parent (me),
359                      0, attach_space, attach_address, attach_size, me);
360
361   port->base = attach_address;
362 }
363
364 static void
365 bfin_gpio_finish (struct hw *me)
366 {
367   struct bfin_gpio *port;
368
369   port = HW_ZALLOC (me, struct bfin_gpio);
370
371   set_hw_data (me, port);
372   set_hw_io_read_buffer (me, bfin_gpio_io_read_buffer);
373   set_hw_io_write_buffer (me, bfin_gpio_io_write_buffer);
374   set_hw_ports (me, bfin_gpio_ports);
375   set_hw_port_event (me, bfin_gpio_port_event);
376
377   attach_bfin_gpio_regs (me, port);
378 }
379
380 const struct hw_descriptor dv_bfin_gpio_descriptor[] =
381 {
382   {"bfin_gpio", bfin_gpio_finish,},
383   {NULL, NULL},
384 };