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