1 /* This file is part of the program psim.
3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
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.
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.
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.
25 #ifndef STATIC_INLINE_HW_MEMORY
26 #define STATIC_INLINE_HW_MEMORY STATIC_INLINE
29 #include "device_table.h"
33 memory - description of system memory
37 This device describes the size and location of the banks of
38 physical memory within the simulation.
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.
46 reg = { <address> <size> } (required)
48 Each pair specify one bank of memory.
50 available = { <address> <size> } (automatic)
52 Each pair specifies a block of memory that is currently unallocated.
56 typedef struct _memory_reg_spec
{
61 typedef struct _hw_memory_chunk hw_memory_chunk
;
62 struct _hw_memory_chunk
{
63 unsigned_word address
;
65 unsigned_word alloc_address
;
66 unsigned_word alloc_size
;
68 hw_memory_chunk
*next
;
71 typedef struct _hw_memory_device
{
72 hw_memory_chunk
*heap
;
77 hw_memory_create(const char *name
,
78 const device_unit
*unit_address
,
81 hw_memory_device
*hw_memory
= ZALLOC(hw_memory_device
);
87 hw_memory_set_available(device
*me
,
88 hw_memory_device
*hw_memory
)
90 hw_memory_chunk
*chunk
= NULL
;
91 memory_reg_spec
*available
= NULL
;
94 int sizeof_available
= 0;
95 /* determine the nr of available chunks */
96 chunk
= hw_memory
->heap
;
98 while (chunk
!= NULL
) {
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
;
109 while (chunk
!= NULL
) {
110 if (chunk
->available
) {
111 available
[curr
].base
= H2BE_4(chunk
->address
);
112 available
[curr
].size
= H2BE_4(chunk
->size
);
118 device_set_array_property(me
, "available", available
, sizeof_available
);
124 hw_memory_init_address(device
*me
)
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
);
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
));
135 /* free up any previous structures */
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
;
147 /* count/allocate memory entries */
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
),
161 access_read_write_exec
,
165 *curr_chunk
= new_chunk
;
166 curr_chunk
= &new_chunk
->next
;
170 /* initialize the alloc property for this device */
171 hw_memory_set_available(me
, hw_memory
);
175 hw_memory_instance_delete(device_instance
*instance
)
181 hw_memory_instance_claim(device_instance
*instance
,
182 unsigned_word address
,
184 unsigned_word alignment
)
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
,
192 /* find a chunk candidate, either according to address or alignment */
193 if (alignment
== 0) {
194 chunk
= hw_memory
->heap
;
196 && (address
+size
) > (chunk
->address
+chunk
->size
))
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
);
203 chunk
= hw_memory
->heap
;
204 while (chunk
!= NULL
&& chunk
->size
< size
)
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
;
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
;
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
;
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
);
247 hw_memory_instance_release(device_instance
*instance
,
248 unsigned_word address
,
249 unsigned_word length
)
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
) {
263 && chunk
->next
!= NULL
&& chunk
->next
->available
) {
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
;
272 /* update the corresponding property */
273 hw_memory_set_available(device_instance_device(instance
), hw_memory
);
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 */
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
290 static device_instance
*
291 hw_memory_create_instance(device
*me
,
295 return device_create_instance_from(me
, NULL
,
296 device_data(me
), /* nothing better */
298 &hw_memory_instance_callbacks
);
301 static device_callbacks
const hw_memory_callbacks
= {
302 { hw_memory_init_address
, },
303 { NULL
, }, /* address */
306 { NULL
, }, /* interrupt */
307 { NULL
, }, /* unit */
308 hw_memory_create_instance
,
311 const device_descriptor hw_memory_device_descriptor
[] = {
312 { "memory", hw_memory_create
, &hw_memory_callbacks
},
316 #endif /* _HW_MEMORY_C_ */