]> Git Repo - binutils.git/blob - sim/lm32/dv-lm32timer.c
Automatic date update in version.in
[binutils.git] / sim / lm32 / dv-lm32timer.c
1 /*  Lattice Mico32 timer model.
2     Contributed by Jon Beniston <[email protected]>
3     
4    Copyright (C) 2009-2022 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   int i;
203
204   timers = HW_ZALLOC (me, struct lm32timer);
205   set_hw_data (me, timers);
206   set_hw_io_read_buffer (me, lm32timer_io_read_buffer);
207   set_hw_io_write_buffer (me, lm32timer_io_write_buffer);
208   set_hw_ports (me, lm32timer_ports);
209
210   /* Attach ourself to our parent bus.  */
211   attach_lm32timer_regs (me, timers);
212
213   /* Initialize the timers.  */
214   timers->status = 0;
215   timers->control = 0;
216   timers->period = 0;
217   timers->snapshot = 0;
218 }
219
220 const struct hw_descriptor dv_lm32timer_descriptor[] = {
221   {"lm32timer", lm32timer_finish,},
222   {NULL},
223 };
This page took 0.037356 seconds and 4 git commands to generate.