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