+set_spu_register (unsigned long value)
+{
+ if (PSW_SM)
+ SET_GPR (SP_IDX, value);
+ SET_HELD_SP (HELD_SPU_IDX, value);
+}
+
+/* Given a virtual address in the DMAP address space, translate it
+ into a physical address. */
+
+unsigned long
+sim_d10v_translate_dmap_addr (unsigned long offset,
+ int nr_bytes,
+ unsigned long *phys,
+ unsigned long (*dmap_register) (int reg_nr))
+{
+ short map;
+ int regno;
+ last_from = "logical-data";
+ if (offset >= DMAP_BLOCK_SIZE * SIM_D10V_NR_DMAP_REGS)
+ {
+ /* Logical address out side of data segments, not supported */
+ return 0;
+ }
+ regno = (offset / DMAP_BLOCK_SIZE);
+ offset = (offset % DMAP_BLOCK_SIZE);
+ if ((offset % DMAP_BLOCK_SIZE) + nr_bytes > DMAP_BLOCK_SIZE)
+ {
+ /* Don't cross a BLOCK boundary */
+ nr_bytes = DMAP_BLOCK_SIZE - (offset % DMAP_BLOCK_SIZE);
+ }
+ map = dmap_register (regno);
+ if (regno == 3)
+ {
+ /* Always maps to data memory */
+ int iospi = (offset / 0x1000) % 4;
+ int iosp = (map >> (4 * (3 - iospi))) % 0x10;
+ last_to = "io-space";
+ *phys = (SIM_D10V_MEMORY_DATA + (iosp * 0x10000) + 0xc000 + offset);
+ }
+ else
+ {
+ int sp = ((map & 0x3000) >> 12);
+ int segno = (map & 0x3ff);
+ switch (sp)
+ {
+ case 0: /* 00: Unified memory */
+ *phys = SIM_D10V_MEMORY_UNIFIED + (segno * DMAP_BLOCK_SIZE) + offset;
+ last_to = "unified";
+ break;
+ case 1: /* 01: Instruction Memory */
+ *phys = SIM_D10V_MEMORY_INSN + (segno * DMAP_BLOCK_SIZE) + offset;
+ last_to = "chip-insn";
+ break;
+ case 2: /* 10: Internal data memory */
+ *phys = SIM_D10V_MEMORY_DATA + (segno << 16) + (regno * DMAP_BLOCK_SIZE) + offset;
+ last_to = "chip-data";
+ break;
+ case 3: /* 11: Reserved */
+ return 0;
+ }
+ }
+ return nr_bytes;
+}
+
+/* Given a virtual address in the IMAP address space, translate it
+ into a physical address. */
+
+unsigned long
+sim_d10v_translate_imap_addr (unsigned long offset,
+ int nr_bytes,
+ unsigned long *phys,
+ unsigned long (*imap_register) (int reg_nr))
+{
+ short map;
+ int regno;
+ int sp;
+ int segno;
+ last_from = "logical-insn";
+ if (offset >= (IMAP_BLOCK_SIZE * SIM_D10V_NR_IMAP_REGS))
+ {
+ /* Logical address outside of IMAP segments, not supported */
+ return 0;
+ }
+ regno = (offset / IMAP_BLOCK_SIZE);
+ offset = (offset % IMAP_BLOCK_SIZE);
+ if (offset + nr_bytes > IMAP_BLOCK_SIZE)
+ {
+ /* Don't cross a BLOCK boundary */
+ nr_bytes = IMAP_BLOCK_SIZE - offset;
+ }
+ map = imap_register (regno);
+ sp = (map & 0x3000) >> 12;
+ segno = (map & 0x007f);
+ switch (sp)
+ {
+ case 0: /* 00: unified memory */
+ *phys = SIM_D10V_MEMORY_UNIFIED + (segno << 17) + offset;
+ last_to = "unified";
+ break;
+ case 1: /* 01: instruction memory */
+ *phys = SIM_D10V_MEMORY_INSN + (IMAP_BLOCK_SIZE * regno) + offset;
+ last_to = "chip-insn";
+ break;
+ case 2: /*10*/
+ /* Reserved. */
+ return 0;
+ case 3: /* 11: for testing - instruction memory */
+ offset = (offset % 0x800);
+ *phys = SIM_D10V_MEMORY_INSN + offset;
+ if (offset + nr_bytes > 0x800)
+ /* don't cross VM boundary */
+ nr_bytes = 0x800 - offset;
+ last_to = "test-insn";
+ break;
+ }
+ return nr_bytes;
+}
+
+unsigned long
+sim_d10v_translate_addr (unsigned long memaddr,
+ int nr_bytes,
+ unsigned long *targ_addr,
+ unsigned long (*dmap_register) (int reg_nr),
+ unsigned long (*imap_register) (int reg_nr))
+{
+ unsigned long phys;
+ unsigned long seg;
+ unsigned long off;
+
+ last_from = "unknown";
+ last_to = "unknown";
+
+ seg = (memaddr >> 24);
+ off = (memaddr & 0xffffffL);
+
+ /* However, if we've asked to use the previous generation of segment
+ mapping, rearrange the segments as follows. */
+
+ if (old_segment_mapping)
+ {
+ switch (seg)
+ {
+ case 0x00: /* DMAP translated memory */
+ seg = 0x10;
+ break;
+ case 0x01: /* IMAP translated memory */
+ seg = 0x11;
+ break;
+ case 0x10: /* On-chip data memory */
+ seg = 0x02;
+ break;
+ case 0x11: /* On-chip insn memory */
+ seg = 0x01;
+ break;
+ case 0x12: /* Unified memory */
+ seg = 0x00;
+ break;
+ }
+ }
+
+ switch (seg)
+ {
+ case 0x00: /* Physical unified memory */
+ last_from = "phys-unified";
+ last_to = "unified";
+ phys = SIM_D10V_MEMORY_UNIFIED + off;
+ if ((off % SEGMENT_SIZE) + nr_bytes > SEGMENT_SIZE)
+ nr_bytes = SEGMENT_SIZE - (off % SEGMENT_SIZE);
+ break;
+
+ case 0x01: /* Physical instruction memory */
+ last_from = "phys-insn";
+ last_to = "chip-insn";
+ phys = SIM_D10V_MEMORY_INSN + off;
+ if ((off % SEGMENT_SIZE) + nr_bytes > SEGMENT_SIZE)
+ nr_bytes = SEGMENT_SIZE - (off % SEGMENT_SIZE);
+ break;
+
+ case 0x02: /* Physical data memory segment */
+ last_from = "phys-data";
+ last_to = "chip-data";
+ phys = SIM_D10V_MEMORY_DATA + off;
+ if ((off % SEGMENT_SIZE) + nr_bytes > SEGMENT_SIZE)
+ nr_bytes = SEGMENT_SIZE - (off % SEGMENT_SIZE);
+ break;
+
+ case 0x10: /* in logical data address segment */
+ nr_bytes = sim_d10v_translate_dmap_addr (off, nr_bytes, &phys,
+ dmap_register);
+ break;
+
+ case 0x11: /* in logical instruction address segment */
+ nr_bytes = sim_d10v_translate_imap_addr (off, nr_bytes, &phys,
+ imap_register);
+ break;
+
+ default:
+ return 0;
+ }
+
+ *targ_addr = phys;
+ return nr_bytes;
+}
+
+/* Return a pointer into the raw buffer designated by phys_addr. It
+ is assumed that the client has already ensured that the access
+ isn't going to cross a segment boundary. */
+
+uint8 *
+map_memory (unsigned phys_addr)