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 | ||
c967f187 DE |
25 | #include "sim-main.h" |
26 | #include "sim-assert.h" | |
f2de7dfd AC |
27 | |
28 | ||
c967f187 DE |
29 | /* "core" module install handler. |
30 | This is called via sim_module_install to install the "core" subsystem | |
31 | into the simulator. */ | |
32 | ||
33 | EXTERN_SIM_CORE\ | |
34 | (SIM_RC) | |
35 | sim_core_install (SIM_DESC sd) | |
36 | { | |
37 | sim_module_add_uninstall_fn (sd, sim_core_uninstall); | |
38 | sim_module_add_init_fn (sd, sim_core_init); | |
39 | return SIM_RC_OK; | |
40 | } | |
41 | ||
42 | ||
43 | /* Uninstall the "core" subsystem from the simulator. */ | |
44 | ||
45 | EXTERN_SIM_CORE\ | |
f2de7dfd | 46 | (void) |
c967f187 DE |
47 | sim_core_uninstall (SIM_DESC sd) |
48 | { | |
49 | /* FIXME: free buffers, etc. */ | |
50 | } | |
51 | ||
52 | ||
53 | EXTERN_SIM_CORE\ | |
54 | (SIM_RC) | |
55 | sim_core_init (SIM_DESC sd) | |
f2de7dfd | 56 | { |
1fe05280 | 57 | sim_core *memory = STATE_CORE(sd); |
c967f187 | 58 | sim_core_maps map; |
f2de7dfd | 59 | for (map = 0; |
c967f187 | 60 | map < nr_sim_core_maps; |
f2de7dfd AC |
61 | map++) { |
62 | /* blow away old mappings */ | |
c967f187 | 63 | sim_core_mapping *curr = memory->map[map].first; |
f2de7dfd | 64 | while (curr != NULL) { |
c967f187 | 65 | sim_core_mapping *tbd = curr; |
f2de7dfd AC |
66 | curr = curr->next; |
67 | if (tbd->free_buffer) { | |
c967f187 | 68 | SIM_ASSERT(tbd->buffer != NULL); |
f2de7dfd AC |
69 | zfree(tbd->buffer); |
70 | } | |
71 | zfree(tbd); | |
72 | } | |
73 | memory->map[map].first = NULL; | |
74 | } | |
c967f187 | 75 | return SIM_RC_OK; |
f2de7dfd AC |
76 | } |
77 | ||
78 | ||
79 | ||
1fe05280 AC |
80 | STATIC_INLINE_SIM_CORE\ |
81 | (const char *) | |
82 | sim_core_map_to_str (sim_core_maps map) | |
83 | { | |
84 | switch (map) | |
85 | { | |
86 | case sim_core_read_map: return "read"; | |
87 | case sim_core_write_map: return "write"; | |
88 | case sim_core_execute_map: return "exec"; | |
89 | default: return "(invalid-map)"; | |
90 | } | |
91 | } | |
92 | ||
93 | ||
f2de7dfd | 94 | STATIC_INLINE_SIM_CORE\ |
c967f187 DE |
95 | (sim_core_mapping *) |
96 | new_sim_core_mapping(SIM_DESC sd, | |
f2de7dfd AC |
97 | attach_type attach, |
98 | int space, | |
99 | unsigned_word addr, | |
100 | unsigned nr_bytes, | |
101 | device *device, | |
102 | void *buffer, | |
103 | int free_buffer) | |
104 | { | |
c967f187 | 105 | sim_core_mapping *new_mapping = ZALLOC(sim_core_mapping); |
f2de7dfd AC |
106 | /* common */ |
107 | new_mapping->level = attach; | |
108 | new_mapping->space = space; | |
109 | new_mapping->base = addr; | |
110 | new_mapping->nr_bytes = nr_bytes; | |
111 | new_mapping->bound = addr + (nr_bytes - 1); | |
112 | if (attach == attach_raw_memory) { | |
113 | new_mapping->buffer = buffer; | |
114 | new_mapping->free_buffer = free_buffer; | |
115 | } | |
116 | else if (attach >= attach_callback) { | |
117 | new_mapping->device = device; | |
118 | } | |
119 | else { | |
c967f187 | 120 | sim_io_error (sd, "new_sim_core_mapping - internal error - unknown attach type %d\n", |
f2de7dfd AC |
121 | attach); |
122 | } | |
123 | return new_mapping; | |
124 | } | |
125 | ||
126 | ||
127 | STATIC_INLINE_SIM_CORE\ | |
128 | (void) | |
c967f187 | 129 | sim_core_map_attach(SIM_DESC sd, |
7a418800 AC |
130 | sim_core_map *access_map, |
131 | attach_type attach, | |
132 | int space, | |
133 | unsigned_word addr, | |
134 | unsigned nr_bytes, /* host limited */ | |
135 | device *client, /*callback/default*/ | |
136 | void *buffer, /*raw_memory*/ | |
137 | int free_buffer) /*raw_memory*/ | |
f2de7dfd AC |
138 | { |
139 | /* find the insertion point for this additional mapping and then | |
140 | insert */ | |
c967f187 DE |
141 | sim_core_mapping *next_mapping; |
142 | sim_core_mapping **last_mapping; | |
f2de7dfd | 143 | |
c967f187 | 144 | SIM_ASSERT((attach >= attach_callback && client != NULL && buffer == NULL && !free_buffer) |
f2de7dfd AC |
145 | || (attach == attach_raw_memory && client == NULL && buffer != NULL)); |
146 | ||
147 | /* actually do occasionally get a zero size map */ | |
148 | if (nr_bytes == 0) { | |
149 | #if (WITH_DEVICES) | |
c967f187 | 150 | device_error(client, "called on sim_core_map_attach with size zero"); |
f2de7dfd | 151 | #else |
c967f187 | 152 | sim_io_error (sd, "called on sim_core_map_attach with size zero"); |
f2de7dfd AC |
153 | #endif |
154 | } | |
155 | ||
156 | /* find the insertion point (between last/next) */ | |
157 | next_mapping = access_map->first; | |
158 | last_mapping = &access_map->first; | |
159 | while(next_mapping != NULL | |
160 | && (next_mapping->level < attach | |
161 | || (next_mapping->level == attach | |
162 | && next_mapping->bound < addr))) { | |
163 | /* provided levels are the same */ | |
164 | /* assert: next_mapping->base > all bases before next_mapping */ | |
165 | /* assert: next_mapping->bound >= all bounds before next_mapping */ | |
166 | last_mapping = &next_mapping->next; | |
167 | next_mapping = next_mapping->next; | |
168 | } | |
169 | ||
170 | /* check insertion point correct */ | |
c967f187 | 171 | SIM_ASSERT(next_mapping == NULL || next_mapping->level >= attach); |
f2de7dfd AC |
172 | if (next_mapping != NULL && next_mapping->level == attach |
173 | && next_mapping->base < (addr + (nr_bytes - 1))) { | |
174 | #if (WITH_DEVICES) | |
175 | device_error(client, "map overlap when attaching %d:0x%lx (%ld)", | |
176 | space, (long)addr, (long)nr_bytes); | |
177 | #else | |
c967f187 | 178 | sim_io_error (sd, "map overlap when attaching %d:0x%lx (%ld)", |
f2de7dfd AC |
179 | space, (long)addr, (long)nr_bytes); |
180 | #endif | |
181 | } | |
182 | ||
183 | /* create/insert the new mapping */ | |
c967f187 | 184 | *last_mapping = new_sim_core_mapping(sd, |
f2de7dfd AC |
185 | attach, |
186 | space, addr, nr_bytes, | |
187 | client, buffer, free_buffer); | |
188 | (*last_mapping)->next = next_mapping; | |
189 | } | |
190 | ||
191 | ||
192 | INLINE_SIM_CORE\ | |
193 | (void) | |
c967f187 | 194 | sim_core_attach(SIM_DESC sd, |
7a418800 AC |
195 | sim_cpu *cpu, |
196 | attach_type attach, | |
197 | access_type access, | |
198 | int space, | |
199 | unsigned_word addr, | |
200 | unsigned nr_bytes, /* host limited */ | |
201 | device *client, | |
202 | void *optional_buffer) | |
f2de7dfd | 203 | { |
1fe05280 | 204 | sim_core *memory = STATE_CORE(sd); |
c967f187 | 205 | sim_core_maps map; |
f2de7dfd AC |
206 | void *buffer; |
207 | int buffer_freed; | |
7a418800 AC |
208 | int i; |
209 | ||
210 | /* check for for attempt to use unimplemented per-processor core map */ | |
211 | if (cpu != NULL) | |
212 | sim_io_error (sd, "sim_core_map_attach - processor specific memory map not yet supported"); | |
213 | ||
f2de7dfd AC |
214 | if ((access & access_read_write_exec) == 0 |
215 | || (access & ~access_read_write_exec) != 0) { | |
216 | #if (WITH_DEVICES) | |
217 | device_error(client, "invalid access for core attach"); | |
218 | #else | |
c967f187 | 219 | sim_io_error (sd, "invalid access for core attach"); |
f2de7dfd AC |
220 | #endif |
221 | } | |
222 | /* verify the attach type */ | |
223 | if (attach == attach_raw_memory) { | |
224 | if (optional_buffer == NULL) { | |
225 | buffer = zalloc(nr_bytes); | |
226 | buffer_freed = 0; | |
227 | } | |
228 | else { | |
229 | buffer = optional_buffer; | |
230 | buffer_freed = 1; | |
231 | } | |
232 | } | |
233 | else if (attach >= attach_callback) { | |
234 | buffer = NULL; | |
235 | buffer_freed = 1; | |
236 | } | |
237 | else { | |
238 | #if (WITH_DEVICES) | |
c967f187 | 239 | device_error(client, "sim_core_attach - conflicting buffer and attach arguments"); |
f2de7dfd | 240 | #else |
c967f187 | 241 | sim_io_error (sd, "sim_core_attach - conflicting buffer and attach arguments"); |
f2de7dfd AC |
242 | #endif |
243 | buffer = NULL; | |
244 | buffer_freed = 1; | |
245 | } | |
246 | /* attach the region to all applicable access maps */ | |
247 | for (map = 0; | |
c967f187 | 248 | map < nr_sim_core_maps; |
f2de7dfd AC |
249 | map++) { |
250 | switch (map) { | |
c967f187 | 251 | case sim_core_read_map: |
f2de7dfd | 252 | if (access & access_read) |
c967f187 | 253 | sim_core_map_attach(sd, &memory->map[map], |
f2de7dfd AC |
254 | attach, |
255 | space, addr, nr_bytes, | |
256 | client, buffer, !buffer_freed); | |
257 | buffer_freed ++; | |
258 | break; | |
c967f187 | 259 | case sim_core_write_map: |
f2de7dfd | 260 | if (access & access_write) |
c967f187 | 261 | sim_core_map_attach(sd, &memory->map[map], |
f2de7dfd AC |
262 | attach, |
263 | space, addr, nr_bytes, | |
264 | client, buffer, !buffer_freed); | |
265 | buffer_freed ++; | |
266 | break; | |
c967f187 | 267 | case sim_core_execute_map: |
f2de7dfd | 268 | if (access & access_exec) |
c967f187 | 269 | sim_core_map_attach(sd, &memory->map[map], |
f2de7dfd AC |
270 | attach, |
271 | space, addr, nr_bytes, | |
272 | client, buffer, !buffer_freed); | |
273 | buffer_freed ++; | |
274 | break; | |
c967f187 DE |
275 | case nr_sim_core_maps: |
276 | sim_io_error (sd, "sim_core_attach - internal error - bad switch"); | |
f2de7dfd AC |
277 | break; |
278 | } | |
279 | } | |
7a418800 AC |
280 | |
281 | /* Just copy this map to each of the processor specific data structures. | |
282 | FIXME - later this will be replaced by true processor specific | |
283 | maps. */ | |
284 | for (i = 0; i < MAX_NR_PROCESSORS; i++) | |
285 | *CPU_CORE (STATE_CPU (sd, i)) = *STATE_CORE (sd); | |
f2de7dfd AC |
286 | } |
287 | ||
288 | ||
289 | STATIC_INLINE_SIM_CORE\ | |
c967f187 | 290 | (sim_core_mapping *) |
7a418800 | 291 | sim_core_find_mapping(sim_core *core, |
c967f187 | 292 | sim_core_maps map, |
f2de7dfd AC |
293 | unsigned_word addr, |
294 | unsigned nr_bytes, | |
7a418800 AC |
295 | int abort, /*either 0 or 1 - hint to inline/-O */ |
296 | sim_cpu *cpu, /* abort => cpu != NULL */ | |
1fe05280 | 297 | sim_cia cia) |
f2de7dfd | 298 | { |
7a418800 AC |
299 | sim_core_mapping *mapping = core->map[map].first; |
300 | ASSERT ((addr & (nr_bytes - 1)) == 0); /* must be aligned */ | |
301 | ASSERT ((addr + (nr_bytes - 1)) >= addr); /* must not wrap */ | |
302 | ASSERT (!abort || cpu != NULL); /* abort needs a non null CPU */ | |
303 | while (mapping != NULL) | |
304 | { | |
305 | if (addr >= mapping->base | |
306 | && (addr + (nr_bytes - 1)) <= mapping->bound) | |
307 | return mapping; | |
308 | mapping = mapping->next; | |
309 | } | |
f2de7dfd | 310 | if (abort) |
7a418800 AC |
311 | { |
312 | if (cpu == NULL) | |
313 | sim_io_error (NULL, "sim_core_find_map - internal error - can not abort without a processor"); | |
314 | else | |
c445af5a | 315 | engine_error (CPU_STATE (cpu), cpu, cia, |
7a418800 AC |
316 | "access to unmaped address 0x%lx (%d bytes)\n", |
317 | (unsigned long) addr, nr_bytes); | |
318 | } | |
f2de7dfd AC |
319 | return NULL; |
320 | } | |
321 | ||
322 | ||
323 | STATIC_INLINE_SIM_CORE\ | |
324 | (void *) | |
c967f187 | 325 | sim_core_translate(sim_core_mapping *mapping, |
f2de7dfd AC |
326 | unsigned_word addr) |
327 | { | |
328 | return (void *)(((char *)mapping->buffer) + addr - mapping->base); | |
329 | } | |
330 | ||
331 | ||
332 | INLINE_SIM_CORE\ | |
333 | (unsigned) | |
c967f187 DE |
334 | sim_core_read_buffer(SIM_DESC sd, |
335 | sim_core_maps map, | |
f2de7dfd AC |
336 | void *buffer, |
337 | unsigned_word addr, | |
338 | unsigned len) | |
339 | { | |
340 | unsigned count = 0; | |
341 | while (count < len) { | |
342 | unsigned_word raddr = addr + count; | |
c967f187 | 343 | sim_core_mapping *mapping = |
7a418800 | 344 | sim_core_find_mapping(STATE_CORE (sd), map, |
f2de7dfd | 345 | raddr, 1, |
1fe05280 | 346 | 0, NULL, NULL_CIA); /*dont-abort*/ |
f2de7dfd AC |
347 | if (mapping == NULL) |
348 | break; | |
349 | #if (WITH_DEVICES) | |
350 | if (mapping->device != NULL) { | |
351 | int nr_bytes = len - count; | |
352 | if (raddr + nr_bytes - 1> mapping->bound) | |
353 | nr_bytes = mapping->bound - raddr + 1; | |
354 | if (device_io_read_buffer(mapping->device, | |
355 | (unsigned_1*)buffer + count, | |
356 | mapping->space, | |
357 | raddr, | |
358 | nr_bytes) != nr_bytes) | |
359 | break; | |
360 | count += nr_bytes; | |
361 | } | |
362 | else | |
363 | #endif | |
364 | { | |
365 | ((unsigned_1*)buffer)[count] = | |
c967f187 | 366 | *(unsigned_1*)sim_core_translate(mapping, raddr); |
f2de7dfd AC |
367 | count += 1; |
368 | } | |
369 | } | |
370 | return count; | |
371 | } | |
372 | ||
373 | ||
374 | INLINE_SIM_CORE\ | |
375 | (unsigned) | |
c967f187 DE |
376 | sim_core_write_buffer(SIM_DESC sd, |
377 | sim_core_maps map, | |
f2de7dfd AC |
378 | const void *buffer, |
379 | unsigned_word addr, | |
380 | unsigned len) | |
381 | { | |
382 | unsigned count = 0; | |
383 | while (count < len) { | |
384 | unsigned_word raddr = addr + count; | |
7a418800 | 385 | sim_core_mapping *mapping = sim_core_find_mapping(STATE_CORE (sd), map, |
c967f187 | 386 | raddr, 1, |
1fe05280 | 387 | 0, NULL, NULL_CIA); /*dont-abort*/ |
f2de7dfd AC |
388 | if (mapping == NULL) |
389 | break; | |
390 | #if (WITH_DEVICES) | |
391 | if (WITH_CALLBACK_MEMORY | |
392 | && mapping->device != NULL) { | |
393 | int nr_bytes = len - count; | |
394 | if (raddr + nr_bytes - 1 > mapping->bound) | |
395 | nr_bytes = mapping->bound - raddr + 1; | |
396 | if (device_io_write_buffer(mapping->device, | |
397 | (unsigned_1*)buffer + count, | |
398 | mapping->space, | |
399 | raddr, | |
400 | nr_bytes) != nr_bytes) | |
401 | break; | |
402 | count += nr_bytes; | |
403 | } | |
404 | else | |
405 | #endif | |
406 | { | |
c967f187 | 407 | *(unsigned_1*)sim_core_translate(mapping, raddr) = |
f2de7dfd AC |
408 | ((unsigned_1*)buffer)[count]; |
409 | count += 1; | |
410 | } | |
411 | } | |
412 | return count; | |
413 | } | |
414 | ||
415 | ||
416 | /* define the read/write 1/2/4/8/word functions */ | |
417 | ||
418 | #define N 1 | |
419 | #include "sim-n-core.h" | |
420 | #undef N | |
421 | ||
422 | #define N 2 | |
423 | #include "sim-n-core.h" | |
424 | #undef N | |
425 | ||
426 | #define N 4 | |
427 | #include "sim-n-core.h" | |
428 | #undef N | |
429 | ||
430 | #define N 8 | |
431 | #include "sim-n-core.h" | |
432 | #undef N | |
433 | ||
434 | #define N word | |
435 | #include "sim-n-core.h" | |
436 | #undef N | |
437 | ||
438 | #endif |