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