--- /dev/null
+
+/*
+ * Ovlymgr.c -- Runtime Overlay Manager for the Mitsubishi D10V
+ */
+
+#include "ovlymgr.h"
+
+/* Local functions and data: */
+
+extern unsigned long _ovly_table[][4], _novlys;
+enum ovly_index { VMA, SIZE, LMA, MAPPED };
+enum ovly_direction { IN, OUT };
+
+static void D10VCopy (unsigned long dst, unsigned long src, long size);
+
+/* OverlayLoad:
+ * Copy the overlay into its runtime region,
+ * and mark the overlay as "mapped".
+ */
+
+void
+OverlayLoad (int ovlyno)
+{
+ int i;
+
+ if (ovlyno < 0 || ovlyno >= _novlys)
+ exit (-1); /* fail, bad ovly number */
+
+ if (_ovly_table[ovlyno][MAPPED])
+ return; /* this overlay already mapped -- nothing to do! */
+
+ for (i = 0; i < _novlys; i++)
+ if (i == ovlyno)
+ _ovly_table[i][MAPPED] = 1; /* this one now mapped */
+ else if (_ovly_table[i][VMA] == _ovly_table[ovlyno][VMA])
+ _ovly_table[i][MAPPED] = 0; /* this one now un-mapped */
+
+ /* copy overlay using D10V DMAP register */
+ D10VCopy (_ovly_table[ovlyno][VMA], _ovly_table[ovlyno][LMA],
+ _ovly_table[ovlyno][SIZE]);
+}
+
+/* OverlayUnload:
+ * Copy the overlay back into its "load" region.
+ * Does NOT mark overlay as "unmapped", therefore may be called
+ * more than once for the same mapped overlay.
+ */
+
+void
+OverlayUnload (int ovlyno)
+{
+ if (ovlyno < 0 || ovlyno >= _novlys)
+ exit (-1); /* fail, bad ovly number */
+
+ if (!_ovly_table[ovlyno][MAPPED])
+ exit (-1); /* error, can't copy out a segment that's not "in" */
+
+ D10VCopy (_ovly_table[ovlyno][LMA], _ovly_table[ovlyno][VMA],
+ _ovly_table[ovlyno][SIZE]);
+}
+
+/* D10VCopy:
+ * Copy a region of memory from src to dest.
+ * Like memcpy, but can copy anywhere in Universal, Data or Instruction memory.
+ */
+
+#define IMAP0 (*(int *)(0xff00))
+#define IMAP1 (*(int *)(0xff02))
+#define DMAP (*(int *)(0xff04))
+
+static void
+D10VTranslate (unsigned long logical,
+ short *dmap,
+ unsigned long **addr)
+{
+ unsigned long physical;
+ unsigned long seg;
+ unsigned long off;
+ int err = 0;
+ /* to access data, we use the following mapping
+ 0x00xxxxxx: Logical data address segment (DMAP translated memory)
+ 0x01xxxxxx: Logical instruction address segment (IMAP translated memory)
+ 0x10xxxxxx: Physical data memory segment (On-chip data memory)
+ 0x11xxxxxx: Physical instruction memory segment (On-chip insn memory)
+ 0x12xxxxxx: Phisical unified memory segment (Unified memory)
+ */
+
+ /* Addresses must be correctly aligned */
+ if (logical & (sizeof (**addr) - 1))
+ exit (-1);
+
+ /* If the address is in one of the two logical address spaces, it is
+ first translated into a physical address */
+ seg = (logical >> 24);
+ off = (logical & 0xffffffL);
+ switch (seg)
+ {
+ case 0x00: /* in logical data address segment */
+ if (off <= 0x7fffL)
+ physical = (0x10L << 24) + off;
+ else
+ /* Logical address out side of on-chip segment, not
+ supported */
+ exit (-1);
+ break;
+ case 0x01: /* in logical instruction address segment */
+ {
+ short map;
+ if (off <= 0x1ffffL)
+ map = IMAP0;
+ else if (off <= 0x3ffffL)
+ map = IMAP1;
+ else
+ /* Logical address outside of IMAP[01] segment, not
+ supported */
+ exit (-1);
+ if (map & 0x1000L)
+ {
+ /* Instruction memory */
+ physical = (0x11L << 24) | off;
+ }
+ else
+ {
+ /* Unified memory */
+ physical = ((map & 0x7fL) << 17) + (off & 0x1ffffL);
+ if (physical > 0xffffffL)
+ /* Address outside of unified address segment */
+ exit (-1);
+ physical |= (0x12L << 24);
+ }
+ break;
+ }
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ physical = logical;
+ break;
+ default:
+ exit (-1); /* error */
+ }
+
+ seg = (physical >> 24);
+ off = (physical & 0xffffffL);
+ switch (seg)
+ {
+ case 0x10: /* dst is a 15 bit offset into the on-chip memory */
+ *dmap = 0;
+ *addr = (long *) (0x0000 + ((int)off & 0x7fff));
+ break;
+ case 0x11: /* dst is an 18-bit offset into the on-chip
+ instruction memory */
+ *dmap = 0x1000L | ((off & 0x3ffffL) >> 14);
+ *addr = (long *) (0x8000 + ((int)off & 0x3fff));
+ break;
+ case 0x12: /* dst is a 24-bit offset into unified memory */
+ *dmap = off >> 14;
+ *addr = (long *) (0x8000 + ((int)off & 0x3fff));
+ break;
+ default:
+ exit (-1); /* error */
+ }
+
+#if 0
+ printf ("D10VTranslate: logical = %08lx, dmap = %04x, addr = %04x\n",
+ logical, *dmap, *addr);
+#endif
+}
+
+static void
+D10VCopy (unsigned long dst, unsigned long src, long size)
+{
+ unsigned long *s, *d, tmp;
+ short dmap_src, dmap_dst;
+ short dmap_save;
+
+#if 0
+ printf ("D10VCopy: dst = %08lx, src = %08lx, size = %ld\n",
+ dst, src, size);
+#endif
+
+ /* all section sizes should by multiples of 4 bytes */
+ dmap_save = DMAP;
+
+ D10VTranslate (src, &dmap_src, &s);
+ D10VTranslate (dst, &dmap_dst, &d);
+
+ while (size > 0)
+ {
+ /* NB: Transfer 4 byte (long) quantites, problems occure
+ when only two bytes are transfered */
+ DMAP = dmap_src;
+ tmp = *s;
+ DMAP = dmap_dst;
+ *d = tmp;
+ d++;
+ s++;
+ size -= sizeof (tmp);
+ src += sizeof (tmp);
+ dst += sizeof (tmp);
+ if ((src & 0x3fff) == 0)
+ D10VTranslate (src, &dmap_src, &s);
+ if ((dst & 0x3fff) == 0)
+ D10VTranslate (dst, &dmap_dst, &d);
+ }
+ DMAP = dmap_save;
+}
+