Add a number of per-simulator options: hostendian, endian, inline, warnings.
[external/binutils.git] / sim / common / sim-core.c
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