10Sduke/*  This file is part of the program psim.
210287Sddmitriev
30Sduke    Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
40Sduke
50Sduke    This program is free software; you can redistribute it and/or modify
60Sduke    it under the terms of the GNU General Public License as published by
70Sduke    the Free Software Foundation; either version 2 of the License, or
80Sduke    (at your option) any later version.
90Sduke
100Sduke    This program is distributed in the hope that it will be useful,
110Sduke    but WITHOUT ANY WARRANTY; without even the implied warranty of
120Sduke    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
130Sduke    GNU General Public License for more details.
140Sduke
150Sduke    You should have received a copy of the GNU General Public License
160Sduke    along with this program; if not, write to the Free Software
170Sduke    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
180Sduke
191472Strims    */
201472Strims
211472Strims
220Sduke#ifndef _CORE_C_
230Sduke#define _CORE_C_
240Sduke
251879Sstefank#include "basics.h"
261879Sstefank#include "device_table.h"
271879Sstefank#include "corefile.h"
281879Sstefank
291879Sstefanktypedef struct _core_mapping core_mapping;
301879Sstefankstruct _core_mapping {
318569Sgziemski  /* common */
3211219Sgziemski  int level;
338569Sgziemski  int space;
347331Sgoetz  unsigned_word base;
358569Sgziemski  unsigned_word bound;
367425Sstefank  unsigned nr_bytes;
3711219Sgziemski  /* memory map */
388413Spliden  void *free_buffer;
391879Sstefank  void *buffer;
404107Sjprovino  /* callback map */
418413Spliden  device *device;
424107Sjprovino  /* growth */
431879Sstefank  core_mapping *next;
441879Sstefank};
451879Sstefank
469111Stwististruct _core_map {
479111Stwisti  core_mapping *first;
489111Stwisti};
491879Sstefank
501879Sstefanktypedef enum {
511879Sstefank  core_read_map,
521879Sstefank  core_write_map,
531879Sstefank  core_execute_map,
541879Sstefank  nr_core_map_types,
550Sduke} core_map_types;
568569Sgziemski
578569Sgziemskistruct _core {
588569Sgziemski  core_map map[nr_core_map_types];
598569Sgziemski};
608569Sgziemski
6111390Scsahu
628569SgziemskiINLINE_CORE\
632852Sphh(core *)
648569Sgziemskicore_create(void)
658569Sgziemski{
668569Sgziemski  return ZALLOC(core);
678569Sgziemski}
6811219Sgziemski
6911219Sgziemski
700SdukeINLINE_CORE\
718569Sgziemski(core *)
728569Sgziemskicore_from_device(device *root)
738569Sgziemski{
748569Sgziemski  root = device_root(root);
758569Sgziemski  ASSERT(strcmp(device_name(root), "core") == 0);
7611390Scsahu  return device_data(root);
778569Sgziemski}
788569Sgziemski
7911219Sgziemski
8011219SgziemskiINLINE_CORE\
810Sduke(void)
828569Sgziemskicore_init(core *memory)
838569Sgziemski{
848569Sgziemski  core_map_types access_type;
858569Sgziemski  for (access_type = 0;
868569Sgziemski       access_type < nr_core_map_types;
878569Sgziemski       access_type++) {
8811219Sgziemski    core_map *map = memory->map + access_type;
8911219Sgziemski    /* blow away old mappings */
903585Stwisti    core_mapping *curr = map->first;
912868Sphh    while (curr != NULL) {
922868Sphh      core_mapping *tbd = curr;
9310722Sgziemski      curr = curr->next;
9410722Sgziemski      if (tbd->free_buffer != NULL) {
9510722Sgziemski	ASSERT(tbd->buffer != NULL);
9610722Sgziemski	free(tbd->free_buffer);
9710722Sgziemski      }
9810722Sgziemski      free(tbd);
9910722Sgziemski    }
10010722Sgziemski    map->first = NULL;
10110722Sgziemski  }
10210722Sgziemski}
10310722Sgziemski
10410722Sgziemski
10510722Sgziemski
10610722Sgziemski/* the core has three sub mappings that the more efficient
10710722Sgziemski   read/write fixed quantity functions use */
10810722Sgziemski
10910722SgziemskiINLINE_CORE\
11010722Sgziemski(core_map *)
11110722Sgziemskicore_readable(core *memory)
11210722Sgziemski{
11310722Sgziemski  return memory->map + core_read_map;
11410722Sgziemski}
11510722Sgziemski
11610722SgziemskiINLINE_CORE\
11710722Sgziemski(core_map *)
11810722Sgziemskicore_writeable(core *memory)
11910722Sgziemski{
12010722Sgziemski  return memory->map + core_write_map;
12110722Sgziemski}
12210722Sgziemski
12310722SgziemskiINLINE_CORE\
12410722Sgziemski(core_map *)
12510722Sgziemskicore_executable(core *memory)
12610722Sgziemski{
12710722Sgziemski  return memory->map + core_execute_map;
12810722Sgziemski}
12910722Sgziemski
13010722Sgziemski
13110722Sgziemski
13210722SgziemskiSTATIC_INLINE_CORE\
13310722Sgziemski(core_mapping *)
13410722Sgziemskinew_core_mapping(attach_type attach,
13510722Sgziemski		 int space,
13610722Sgziemski		 unsigned_word addr,
13710722Sgziemski		 unsigned nr_bytes,
13810722Sgziemski		 device *device,
13910722Sgziemski		 void *buffer,
14010722Sgziemski		 void *free_buffer)
14110722Sgziemski{
14210722Sgziemski  core_mapping *new_mapping = ZALLOC(core_mapping);
1435829Sccheung  /* common */
1445829Sccheung  new_mapping->level = attach;
1455829Sccheung  new_mapping->space = space;
1465829Sccheung  new_mapping->base = addr;
1475829Sccheung  new_mapping->nr_bytes = nr_bytes;
1485829Sccheung  new_mapping->bound = addr + (nr_bytes - 1);
1495829Sccheung  if (attach == attach_raw_memory) {
1505829Sccheung    new_mapping->buffer = buffer;
15111219Sgziemski    new_mapping->free_buffer = free_buffer;
1525355Stwisti  }
1539056Sdavid  else if (attach >= attach_callback) {
1545355Stwisti    new_mapping->device = device;
15511219Sgziemski  }
15611219Sgziemski  else {
15711219Sgziemski    error("new_core_mapping() - internal error - unknown attach type %d\n",
15811219Sgziemski	  attach);
15911219Sgziemski  }
16011219Sgziemski  return new_mapping;
16111219Sgziemski}
16211219Sgziemski
16311219Sgziemski
16411219SgziemskiSTATIC_INLINE_CORE\
16511219Sgziemski(void)
16611219Sgziemskicore_map_attach(core_map *access_map,
16711219Sgziemski		attach_type attach,
16811219Sgziemski		int space,
16911219Sgziemski		unsigned_word addr,
17011219Sgziemski		unsigned nr_bytes, /* host limited */
17111219Sgziemski		device *client, /*callback/default*/
17211219Sgziemski		void *buffer, /*raw_memory*/
17311219Sgziemski		void *free_buffer) /*raw_memory*/
17411219Sgziemski{
17511219Sgziemski  /* find the insertion point for this additional mapping and insert */
17611219Sgziemski  core_mapping *next_mapping;
17711219Sgziemski  core_mapping **last_mapping;
17811219Sgziemski
17911219Sgziemski  /* actually do occasionally get a zero size map */
1805355Stwisti  if (nr_bytes == 0) {
1815355Stwisti    device_error(client, "called on core_map_attach() with size zero");
1825355Stwisti  }
1835355Stwisti
1845355Stwisti  /* find the insertion point (between last/next) */
1855355Stwisti  next_mapping = access_map->first;
1865355Stwisti  last_mapping = &access_map->first;
1875355Stwisti  while(next_mapping != NULL
1885355Stwisti	&& (next_mapping->level < attach
1895355Stwisti	    || (next_mapping->level == attach
19011219Sgziemski		&& next_mapping->bound < addr))) {
19111219Sgziemski    /* provided levels are the same */
19211219Sgziemski    /* assert: next_mapping->base > all bases before next_mapping */
19311219Sgziemski    /* assert: next_mapping->bound >= all bounds before next_mapping */
19411219Sgziemski    last_mapping = &next_mapping->next;
19511219Sgziemski    next_mapping = next_mapping->next;
1965355Stwisti  }
1975355Stwisti
1988522Sdavid  /* check insertion point correct */
1998522Sdavid  ASSERT(next_mapping == NULL || next_mapping->level >= attach);
2008522Sdavid  if (next_mapping != NULL && next_mapping->level == attach
2018522Sdavid      && next_mapping->base < (addr + (nr_bytes - 1))) {
2028522Sdavid    device_error(client, "map overlap when attaching %d:0x%lx (%ld)",
2038522Sdavid		 space, (long)addr, (long)nr_bytes);
2048522Sdavid  }
2058522Sdavid
20611219Sgziemski  /* create/insert the new mapping */
20711219Sgziemski  *last_mapping = new_core_mapping(attach,
20811219Sgziemski				   space, addr, nr_bytes,
20911219Sgziemski				   client, buffer, free_buffer);
21011219Sgziemski  (*last_mapping)->next = next_mapping;
21111219Sgziemski}
2128522Sdavid
2138522Sdavid
2148522SdavidINLINE_CORE\
2158522Sdavid(void)
2168522Sdavidcore_attach(core *memory,
2178522Sdavid	    attach_type attach,
2188522Sdavid	    int space,
2198522Sdavid	    access_type access,
2208522Sdavid	    unsigned_word addr,
2218522Sdavid	    unsigned nr_bytes, /* host limited */
22211219Sgziemski	    device *client) /*callback/default*/
22311219Sgziemski{
22411219Sgziemski  core_map_types access_map;
22511219Sgziemski  void *buffer;
22611219Sgziemski  void *free_buffer;
22711219Sgziemski  if (attach == attach_raw_memory) {
2288522Sdavid    /* Padd out the raw buffer to ensure that ADDR starts on a
2298522Sdavid       correctly aligned boundary */
2305355Stwisti    int padding = (addr % sizeof (unsigned64));
2315355Stwisti    free_buffer = zalloc(nr_bytes + padding);
2325355Stwisti    buffer = (char*)free_buffer + padding;
2335355Stwisti  }
2345355Stwisti  else {
2355355Stwisti    buffer = NULL;
2365355Stwisti    free_buffer = &buffer; /* marker for assertion */
2375355Stwisti  }
23811219Sgziemski  for (access_map = 0;
23911219Sgziemski       access_map < nr_core_map_types;
24011219Sgziemski       access_map++) {
24111219Sgziemski    switch (access_map) {
24211219Sgziemski    case core_read_map:
24311219Sgziemski      if (access & access_read)
2445355Stwisti	core_map_attach(memory->map + access_map,
2455355Stwisti			attach,
2465355Stwisti			space, addr, nr_bytes,
2475355Stwisti			client, buffer, free_buffer);
2485355Stwisti      free_buffer = NULL;
2495355Stwisti      break;
2505355Stwisti    case core_write_map:
2515355Stwisti      if (access & access_write)
2525355Stwisti	core_map_attach(memory->map + access_map,
2535355Stwisti			attach,
25411219Sgziemski			space, addr, nr_bytes,
25511219Sgziemski			client, buffer, free_buffer);
25611219Sgziemski      free_buffer = NULL;
25711219Sgziemski      break;
25811219Sgziemski    case core_execute_map:
25911219Sgziemski      if (access & access_exec)
2605355Stwisti	core_map_attach(memory->map + access_map,
2615355Stwisti			attach,
2625355Stwisti			space, addr, nr_bytes,
2635355Stwisti			client, buffer, free_buffer);
2645355Stwisti      free_buffer = NULL;
2655355Stwisti      break;
2665355Stwisti    default:
2675355Stwisti      error("core_attach() internal error\n");
2685355Stwisti      break;
2695355Stwisti    }
27011219Sgziemski  }
27111219Sgziemski  /* allocated buffer must attach to at least one thing */
27211219Sgziemski  ASSERT(free_buffer == NULL);
27311219Sgziemski}
27411219Sgziemski
27511219Sgziemski
2765355StwistiSTATIC_INLINE_CORE\
2775355Stwisti(core_mapping *)
2786866Sstefankcore_map_find_mapping(core_map *map,
2796866Sstefank		      unsigned_word addr,
2806866Sstefank		      unsigned nr_bytes,
2816866Sstefank		      cpu *processor,
2826866Sstefank		      unsigned_word cia,
2836866Sstefank		      int abort) /*either 0 or 1 - helps inline */
2846866Sstefank{
2856866Sstefank  core_mapping *mapping = map->first;
28611219Sgziemski  ASSERT((addr & (nr_bytes - 1)) == 0); /* must be aligned */
28711219Sgziemski  ASSERT((addr + (nr_bytes - 1)) >= addr); /* must not wrap */
28811219Sgziemski  while (mapping != NULL) {
28911219Sgziemski    if (addr >= mapping->base
29011219Sgziemski	&& (addr + (nr_bytes - 1)) <= mapping->bound)
29111219Sgziemski      return mapping;
2926866Sstefank    mapping = mapping->next;
2936866Sstefank  }
2945355Stwisti  if (abort)
2955355Stwisti    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",
2965355Stwisti	  addr, nr_bytes, processor, cia);
2975355Stwisti  return NULL;
2985355Stwisti}
2995355Stwisti
3005355Stwisti
3015355StwistiSTATIC_INLINE_CORE\
30211219Sgziemski(void *)
30311219Sgziemskicore_translate(core_mapping *mapping,
30411219Sgziemski	       unsigned_word addr)
30511219Sgziemski{
30611219Sgziemski  return (void *)(((char *)mapping->buffer) + addr - mapping->base);
30711219Sgziemski}
3085355Stwisti
3095355Stwisti
3105355StwistiINLINE_CORE\
3115355Stwisti(unsigned)
3125355Stwisticore_map_read_buffer(core_map *map,
3135355Stwisti		     void *buffer,
3145355Stwisti		     unsigned_word addr,
3155355Stwisti		     unsigned len)
3165355Stwisti{
3175355Stwisti  unsigned count = 0;
3185355Stwisti  while (count < len) {
3195355Stwisti    unsigned_word raddr = addr + count;
3205355Stwisti    core_mapping *mapping =
3215355Stwisti      core_map_find_mapping(map,
32211219Sgziemski			    raddr, 1,
32311219Sgziemski			    NULL, /*processor*/
32411219Sgziemski			    0, /*cia*/
32511219Sgziemski			    0); /*dont-abort*/
32611219Sgziemski    if (mapping == NULL)
32711219Sgziemski      break;
3285355Stwisti    if (mapping->device != NULL) {
3295355Stwisti      int nr_bytes = len - count;
3305355Stwisti      if (raddr + nr_bytes - 1> mapping->bound)
3315355Stwisti	nr_bytes = mapping->bound - raddr + 1;
3325355Stwisti      if (device_io_read_buffer(mapping->device,
3335355Stwisti				(unsigned_1*)buffer + count,
3345355Stwisti				mapping->space,
3355355Stwisti				raddr,
3365355Stwisti				nr_bytes,
33711608Sjwilhelm				0, /*processor*/
33811608Sjwilhelm				0 /*cpu*/) != nr_bytes)
3395355Stwisti	break;
3405355Stwisti      count += nr_bytes;
3415355Stwisti    }
3425355Stwisti    else {
3435355Stwisti      ((unsigned_1*)buffer)[count] =
3445355Stwisti	*(unsigned_1*)core_translate(mapping, raddr);
3455355Stwisti      count += 1;
3465355Stwisti    }
3475355Stwisti  }
3485355Stwisti  return count;
3495355Stwisti}
35011608Sjwilhelm
35111608Sjwilhelm
35211608SjwilhelmINLINE_CORE\
35311608Sjwilhelm(unsigned)
35411608Sjwilhelmcore_map_write_buffer(core_map *map,
3555355Stwisti		      const void *buffer,
3565355Stwisti		      unsigned_word addr,
3575355Stwisti		      unsigned len)
3585355Stwisti{
3595355Stwisti  unsigned count = 0;
3605355Stwisti  while (count < len) {
3615355Stwisti    unsigned_word raddr = addr + count;
3625355Stwisti    core_mapping *mapping = core_map_find_mapping(map,
3635355Stwisti						  raddr, 1,
3645355Stwisti						  NULL, /*processor*/
3655355Stwisti						  0, /*cia*/
3665355Stwisti						  0); /*dont-abort*/
3675355Stwisti    if (mapping == NULL)
3685355Stwisti      break;
3695355Stwisti    if (mapping->device != NULL) {
3705355Stwisti      int nr_bytes = len - count;
3715355Stwisti      if (raddr + nr_bytes - 1 > mapping->bound)
3725355Stwisti	nr_bytes = mapping->bound - raddr + 1;
3735355Stwisti      if (device_io_write_buffer(mapping->device,
3745355Stwisti				 (unsigned_1*)buffer + count,
3755355Stwisti				 mapping->space,
3765355Stwisti				 raddr,
3775355Stwisti				 nr_bytes,
3785355Stwisti				 0, /*processor*/
3795355Stwisti				 0 /*cpu*/) != nr_bytes)
3805355Stwisti	break;
3815355Stwisti      count += nr_bytes;
3825355Stwisti    }
3835355Stwisti    else {
3845355Stwisti      *(unsigned_1*)core_translate(mapping, raddr) =
3855355Stwisti	((unsigned_1*)buffer)[count];
3865355Stwisti      count += 1;
3875355Stwisti    }
3885355Stwisti  }
3895355Stwisti  return count;
3905355Stwisti}
3915355Stwisti
3925355Stwisti
3935355Stwisti/* define the read/write 1/2/4/8/word functions */
3945355Stwisti
3955355Stwisti#define N 1
3965355Stwisti#include "corefile-n.h"
3975355Stwisti#undef N
3985355Stwisti
3995355Stwisti#define N 2
4005355Stwisti#include "corefile-n.h"
4010Sduke#undef N
4025355Stwisti
4035355Stwisti#define N 4
4042868Sphh#include "corefile-n.h"
4050Sduke#undef N
4060Sduke
4070Sduke#define N 8
4085355Stwisti#include "corefile-n.h"
4090Sduke#undef N
4105355Stwisti
4115355Stwisti#define N word
412350Sysr#include "corefile-n.h"
4130Sduke#undef N
4145355Stwisti
4150Sduke#endif /* _CORE_C_ */
4160Sduke