xref: /netbsd-src/external/gpl3/gdb.old/dist/sim/lm32/dv-lm32timer.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1a5a4af3bSchristos /*  Lattice Mico32 timer model.
2a5a4af3bSchristos     Contributed by Jon Beniston <jon@beniston.com>
3a5a4af3bSchristos 
4*8b657b07Schristos    Copyright (C) 2009-2023 Free Software Foundation, Inc.
5a5a4af3bSchristos 
6a5a4af3bSchristos    This file is part of GDB.
7a5a4af3bSchristos 
8a5a4af3bSchristos    This program is free software; you can redistribute it and/or modify
9a5a4af3bSchristos    it under the terms of the GNU General Public License as published by
10a5a4af3bSchristos    the Free Software Foundation; either version 3 of the License, or
11a5a4af3bSchristos    (at your option) any later version.
12a5a4af3bSchristos 
13a5a4af3bSchristos    This program is distributed in the hope that it will be useful,
14a5a4af3bSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
15a5a4af3bSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16a5a4af3bSchristos    GNU General Public License for more details.
17a5a4af3bSchristos 
18a5a4af3bSchristos    You should have received a copy of the GNU General Public License
19a5a4af3bSchristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20a5a4af3bSchristos 
21*8b657b07Schristos /* This must come before any other includes.  */
22*8b657b07Schristos #include "defs.h"
23*8b657b07Schristos 
24a5a4af3bSchristos #include "sim-main.h"
25a5a4af3bSchristos #include "hw-main.h"
26a5a4af3bSchristos #include "sim-assert.h"
27a5a4af3bSchristos 
28a5a4af3bSchristos struct lm32timer
29a5a4af3bSchristos {
30a5a4af3bSchristos   unsigned base;		/* Base address of this timer.  */
31a5a4af3bSchristos   unsigned limit;		/* Limit address of this timer.  */
32a5a4af3bSchristos   unsigned int status;
33a5a4af3bSchristos   unsigned int control;
34a5a4af3bSchristos   unsigned int period;
35a5a4af3bSchristos   unsigned int snapshot;
36a5a4af3bSchristos   struct hw_event *event;
37a5a4af3bSchristos };
38a5a4af3bSchristos 
39a5a4af3bSchristos /* Timer registers.  */
40a5a4af3bSchristos #define LM32_TIMER_STATUS       0x0
41a5a4af3bSchristos #define LM32_TIMER_CONTROL      0x4
42a5a4af3bSchristos #define LM32_TIMER_PERIOD       0x8
43a5a4af3bSchristos #define LM32_TIMER_SNAPSHOT     0xc
44a5a4af3bSchristos 
45a5a4af3bSchristos /* Timer ports.  */
46a5a4af3bSchristos 
47a5a4af3bSchristos enum
48a5a4af3bSchristos {
49a5a4af3bSchristos   INT_PORT
50a5a4af3bSchristos };
51a5a4af3bSchristos 
52a5a4af3bSchristos static const struct hw_port_descriptor lm32timer_ports[] = {
53a5a4af3bSchristos   {"int", INT_PORT, 0, output_port},
54a5a4af3bSchristos   {}
55a5a4af3bSchristos };
56a5a4af3bSchristos 
57a5a4af3bSchristos static void
58a5a4af3bSchristos do_timer_event (struct hw *me, void *data)
59a5a4af3bSchristos {
60a5a4af3bSchristos   struct lm32timer *timer = hw_data (me);
61a5a4af3bSchristos 
62a5a4af3bSchristos   /* Is timer started? */
63a5a4af3bSchristos   if (timer->control & 0x4)
64a5a4af3bSchristos     {
65a5a4af3bSchristos       if (timer->snapshot)
66a5a4af3bSchristos 	{
67a5a4af3bSchristos 	  /* Decrement timer.  */
68a5a4af3bSchristos 	  timer->snapshot--;
69a5a4af3bSchristos 	}
70a5a4af3bSchristos       else if (timer->control & 1)
71a5a4af3bSchristos 	{
72a5a4af3bSchristos 	  /* Restart timer.  */
73a5a4af3bSchristos 	  timer->snapshot = timer->period;
74a5a4af3bSchristos 	}
75a5a4af3bSchristos     }
76a5a4af3bSchristos   /* Generate interrupt when timer is at 0, and interrupt enable is 1.  */
77a5a4af3bSchristos   if ((timer->snapshot == 0) && (timer->control & 1))
78a5a4af3bSchristos     {
79a5a4af3bSchristos       /* Generate interrupt.  */
80a5a4af3bSchristos       hw_port_event (me, INT_PORT, 1);
81a5a4af3bSchristos     }
82a5a4af3bSchristos   /* If timer is started, schedule another event to decrement the timer again.  */
83a5a4af3bSchristos   if (timer->control & 4)
84a5a4af3bSchristos     hw_event_queue_schedule (me, 1, do_timer_event, 0);
85a5a4af3bSchristos }
86a5a4af3bSchristos 
87a5a4af3bSchristos static unsigned
88a5a4af3bSchristos lm32timer_io_write_buffer (struct hw *me,
89a5a4af3bSchristos 			   const void *source,
90a5a4af3bSchristos 			   int space, unsigned_word base, unsigned nr_bytes)
91a5a4af3bSchristos {
92a5a4af3bSchristos   struct lm32timer *timers = hw_data (me);
93a5a4af3bSchristos   int timer_reg;
94a5a4af3bSchristos   const unsigned char *source_bytes = source;
95a5a4af3bSchristos   int value = 0;
96a5a4af3bSchristos 
97a5a4af3bSchristos   HW_TRACE ((me, "write to 0x%08lx length %d with 0x%x", (long) base,
98a5a4af3bSchristos 	     (int) nr_bytes, value));
99a5a4af3bSchristos 
100a5a4af3bSchristos   if (nr_bytes == 4)
101a5a4af3bSchristos     value = (source_bytes[0] << 24)
102a5a4af3bSchristos       | (source_bytes[1] << 16) | (source_bytes[2] << 8) | (source_bytes[3]);
103a5a4af3bSchristos   else
104a5a4af3bSchristos     hw_abort (me, "write with invalid number of bytes: %d", nr_bytes);
105a5a4af3bSchristos 
106a5a4af3bSchristos   timer_reg = base - timers->base;
107a5a4af3bSchristos 
108a5a4af3bSchristos   switch (timer_reg)
109a5a4af3bSchristos     {
110a5a4af3bSchristos     case LM32_TIMER_STATUS:
111a5a4af3bSchristos       timers->status = value;
112a5a4af3bSchristos       break;
113a5a4af3bSchristos     case LM32_TIMER_CONTROL:
114a5a4af3bSchristos       timers->control = value;
115a5a4af3bSchristos       if (timers->control & 0x4)
116a5a4af3bSchristos 	{
117a5a4af3bSchristos 	  /* Timer is started.  */
118a5a4af3bSchristos 	  hw_event_queue_schedule (me, 1, do_timer_event, 0);
119a5a4af3bSchristos 	}
120a5a4af3bSchristos       break;
121a5a4af3bSchristos     case LM32_TIMER_PERIOD:
122a5a4af3bSchristos       timers->period = value;
123a5a4af3bSchristos       break;
124a5a4af3bSchristos     default:
125a5a4af3bSchristos       hw_abort (me, "invalid register address: 0x%x.", timer_reg);
126a5a4af3bSchristos     }
127a5a4af3bSchristos 
128a5a4af3bSchristos   return nr_bytes;
129a5a4af3bSchristos }
130a5a4af3bSchristos 
131a5a4af3bSchristos static unsigned
132a5a4af3bSchristos lm32timer_io_read_buffer (struct hw *me,
133a5a4af3bSchristos 			  void *dest,
134a5a4af3bSchristos 			  int space, unsigned_word base, unsigned nr_bytes)
135a5a4af3bSchristos {
136a5a4af3bSchristos   struct lm32timer *timers = hw_data (me);
137a5a4af3bSchristos   int timer_reg;
138a5a4af3bSchristos   int value;
139a5a4af3bSchristos   unsigned char *dest_bytes = dest;
140a5a4af3bSchristos 
141a5a4af3bSchristos   HW_TRACE ((me, "read 0x%08lx length %d", (long) base, (int) nr_bytes));
142a5a4af3bSchristos 
143a5a4af3bSchristos   timer_reg = base - timers->base;
144a5a4af3bSchristos 
145a5a4af3bSchristos   switch (timer_reg)
146a5a4af3bSchristos     {
147a5a4af3bSchristos     case LM32_TIMER_STATUS:
148a5a4af3bSchristos       value = timers->status;
149a5a4af3bSchristos       break;
150a5a4af3bSchristos     case LM32_TIMER_CONTROL:
151a5a4af3bSchristos       value = timers->control;
152a5a4af3bSchristos       break;
153a5a4af3bSchristos     case LM32_TIMER_PERIOD:
154a5a4af3bSchristos       value = timers->period;
155a5a4af3bSchristos       break;
156a5a4af3bSchristos     case LM32_TIMER_SNAPSHOT:
157a5a4af3bSchristos       value = timers->snapshot;
158a5a4af3bSchristos       break;
159a5a4af3bSchristos     default:
160a5a4af3bSchristos       hw_abort (me, "invalid register address: 0x%x.", timer_reg);
161a5a4af3bSchristos     }
162a5a4af3bSchristos 
163a5a4af3bSchristos   if (nr_bytes == 4)
164a5a4af3bSchristos     {
165a5a4af3bSchristos       dest_bytes[0] = value >> 24;
166a5a4af3bSchristos       dest_bytes[1] = value >> 16;
167a5a4af3bSchristos       dest_bytes[2] = value >> 8;
168a5a4af3bSchristos       dest_bytes[3] = value;
169a5a4af3bSchristos     }
170a5a4af3bSchristos   else
171a5a4af3bSchristos     hw_abort (me, "read of unsupported number of bytes: %d", nr_bytes);
172a5a4af3bSchristos 
173a5a4af3bSchristos   return nr_bytes;
174a5a4af3bSchristos }
175a5a4af3bSchristos 
176a5a4af3bSchristos static void
177a5a4af3bSchristos attach_lm32timer_regs (struct hw *me, struct lm32timer *timers)
178a5a4af3bSchristos {
179a5a4af3bSchristos   unsigned_word attach_address;
180a5a4af3bSchristos   int attach_space;
181a5a4af3bSchristos   unsigned attach_size;
182a5a4af3bSchristos   reg_property_spec reg;
183a5a4af3bSchristos 
184a5a4af3bSchristos   if (hw_find_property (me, "reg") == NULL)
185a5a4af3bSchristos     hw_abort (me, "Missing \"reg\" property");
186a5a4af3bSchristos   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
187a5a4af3bSchristos     hw_abort (me, "\"reg\" property must contain three addr/size entries");
188a5a4af3bSchristos   hw_unit_address_to_attach_address (hw_parent (me),
189a5a4af3bSchristos 				     &reg.address,
190a5a4af3bSchristos 				     &attach_space, &attach_address, me);
191a5a4af3bSchristos   timers->base = attach_address;
192a5a4af3bSchristos   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
193a5a4af3bSchristos   timers->limit = attach_address + (attach_size - 1);
194a5a4af3bSchristos   hw_attach_address (hw_parent (me),
195a5a4af3bSchristos 		     0, attach_space, attach_address, attach_size, me);
196a5a4af3bSchristos }
197a5a4af3bSchristos 
198a5a4af3bSchristos static void
199a5a4af3bSchristos lm32timer_finish (struct hw *me)
200a5a4af3bSchristos {
201a5a4af3bSchristos   struct lm32timer *timers;
202a5a4af3bSchristos   int i;
203a5a4af3bSchristos 
204a5a4af3bSchristos   timers = HW_ZALLOC (me, struct lm32timer);
205a5a4af3bSchristos   set_hw_data (me, timers);
206a5a4af3bSchristos   set_hw_io_read_buffer (me, lm32timer_io_read_buffer);
207a5a4af3bSchristos   set_hw_io_write_buffer (me, lm32timer_io_write_buffer);
208a5a4af3bSchristos   set_hw_ports (me, lm32timer_ports);
209a5a4af3bSchristos 
210a5a4af3bSchristos   /* Attach ourself to our parent bus.  */
211a5a4af3bSchristos   attach_lm32timer_regs (me, timers);
212a5a4af3bSchristos 
213a5a4af3bSchristos   /* Initialize the timers.  */
214a5a4af3bSchristos   timers->status = 0;
215a5a4af3bSchristos   timers->control = 0;
216a5a4af3bSchristos   timers->period = 0;
217a5a4af3bSchristos   timers->snapshot = 0;
218a5a4af3bSchristos }
219a5a4af3bSchristos 
220a5a4af3bSchristos const struct hw_descriptor dv_lm32timer_descriptor[] = {
221a5a4af3bSchristos   {"lm32timer", lm32timer_finish,},
222a5a4af3bSchristos   {NULL},
223a5a4af3bSchristos };
224