Commit | Line | Data |
---|---|---|
f2de7dfd AC |
1 | /* This file is part of the program psim. |
2 | ||
3 | Copyright (C) 1994-1997, 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 _SIM_CORE_C_ | |
23 | #define _SIM_CORE_C_ | |
24 | ||
25 | #include "engine.h" | |
26 | ||
27 | ||
28 | INLINE_SIM_CORE\ | |
29 | (void) | |
30 | core_init(engine *system) | |
31 | { | |
32 | core *memory = &system->memory; | |
33 | core_maps map; | |
34 | for (map = 0; | |
35 | map < nr_core_maps; | |
36 | map++) { | |
37 | /* blow away old mappings */ | |
38 | core_mapping *curr = memory->map[map].first; | |
39 | while (curr != NULL) { | |
40 | core_mapping *tbd = curr; | |
41 | curr = curr->next; | |
42 | if (tbd->free_buffer) { | |
43 | ASSERT(tbd->buffer != NULL); | |
44 | zfree(tbd->buffer); | |
45 | } | |
46 | zfree(tbd); | |
47 | } | |
48 | memory->map[map].first = NULL; | |
49 | } | |
50 | } | |
51 | ||
52 | ||
53 | ||
54 | STATIC_INLINE_SIM_CORE\ | |
55 | (core_mapping *) | |
56 | new_core_mapping(engine *system, | |
57 | attach_type attach, | |
58 | int space, | |
59 | unsigned_word addr, | |
60 | unsigned nr_bytes, | |
61 | device *device, | |
62 | void *buffer, | |
63 | int free_buffer) | |
64 | { | |
65 | core_mapping *new_mapping = ZALLOC(core_mapping); | |
66 | /* common */ | |
67 | new_mapping->level = attach; | |
68 | new_mapping->space = space; | |
69 | new_mapping->base = addr; | |
70 | new_mapping->nr_bytes = nr_bytes; | |
71 | new_mapping->bound = addr + (nr_bytes - 1); | |
72 | if (attach == attach_raw_memory) { | |
73 | new_mapping->buffer = buffer; | |
74 | new_mapping->free_buffer = free_buffer; | |
75 | } | |
76 | else if (attach >= attach_callback) { | |
77 | new_mapping->device = device; | |
78 | } | |
79 | else { | |
80 | engine_error(system, "new_core_mapping - internal error - unknown attach type %d\n", | |
81 | attach); | |
82 | } | |
83 | return new_mapping; | |
84 | } | |
85 | ||
86 | ||
87 | STATIC_INLINE_SIM_CORE\ | |
88 | (void) | |
89 | core_map_attach(engine *system, | |
90 | core_map *access_map, | |
91 | attach_type attach, | |
92 | int space, | |
93 | unsigned_word addr, | |
94 | unsigned nr_bytes, /* host limited */ | |
95 | device *client, /*callback/default*/ | |
96 | void *buffer, /*raw_memory*/ | |
97 | int free_buffer) /*raw_memory*/ | |
98 | { | |
99 | /* find the insertion point for this additional mapping and then | |
100 | insert */ | |
101 | core_mapping *next_mapping; | |
102 | core_mapping **last_mapping; | |
103 | ||
104 | ASSERT((attach >= attach_callback && client != NULL && buffer == NULL && !free_buffer) | |
105 | || (attach == attach_raw_memory && client == NULL && buffer != NULL)); | |
106 | ||
107 | /* actually do occasionally get a zero size map */ | |
108 | if (nr_bytes == 0) { | |
109 | #if (WITH_DEVICES) | |
110 | device_error(client, "called on core_map_attach with size zero"); | |
111 | #else | |
112 | engine_error(system, "called on core_map_attach with size zero"); | |
113 | #endif | |
114 | } | |
115 | ||
116 | /* find the insertion point (between last/next) */ | |
117 | next_mapping = access_map->first; | |
118 | last_mapping = &access_map->first; | |
119 | while(next_mapping != NULL | |
120 | && (next_mapping->level < attach | |
121 | || (next_mapping->level == attach | |
122 | && next_mapping->bound < addr))) { | |
123 | /* provided levels are the same */ | |
124 | /* assert: next_mapping->base > all bases before next_mapping */ | |
125 | /* assert: next_mapping->bound >= all bounds before next_mapping */ | |
126 | last_mapping = &next_mapping->next; | |
127 | next_mapping = next_mapping->next; | |
128 | } | |
129 | ||
130 | /* check insertion point correct */ | |
131 | ASSERT(next_mapping == NULL || next_mapping->level >= attach); | |
132 | if (next_mapping != NULL && next_mapping->level == attach | |
133 | && next_mapping->base < (addr + (nr_bytes - 1))) { | |
134 | #if (WITH_DEVICES) | |
135 | device_error(client, "map overlap when attaching %d:0x%lx (%ld)", | |
136 | space, (long)addr, (long)nr_bytes); | |
137 | #else | |
138 | engine_error(system, "map overlap when attaching %d:0x%lx (%ld)", | |
139 | space, (long)addr, (long)nr_bytes); | |
140 | #endif | |
141 | } | |
142 | ||
143 | /* create/insert the new mapping */ | |
144 | *last_mapping = new_core_mapping(system, | |
145 | attach, | |
146 | space, addr, nr_bytes, | |
147 | client, buffer, free_buffer); | |
148 | (*last_mapping)->next = next_mapping; | |
149 | } | |
150 | ||
151 | ||
152 | INLINE_SIM_CORE\ | |
153 | (void) | |
154 | core_attach(engine *system, | |
155 | attach_type attach, | |
156 | access_type access, | |
157 | int space, | |
158 | unsigned_word addr, | |
159 | unsigned nr_bytes, /* host limited */ | |
160 | device *client, | |
161 | void *optional_buffer) | |
162 | { | |
163 | core *memory = &system->memory; | |
164 | core_maps map; | |
165 | void *buffer; | |
166 | int buffer_freed; | |
167 | if ((access & access_read_write_exec) == 0 | |
168 | || (access & ~access_read_write_exec) != 0) { | |
169 | #if (WITH_DEVICES) | |
170 | device_error(client, "invalid access for core attach"); | |
171 | #else | |
172 | engine_error(system, "invalid access for core attach"); | |
173 | #endif | |
174 | } | |
175 | /* verify the attach type */ | |
176 | if (attach == attach_raw_memory) { | |
177 | if (optional_buffer == NULL) { | |
178 | buffer = zalloc(nr_bytes); | |
179 | buffer_freed = 0; | |
180 | } | |
181 | else { | |
182 | buffer = optional_buffer; | |
183 | buffer_freed = 1; | |
184 | } | |
185 | } | |
186 | else if (attach >= attach_callback) { | |
187 | buffer = NULL; | |
188 | buffer_freed = 1; | |
189 | } | |
190 | else { | |
191 | #if (WITH_DEVICES) | |
192 | device_error(client, "core_attach - conflicting buffer and attach arguments"); | |
193 | #else | |
194 | engine_error(system, "core_attach - conflicting buffer and attach arguments"); | |
195 | #endif | |
196 | buffer = NULL; | |
197 | buffer_freed = 1; | |
198 | } | |
199 | /* attach the region to all applicable access maps */ | |
200 | for (map = 0; | |
201 | map < nr_core_maps; | |
202 | map++) { | |
203 | switch (map) { | |
204 | case core_read_map: | |
205 | if (access & access_read) | |
206 | core_map_attach(system, &memory->map[map], | |
207 | attach, | |
208 | space, addr, nr_bytes, | |
209 | client, buffer, !buffer_freed); | |
210 | buffer_freed ++; | |
211 | break; | |
212 | case core_write_map: | |
213 | if (access & access_write) | |
214 | core_map_attach(system, &memory->map[map], | |
215 | attach, | |
216 | space, addr, nr_bytes, | |
217 | client, buffer, !buffer_freed); | |
218 | buffer_freed ++; | |
219 | break; | |
220 | case core_execute_map: | |
221 | if (access & access_exec) | |
222 | core_map_attach(system, &memory->map[map], | |
223 | attach, | |
224 | space, addr, nr_bytes, | |
225 | client, buffer, !buffer_freed); | |
226 | buffer_freed ++; | |
227 | break; | |
228 | case nr_core_maps: | |
229 | engine_error(system, "core_attach - internal error - bad switch"); | |
230 | break; | |
231 | } | |
232 | } | |
233 | } | |
234 | ||
235 | ||
236 | STATIC_INLINE_SIM_CORE\ | |
237 | (core_mapping *) | |
238 | core_map_find_mapping(engine *system, | |
239 | core_maps map, | |
240 | unsigned_word addr, | |
241 | unsigned nr_bytes, | |
242 | int abort) /*either 0 or 1 - helps inline */ | |
243 | { | |
244 | core_mapping *mapping = system->memory.map[map].first; | |
245 | ASSERT((addr & (nr_bytes - 1)) == 0); /* must be aligned */ | |
246 | ASSERT((addr + (nr_bytes - 1)) >= addr); /* must not wrap */ | |
247 | while (mapping != NULL) { | |
248 | if (addr >= mapping->base | |
249 | && (addr + (nr_bytes - 1)) <= mapping->bound) | |
250 | return mapping; | |
251 | mapping = mapping->next; | |
252 | } | |
253 | if (abort) | |
254 | engine_error(system, "access to unmaped address 0x%x (%d bytes)\n", | |
255 | addr, nr_bytes); | |
256 | return NULL; | |
257 | } | |
258 | ||
259 | ||
260 | STATIC_INLINE_SIM_CORE\ | |
261 | (void *) | |
262 | core_translate(core_mapping *mapping, | |
263 | unsigned_word addr) | |
264 | { | |
265 | return (void *)(((char *)mapping->buffer) + addr - mapping->base); | |
266 | } | |
267 | ||
268 | ||
269 | INLINE_SIM_CORE\ | |
270 | (unsigned) | |
271 | core_map_read_buffer(engine *system, | |
272 | core_maps map, | |
273 | void *buffer, | |
274 | unsigned_word addr, | |
275 | unsigned len) | |
276 | { | |
277 | unsigned count = 0; | |
278 | while (count < len) { | |
279 | unsigned_word raddr = addr + count; | |
280 | core_mapping *mapping = | |
281 | core_map_find_mapping(system, map, | |
282 | raddr, 1, | |
283 | 0); /*dont-abort*/ | |
284 | if (mapping == NULL) | |
285 | break; | |
286 | #if (WITH_DEVICES) | |
287 | if (mapping->device != NULL) { | |
288 | int nr_bytes = len - count; | |
289 | if (raddr + nr_bytes - 1> mapping->bound) | |
290 | nr_bytes = mapping->bound - raddr + 1; | |
291 | if (device_io_read_buffer(mapping->device, | |
292 | (unsigned_1*)buffer + count, | |
293 | mapping->space, | |
294 | raddr, | |
295 | nr_bytes) != nr_bytes) | |
296 | break; | |
297 | count += nr_bytes; | |
298 | } | |
299 | else | |
300 | #endif | |
301 | { | |
302 | ((unsigned_1*)buffer)[count] = | |
303 | *(unsigned_1*)core_translate(mapping, raddr); | |
304 | count += 1; | |
305 | } | |
306 | } | |
307 | return count; | |
308 | } | |
309 | ||
310 | ||
311 | INLINE_SIM_CORE\ | |
312 | (unsigned) | |
313 | core_map_write_buffer(engine *system, | |
314 | core_maps map, | |
315 | const void *buffer, | |
316 | unsigned_word addr, | |
317 | unsigned len) | |
318 | { | |
319 | unsigned count = 0; | |
320 | while (count < len) { | |
321 | unsigned_word raddr = addr + count; | |
322 | core_mapping *mapping = core_map_find_mapping(system, map, | |
323 | raddr, 1, | |
324 | 0); /*dont-abort*/ | |
325 | if (mapping == NULL) | |
326 | break; | |
327 | #if (WITH_DEVICES) | |
328 | if (WITH_CALLBACK_MEMORY | |
329 | && mapping->device != NULL) { | |
330 | int nr_bytes = len - count; | |
331 | if (raddr + nr_bytes - 1 > mapping->bound) | |
332 | nr_bytes = mapping->bound - raddr + 1; | |
333 | if (device_io_write_buffer(mapping->device, | |
334 | (unsigned_1*)buffer + count, | |
335 | mapping->space, | |
336 | raddr, | |
337 | nr_bytes) != nr_bytes) | |
338 | break; | |
339 | count += nr_bytes; | |
340 | } | |
341 | else | |
342 | #endif | |
343 | { | |
344 | *(unsigned_1*)core_translate(mapping, raddr) = | |
345 | ((unsigned_1*)buffer)[count]; | |
346 | count += 1; | |
347 | } | |
348 | } | |
349 | return count; | |
350 | } | |
351 | ||
352 | ||
353 | /* define the read/write 1/2/4/8/word functions */ | |
354 | ||
355 | #define N 1 | |
356 | #include "sim-n-core.h" | |
357 | #undef N | |
358 | ||
359 | #define N 2 | |
360 | #include "sim-n-core.h" | |
361 | #undef N | |
362 | ||
363 | #define N 4 | |
364 | #include "sim-n-core.h" | |
365 | #undef N | |
366 | ||
367 | #define N 8 | |
368 | #include "sim-n-core.h" | |
369 | #undef N | |
370 | ||
371 | #define N word | |
372 | #include "sim-n-core.h" | |
373 | #undef N | |
374 | ||
375 | #endif |