New simulator changes from Andrew
[deliverable/binutils-gdb.git] / sim / ppc / hw_memory.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21
22 #ifndef _HW_MEMORY_C_
23 #define _HW_MEMORY_C_
24
25 #ifndef STATIC_INLINE_HW_MEMORY
26 #define STATIC_INLINE_HW_MEMORY STATIC_INLINE
27 #endif
28
29 #include "device_table.h"
30
31 /* DEVICE
32
33 memory - description of system memory
34
35 DESCRIPTION
36
37 This device describes the size and location of the banks of
38 physical memory within the simulation.
39
40 In addition, this device supports the "claim" and "release" methods
41 that can be used by OpenBoot client programs to manage the
42 allocation of physical memory.
43
44 PROPERTIES
45
46 reg = { <address> <size> } (required)
47
48 Each pair specify one bank of memory.
49
50 available = { <address> <size> } (automatic)
51
52 Each pair specifies a block of memory that is currently unallocated.
53
54 */
55
56 typedef struct _memory_reg_spec {
57 unsigned32 base;
58 unsigned32 size;
59 } memory_reg_spec;
60
61 typedef struct _hw_memory_chunk hw_memory_chunk;
62 struct _hw_memory_chunk {
63 unsigned_word address;
64 unsigned_word size;
65 unsigned_word alloc_address;
66 unsigned_word alloc_size;
67 int available;
68 hw_memory_chunk *next;
69 };
70
71 typedef struct _hw_memory_device {
72 hw_memory_chunk *heap;
73 } hw_memory_device;
74
75
76 static void *
77 hw_memory_create(const char *name,
78 const device_unit *unit_address,
79 const char *args)
80 {
81 hw_memory_device *hw_memory = ZALLOC(hw_memory_device);
82 return hw_memory;
83 }
84
85
86 static void
87 hw_memory_set_available(device *me,
88 hw_memory_device *hw_memory)
89 {
90 hw_memory_chunk *chunk = NULL;
91 memory_reg_spec *available = NULL;
92 int nr_available = 0;
93 int curr = 0;
94 int sizeof_available = 0;
95 /* determine the nr of available chunks */
96 chunk = hw_memory->heap;
97 nr_available = 0;
98 while (chunk != NULL) {
99 if (chunk->available)
100 nr_available += 1;
101 chunk = chunk->next;
102 }
103 /* now create the available struct */
104 ASSERT(nr_available > 0);
105 sizeof_available = sizeof(memory_reg_spec) * nr_available;
106 available = zalloc(sizeof_available);
107 chunk = hw_memory->heap;
108 curr = 0;
109 while (chunk != NULL) {
110 if (chunk->available) {
111 available[curr].base = H2BE_4(chunk->address);
112 available[curr].size = H2BE_4(chunk->size);
113 curr += 1;
114 }
115 chunk = chunk->next;
116 }
117 /* update */
118 device_set_array_property(me, "available", available, sizeof_available);
119 zfree(available);
120 }
121
122
123 static void
124 hw_memory_init_address(device *me)
125 {
126 hw_memory_device *hw_memory = (hw_memory_device*)device_data(me);
127 const device_property *reg = device_find_array_property(me, "reg");
128 const memory_reg_spec *spec = reg->array;
129 int nr_entries = reg->sizeof_array / sizeof(*spec);
130
131 /* sanity check reg property */
132 if ((reg->sizeof_array % sizeof(*spec)) != 0)
133 error("devices/%s reg property of incorrect size\n", device_name(me));
134
135 /* free up any previous structures */
136 {
137 hw_memory_chunk *curr_chunk = hw_memory->heap;
138 hw_memory->heap = NULL;
139 while (curr_chunk != NULL) {
140 hw_memory_chunk *dead_chunk = curr_chunk;
141 curr_chunk = dead_chunk->next;
142 dead_chunk->next = NULL;
143 zfree(dead_chunk);
144 }
145 }
146
147 /* count/allocate memory entries */
148 {
149 hw_memory_chunk **curr_chunk = &hw_memory->heap;
150 while (nr_entries > 0) {
151 hw_memory_chunk *new_chunk = ZALLOC(hw_memory_chunk);
152 new_chunk->address = BE2H_4(spec->base);
153 new_chunk->size = BE2H_4(spec->size);
154 new_chunk->available = 1;
155 device_attach_address(device_parent(me),
156 device_name(me),
157 attach_raw_memory,
158 0 /*address space*/,
159 new_chunk->address,
160 new_chunk->size,
161 access_read_write_exec,
162 me);
163 spec++;
164 nr_entries--;
165 *curr_chunk = new_chunk;
166 curr_chunk = &new_chunk->next;
167 }
168 }
169
170 /* initialize the alloc property for this device */
171 hw_memory_set_available(me, hw_memory);
172 }
173
174 static void
175 hw_memory_instance_delete(device_instance *instance)
176 {
177 return;
178 }
179
180 static unsigned_word
181 hw_memory_instance_claim(device_instance *instance,
182 unsigned_word address,
183 unsigned_word size,
184 unsigned_word alignment)
185 {
186 hw_memory_device *hw_memory = device_instance_data(instance);
187 hw_memory_chunk *chunk = NULL;
188 DTRACE(memory, ("claim - address=0x%lx size=0x%lx alignment=%d\n",
189 (unsigned long)address,
190 (unsigned long)size,
191 (int)alignment));
192 /* find a chunk candidate, either according to address or alignment */
193 if (alignment == 0) {
194 chunk = hw_memory->heap;
195 while (chunk != NULL
196 && (address+size) > (chunk->address+chunk->size))
197 chunk = chunk->next;
198 if (chunk == NULL || address < chunk->address || !chunk->available)
199 error("hw_memory_instance_claim: failed to allocate @0x%lx, size %ld\n",
200 (unsigned long)address, (unsigned long)size);
201 }
202 else {
203 chunk = hw_memory->heap;
204 while (chunk != NULL && chunk->size < size)
205 chunk = chunk->next;
206 if (chunk == NULL || FLOOR_PAGE(alignment-1) > 0)
207 error("hw_memory_instance_claim: failed to allocate %ld, align %ld\n",
208 (unsigned long)size, (unsigned long)size);
209 address = chunk->address;
210 }
211 /* break of a part before this memory if needed */
212 ASSERT(address >= chunk->address);
213 if (FLOOR_PAGE(address) > chunk->address) {
214 hw_memory_chunk *last_chunk = chunk;
215 /* insert a new earlier chunk */
216 chunk = ZALLOC(hw_memory_chunk);
217 chunk->next = last_chunk->next;
218 last_chunk->next = chunk;
219 /* adjust the address/size */
220 chunk->address = FLOOR_PAGE(address);
221 chunk->size = last_chunk->size - (chunk->address - last_chunk->address);
222 last_chunk->size = chunk->address - last_chunk->address;
223 }
224 ASSERT(FLOOR_PAGE(address) == chunk->address);
225 /* break of a bit after this chunk if needed */
226 if (ALIGN_PAGE(address+size) < chunk->address + chunk->size) {
227 hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk);
228 /* insert it in to the list */
229 next_chunk->next = chunk->next;
230 chunk->next = next_chunk;
231 next_chunk->available = 1;
232 /* adjust the address/size */
233 next_chunk->address = ALIGN_PAGE(address+size);
234 next_chunk->size = chunk->address + chunk->size - next_chunk->address;
235 chunk->size = next_chunk->address - chunk->address;
236 }
237 ASSERT(ALIGN_PAGE(address+size) == chunk->address + chunk->size);
238 /* now allocate it */
239 chunk->alloc_address = address;
240 chunk->alloc_size = size;
241 chunk->available = 0;
242 hw_memory_set_available(device_instance_device(instance), hw_memory);
243 return address;
244 }
245
246 static void
247 hw_memory_instance_release(device_instance *instance,
248 unsigned_word address,
249 unsigned_word length)
250 {
251 hw_memory_device *hw_memory = device_instance_data(instance);
252 hw_memory_chunk *chunk = hw_memory->heap;
253 while (chunk != NULL) {
254 if (chunk->alloc_address == address
255 && chunk->alloc_size == length
256 && chunk->available == 0) {
257 /* free this chunk */
258 chunk->available = 1;
259 /* check for merge */
260 chunk = hw_memory->heap;
261 while (chunk != NULL) {
262 if (chunk->available
263 && chunk->next != NULL && chunk->next->available) {
264 /* adjacent */
265 hw_memory_chunk *delete = chunk->next;
266 ASSERT(chunk->address + chunk->size == delete->address);
267 chunk->size += delete->size;
268 chunk->next = delete->next;
269 zfree(delete);
270 }
271 }
272 /* update the corresponding property */
273 hw_memory_set_available(device_instance_device(instance), hw_memory);
274 return;
275 }
276 chunk = chunk->next;
277 }
278 error("hw_memory_instance_release: Address 0x%lx, size %ld not found\n",
279 (unsigned long)address, (unsigned long)length);
280 /* FIXME - dump allocated */
281 /* FIXME - dump arguments */
282 }
283
284 static device_instance_callbacks const hw_memory_instance_callbacks = {
285 hw_memory_instance_delete,
286 NULL /*read*/, NULL /*write*/, NULL /*seek*/,
287 hw_memory_instance_claim, hw_memory_instance_release
288 };
289
290 static device_instance *
291 hw_memory_create_instance(device *me,
292 const char *path,
293 const char *args)
294 {
295 return device_create_instance_from(me, NULL,
296 device_data(me), /* nothing better */
297 path, args,
298 &hw_memory_instance_callbacks);
299 }
300
301 static device_callbacks const hw_memory_callbacks = {
302 { hw_memory_init_address, },
303 { NULL, }, /* address */
304 { NULL, }, /* IO */
305 { NULL, }, /* DMA */
306 { NULL, }, /* interrupt */
307 { NULL, }, /* unit */
308 hw_memory_create_instance,
309 };
310
311 const device_descriptor hw_memory_device_descriptor[] = {
312 { "memory", hw_memory_create, &hw_memory_callbacks },
313 { NULL },
314 };
315
316 #endif /* _HW_MEMORY_C_ */
This page took 0.049623 seconds and 4 git commands to generate.