diff -urN gdb-5.2.1/gdb/Makefile.in gdb-5.2.1-mpcbdm/gdb/Makefile.in
--- gdb-5.2.1/gdb/Makefile.in	Fri Jul 19 14:22:06 2002
+++ gdb-5.2.1-mpcbdm/gdb/Makefile.in	Mon Jan 27 21:22:56 2003
@@ -1772,6 +1772,12 @@
 	$(inferior_h) $(target_h) $(serial_h) $(terminal_h) $(gdb_string_h) \
 	$(regcache_h)
 
+mpcbdm.o: mpcbdm.c mpcbdm.h defs.h gdbcore.h target.h $(wait_h) $(bfd_h) \
+	$(unistd_h) $(stdlib_h) $(errno_h) $(signal_h) $(string_h) $(stdio_h) \
+	$(fcntl_h) $(ctype_h) $(sys/types_h) $(sys/ioctl_h) command.h \
+	inferior.h value.h breakpoint.h gdb_string.h frame.h symfile.h \
+	gdbcmd.h objfiles.h dcache.h serial.h
+
 Onindy.o: nindy-share/Onindy.c gdb_wait.h nindy-share/block_io.h \
 	nindy-share/env.h
 	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/nindy-share/Onindy.c
diff -urN gdb-5.2.1/gdb/config/powerpc/linux.mt gdb-5.2.1-mpcbdm/gdb/config/powerpc/linux.mt
--- gdb-5.2.1/gdb/config/powerpc/linux.mt	Fri Oct 19 20:16:44 2001
+++ gdb-5.2.1-mpcbdm/gdb/config/powerpc/linux.mt	Mon Jan 27 21:20:37 2003
@@ -1,5 +1,5 @@
 # Target: Motorola PPC on Linux
-TDEPFILES= rs6000-tdep.o ppc-linux-tdep.o solib.o solib-svr4.o solib-legacy.o
+TDEPFILES= rs6000-tdep.o ppc-linux-tdep.o mpcbdm.o solib.o solib-svr4.o solib-legacy.o
 TM_FILE= tm-linux.h
 
 SIM_OBS = remote-sim.o
diff -urN gdb-5.2.1/gdb/mpcbdm.c gdb-5.2.1-mpcbdm/gdb/mpcbdm.c
--- gdb-5.2.1/gdb/mpcbdm.c	Wed Dec 31 19:00:00 1969
+++ gdb-5.2.1-mpcbdm/gdb/mpcbdm.c	Mon Jan 27 22:39:37 2003
@@ -0,0 +1,5384 @@
+/******************************************************************
+*                                                                 *
+* File:         mpcbdm.c                                          *
+* Project:      MPCBDM                                            *
+* Version:      1.2.3                                             *
+* Date:         2001/10/25                                        *
+* FirstDate:    1999/12/07                                        *
+* Author:       FP                                                *
+* Copyright:    (c) 1999,2000,2001 VAS-EntwicklungsgesellschaftmbH*
+* Description:  gdb remote target for Motorola's MPC              *
+*               via parallel port interface                       *
+*                                                                 *
+******************************************************************/
+
+/******************************************************************
+* Includes                                                        *
+******************************************************************/
+
+#include "mpcbdm.h"
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "wait.h"
+#include <bfd.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include "command.h"
+#include "inferior.h"
+#include "value.h"
+#include "breakpoint.h"
+
+#include "gdb_string.h"
+#include "frame.h"
+#include "symfile.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "dcache.h"
+#include "serial.h" /*?*/
+#include "regcache.h"
+
+#define	MQ_REGNUM 70		/* Multiply/quotient register */
+
+
+/******************************************************************
+* macros                                                          *
+******************************************************************/
+
+/******************************************************************
+* prototypes                                                      *
+******************************************************************/
+
+u_int bdm_getspr(int reg);
+static void mpcbdm_dcache_flush(u_int Adr, int bAll);
+void print_spr_info(int num,u_int val, int bName, int bDef, int bVal, int bPretty);
+
+/******************************************************************
+* global variables                                                *
+******************************************************************/
+
+static char sVersion[] = "1.2.3 / 2001/10/25";
+
+static uid_t nEuid = -1; /* effective user id */
+static int LastICR; /*save last returned interrupt cause*/
+static int LastDER; /*save previous Debug Enable Register value*/
+static u_int LastMSR; /*copy of srr1, MSR before exception*/
+
+static unsigned int mpcbdm_delay = 0;	/* delay port output */
+static unsigned int mpcbdm_verbose = 0;	/* set verbosity level to quiet */
+static int mpcbdm_mmu = 1;		/*allow table walks*/
+static int mpcbdm_reattach = 0; /* resume without command to MPC */
+/*use with unplug-plug then c to wait for FRZ*/
+static unsigned long int mpcbdm_sleep = 250000; /* sleep 0.25 seconds between FRZ polls*/
+static int mpcbdm_hwbrk = 1; /*use hardware breakpoints*/
+static int mpcbdm_maxhwbrk = MAX_HWBRK; /*use cmp register a..d*/
+static unsigned int mpcbdm_wait = 40; /* toggle maximum 40 times DSCK to wait for target CPU clear DSDO */
+static unsigned int mpcbdm_toggle = 4000000; /* flash toggle or poll loop maximum values for timeout*/
+static int mpcbdm_fflash = 1; /*use fast flash programming routine */
+static int mpcbdm_dflush = 0; /*use automatic data cache flushing when returning into mpcbdm */
+static int mpcbdm_relaxed = 0; /* relax timing on bdm port */
+static unsigned int mpcbdm_kbase = 0xc0000000; /* kernel base address */
+static unsigned int mpcbdm_pgdir = 0; /* used to debug kernel routines from user process for linux 2.4*/
+static unsigned int mpcbdm_pram = 0; /* pointer to where to load ppc subroutine */
+static unsigned int mpcbdm_fbuf = 0xfff02000; /* pointer to target buffer, default mpc860 DPRAM */
+static unsigned int mpcbdm_fsizebuf = 4096; /* size of target buffer, default mpc860 DPRAM size */
+static int mpcbdm_fquery = 1; /* query for confirm when erase/write flash */
+
+static unsigned int RegBuffer[36];
+static unsigned int membuf[MAXBUFFERLEN]; /*temporary buffer*/
+static unsigned int pramlen = 0; /* store length of actual subroutine */
+
+static char break_insn[] = BDM_BREAKPOINT; /* use software emulation for breakpoint*/
+
+static int hwbrk_used[MAX_HWBRK]; /* flag for usage of hardware registers */
+static unsigned int hwbrk_adr[MAX_HWBRK]; /* addresses in use for breakpoints*/
+
+static int ctrlc; /*Counter for occurance of <ctrl>-c*/
+
+static u_int mpcbdm_stat; /* ready and stat values from DSDO protocol */
+static u_int mpcbdm_freeze; /* freeze value from DSDO protocol, one means frozen */
+static u_int mpcbdm_dpi; /* dpi value from DSDO protocol, zero means active! */
+static u_int mpcbdm_icr_or; /* counter for core interrupts during BDM */
+
+static int mpcbdm_kill_kludge; /* Workaraound:If nonzero, ignore the next kill.  */
+
+static struct target_ops *current_ops = NULL;
+struct target_ops mpcbdm_ops ;
+
+static int bdm_regmap[] = {BDM_REGMAP};
+
+extern struct cmd_list_element *cmdlist; /*gdb command list*/
+
+static FlashBank FB[MAXFLASHBANKS]; /* stores informatins about configured FLASH banks*/
+static int FBank; /* selected FLASH bank */
+static int FSec; /* actual sector in selected FLASH bank */
+static FlashBank * pFB; /* pointer to selected FB */
+static int mpcbdm_nBank = 0; /* number of configured FLASH banks */
+static char * mpcbdm_flashdev; /* string pointer for flash configuration file path */
+static FILE * f;
+static char FileBuffer[MAXBUFFERLEN];
+static char * pParse;
+
+/***************************************************************
+* low level port routines                                      *
+****************************************************************/
+
+static Port PP;
+
+static short portadr[] =
+{
+	0x378,						/* lpt0 */
+	0x278,						/* lpt1 */
+	0x3bc,						/* lpt2 */
+};
+
+/* use 'set mpcbdm_adapter 1|2' to force adapter version. */
+static unsigned int mpcbdm_adapter = 0; /* adapter identification */
+/* use 'set mpcbdm_power 1' to turn on powering from parallel port*/
+static int mpcbdm_power = 0; /* default :do not use power from parallel port*/
+
+#define INB(x,port)		asm volatile("inb %1, %0" : "=a" (x) : "d" (port))
+#define OUTB(x,port)	asm volatile("outb %0, %1" : : "a" (x), "d" (port))
+/* in case of asm trouble (red hat 7.0?) try the code below and compile with -O option */
+/*#include <asm/io.h>
+#define INB(x,port)		x = inb(port)
+#define OUTB(x,port)	outb(x,port)*/
+
+/* slow down host for not overrunning target */
+void bdm_delay(int counter)
+{
+	unsigned char dummy;
+
+	while (counter--)
+	{
+/* since usleep and sisters are to slow (10-20msec minimum)
+    , and nop's depend on CPU speed
+    we try I/O port reads for a delay of round about 1usec */
+//		asm volatile ("nop");
+ 		INB(dummy,PP.STATAddr);
+	}
+}
+
+int PortRead(void)
+{
+	INB(PP.STAT,PP.STATAddr);
+	return PP.STAT;
+}
+
+void PortStatus(void)
+{
+	INB(PP.DATA, PP.DATAAddr);
+	INB(PP.STAT, PP.STATAddr);
+	INB(PP.CTRL, PP.CTRLAddr);
+	printf_filtered("PortStatus : DATA=0x%02X STAT=0x%02X CTRL=0x%02X\n",PP.DATA,PP.STAT,PP.CTRL);
+}
+
+void PortPowerV1(unsigned char Power)
+{
+	if (Power) /* turn power on? */
+	{
+		PP.POWER	= 0xff; /* V1 uses D0-D7 */
+		OUTB(PP.POWER, PP.DATAAddr);
+	}
+	else /* turn power off */
+	{
+		PP.POWER	= 0x00;
+		OUTB(0x00, PP.DATAAddr);
+	}
+}
+
+void PortWriteV1(unsigned char Data)
+{
+	PP.CTRL = PP.CTRL & PP.CTRLMask | (Data & PP.DSDI) | ~(Data & PP.DSCK)&PP.DSCK;
+	OUTB(PP.CTRL, PP.CTRLAddr);
+   	bdm_delay(mpcbdm_delay);
+}
+
+void PortResetV1(unsigned char Data)
+{
+	PP.CTRL = PP.CTRL & PP.DATAMask | (~(Data & PP.CTRLMask))&PP.CTRLMask;
+	OUTB(PP.CTRL, PP.CTRLAddr);
+}
+
+void PortStatusV1(void)
+{
+	int i;
+	int l;
+
+	INB(PP.DATA, PP.DATAAddr);
+	INB(PP.STAT, PP.STATAddr);
+	INB(PP.CTRL, PP.CTRLAddr);
+
+	printf_filtered("PortStatusV1: DATA=0x%02X STAT=0x%02X CTRL=0x%02X\n",PP.DATA,PP.STAT,PP.CTRL);
+
+	i = 0;
+	if (PP.DATA & PP.POWER)
+	{
+		sprintf(&(PP.sStatus[i]),"POWER %n",&l);
+		i += l;
+	}
+	if (PP.STAT & PP.VFLS0)
+	{
+		sprintf(&(PP.sStatus[i]),"VFLS0 %n",&l);
+		i += l;
+	}
+	if (PP.STAT & PP.VDD1)
+	{
+		sprintf(&(PP.sStatus[i]),"VDD1 %n",&l);
+		i += l;
+	}
+	if (PP.STAT & PP.DSDO)
+	{
+		sprintf(&(PP.sStatus[i]),"DSD0 %n",&l);
+		i += l;
+	}
+	if (!(PP.CTRL & PP.DSCK))
+	{
+		sprintf(&(PP.sStatus[i]),"DSCK %n",&l);
+		i += l;
+	}
+	if (PP.CTRL & PP.DSDI)
+	{
+		sprintf(&(PP.sStatus[i]),"DSDI %n",&l);
+		i += l;
+	}
+	if (!(PP.CTRL & PP.HRESET))
+	{
+		sprintf(&(PP.sStatus[i]),"HRESET %n",&l);
+		i += l;
+	}
+	if (!(PP.CTRL & PP.SRESET))
+	{
+		sprintf(&(PP.sStatus[i]),"SRESET %n",&l);
+		i += l;
+	}
+	printf_filtered("Port active lines: '%s'\n",PP.sStatus);
+}
+
+void PortPowerV2(unsigned char Power)
+{
+	if (Power) /* turn power on? */
+	{
+		PP.POWER = 0xf8; /* set mask for power lines */
+		OUTB((PP.DATA | PP.POWER), PP.DATAAddr);
+	}
+	else /* turn power off */
+	{
+		PP.POWER = 0x00; /* reset mask for power lines */
+		PP.DATA=PP.DATA&(~0xf8);
+		OUTB(PP.DATA, PP.DATAAddr);
+	}
+}
+
+void PortWriteV2(unsigned char Data)
+{
+	PP.DATA = Data;
+	OUTB((Data | PP.POWER), PP.DATAAddr);
+   	bdm_delay(mpcbdm_delay);
+	if (mpcbdm_verbose&VERBOSE_BDM)
+	{
+		printf_filtered("Write: ");
+		PP.Status();
+	}
+}
+
+void PortResetV2(unsigned char Data)
+{
+	PP.CTRL = Data;
+	OUTB(Data, PP.CTRLAddr);
+	if (mpcbdm_verbose&VERBOSE_BDM)
+	{
+		printf_filtered("Reset: ");
+		PP.Status();
+	}
+}
+
+void PortStatusV2(void)
+{
+	int i;
+	int l;
+
+	INB(PP.DATA, PP.DATAAddr);
+	INB(PP.STAT, PP.STATAddr);
+	INB(PP.CTRL, PP.CTRLAddr);
+
+	i = 0;
+
+	if (!(mpcbdm_verbose&VERBOSE_BDM)) /* called from user via port command */
+		printf_filtered("PortStatusV2: DATA=0x%02X STAT=0x%02X CTRL=0x%02X\n",PP.DATA,PP.STAT,PP.CTRL);
+
+	sprintf(&(PP.sStatus[i]),"out: %n",&l);
+	i += l;
+	if (PP.CTRL & PP.HRESET)
+	{
+		sprintf(&(PP.sStatus[i]),"HRESET %n",&l);
+		i += l;
+	}
+	if (PP.CTRL & PP.SRESET)
+	{
+		sprintf(&(PP.sStatus[i]),"SRESET %n",&l);
+		i += l;
+	}
+	if (PP.CTRL & PP.TRST)
+	{
+		sprintf(&(PP.sStatus[i]),"TRST %n",&l);
+		i += l;
+	}
+	if (PP.DATA & PP.DSCK)
+	{
+		sprintf(&(PP.sStatus[i]),"DSCK %n",&l);
+		i += l;
+	}
+	if (PP.DATA & PP.DSDI)
+	{
+		sprintf(&(PP.sStatus[i]),"DSDI %n",&l);
+		i += l;
+	}
+	if (PP.DATA & PP.TMS)
+	{
+		sprintf(&(PP.sStatus[i]),"TMS %n",&l);
+		i += l;
+	}
+	if (PP.DATA & PP.POWER)
+	{
+		sprintf(&(PP.sStatus[i]),"POWER %n",&l);
+		i += l;
+	}
+	sprintf(&(PP.sStatus[i]),"\tin: %n",&l);
+	i += l;
+	if (PP.STAT & PP.VFLS0)
+	{
+		sprintf(&(PP.sStatus[i]),"VFLS0 %n",&l);
+		i += l;
+	}
+	if (PP.STAT & PP.VFLS1)
+	{
+		sprintf(&(PP.sStatus[i]),"VFLS1 %n",&l);
+		i += l;
+	}
+	if (PP.STAT & PP.VDD1)
+	{
+		sprintf(&(PP.sStatus[i]),"VDD1 %n",&l);
+		i += l;
+	}
+	if (PP.STAT & PP.VDD2)
+	{
+		sprintf(&(PP.sStatus[i]),"VDD2 %n",&l);
+		i += l;
+	}
+	if (PP.STAT & PP.DSDO)
+	{
+		sprintf(&(PP.sStatus[i]),"DSD0 %n",&l);
+		i += l;
+	}
+	if (mpcbdm_verbose&VERBOSE_BDM) /* debug BDM protocol: be a little more compact */
+		printf_filtered("%s\n",PP.sStatus);
+	else /* or called from user via port command */
+		printf_filtered("Port active lines: %s\n",PP.sStatus);
+}
+
+void PortError(unsigned char Data)
+{
+	if (mpcbdm_verbose&VERBOSE_BDM)
+	{
+		printf_filtered("PortError: called uninitialized port function\n");
+	}
+	else
+	{
+		printf_filtered("P!");
+	}
+}
+void PortErrorV(void)
+{
+	if (mpcbdm_verbose&VERBOSE_BDM)
+	{
+		printf_filtered("PortError: called uninitialized port function\n");
+	}
+	else
+	{
+		printf_filtered("P!");
+	}
+}
+
+/* setup port parameters, try version 2 for default */
+int PortInit(int Port)
+{
+	int nResult;
+	int nLast;
+
+	PP.port = -1;
+
+	PP.DATAAddr = 0;
+	PP.STATAddr = 0;
+	PP.CTRLAddr = 0;
+	PP.DATA = 0;
+	PP.STAT = 0;
+	PP.CTRL = 0;
+	PP.POWER = 0x00;
+
+	if ((Port <0) || (Port > 2))
+	{
+		printf_filtered("invalid printer port %d. Use 0..2\n",Port);
+		return RETURN_FAIL;
+	}
+	PP.DATAAddr = portadr[Port];
+	PP.STATAddr = PP.DATAAddr + 1;
+	PP.CTRLAddr = PP.DATAAddr + 2;
+
+	if (nEuid == -1)
+	{
+		nEuid = geteuid();
+	}
+	else
+	{
+		nResult = seteuid(nEuid);
+
+		if (nResult == -1)
+		{
+			printf_filtered("unable to change process effective user ID\n");
+			PP.DATAAddr = 0;
+			PP.STATAddr = 0;
+			PP.CTRLAddr = 0;
+			return RETURN_FAIL;
+		}
+	}
+
+	nResult = ioperm(PP.DATAAddr,3,1);
+
+	seteuid(getuid());
+
+	if (nResult == -1)
+	{
+		printf_filtered("unable to get access rights for printer port %d addr 0x%3X..0x%3X\n",Port,PP.DATAAddr,PP.CTRLAddr);
+		PP.DATAAddr = 0;
+		PP.STATAddr = 0;
+		PP.CTRLAddr = 0;
+		return RETURN_FAIL;
+	}
+	printf_filtered("got access rights for printer port %d addr 0x%3X..0x%3X\n",Port,PP.DATAAddr,PP.CTRLAddr);
+	PP.port = Port; /* remember port number */
+
+	OUTB(0x00,PP.DATAAddr); /* reset all data lines -> disable power from port */
+	OUTB(0xC0,PP.CTRLAddr); /* set data lines for output */
+	printf_filtered("disabled power at port %d\n",PP.port);
+	usleep(mpcbdm_sleep); /* allow changes on port lines */
+
+/* Removed the buggy auto detection, default is adapter version 2.
+   The very rare adapter 1 users have to explicitly 'set mpcbdm_adapter 1'
+   before initializing the 'target' */
+	if (!mpcbdm_adapter)
+		mpcbdm_adapter=2; /* use adpater version 2, if no other is specified */
+
+	switch (mpcbdm_adapter) /* initialize version dependencies */
+	{
+	case 1:
+		PP.Read = PortRead;
+		PP.Status = PortStatusV1;
+		PP.Power = PortPowerV1;
+		PP.Write = PortWriteV1;
+		PP.Reset = PortResetV1;
+
+		PP.DSCK		= 0x01;
+		PP.DSDI		= 0x04;
+		PP.VFLS0	= 0x08;
+		PP.DSDO		= 0x20;
+		PP.VDD1		= 0x40;
+		PP.SRESET	= 0x02;
+		PP.HRESET	= 0x08;
+
+		PP.FREEZE	= PP.VFLS0; /* bug of v1 adapter, only VFLS0 connected */
+
+		PP.CTRLMask = PP.HRESET | PP.SRESET;
+		PP.DATAMask = PP.DSDI | PP.DSCK;
+
+		nResult = PP.Read(); /* plausibility check for adapter v1 */
+		if (nResult & 0x80) /* STAT[7] is NC on v1 -> always low (because of invert)*/
+		{
+			printf_filtered("adapter v1 specified, but STAT[7] !=0\n");
+			PortStatus();
+			return RETURN_FAIL;
+		}
+
+		break;
+	case 2:
+		PP.Read = PortRead;
+		PP.Power = PortPowerV2;
+		PP.Write = PortWriteV2;
+		PP.Reset = PortResetV2;
+		PP.Status = PortStatusV2;
+
+		PP.DSCK		= 0x01;
+		PP.DSDI		= 0x02;
+		PP.TMS		= 0x04;
+		PP.VFLS0	= 0x08;
+		PP.VDD2		= 0x10;
+		PP.DSDO		= 0x20;
+		PP.VDD1		= 0x40;
+		PP.VFLS1	= 0x80;
+		PP.TRST		= 0x01;
+		PP.SRESET	= 0x02;
+		PP.HRESET	= 0x08;
+
+		PP.FREEZE	= PP.VFLS0 | PP.VFLS1;
+		break;
+	default:
+		printf_filtered("invalid adapter version %d specified\n",mpcbdm_adapter);
+		return RETURN_FAIL;
+		break;
+	}
+
+	if (mpcbdm_power)
+	{
+		PP.Power(1); /* enable power if requested */
+		printf_filtered("turned on powering from port %d\n",PP.port);
+	}
+
+	PP.Write(0x00); /* DSDI and DSCK low*/
+
+	printf_filtered("adapter version %d initialized\n",mpcbdm_adapter);
+
+	nResult = PP.Read();
+	if (!(nResult & PP.VDD1))
+	{
+		printf_filtered("please turn on power at target\n");
+	}
+	while (!(nResult & PP.VDD1)) /* until target powered up */
+	{
+		nLast = nResult;
+		nResult = PP.Read();
+		if (nResult != nLast)
+		{
+			PP.Status();
+		}
+		usleep(mpcbdm_sleep);
+	}
+	return RETURN_OK;
+}
+
+static void mpcbdm_port(char *args, int from_tty)
+{
+	if (!mpcbdm_adapter)
+	{
+		printf("unknow port adapter\n");
+		return;
+	}
+	printf("port: adapter version %d at port %d ioaddr from 0x%03X to 0x%03X, FREEZE=0x%02X\n",mpcbdm_adapter,PP.port,PP.DATAAddr,PP.CTRLAddr,PP.FREEZE);
+	if (mpcbdm_power)
+	{
+		printf("powering adapter from port, POWER=0x%02X\n",PP.POWER);
+	}
+	PP.Status();
+}
+
+/***************************************************************
+* low level, serial BDM routines                               *
+****************************************************************/
+
+static void WaitFreeze(void)
+{
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf_filtered("WaitFreeze:\n");
+	}
+	while(!(PP.Read() & PP.FREEZE))
+	{
+		usleep(mpcbdm_sleep);
+	}
+}
+
+
+/* keep DSDI low and toggle DSCK until DSDO goes low */
+
+static void ser_wait_ready(void)
+{
+	unsigned int i = 0;
+	if (!mpcbdm_reattach)
+	{
+		if ((mpcbdm_verbose&VERBOSE_SER) && (mpcbdm_verbose&VERBOSE_BDM))
+		{
+			printf_filtered("ser_wait_ready: start\n");
+		}
+		do
+		{
+			if (mpcbdm_relaxed)
+			{
+		  		PP.Write(0x00); /* relaxed BDM port timing */
+			}
+			PP.Write(PP.DSCK);
+			PP.Write(0x00);
+			i++;
+			if (i > mpcbdm_wait)
+			{
+				printf_filtered("target CPU does not clear DSDO. No connection?\n");
+				mpcbdm_reattach = 1;
+				printf_filtered("-> forced 'set mpcbdm_reattach on' \n");
+				return;
+			}
+			bdm_delay(1); /* assure host independent timing */
+		} while(PP.Read() & PP.DSDO);
+
+		if (mpcbdm_verbose&VERBOSE_SER)
+		{
+			printf_filtered("ser_wait_ready: waited %d cycles\n",i);
+		}
+	}
+};
+
+static void ser_clkpref(u_int word)
+{
+	int n;
+
+	u_int bit;
+
+	mpcbdm_stat = 0; /* begin new sequence, clear values */
+	mpcbdm_freeze = 0;
+	mpcbdm_dpi=0;
+
+	/* if target processor is frozen, get BDM ready */
+	if (PP.Read() & PP.FREEZE)
+	{
+		ser_wait_ready();
+	}
+
+	for(n = 0; n < 3; ++n)
+	{
+
+		mpcbdm_stat <<= 1;
+		if (PP.Read() & PP.DSDO) mpcbdm_stat |= 1;
+ /* test if target is signaling READY, this should always happen, (stat == 0)
+    as we just checked ser_wait_ready, waiting for DSDO going low */
+		if ((n == 0) && (mpcbdm_stat))
+		{
+			if (mpcbdm_verbose&VERBOSE_SER)
+			{
+				printf_filtered("ser_clkpref: target not ready?\n");
+			}
+			else
+			{
+				printf_filtered("R!");
+			}
+		}
+		bit = (word & 4) ? PP.DSDI : 0;
+		if (mpcbdm_relaxed)
+		{
+			PP.Write(bit); /* relaxed BDM port timing */
+		}
+		PP.Write(bit | PP.DSCK); /* clock DSCK High after setting data bit on DSDI*/
+		PP.Write(bit); /*clock DSCK low for reading DSDO next */
+		word <<= 1;
+	}
+}
+
+static void ser_clk(u_int word, int len, u_int *data)
+{
+	int n;
+	int reslen = 0;
+	u_int mask = 1 << (len-1);
+
+	if(data) *data = 0; /* if pointer to receive data buffer given, clear buffer */
+
+	switch(mpcbdm_stat)
+	{
+	case DSDO_CORE_DATA:
+		mpcbdm_dpi = 1; /* this bit is not transmitted, but normal data is in progress */
+		reslen = 32;
+		break;
+	case DSDO_SEQ_ERROR: /* debug command while target not in debug mode */
+		if (mpcbdm_verbose&VERBOSE_SER)
+			printf_filtered("BDM sequence error: stat %d word 0x%08x len %d data 0x%08x\n", mpcbdm_stat, word, len, data);
+		else
+			printf_filtered("E!");
+		reslen = 7;
+		break;
+	case DSDO_CORE_INTERRUPT: /* interrupt occurred, have to read ICR to clear */
+		if (mpcbdm_verbose&VERBOSE_SER)
+			printf_filtered("BDM core interrupt: stat %d word 0x%08x len %d data 0x%08x\n", mpcbdm_stat, word, len, data);
+		else
+			printf_filtered("I!");
+		mpcbdm_icr_or++;
+		reslen = 7;
+		break;
+	case DSDO_NULL:
+		reslen = 7;
+		break;
+	default:
+		if (mpcbdm_verbose&VERBOSE_SER)
+			printf_filtered("BDM bad stat: stat %d word 0x%08x len %d data 0x%08x\n", mpcbdm_stat, word, len, data);
+		else
+			printf_filtered("S!");
+		break;
+	}
+	for(n = 0; n < len; ++n)
+	{
+		int bit;
+
+		if(data) *data <<= 1;
+		if(PP.Read() & PP.DSDO)
+		{
+			if (data) *data |= 1;
+			if (mpcbdm_stat != 0)
+			{
+				if (n == 0)
+					mpcbdm_freeze = 1;
+				else if (n == 1)
+					mpcbdm_dpi = 1;
+			}
+		}
+		bit = (word & mask) ? PP.DSDI : 0;
+		if (mpcbdm_relaxed)
+		{
+			PP.Write(bit); /* relaxed BDM port timing */
+		}
+		PP.Write(bit | PP.DSCK); /* output bit with high clock*/
+		PP.Write(bit); /*clock DSCK low for reading DSDO*/
+		word <<= 1;
+	}
+	for(;n < reslen;) /* clock rest of data in with writing zeros*/
+	{
+		if(data) *data <<= 1;
+		if (PP.Read() & PP.DSDO)
+		{
+			if(data) *data |= 1;
+		}
+		if (mpcbdm_relaxed)
+		{
+			PP.Write(0x00); /* relaxed BDM port timing */
+		}
+		PP.Write(PP.DSCK); /*clock DSCK high*/
+		n++;
+		if (n == reslen) break;
+		PP.Write(0x00);/* clock DSCK low */
+	}
+	PP.Write(0x00); /* reset data bit on DSDI */
+}
+
+
+static void ser_clkinstr(u_int word, u_int *data)
+{
+	if (!mpcbdm_reattach)
+	{
+		if ((mpcbdm_verbose&VERBOSE_SER) && (mpcbdm_verbose&VERBOSE_BDM))
+			printf_filtered("ser_clkinstr: start word=0x%08x ,data=0x%08x\n",word,data);
+		ser_clkpref(DSDI_PREF3_CORE_INSTRUCTION);
+		ser_clk(word, 32, data);
+
+		if (mpcbdm_verbose&VERBOSE_SER)
+		{
+			if (data)
+			{
+				printf_filtered("ser_clkinstr: word=0x%08x ,*data=0x%08x -> stat %d freeze %d dpi %d\n",word,*data,mpcbdm_stat,mpcbdm_freeze,mpcbdm_dpi);
+			}
+			else
+			{
+				printf_filtered("ser_clkinstr: word=0x%08x ,data=Null -> stat %d freeze %d dpi %d\n",word,mpcbdm_stat,mpcbdm_freeze,mpcbdm_dpi);
+			}
+		}
+	}
+}
+
+static void ser_clkdata(u_int word, u_int *data)
+{
+	if (!mpcbdm_reattach)
+	{
+		if ((mpcbdm_verbose&VERBOSE_SER) && (mpcbdm_verbose&VERBOSE_BDM))
+			printf_filtered("ser_clkidata: start word=0x%08x ,data=0x%08x\n",word,data);
+
+		ser_clkpref(DSDI_PREF3_CORE_DATA);
+		ser_clk(word, 32, data);
+
+		if (mpcbdm_verbose&VERBOSE_SER)
+		{
+			if (data)
+			{
+				printf_filtered("ser_clkdata: word=0x%08x ,*data=0x%08x -> stat %d freeze %d dpi %d\n",word,*data,mpcbdm_stat,mpcbdm_freeze,mpcbdm_dpi);
+			}
+			else
+			{
+				printf_filtered("ser_clkdata: word=0x%08x ,data=Null) -> stat %d freeze %d dpi %d\n",word,mpcbdm_stat,mpcbdm_freeze,mpcbdm_dpi);
+			}
+		}
+	}
+}
+
+static void ser_clkdpc(u_int word, u_int *data)
+{
+	if (!mpcbdm_reattach)
+	{
+		if ((mpcbdm_verbose&VERBOSE_SER) && (mpcbdm_verbose&VERBOSE_BDM))
+			printf_filtered("ser_clkdpc: start word=0x%08x ,data=0x%08x\n",word,data);
+
+		ser_clkpref(DSDI_PREF3_DPC);
+	 	ser_clk(word, 7, data);
+
+		if (mpcbdm_verbose&VERBOSE_SER)
+		{
+			if (data)
+			{
+				printf_filtered("ser_clkdpc: word=0x%08x ,*data=0x%08x -> stat %d freeze %d dpi %d\n",word,*data,mpcbdm_stat,mpcbdm_freeze,mpcbdm_dpi);
+			}
+			else
+			{
+				printf_filtered("ser_clkdpc: word=0x%08x ,data=Null) -> stat %d freeze %d dpi %d\n",word,mpcbdm_stat,mpcbdm_freeze,mpcbdm_dpi);
+			}
+		}
+	}
+}
+
+/***************************************************************
+* BDM routines, using low level routines                       *
+****************************************************************/
+
+static u_int bdm_getreg(int reg)
+{
+	u_int data;
+	u_int com;
+
+	reg &= ~GPR_REG_MASK;
+/*DPDR = SPR 630 = /t 10011 10110*/
+/*spr field in instruction is split field = SPR[5-9] || SPR[0-4]*/
+/*-> spr = /t 10110 10011 = 723*/
+	com = (31 << 26) | (reg << 21) | (723 << 11) | (467 << 1); /*mtspr DPDR,rreg*/
+	ser_clkinstr(com, 0); /*copy reg to debug port data register*/
+	ser_clkinstr(DSDI_COM_NOP, &data); /*get data*/
+
+	return data;
+}
+
+static void bdm_setreg(int reg, u_int word)
+{
+	u_int data;
+	u_int com;
+
+	reg &= ~GPR_REG_MASK;
+	com = (31 << 26) | (reg << 21) | (723 << 11) | (339 << 1); /*mfspr rreg,DPDR*/
+	ser_clkinstr(com, 0); /*copy debug port register to reg*/
+	ser_clkdata(word, &data); /*put data to execute instruction*/
+}
+
+static u_int bdm_getmsr(void)
+{
+	u_int r0;
+	u_int spr;
+	u_int com;
+
+	r0 = bdm_getreg(0); /*save r0*/
+	com = (31 << 26) | (83 << 1); /*mfmsr r0*/
+	ser_clkinstr(com, 0); /*copy msr to r0*/
+	spr = bdm_getreg(0); /*get r0*/
+	bdm_setreg(0, r0); /*restore r0*/
+
+	return spr;
+}
+
+static void bdm_setmsr(u_int word)
+{
+	u_int data;
+	u_int r0;
+	u_int com;
+
+	r0 = bdm_getreg(0); /*save r0*/
+	com = (31 << 26) | (723 << 11) | (339 << 1); /*mfspr r0,DPDR*/
+	ser_clkinstr(com, 0); /*get data from debug port*/
+	ser_clkdata(word, &data); /*place data to debug port*/
+	com = (31 << 26) | (146 << 1); /*mtmsr r0*/
+	ser_clkinstr(com, 0); /*copy r0 to msr*/
+	bdm_setreg(0, r0); /*restore r0*/
+}
+
+
+static u_int bdm_getcr(void)
+{
+	u_int r0;
+	u_int spr;
+	u_int com;
+
+	r0 = bdm_getreg(0); /*save r0*/
+	com = (31 << 26) | (19 << 1); /*mfcr r0*/
+	ser_clkinstr(com, 0); /*copy cr to r0*/
+	spr = bdm_getreg(0); /*get r0*/
+	bdm_setreg(0, r0); /*restore r0*/
+
+	return spr;
+}
+
+static void bdm_setcr(u_int word)
+{
+	u_int data;
+	u_int r0;
+	u_int com;
+
+	r0 = bdm_getreg(0); /*save r0*/
+	com = (31 << 26) | (723 << 11) | (339 << 1); /*mfspr r0,DPDR*/
+	ser_clkinstr(com, 0); /*get data from debug port*/
+	ser_clkdata(word, &data); /*place data*/
+	com = (31 << 26) | (0xFF << 12) | (144 << 1); /*mtcrf 0xff,r0*/
+	ser_clkinstr(com, 0); /*copy r0 to cr*/
+	bdm_setreg(0, r0); /*restore r0*/
+}
+
+
+
+static u_int bdm_getspri(int reg)
+{
+	u_int immr;
+	u_int r0;
+	u_int r1;
+	u_int n;
+	u_int com;
+
+	immr = bdm_getspr(SPR_IMMR); /*get offset for memory mapped sprs*/
+	r0 = bdm_getreg(0); /*save r0*/
+	r1 = bdm_getreg(1); /*save r1*/
+	bdm_setreg(1,(immr&0xFFFF0000) + reg); /*load r1 with adr for spri*/
+	com = (32 << 26) | (1 << 16); /*lwz r0,0(r1)*/
+	ser_clkinstr(com, 0); /*copy spri to r0*/
+	n = bdm_getreg(0); /*get spri value from r0*/
+	bdm_setreg(1,r1); /*restore r1*/
+	bdm_setreg(0,r0); /*restore r0*/
+
+	return n;
+}
+
+static void bdm_setspri(int reg, u_int word)
+{
+	u_int immr;
+	u_int r0;
+	u_int r1;
+	u_int com;
+
+	immr = bdm_getspr(SPR_IMMR); /*get offset for memory mapped sprs*/
+	r0 = bdm_getreg(0); /*save r0*/
+	r1 = bdm_getreg(1); /*save r1*/
+	bdm_setreg(1,(immr&0xFFFF0000) + reg); /*load r1 with adr for spr*/
+	bdm_setreg(0, word); /*set r0 with value*/
+	com = (36 << 26) | (1 << 16); /*stw r0,0(r1)*/
+	ser_clkinstr(com, 0); /*store value to spr*/
+	bdm_setreg(1,r1); /*restore r1*/
+	bdm_setreg(0,r0); /*restore r0*/
+}
+
+static void bdm_setsprihw(int reg, u_int word)
+{
+	u_int immr;
+	u_int r0;
+	u_int r1;
+	u_int com;
+
+	immr = bdm_getspr(SPR_IMMR); /*get offset for memory mapped sprs*/
+	r0 = bdm_getreg(0); /*save r0*/
+	r1 = bdm_getreg(1); /*save r1*/
+
+	bdm_setreg(1,(immr&0xFFFF0000) + reg); /*load r1 with adr for spr*/
+	bdm_setreg(0, word); /*set r0 with data*/
+	com = (44 << 26) | (1 << 16); /*sth r0,0(r1)*/
+	ser_clkinstr(com, 0); /*copy data to spr*/
+	bdm_setreg(1,r1); /*restore r1*/
+	bdm_setreg(0,r0); /*restore r0*/
+}
+
+
+
+u_int bdm_getspr(int reg)
+{
+	u_int r0;
+	u_int spr;
+	u_int com;
+
+	if(reg == SPR_MSR) return bdm_getmsr(); /*special for msr*/
+	if(reg == SPR_CR) return bdm_getcr(); /*special for cr*/
+	if(reg & SPRI_MASK) return bdm_getspri(reg & ~SPRI_MASK); /*memory mapped sprs*/
+	r0 = bdm_getreg(0); /*save r0*/
+/*mfspr r0,SPRreg*/
+	com = (31 << 26) | ((((reg&0x1f) << 5) | ((reg >> 5)&0x1f)) << 11) | (339 << 1);
+	ser_clkinstr(com, 0); /*copy spr to r0*/
+	spr = bdm_getreg(0); /*read r0*/
+	bdm_setreg(0, r0); /*restore r0*/
+
+	return spr;
+}
+
+void bdm_setspr(int reg, u_int word)
+{
+	u_int data;
+	u_int r0;
+	u_int com;
+
+	if(reg == SPR_MSR) return bdm_setmsr(word); /*special for msr*/
+	if(reg == SPR_CR) return bdm_setcr(word); /*special for cr*/
+	if(reg & SPRI_MASK) return bdm_setspri(reg & ~SPRI_MASK, word); /*memory mapped sprs*/
+	r0 = bdm_getreg(0); /*save r0*/
+	com = (31 << 26) | (723 << 11) | (339 << 1); /*mfspr r0,DPDR*/
+	ser_clkinstr(com, 0); /*copy data to r0*/
+	ser_clkdata(word, &data); /*provide data to r0*/
+/*mtspr SPRreg,r0*/
+	com = (31 << 26) | ((((reg&0x1f) << 5) | ((reg >> 5)&0x1f)) << 11) | (467 << 1);
+	ser_clkinstr(com, 0);
+	bdm_setreg(0, r0); /*restore r0*/
+}
+
+
+u_int ppc_read_bdm_register(int reg)
+{
+	u_int val;
+
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf_filtered("ppc_read_bdm_register: reg=0x%08x\n",reg);
+	}
+	if(reg & GPR_REG_MASK) val = bdm_getreg(reg);
+	else val = bdm_getspr(reg);
+	val = extract_unsigned_integer(&val, sizeof(val));
+	return val;
+}
+
+void ppc_write_bdm_register(int reg, u_int word)
+{
+	u_int val = extract_unsigned_integer(&word, sizeof(word));
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf_filtered("ppc_write_bdm_register: reg=0x%08x\n",reg);
+	}
+	if(reg & GPR_REG_MASK) return bdm_setreg(reg, val);
+	return bdm_setspr(reg, val);
+}
+
+u_int ppc_bdm_getword(u_int addr)
+{
+	u_int r0;
+	u_int r1;
+	u_int val;
+	u_int com;
+
+	r0 = bdm_getreg(0); /*save r0*/
+	r1 = bdm_getreg(1); /*save r1*/
+	bdm_setreg(1, addr); /*set addr to r1*/
+	com = (32 << 26) | (1 << 16); /*lwz r0,0(r1)*/
+	ser_clkinstr(com, 0); /*load r0 with data from mem*/
+	val = bdm_getreg(0); /*get data from r0*/
+	bdm_setreg(0, r0); /*restore data*/
+	bdm_setreg(1, r1); /*restore data*/
+
+	return val;
+}
+
+void ppc_bdm_setword(u_int addr, u_int val)
+{
+	u_int r0;
+	u_int r1;
+	u_int com;
+
+	r0 = bdm_getreg(0); /*save r0*/
+	r1 = bdm_getreg(1); /*save r1*/
+	bdm_setreg(1, addr); /*put addr in r1*/
+	bdm_setreg(0, val); /*put data in r0*/
+	com = (36 << 26) | (1 << 16); /*stw r0,0(r1)*/
+	ser_clkinstr(com, 0); /*store data into mem*/
+	bdm_setreg(0, r0); /*restore r0*/
+	bdm_setreg(1, r1); /*restore r1*/
+}
+
+u_int ppc_bdm_gethalfword(u_int addr)
+{
+	u_int r0;
+	u_int r1;
+	u_int val;
+	u_int com;
+
+	r0 = bdm_getreg(0); /*save r0*/
+	r1 = bdm_getreg(1); /*save r1*/
+	bdm_setreg(1, addr); /*set addr to r1*/
+	com = (40 << 26) | (1 << 16); /*lhz r0,0(r1)*/
+	ser_clkinstr(com, 0); /*load r0 with data from mem*/
+	val = bdm_getreg(0); /*get data from r0*/
+	bdm_setreg(0, r0); /*restore data*/
+	bdm_setreg(1, r1); /*restore data*/
+
+	return val;
+}
+
+void ppc_bdm_sethalfword(u_int addr, u_int val)
+{
+	u_int r0;
+	u_int r1;
+	u_int com;
+
+	r0 = bdm_getreg(0); /*save r0*/
+	r1 = bdm_getreg(1); /*save r1*/
+	bdm_setreg(1, addr); /*put addr in r1*/
+	bdm_setreg(0, val); /*put data in r0*/
+	com = (44 << 26) | (1 << 16); /*sth r0,0(r1)*/
+	ser_clkinstr(com, 0); /*store data into mem*/
+	bdm_setreg(0, r0); /*restore r0*/
+	bdm_setreg(1, r1); /*restore r1*/
+}
+
+u_int ppc_bdm_getbyte(u_int addr)
+{
+	u_int r0;
+	u_int r1;
+	u_int val;
+	u_int com;
+
+	r0 = bdm_getreg(0); /*save r0*/
+	r1 = bdm_getreg(1); /*save r1*/
+	bdm_setreg(1, addr); /*set addr to r1*/
+	com = (34 << 26) | (1 << 16); /*lbz r0,0(r1)*/
+	ser_clkinstr(com, 0); /*load r0 with data from mem*/
+	val = bdm_getreg(0); /*get data from r0*/
+	bdm_setreg(0, r0); /*restore data*/
+	bdm_setreg(1, r1); /*restore data*/
+
+	return val;
+}
+
+void ppc_bdm_setbyte(u_int addr, u_int val)
+{
+	u_int r0;
+	u_int r1;
+	u_int com;
+
+	r0 = bdm_getreg(0); /*save r0*/
+	r1 = bdm_getreg(1); /*save r1*/
+	bdm_setreg(1, addr); /*put addr in r1*/
+	bdm_setreg(0, val); /*put data in r0*/
+	com = (38 << 26) | (1 << 16); /*stb r0,0(r1)*/
+	ser_clkinstr(com, 0); /*store data into mem*/
+	bdm_setreg(0, r0); /*restore r0*/
+	bdm_setreg(1, r1); /*restore r1*/
+}
+
+
+u_int ppc_bdm_tablewalk(u_int vAddr)
+{
+	u_int EPN;
+	u_int TWC;
+	u_int Level1;
+	u_int Level2;
+	u_int Level2Desc;
+	u_int pAddr;
+
+/* return value in case of mmu problems : */
+/* emergency solution for second stage loader */
+	pAddr = vAddr - mpcbdm_kbase; /* =-0xc0000000 */
+
+	EPN = bdm_getspr(SPR_MD_EPN); /* save EPN register */
+	TWC = bdm_getspr(SPR_MD_TWC); /* save TWC register */
+
+	bdm_setspr(SPR_MD_EPN,vAddr); /* set effective addr to virtual addr*/
+	Level1 = bdm_getspr(SPR_M_TWB); /* do table walk level 1*/
+	if (Level1 == 0)
+	{
+		if (mpcbdm_verbose&VERBOSE_MMU)
+		{
+			printf("ppc_bdm_tablewalk: invalid level one descriptor for vAddr 0x%08x\n",vAddr);
+		}
+		else
+		{
+			printf("M!");
+		}
+		return pAddr;
+	}
+	if ((Level1 & 0x0800)&&(mpcbdm_pgdir != 0)) /* kernel function? */
+	{
+		Level1 = ((mpcbdm_pgdir & 0x3ffff000) | (Level1&0x00000fff));
+		if (mpcbdm_verbose&VERBOSE_MMU)
+		{
+			printf("ppc_bdm_tablewalk: pgdir -> Level1 = 0x%08x for vAddr 0x%08x\n",Level1,vAddr);
+		}
+	}
+	Level2 = ppc_bdm_getword(Level1);
+	Level2 &= (u_int)0xfffff000;
+	if (Level2 == 0)
+	{
+		if (mpcbdm_verbose&VERBOSE_MMU)
+		{
+			printf("ppc_bdm_tablewalk: invalid level two base for vAddr 0x%08x and level one = 0x%08x\n",vAddr,Level1);
+		}
+		else
+		{
+			printf("M!");
+		}
+		return pAddr;
+	}
+	Level2 -=mpcbdm_kbase; /* tophys, like table miss does, default=-0xc0000000 */
+	Level2 |=0x000000001; /* set valid bit in physical L2 page */
+
+	bdm_setspr(SPR_MD_TWC,Level2);
+	Level2Desc= bdm_getspr(SPR_MD_TWC); /* perform table walk level 2*/
+	if (Level2Desc == 0)
+	{
+		if (mpcbdm_verbose&VERBOSE_MMU)
+		{
+			printf("ppc_bdm_tablewalk: invalid level two descriptor for vAddr 0x%08x, level one 0x%08x, level two 0x%08x\n",vAddr,Level1,Level2);
+		}
+		else
+		{
+			printf("M!");
+		}
+		return pAddr;
+	}
+	pAddr = ppc_bdm_getword(Level2Desc); /*get physical page addr*/
+	pAddr = (pAddr & (u_int)0xfffff000) | (vAddr & (u_int)0xfff); /*calc physical addr*/
+
+	if (mpcbdm_verbose&VERBOSE_MMU)
+	{
+		printf("ppc_bdm_tablewalk: MMU translates virtual 0x%08x to physical 0x%08x\n",vAddr,pAddr);
+	}
+
+	bdm_setspr(SPR_MD_TWC,TWC); /* restore TWC register */
+	bdm_setspr(SPR_MD_EPN,EPN); /* restore EPN register */
+
+	return pAddr;
+}
+
+void ppc_bdm_read_block(u_int from, char *to, int len)
+{
+	int n;
+	int val;
+	u_int r0 = bdm_getreg(0); /*save r0*/
+	u_int r1 = bdm_getreg(1); /*save r1*/
+
+	if ((LastMSR & MSR_IR)&&(mpcbdm_mmu)) /*mmu on and option activated*/
+	{
+		from = ppc_bdm_tablewalk(from);
+	}
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf_filtered("ppc_bdm_read_block: from=0x%08x, len=%d\n",from,len);
+	}
+
+	if(len > 0)
+	while((from & 3) || len < 4) /*no word aligned start adr?*/
+	{
+		bdm_setreg(1, (int)from);
+		from += 1;
+		ser_clkinstr(0x88010000, 0);	/* lbz r0,0(r1) */
+		val = bdm_getreg(0);			/* read byte*/
+		*(u_char*)to = val & 0xFF;		/* store byte*/
+		to += 1;
+		if(!--len) break;
+	}
+
+	if(len > 0 ) bdm_setreg(1, from - 4);
+	for(len; len > 3; len -= 4)	/* loop for aligned words*/
+	{
+		ser_clkinstr(0x84010004, 0);	/* lwzu r0,4(r1) */
+		val = bdm_getreg(0);			/* read word*/
+		val = extract_unsigned_integer(&val, sizeof(val));
+		memcpy(to, &val, 4);			/* store word */
+		to += 4;
+		from +=4; /* FP: this one was missing ! */
+	}
+	while(len > 0 && len < 4)	/*misaligned bytes to read at end?*/
+	{
+		bdm_setreg(1, from);
+		from += 1;
+		ser_clkinstr(0x88010000, 0);	/* lbz r0,0(r1) */
+		val = bdm_getreg(0);			/*read byte*/
+		*(u_char*)to = val & 0xFF;		/*store byte*/
+		to += 1;
+		--len;
+	}
+
+	bdm_setreg(0, r0); /* restore r0*/
+	bdm_setreg(1, r1); /* restore r1*/
+}
+
+void ppc_bdm_write_block(u_int mem, u_char *ozu, int len)
+{
+	u_int val;
+	u_int r30 = bdm_getreg(30);
+ 	u_int r31 = bdm_getreg(31);
+
+	if ((LastMSR & MSR_IR)&&(mpcbdm_mmu)) /*mmu on and option activated*/
+	{
+		mem = ppc_bdm_tablewalk(mem);
+	}
+
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf_filtered("ppc_bdm_write_block: mem=0x%08x, len=%d\n",mem,len);
+	}
+
+	if(len > 0)
+	while((mem & 3) || len < 4)
+	{
+		bdm_setreg(30, (int)mem); mem += 1;
+		val = *(u_char*)ozu; ozu += 1;
+		bdm_setreg(31, val);
+		ser_clkinstr(0x9BFE0000, 0);  /* stb r31,0(r30) */
+		if(!--len) break;
+	}
+
+	if(len > 3 )		/*for aligned words use BDM download feature*/
+	{
+		bdm_setreg(30, mem - 4);
+		ser_clkdpc(DSDI_DPC_START_DOWNLOAD, 0);
+		for(; len > 3; len -= 4)
+		{
+			memcpy(&val, ozu, 4); ozu += 4;
+			val = extract_unsigned_integer(&val, sizeof(val));
+			ser_clkdata(val, 0);
+			mem += 4;
+		}
+		ser_clkdpc(DSDI_DPC_END_DOWNLOAD, 0);
+		ser_clkdata(val, 0);
+	}
+
+	while(len > 0)
+	{
+		bdm_setreg(30, (int)mem); mem += 1;
+		val = *(u_char*)ozu; ozu += 1;
+		bdm_setreg(31, val);
+		ser_clkinstr(0x9BFE0000, 0);  /* stb r31,0(r30) */
+		--len;
+	}
+
+	bdm_setreg(30, r30);
+	bdm_setreg(31, r31);
+}
+
+
+/***************************************************************
+* MPCBDM target operations                                     *
+****************************************************************/
+
+static void show_regs(void)
+{
+	int n;
+	int data;
+
+	for(n = 0; n < 32; ++n)
+	{
+		data = bdm_getreg(n);
+		printf("R%02d=0x%08X ", n, data);
+		if(!((n + 1) % 4)) printf("\n");
+	}
+	printf("\n");
+}
+
+
+void ppc_bdm_stop(void)
+{
+/* Reset and set DSCK and /DSDI for immediate Debug Mode, asynchronously clocked */
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf_filtered("ppc_bdm_stop: assert Reset for immediate debug mode, asynchronous clocked\n");
+	}
+	PP.Write(PP.DSCK); /* set DSCK and /DSDI, implicite wait in Write */
+/* assert /HRESET and /SRESET, hold DSCK and /DSDI : Debug Mode enable */
+/* Note: I added HRESET here, because sometimes only SRESET
+ didn't bring the processor in a stable state. So I completely removed
+ ppc_bdm_reset. But I'm not shure I broke something here...*/
+ 	PP.Reset(PP.HRESET|PP.SRESET);
+/* hold reset for some while, since here occured some problems with fast CPUs*/
+	usleep(mpcbdm_sleep);
+/* release H&SRESET, hold DSCK, /DSDI: immediate Debug Mode, asynchr. clocked*/
+	PP.Reset(0x00);
+/* we have to hold DSDI low for at least eight MPC cycles*/
+	usleep(mpcbdm_sleep);
+	WaitFreeze();
+	LastMSR = bdm_getspr(SPR_SRR1);
+	if (mpcbdm_verbose&VERBOSE_SRR1)
+	{
+		printf_filtered("ppc_bdm_stop: ");
+		print_spr_info(SPR_SRR1, LastMSR, 1, 1, 1, 1);
+		printf_filtered("\n");
+	}
+}
+
+/*FIXME: remove?*/
+void ppc_bdm_reset(void)
+{
+	printf("assert HRESET\n");
+	PP.Write(PP.DSCK);
+	PP.Reset(PP.HRESET); /*FP: assert HRESET with DSCK : Debug Mode enable */
+/* hold reset for some while, since here occured some problems with fast CPUs*/
+	usleep(mpcbdm_sleep);
+	PP.Reset(0x00); /* release HRESET with DSCK, /DSDI: immediately debug, asynchr. clocked*/
+}
+
+
+void ppc_bdm_resume()
+{
+	if (mpcbdm_reattach)
+	{
+		printf("*** Resume without communicating with the MPC (mpcbdm_reattach)\n");
+		mpcbdm_reattach = 0;
+		ctrlc = 0;
+		return;
+	}
+	printf("*** Resume\n");
+	ctrlc = 0;
+	bdm_getspr(SPR_ICR); /*read ICR to clear pending interrupts*/
+	bdm_setspr(SPR_IC_CST, 0x0C000000); /*invalidate instruction cache*/
+	/*tell PPC to exit from Debug Port Interrupt*/
+	ser_clkinstr(DSDI_COM_RFI, 0); /*return from interrupt*/
+}
+
+
+static void ppc_bdm_interrupt (int signo)
+{
+	signal(signo, ppc_bdm_interrupt);
+
+	printf("CTRL-C catched - %d\n", ++ctrlc);
+	if(ctrlc >= 5)
+	{
+		printf("\n caught five times CTRL-C: BDM port is not responding.\nQuitting gdb\n");
+		exit(-1);
+	}
+	ser_clkdpc(DSDI_DPC_ASSERT_NMASK_BREAK,0); /*signal debug port interrupt*/
+	printf("Sending Debug Port Interrupt Request to PPC...\n");
+}
+
+
+int ppc_bdm_wait(void)
+{
+	int icr = 0;
+	void (*ofunc)();
+
+	ofunc = signal (SIGINT, ppc_bdm_interrupt); /*install our handler*/
+	printf("*** wait freeze\n");
+	WaitFreeze(); /*wait for ppc to come into debug mode*/
+	/*or interrupt ppc with ctrl-c with our handler*/
+	signal (SIGINT, ofunc); /*restore old handler*/
+	icr = bdm_getspr(SPR_ICR); /*interrupt cause register*/
+	LastICR = icr; /*save interupt cause*/
+/*get srr1, contents of MSR before debug exception*/
+ 	LastMSR = bdm_getspr(SPR_SRR1);
+	if (mpcbdm_verbose&VERBOSE_SRR1)
+	{
+		printf_filtered("ppc_bdm_wait: ");
+		print_spr_info(SPR_SRR1, LastMSR, 1, 1, 1, 1);
+		printf_filtered("\n");
+	}
+
+	ser_clkdpc(DSDI_DPC_NEGATE_NMASK_BREAK,0); /*negate debug port interrupt request*/
+//  ser_clkinstr(0x7C0004AC, 0); /* sync */
+//  ser_clkinstr(0x4C00012C, 0); /* isync */
+	if (mpcbdm_dflush)
+	{
+/* flush all data cache blocks to see valid data, but this is slow*/
+ 		mpcbdm_dcache_flush(0,1);
+	}
+	bdm_setspr(SPR_IC_CST, 0x0C000000); /*invalidate instruction cache*/
+
+	if(icr & PPC_BIT(17)) icr = 1; /* ICR[SEI] -> INT */
+	else icr = 0;	/* else TRAP */
+	return icr;
+}
+
+
+void ppc_bdm_step(void)
+{
+	if (mpcbdm_reattach)
+	{
+		printf("*** step without communicating with the MPC (mpcbdm_reattach)\n");
+	}
+	else
+	{
+		printf("*** step\n");
+		LastDER = bdm_getspr(SPR_DER); /*save previous Debug Enable Register value*/
+		bdm_setspr(SPR_DER, LastDER | PPC_BIT(14)); /* force TRE for single step*/
+/* set single step trace enable in next MSR */
+		bdm_setspr(SPR_SRR1, bdm_getspr(SPR_SRR1) | PPC_BIT(21));
+	}
+	ppc_bdm_resume(); /*execute one step*/
+}
+
+
+void ppc_bdm_run(void)
+{
+	if (mpcbdm_reattach)
+	{
+		printf("*** run without communicating with the MPC (mpcbdm_reattach)\n");
+	}
+	else
+	{
+		printf("*** run\n");
+		LastDER = bdm_getspr(SPR_DER); /*save previous Debug Enable Register value*/
+/* disable single step trace enable (SE) */
+		bdm_setspr(SPR_SRR1, bdm_getspr(SPR_SRR1) & ~(PPC_BIT(21)));
+	}
+	ppc_bdm_resume();
+}
+
+void ppc_bdm_init(void)
+{
+	int i;
+	int n;
+	u_int pvr;
+	u_int partmask;
+	u_int revnum;
+	u_int word;
+	u_int partnum;
+	u_int masknum;
+
+	if (mpcbdm_reattach)
+	{
+		return;
+	}
+
+	printf_filtered("*** init\n");
+
+/* try to identify processor */
+	pvr = bdm_getspr(SPR_PVR); /* get processor version register */
+	partmask = 0x0000ffff & bdm_getspr(SPR_IMMR); /* get IMMR */
+	partnum = (partmask & 0x0000ff00) >> 8;
+	masknum = partmask & 0x000000ff;
+	word = bdm_getspri(SPRI_REV_NUM); /* get REV_NUM */
+	revnum = (word & 0xffff0000) >> 16;
+	printf_filtered("Target cpu PVR=0x%08X PARTNUM=0x%02X MASKNUM=0x%02X REV_NUM=0x%04X\n",
+					pvr,partnum,masknum,revnum);
+
+	for (i=0; CPU[i].name; i++)
+	{
+		if ((pvr == CPU[i].pvr) && (partmask == CPU[i].partmask) && (revnum == CPU[i].revnum))
+		{
+			printf_filtered("Target cpu is a '%s'\n",CPU[i].name);
+			if (CPU[i].regfile)
+			{
+				printf_filtered("Reading CPU register description file '%s'\n",CPU[i].regfile);
+			}
+			break;
+		}
+	}
+	if (!(CPU[i].name))
+	{
+		printf_filtered("warning: unknown CPU. Using default register description\n");
+	}
+
+/*initial value for Debug Enable Register*/
+/* SEIE for soft breakpoint recognition (illegal opcode) needed */
+	bdm_setspr(SPR_DER, 0x7002400F); /*RSTE,CHSTPE,MCIE,TRE,SEIE,LBRKE,IBRKE,EBRKE,DPIE*/
+	bdm_setspr(SPRI_PLPRCR, bdm_getspr(SPRI_PLPRCR) | PPC_BIT(24)); /*CSE, CheckStopEnable*/
+	bdm_setsprihw(SPRI_SWSR, 0x556C); /*trigger software watch dog*/
+	bdm_setsprihw(SPRI_SWSR, 0xAA39);
+	LastMSR = bdm_getspr(SPR_SRR1);
+	if (mpcbdm_verbose&VERBOSE_SRR1)
+	{
+		printf_filtered("ppc_bdm_init: ");
+		print_spr_info(SPR_SRR1, LastMSR, 1, 1, 1, 1);
+		printf_filtered("\n");
+	}
+	printf("\007BDM initialized\n");
+}
+
+/***********************************************************
+* routines from ocd.c                                      *
+***********************************************************/
+
+/*  Return nonzero if the thread TH is still alive on the remote system.  */
+
+int	mpcbdm_thread_alive (ptid_t pid_t)
+{
+ 	return 1;
+}
+
+/* Clean up connection to a remote debugger.  */
+
+/* ARGSUSED */
+void mpcbdm_close (int quitting)
+{
+  /* if (mpcbdm_desc)
+    SERIAL_CLOSE (mpcbdm_desc);
+  mpcbdm_desc = NULL; */
+}
+
+/* Stub for catch_errors.  */
+
+static int mpcbdm_start_remote (PTR dummy)
+{
+	int nResult;
+	int port;
+
+	if (!dummy)
+	{
+		if (PP.port == -1)
+		{
+			printf_filtered("port number is required\n");
+			return 0;
+		}
+		else
+		{
+			port = PP.port; /* preveously used port*/
+		}
+	}
+	else /* port number specified */
+	{
+		PP.port = -1;
+		port = (int)strtoul((char*) dummy,0,0); /* read port number */
+	}
+
+	immediate_quit = 1; 	  /* Allow user to interrupt it */
+
+	nResult = PortInit(port);
+	if (nResult == RETURN_FAIL)
+	{
+		printf_filtered("error on opening printer port %d\n",port);
+		return 0;
+	}
+
+	mpcbdm_icr_or = 0; /* init core interrupt counter */
+
+/* setup processor vor debugging */
+	ppc_bdm_stop();
+	ppc_bdm_init();
+
+	immediate_quit = 0;
+
+/* This is really the job of start_remote however, that makes an assumption
+   that the target is about to print out a status message of some sort.  That
+   doesn't happen here (in fact, it may not be possible to get the monitor to
+   send the appropriate packet).  */
+
+	flush_cached_frames ();
+	registers_changed ();
+	stop_pc = read_pc ();
+	set_current_frame (create_new_frame (read_fp (), stop_pc));
+	select_frame (get_current_frame (), 0);
+	print_stack_frame (selected_frame, -1, 1);
+
+	return 1;
+}
+
+/* Open a connection to a remote debugger.
+   NAME is the filename used for communication.  */
+
+/* static DCACHE *mpcbdm_dcache; */
+
+void mpcbdm_open (char *name, int from_tty)
+{
+	unsigned char buf[10], *p;
+	int status;
+
+	target_preopen (from_tty);
+
+	current_ops = &mpcbdm_ops;
+
+	unpush_target (current_ops);
+
+	/* mpcbdm_dcache = dcache_init (mpcbdm_read_bytes, mpcbdm_write_bytes); */
+
+	// printf("FP_REGNUM=%d\n", FP_REGNUM);
+
+	printf_filtered("MPCBDM version %s\n",sVersion);
+/*
+	if (from_tty)
+	{
+		puts_filtered ("Remote target MPCBDM connected to parallel port ");
+		puts_filtered (name);
+		puts_filtered ("\n");
+	}
+*/
+
+	push_target (current_ops);    /* Switch to using remote target now */
+
+  /* Without this, some commands which require an active target (such as kill)
+     won't work.  This variable serves (at least) double duty as both the pid
+     of the target process (if it has such), and as a flag indicating that a
+     target is active.  These functions should be split out into seperate
+     variables, especially since GDB will someday have a notion of debugging
+     several processes.  */
+
+	inferior_ptid.pid = 42000;
+  /* Start the remote connection; if error (0), discard this target.
+     In particular, if the user quits, be sure to discard it
+     (we'd be in an inconsistent state otherwise).  */
+
+
+	if (!catch_errors (mpcbdm_start_remote, name,
+		"Couldn't establish connection to remote target\n",
+		RETURN_MASK_ALL))
+	{
+    	pop_target();
+		error("Failed to connect to target 'mpcbdm'");
+	}
+}
+
+/* This takes a program previously attached to and detaches it.  After
+   this is done, GDB can be used to debug some other program.  We
+   better not have left any breakpoints in the target program or it'll
+   die when it hits one.  */
+
+void mpcbdm_detach (char *args, int from_tty)
+{
+	if (args)
+		error ("Argument given to \"detach\" when remotely debugging.");
+
+	pop_target ();
+	if (from_tty)
+		puts_filtered ("Ending remote debugging.\n");
+}
+
+/* Tell the remote machine to resume.  */
+
+void mpcbdm_resume (ptid_t pid_t, int step, enum target_signal siggnal)
+{
+	int pid = pid_t.pid;
+
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf("mpcbdm_resume %s\n", step?"step":"run");
+	}
+	/* dcache_flush (mpcbdm_dcache); */
+	if(step) ppc_bdm_step();
+	else ppc_bdm_run();
+}
+
+/* Wait until the remote machine stops, then return,
+   storing status in STATUS just as `wait' would.
+   Returns "pid" (though it's not clear what, if anything, that
+   means in the case of this target).  */
+
+void mpcbdm_prepare_to_store (void)
+{
+}
+
+
+/* Read or write LEN bytes from inferior memory at MEMADDR, transferring
+   to or from debugger address MYADDR.  Write to inferior if SHOULD_WRITE is
+   nonzero.  Returns length of data written or read; 0 for error.  */
+
+int mpcbdm_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
+						int should_write, struct target_ops *target)
+{
+	u_int val;
+	u_int n;
+	u_int mem = memaddr;
+
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf("mpcbdm_xfer_memory: memaddr 0x%08x myaddr 0x%08x len %d write %d\n",memaddr,myaddr,len,should_write);
+	}
+
+	if(should_write)
+	{
+		ppc_bdm_write_block(mem, myaddr, len);
+	}
+	else
+	{
+		ppc_bdm_read_block(mem, myaddr, len);
+	}
+	return len;
+}
+
+void mpcbdm_files_info (struct target_ops *ignore)
+{
+ 	puts_filtered ("Debugging a MPC target through the BDM interface over a parallel port.\n");
+}
+
+
+void mpcbdm_kill (void)
+{
+  /* For some mysterious reason, wait_for_inferior calls kill instead of
+     mourn after it gets TARGET_WAITKIND_SIGNALLED.  Work around it.  */
+	if (mpcbdm_kill_kludge)
+	{
+		mpcbdm_kill_kludge = 0;
+		target_mourn_inferior ();
+		return;
+	}
+
+/* Don't wait for it to die.  I'm not really sure it matters whether
+   we do or not.  */
+	target_mourn_inferior ();
+}
+
+void mpcbdm_mourn (void)
+{
+	unpush_target (current_ops);
+	generic_mourn_inferior ();
+}
+
+/* All we actually do is set the PC to the start address of exec_bfd, and start
+   the program at that point.  */
+
+void mpcbdm_create_inferior (char *exec_file, char *args, char **env)
+{
+	if (args && *args)
+		error ("Args are not supported by BDM.");
+
+	clear_proceed_status ();
+	proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0);
+}
+
+void mpcbdm_load (char *args, int from_tty)
+{
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf("mpcbdm_load: args %s from_tty %d\n",args,from_tty);
+	}
+
+	generic_load (args, from_tty);
+
+/*FP	inferior_ptid = 0;*/
+
+/* This is necessary because many things were based on the PC at the time that
+   we attached to the monitor, which is no longer valid now that we have loaded
+   new code (and just changed the PC).  Another way to do this might be to call
+   normal_stop, except that the stack may not be valid, and things would get
+   horribly confused... */
+
+	clear_symtab_users ();
+}
+
+/* This should be defined for each target */
+/* But we want to be able to compile this file for some configurations
+   not yet supported fully */
+
+int mpcbdm_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+	int i;
+	unsigned int ictrl;
+	unsigned int hwmask;
+
+	if (mpcbdm_hwbrk)	/*use MPC hardware registers?*/
+	{
+		for (i = 0; i < mpcbdm_maxhwbrk; i++)
+		{
+			if (!hwbrk_used[i])
+				break;
+		}
+		if (i >= mpcbdm_maxhwbrk)
+		{
+			printf("too many hardware breakpoints: only %d supported\n",mpcbdm_maxhwbrk);
+			return 1;
+		}
+
+		ictrl = bdm_getspr(SPR_ICTRL);
+
+		/*mask for ictrl: CTx = 100 | IWx = 10 | SIWxEN = 1*/
+		hwmask = (1<<(31-i*3)) | (1<<(19-i*2)) | (1<<(11-i));
+		if (mpcbdm_verbose&VERBOSE_BRK)
+			printf("enable hardware breakpoint %d : addr 0x%08x ICTRL mask = 0x%08x\n",i,addr,hwmask);
+
+		ictrl |= hwmask; /*enable CMPx*/
+		bdm_setspr(SPR_ICTRL,ictrl);
+		bdm_setspr(SPR_CMPA+i, (unsigned int) addr);
+
+		hwbrk_used[i] = 1; /* remember break point and addr*/
+		hwbrk_adr[i] = (unsigned int) addr;
+
+		return 0;
+	}
+
+	/* use illegal opcodes for software emulation exception*/
+
+	target_read_memory (addr, contents_cache, sizeof (break_insn));
+	target_write_memory (addr, break_insn, sizeof (break_insn));
+	return 0;
+}
+
+int mpcbdm_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+	int i;
+	unsigned int ictrl;
+	unsigned int hwmask;
+
+	if (mpcbdm_hwbrk)	/*use MPC hardware registers?*/
+	{
+		for (i = 0; i < mpcbdm_maxhwbrk; i++)
+		{
+			if (hwbrk_used[i] && (hwbrk_adr[i] == (unsigned int) addr)) /* brkp found?*/
+				break;
+		}
+		if (i >= mpcbdm_maxhwbrk)
+		{
+			printf("no matching hardware breakpoint found\n");
+			return 1;
+		}
+		ictrl = bdm_getspr(SPR_ICTRL);
+		hwmask = (1<<(31-i*3)) | (1<<(19-i*2)) | (1<<(11-i));
+		if (mpcbdm_verbose&VERBOSE_BRK)
+			printf("disable hardware breakpoint %d : addr 0x%08x ICTRL mask = 0x%08x\n",i,addr,hwmask);
+		ictrl &= ~hwmask; /*disable CMPx*/
+		bdm_setspr(SPR_ICTRL,ictrl);
+
+		hwbrk_used[i] = 0;
+
+		return 0;
+	}
+
+	/* use illegal opcodes for software emulation exception*/
+
+	target_write_memory (addr, contents_cache, sizeof (break_insn));
+
+	return 0;
+}
+
+static void bdm_command (char *args, int from_tty)
+{
+	error ("try 'help mpcbdm' for target specific commands");
+}
+
+static void mpcbdm_reset_command (char *args, int from_tty)
+{
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf("mpcbdm_reset_command: args %s from_tty %d\n",args,from_tty);
+	}
+	ppc_bdm_stop();
+}
+
+static void mpcbdm_restart_command (char *args, int from_tty)
+{
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf("mpcbdm_restart_command: args %s from_tty %d\n",args,from_tty);
+	}
+	mpcbdm_start_remote(args);
+}
+
+/* Temporary replacement for target_store_registers().  This prevents
+   generic_load from trying to set the PC.  */
+
+static void noop_store_registers (int regno)
+{
+}
+
+static int findsprnum(char *pch)
+{
+	int n;
+	char *p;
+
+	for(p = pch; *p ; ++p) *p = toupper(*p);
+
+	for(n = 0; sprnames[n].name; ++n)
+	{
+		if(!strcmp(sprnames[n].name, pch)) return sprnames[n].num;
+	}
+
+	return -1;
+}
+
+void print_spr_info(int num,u_int val, int bName, int bDef, int bVal, int bPretty)
+{
+	int i;
+	int index;
+	int startbit,bit;
+	int len;
+	int bFirstPrinted;
+	int bSPRI;
+	u_int bitmask;
+	u_int bitfieldmask;
+	u_int bitfieldval;
+	char *pFormat;
+	char *pFieldName;
+	char *pFieldNameEnd;
+	char FieldName[255];
+
+	index = -1;
+	for(i = 0; sprnames[i].name ; ++i)
+	{
+		if(sprnames[i].num == num)
+		{
+			index = i;
+			break;
+		}
+	}
+
+	bSPRI = (num & SPRI_MASK);
+	num &= (GPR_REG_MASK-1); /*remove register markings*/
+
+	if (index < 0) /*not in sprnames*/
+	{
+		if (bName)
+		{
+			if (bSPRI)
+				printf("SPRI 0x%x", num);
+			else
+			printf("SPR %d", num);
+		}
+		if (bVal)
+		{
+			printf(" = 0x%08x", val);
+		}
+		return;
+	}
+
+	pFormat = sprnames[i].Namefield;
+	if (!pFormat)	/*no bitfield description available?*/
+	{
+		if (bDef)
+		{
+			if (bSPRI)
+			{
+				printf("IMMR + 0x%x",num);
+			}
+			else
+			{
+				printf("SPR %d",num);
+			}
+			if ((bName) && (sprnames[i].name))
+				printf(" : %s", sprnames[i].name);
+		}
+		else if ((bName) && (sprnames[i].name))
+			printf("%s", sprnames[i].name);
+
+		if (bVal)
+			printf(" = 0x%08x", val);
+		if (bDef)
+		{
+			if (sprnames[i].Longname) printf(" , %s", sprnames[i].Longname);
+			if (sprnames[i].Reference) printf(" , %s", sprnames[i].Reference);
+			if ((sprnames[i].Longname) || (sprnames[i].Reference)) printf("\n");
+		}
+		return; /*for no Format description, we are finished here */
+	}
+
+/*start of pretty print*/
+	if (bDef) /* print name and format description field?*/
+	{
+		printf("%s := (%s)\n",sprnames[index].name,sprnames[index].Namefield);
+		if (bSPRI)
+			printf("IMMR + 0x%x:",num);
+		else
+			printf("SPR %d:",num);
+		if (sprnames[i].Longname)
+		{
+			printf("%s", sprnames[i].Longname);
+			if (sprnames[i].Reference) printf(", ");
+		}
+		if (sprnames[i].Reference) printf("%s", sprnames[i].Reference);
+		printf("\n");
+	}
+	if (bName)
+	{
+	 	if (sprnames[i].name) printf("%s", sprnames[i].name);
+		else
+		{
+			if (bSPRI)
+				printf("IMMR + 0x%x",num);
+			else
+				printf("SPR %d",num);
+		}
+	}
+	if (bVal)
+	{
+		printf(" = 0x%08x", val);
+	}
+	if (bPretty)
+	{
+		startbit = 0;
+		bFirstPrinted = 0;
+		if (isdigit(*pFormat))	/*extra case first field starting not at bit zero*/
+		{
+			i = sscanf(pFormat,"%d",&startbit);
+			if ((startbit<0) || (startbit >PPC_BITS)|| (i!=1))
+			{
+				printf("\nerror in bitfield description string %s\n",sprnames[index].Namefield);
+				printf(" wrong bit position %d at %s\n",startbit, pFormat);
+				return;
+			}
+			do
+			{
+				pFormat++;
+			} while (isdigit(*pFormat));
+		}
+		while ((*pFormat))
+		{
+			pFieldName = pFormat;
+			pFormat = strchr(pFormat,'|');
+			if (!pFormat) /*last entry*/
+			{
+				bit = PPC_BITS; /*reached last bit*/
+				len = strlen(pFieldName);
+			}
+			else
+			{
+				len = pFormat-pFieldName;
+				pFormat++; /*skip |*/
+				if (isdigit(*pFormat))	/*bitfield or single bit*/
+				{
+					i = sscanf(pFormat,"%d",&bit);
+					if ((bit<0) || (bit >PPC_BITS) ||(bit <=startbit) || (i!=1))
+					{
+						printf("error in bitfield description string %s\n",sprnames[index].Namefield);
+						printf(" wrong bit position %d at %s\n",bit,pFormat);
+						return;
+					}
+					do
+					{
+						pFormat++;
+					} while (isdigit(*pFormat));
+				}
+				else bit = startbit + 1;
+			}
+			strncpy(FieldName,pFieldName,len);
+			FieldName[len]= 0;
+
+			bitmask = PPC_BIT(startbit);
+			bitfieldval = 0;
+			for (i = startbit; i<bit;i++)
+			{
+				bitfieldval = (bitfieldval << 1);
+				if (val & bitmask) bitfieldval |=1;
+				bitmask = bitmask >> 1;
+			}
+			if (len != 0) /*name, no spare bit field?*/
+			{
+				if (bit-startbit >1) /*multi bitfield*/
+				{
+					if (!bFirstPrinted)
+					{
+						bFirstPrinted = 1;
+						printf(" = (");
+					}
+					else printf("|");
+					printf("%s=0x%x",FieldName,bitfieldval);
+				}
+				else if (bitfieldval) /*single bit*/
+				{
+					if (!bFirstPrinted)
+					{
+						bFirstPrinted = 1;
+						printf(" = (");
+					}
+					else printf("|");
+					printf("%s",FieldName);
+				}
+			}
+			if (bit >= PPC_BITS)
+			{
+				break;
+			}
+			startbit = bit;
+		}
+		if (bFirstPrinted) printf(")");
+	}
+}
+
+
+static void mpcbdm_spr_command (char *args, int from_tty)
+{
+	int reg;
+	u_int val;
+	char *name;
+	char *svalue = 0;
+	char *pch;
+	int i;
+	int num;
+
+	if (!args)
+	{
+		printf_filtered("List of supported SPRs:\n");
+		for(i = 0; sprnames[i].name ; ++i)
+		{
+			printf_filtered("%s",sprnames[i].name);
+			num = sprnames[i].num;
+			if (num & SPRI_MASK)
+				printf_filtered("\tIMMR + 0x%x",num & ~SPRI_MASK);
+			else if (num & SPR_MASK)
+				printf_filtered("\t");
+			else
+				printf_filtered("\tSPR %d ",num);
+			if (sprnames[i].Longname)
+			{
+				printf_filtered("\t%s", sprnames[i].Longname);
+			}
+			printf_filtered("\n");
+		}
+		return;
+	}
+
+	if (mpcbdm_reattach)
+	{
+		printf_filtered("!C\n");
+		return;
+	}
+
+	if (pch = strchr(args,'=')) /*set command ?*/
+	{
+		svalue = pch+1;
+		while(*svalue <= 040) ++svalue; /*read spaces*/
+		*pch-- = 0;
+		while(*pch <= 040) *pch-- = 0;
+	}
+	if (isdigit(*args)) /*spr by number?*/
+	{
+		reg = strtol(args,0,0);
+	}
+	else	/*by name?*/
+	{
+		reg = findsprnum(args);
+	}
+
+	if (reg < 0)
+	{
+		printf_filtered("Invalid SPR\n");
+		return;
+	}
+
+	if (svalue) /*set command?*/
+	{
+		val = strtoul(svalue,0,0);
+		bdm_setspr(reg,val); /*set value*/
+	}
+	else /* show register */
+	{
+		if (reg == SPR_ICR)	/* reading ICR clears bits, so show old values */
+		{
+			val = LastICR;
+		}
+		else val = bdm_getspr(reg);
+
+		print_spr_info(reg,val,1,1,1,1); /* show register name, def, val and pretty */
+		printf_filtered("\n");
+	}
+}
+
+
+/***********************************************************
+* routines from ppc-bdm.c                                  *
+***********************************************************/
+
+/* Wait until the remote machine stops, then return,
+   storing status in STATUS just as `wait' would.
+   Returns "pid" (though it's not clear what, if anything, that
+   means in the case of this target).  */
+
+static ptid_t bdm_ppc_wait (ptid_t pid_t, struct target_waitstatus *target_status)
+{
+	int pid = pid_t.pid;
+	int stop_reason;
+
+	if (mpcbdm_verbose&VERBOSE_SER)
+	{
+		printf("bdm_ppc_wait:\n");
+	}
+	target_status->kind = TARGET_WAITKIND_STOPPED;
+
+	stop_reason = ppc_bdm_wait();
+
+	if (stop_reason)
+	{
+		target_status->value.sig = TARGET_SIGNAL_INT;
+		return inferior_ptid;
+	}
+
+	target_status->value.sig = TARGET_SIGNAL_TRAP; /* XXX for now */
+	return inferior_ptid;
+}
+
+/* Read the remote registers into regs.
+   Fetch register REGNO, or all registers if REGNO == -1
+
+ */
+
+static void bdm_ppc_fetch_registers (int regno)
+{
+	int i;
+	int first;
+	int last;
+	int val;
+
+	if (mpcbdm_verbose&VERBOSE_SER)
+	{
+		printf("bdm_ppc_fetch_registers: regno %d",regno);
+	}
+	if(regno == -1)
+	{
+		first = 0;
+		last = NUM_REGS-1;
+	}
+	else
+	{
+		first = last = regno;
+	}
+
+	for (i = first; i <= last; i++)
+	{
+		if(i == MQ_REGNUM || (i >= FP0_REGNUM && i <= FPLAST_REGNUM))
+		{
+			supply_register(i, 0);
+			continue;
+		}
+		val = ppc_read_bdm_register(bdm_regmap[i]);
+		supply_register(i, (char*)&val);
+	}
+}
+
+/* Store register REGNO, or all registers if REGNO == -1, from the contents
+   of REGISTERS.  FIXME: ignores errors.  */
+
+static void bdm_ppc_store_registers (int regno)
+{
+	int i;
+	int first;
+	int last;
+	int val;
+
+	if (mpcbdm_verbose&VERBOSE_TAR)
+	{
+		printf("bdm_ppc_store_registers: regno %d",regno);
+	}
+	if(regno == -1)
+	{
+		first = 0;
+		last = NUM_REGS-1;
+	}
+	else
+	{
+		first = last = regno;
+	}
+
+	for (i = first; i <= last; i++)
+	{
+		if(i == MQ_REGNUM || (i >= FP0_REGNUM && i <= FPLAST_REGNUM))
+			continue;
+		memcpy (&val , &registers[REGISTER_BYTE (i)], REGISTER_RAW_SIZE (i));
+		ppc_write_bdm_register(bdm_regmap[i], val);
+	}
+}
+
+/* Define the target subroutine names */
+static void init_mpcbdm_ops(void)
+{
+	mpcbdm_ops.to_shortname 		  = "mpcbdm";
+	mpcbdm_ops.to_longname  		  = "Background Debug Mode Interface for Motorola MPC-Family";
+	mpcbdm_ops.to_doc				  = "Use On-Chip Debugging on MPC's via parallel port BDM interface" ;    /* to_doc */
+	mpcbdm_ops.to_open  			  = mpcbdm_open;
+	mpcbdm_ops.to_close 			  = mpcbdm_close;
+	mpcbdm_ops.to_attach			  = NULL;
+	mpcbdm_ops.to_post_attach		  = NULL;
+	mpcbdm_ops.to_require_attach	  = NULL;
+	mpcbdm_ops.to_detach			  = mpcbdm_detach;
+	mpcbdm_ops.to_require_detach	  = NULL;
+	mpcbdm_ops.to_resume			  = mpcbdm_resume;
+	mpcbdm_ops.to_wait  			  = bdm_ppc_wait;
+	mpcbdm_ops.to_post_wait 		  = NULL;
+	mpcbdm_ops.to_fetch_registers	  = bdm_ppc_fetch_registers;
+	mpcbdm_ops.to_store_registers	  = bdm_ppc_store_registers;
+	mpcbdm_ops.to_prepare_to_store    = mpcbdm_prepare_to_store;
+	mpcbdm_ops.to_xfer_memory		  = mpcbdm_xfer_memory;
+	mpcbdm_ops.to_files_info		  = mpcbdm_files_info;
+	mpcbdm_ops.to_insert_breakpoint   = mpcbdm_insert_breakpoint;
+	mpcbdm_ops.to_remove_breakpoint   = mpcbdm_remove_breakpoint;
+	mpcbdm_ops.to_terminal_init 	  = NULL;
+	mpcbdm_ops.to_terminal_inferior   = NULL;
+	mpcbdm_ops.to_terminal_ours_for_output = NULL;
+	mpcbdm_ops.to_terminal_ours 	  = NULL;
+	mpcbdm_ops.to_terminal_info 	  = NULL;
+	mpcbdm_ops.to_kill  			  = mpcbdm_kill;
+	mpcbdm_ops.to_load  			  = mpcbdm_load;
+	mpcbdm_ops.to_lookup_symbol 	  = NULL;
+	mpcbdm_ops.to_create_inferior	  = mpcbdm_create_inferior;
+	mpcbdm_ops.to_post_startup_inferior = NULL;
+	mpcbdm_ops.to_acknowledge_created_inferior = NULL;
+	mpcbdm_ops.to_clone_and_follow_inferior = NULL;
+	mpcbdm_ops.to_post_follow_inferior_by_clone = NULL;
+	mpcbdm_ops.to_insert_fork_catchpoint = NULL;
+	mpcbdm_ops.to_remove_fork_catchpoint = NULL;
+	mpcbdm_ops.to_insert_vfork_catchpoint = NULL;
+	mpcbdm_ops.to_remove_vfork_catchpoint = NULL;
+	mpcbdm_ops.to_has_forked		  = NULL;
+	mpcbdm_ops.to_has_vforked		  = NULL;
+	mpcbdm_ops.to_can_follow_vfork_prior_to_exec = NULL;
+	mpcbdm_ops.to_post_follow_vfork   = NULL;
+	mpcbdm_ops.to_insert_exec_catchpoint = NULL;
+	mpcbdm_ops.to_remove_exec_catchpoint = NULL;
+	mpcbdm_ops.to_has_execd 		  = NULL;
+	mpcbdm_ops.to_reported_exec_events_per_exec_call = NULL;
+	mpcbdm_ops.to_has_exited		  = NULL;
+	mpcbdm_ops.to_mourn_inferior	  = mpcbdm_mourn;
+	mpcbdm_ops.to_can_run			  = 0;
+	mpcbdm_ops.to_notice_signals	  = 0;
+	mpcbdm_ops.to_thread_alive  	  = mpcbdm_thread_alive;
+	mpcbdm_ops.to_stop  			  = ppc_bdm_stop;
+	mpcbdm_ops.to_pid_to_exec_file    = NULL;
+	mpcbdm_ops.to_stratum			  = process_stratum;
+	mpcbdm_ops.DONT_USE 			  = NULL;
+	mpcbdm_ops.to_has_all_memory	  = 1;
+	mpcbdm_ops.to_has_memory		  = 1;
+	mpcbdm_ops.to_has_stack 		  = 1;
+	mpcbdm_ops.to_has_registers 	  = 1;
+	mpcbdm_ops.to_has_execution 	  = 1;
+	mpcbdm_ops.to_sections  		  = NULL;
+	mpcbdm_ops.to_sections_end  	  = NULL;
+	mpcbdm_ops.to_magic 			  = OPS_MAGIC;
+} /* init_mpcbdm_ops */
+
+/***********************************************************
+* mpcbdm obscure routines                                  *
+***********************************************************/
+
+static void mpcbdm_obscure_upms(char *args, int from_tty)
+{
+	int n;
+
+	printf("============\n");
+	for(n = 0; n < 64; ++n)
+	{
+		bdm_setspr(SPRI_MCR, (01 << 30) | n);
+		printf("MDR%02d=0x%08x   ", n, bdm_getspr(SPRI_MDR));
+		if(!((n+1) % 4)) printf("\n");
+	}
+	printf("============\n");
+
+	printf("BR0=0x%08x\n", bdm_getspr(SPRI_BRx(0)));
+	printf("OR0=0x%08x\n", bdm_getspr(SPRI_ORx(0)));
+	printf("BR1=0x%08x\n", bdm_getspr(SPRI_BRx(1)));
+	printf("OR1=0x%08x\n", bdm_getspr(SPRI_ORx(1)));
+	printf("BR2=0x%08x\n", bdm_getspr(SPRI_BRx(2)));
+	printf("OR2=0x%08x\n", bdm_getspr(SPRI_ORx(2)));
+
+	printf("MAMR=0x%08x\n", bdm_getspr(SPRI_MAMR));
+	printf("MAR=0x%08x\n", bdm_getspr(SPRI_MAR));
+	printf("MDR=0x%08x\n", bdm_getspr(SPRI_MDR));
+	printf("MCR=0x%08x\n", bdm_getspr(SPRI_MCR));
+	printf("MSTAT=0x%08x\n", bdm_getspr(SPRI_MSTAT));
+}
+
+static void show_spr(char *args, int from_tty)
+{
+	int i;
+	u_int val;
+
+	int RegList[] =
+	{
+		SPR_SRR0,
+		SPR_SRR1,
+		SPR_MSR,
+		SPR_BAR,
+		SPR_DAR,
+		SPR_DSISR,
+		SPR_DER,
+		SPR_ICR,
+		SPR_ICTRL,
+		SPRI_PLPRCR,
+		SPRI_RSR,
+		SPRI_SCCR,
+		SPRI_SYPCR,
+		SPRI_SIUMCR,
+		0
+	};
+
+	for (i = 0; RegList[i]; i++)
+	{
+		val = bdm_getspr(RegList[i]);
+		print_spr_info(RegList[i], val,1,0,0,0); /* show name*/
+		printf_filtered("\t");
+		print_spr_info(RegList[i], val,0,0,1,1); /* val and pretty */
+		printf_filtered("\n");
+	}
+}
+
+/*****************************************************************
+* memory dump routines                                           *
+*****************************************************************/
+static char * parse_filename(char** sArgs)
+{
+	char *fq;
+	char *lq;
+
+	if (!sArgs) return NULL;
+	if (!(*sArgs)) return NULL;
+
+	fq = strchr(*sArgs,'\"'); /* get first double quote */
+	if (!fq) return NULL;
+
+	lq = strrchr(*sArgs,'\"'); /* get last double quote */
+	if ((!lq) || (lq <= fq)) return NULL;
+
+	(*lq) = 0; /* set end of filename string FIXME: better copy name, instead of messing arround?*/
+
+	(*sArgs) = lq + 1; /* adjust argument pointer */
+
+	return fq + 1; /*return pointer to beginning of filename*/
+}
+
+/*****************************************************************/
+static void mem_load(char * sFilename, u_int start, u_int len)
+{
+	FILE * f;
+	u_int	nTotal;
+	u_int	nBuffer;
+	u_int	nLeft;
+	int nResult;
+
+	printf_filtered("mem load \"%s\" to 0x%08x len %d\n", sFilename, start, len);
+
+	if (!sFilename)
+	{
+		error("parameter syntax error.");
+		return;
+	}
+
+	f = fopen(sFilename, "rb");
+
+	if(!f)
+	{
+		error("failed to open input file.");
+		return;
+	}
+
+	if (!len)
+	{
+		nResult = fseek(f, 0, SEEK_END);
+		if (nResult)
+		{
+			error("fseek error.");
+			if (f) fclose(f);
+			return;
+		}
+		len = ftell(f);
+		printf_filtered(" len = 0x%08x, total file length\n", len);
+		rewind(f);
+	}
+
+	for (nTotal = 0, nLeft = len; nLeft > 0; nTotal += nBuffer, nLeft -= nBuffer)
+	{
+		if(nLeft > MAXBUFFERLEN)
+		{
+			nBuffer = MAXBUFFERLEN;
+		}
+		else
+		{
+			nBuffer = nLeft;
+		}
+		nResult = fread(FileBuffer, 1, nBuffer, f);
+		if (nResult != nBuffer)
+		{
+			error("read error.");
+			break;
+		}
+
+		ppc_bdm_write_block(start + nTotal, FileBuffer, nBuffer);
+
+	}
+	if (f) fclose(f);
+}
+
+/*****************************************************************/
+
+static void mem_save(char * sFilename, u_int start, u_int len)
+{
+	FILE * f;
+	u_int	nTotal;
+	u_int	nBuffer;
+	u_int	nLeft;
+	int nResult;
+
+	printf_filtered("mem save \"%s\" from 0x%08x len %d\n", sFilename, start, len);
+
+	if ((!sFilename) || (!len))
+	{
+		error("parameter syntax error.");
+		return;
+	}
+
+	f = fopen(sFilename, "wb");
+
+	if(!f)
+	{
+		error("failed to open output file.");
+		return;
+	}
+
+	for (nTotal = 0, nLeft = len; nLeft > 0; nTotal += nBuffer, nLeft -= nBuffer)
+	{
+		if(nLeft > MAXBUFFERLEN)
+		{
+			nBuffer = MAXBUFFERLEN;
+		}
+		else
+		{
+			nBuffer = nLeft;
+		}
+		ppc_bdm_read_block(start + nTotal, FileBuffer, nBuffer);
+
+		nResult = fwrite(FileBuffer, 1, nBuffer, f);
+
+		if (nResult != nBuffer)
+		{
+			error("write error.");
+			break;
+		}
+	}
+	if (f) fclose(f);
+}
+
+/*****************************************************************/
+static void mpcbdm_mem(char *args, int from_tty)
+{
+	u_int MemStart,MemEnd,MemLen; /* memory range */
+	char *sParse;
+	char *sFilename;
+
+	if (args != 0) /* arguments ?*/
+	{
+		sParse = args;
+		if (strncmp(sParse,"load ",5) == 0)
+		{
+			sParse +=5;
+
+			sFilename = parse_filename(&sParse);
+			if (!sFilename)
+			{
+				printf_filtered("error while parsing filename\n");
+				return;
+			}
+
+			MemStart = strtoul(sParse,&sParse,0); /*for testing destination ADDR*/
+			MemLen = strtoul(sParse,&sParse,0);  /*for testing len */
+
+			mem_load(sFilename, MemStart, MemLen);
+			return;
+		}
+		else if (strncmp(sParse,"save ",5) == 0)
+		{
+			sParse +=5;
+
+			sFilename = parse_filename(&sParse);
+			if (!sFilename)
+			{
+				printf_filtered("error while parsing filename\n");
+				return;
+			}
+
+			MemStart = strtoul(sParse,&sParse,0); /*for testing destination ADDR*/
+			MemLen = strtoul(sParse,&sParse,0);  /*for testing len */
+
+			mem_save(sFilename, MemStart, MemLen);
+			return;
+		}
+	}
+
+	printf_filtered("try 'help mpcbdm mem' for a list of supported commands\n");
+}
+
+/*****************************************************************
+* Cache routines                                                 *
+/*****************************************************************/
+static void mpcbdm_icache(char *args, int from_tty)
+{
+	u_int CacheAdr; /* IC_ADR value for reading cache content */
+	u_int CacheDat; /* IC_DAT value for reading cache content */
+	u_int OldICacheAdr; /* IC_ADR value for restoring */
+	u_int IC_CST; /* IC_CST value*/
+	u_int adr; /* cached adr */
+	u_int LRU; /* Last Recently Used Code: 1 bit for 860, 6 bit for 860P/DP instruction cache */
+
+	int set;
+	int way;
+
+	if (args == 0) /* no arguments ?*/
+	{
+		IC_CST = bdm_getspr(SPR_IC_CST);
+		printf_filtered("icache:");
+		if (IC_CST & MPC_IC_CST_IEN)
+		{
+			printf_filtered(" enabled");
+		}
+		else
+		{
+			printf_filtered(" disabled");
+		}
+		printf_filtered("\n");
+		OldICacheAdr = bdm_getspr(SPR_IC_ADR);
+		for (set=0; set < MPC_ICACHE_SETS; set++)
+		{
+			printf_filtered("set0x%02x: ",set);
+			for (way=0; way < MPC_ICACHE_WAYS; way++)
+			{
+/* read tags */
+				CacheAdr = (way<<(31-19)) | (set << (31-27));
+				bdm_setspr(SPR_IC_ADR, CacheAdr);
+				CacheDat = bdm_getspr(SPR_IC_DAT);
+				adr = (CacheDat & MPC_IC_DAT_TAG) | (set << (31-27));
+
+				if (way == 0) /* first output ?*/
+				{
+					LRU = (CacheDat & MPC_IC_DAT_LRU) >> MPC_IC_DAT_LRU_SHIFT;
+					printf_filtered("LRU=0x%1x ",LRU);
+				}
+				else /* not first way, print separator */
+				{
+					printf_filtered(", ");
+				}
+
+				printf_filtered("way%1x:0x%08x..%1x",way,adr,MPC_ICACHE_SIZE-1);
+				if (CacheDat & MPC_IC_DAT_VALID)
+					printf_filtered(" val");
+				else
+					printf_filtered("    ");
+				if (CacheDat & MPC_IC_DAT_LOCKED)
+					printf_filtered(" lck");
+				else
+					printf_filtered("    ");
+			}
+			printf_filtered("\n");
+		}
+		bdm_setspr(SPR_IC_ADR,OldICacheAdr);
+	}
+	else
+	{
+		printf_filtered("no args supported for 'mpcbdm icache'\n");
+	}
+}
+
+/*****************************************************************/
+static void mpcbdm_dcache_flush(u_int Adr, int bAll)
+{
+	u_int CacheAdr; /* DC_ADR value for reading cache content */
+	u_int CacheDat; /* DC_DAT value for reading cache content */
+	u_int OldDCacheAdr; /* DC_ADR value for restoring */
+	u_int DC_CST; /* DC_CST value*/
+	u_int adr; /* cached adr */
+	u_int pAddr; /* cached physical address */
+	u_int ValMod; /* helper variable for valid modified entry test */
+
+	int set;
+	int way;
+
+	if (bAll)
+	{
+/* if verbose on data cache ops, be informative, */
+/* but allow flushing in all cases, even if unnecessary */
+		if (mpcbdm_verbose&VERBOSE_DCA)
+		{
+			DC_CST = bdm_getspr(SPR_DC_CST);
+
+			if (!(DC_CST & MPC_DC_CST_DEN)) /* data cache enabled? */
+			{
+				printf_filtered("mpcbdm_dcache_flush: data cache not enabled\n");
+			}
+			if (DC_CST & MPC_DC_CST_DFWT) /* data cache forced write through enable? */
+			{
+				printf_filtered("mpcbdm_dcache_flush: data cache DFWT enabled\n");
+			}
+		}
+		set = 0;
+	}
+	else /* specific address */
+	{
+		if ((LastMSR & MSR_DR)&&(mpcbdm_mmu)) /* data mmu on and option activated*/
+		{
+			Adr = ppc_bdm_tablewalk(Adr);
+		}
+		set = ((Adr & MPC_DCACHE_SETMASK) >> MPC_DCACHE_SETSHIFT);
+	}
+
+	OldDCacheAdr = bdm_getspr(SPR_DC_ADR); /* save DC_ADR */
+
+	for (; set < MPC_DCACHE_SETS; set++)
+	{
+		for (way=0; way < MPC_DCACHE_WAYS; way++)
+		{
+/* address format for reading cache flags AND for flushing blocks */
+/* flushing blocks need this format, not physical address as stated in 860UM.pdf */
+			CacheAdr = ((way<<(31-19)) | (set << (31-27)));
+			bdm_setspr(SPR_DC_ADR, CacheAdr);
+			CacheDat = bdm_getspr(SPR_DC_DAT);
+			pAddr = ((CacheDat & MPC_DC_DAT_TAG) | (set << (31-27)));
+/* If flushing all command */
+/* only flush modified valid (the necessary) cache lines  for speed up. */
+			ValMod = (CacheDat & (MPC_DC_DAT_VALID | MPC_DC_DAT_MOD));
+			if (((bAll) && (ValMod == (MPC_DC_DAT_VALID | MPC_DC_DAT_MOD)))
+				 || ((!bAll) && (pAddr == (Adr & (~(MPC_DCACHE_SIZE-1))))))
+			{
+/* replaced call to low level data cache flush block stuff, for speed up */
+				if (CacheDat & MPC_DC_DAT_LOCKED)
+				{
+					if (mpcbdm_verbose&VERBOSE_DCA)
+					{
+						printf_filtered("mpcbdm_dcache_flush: unlocking set 0x%02x way 0x%1x for physical adr 0x%08x\n",set,way,pAddr);
+					}
+					bdm_setspr(SPR_DC_ADR, pAddr); /* set physical address of cached line */
+					bdm_setspr(SPR_DC_CST, MPC_DC_CST_UNLOCK); /* unlock block */
+				}
+				if (mpcbdm_verbose&VERBOSE_DCA)
+				{
+					printf_filtered("mpcbdm_dcache_flush: flushing set 0x%02x way 0x%1x for physical adr 0x%08x\n",set,way,pAddr);
+				}
+/* FIXME: this took me half an day: ADR has to be in DC_DAT reading format for CMD=FLUSH?*/
+/*        and not given as physical address as stated in the manuals!!!*/
+				bdm_setspr(SPR_DC_ADR, CacheAdr); /* set address of cache block */
+				bdm_setspr(SPR_DC_CST, MPC_DC_CST_FLUSH); /* flush block to get modified cache content into memory */
+				if (CacheDat & MPC_DC_DAT_LOCKED)
+				{
+					if (mpcbdm_verbose&VERBOSE_DCA)
+					{
+						printf_filtered("mpcbdm_dcache_flush: relocking set 0x%02x way 0x%1x for physical adr 0x%08x\n",set,way,pAddr);
+					}
+					bdm_setspr(SPR_DC_ADR, pAddr); /* set physical address of cached line */
+					bdm_setspr(SPR_DC_CST, MPC_DC_CST_LOCK); /* load and lock block again for restauration */
+				}
+				if (!bAll)
+					break; /* only one way entry can be valid, so leave way loop*/
+			}
+		}
+		if (!bAll)
+			break; /* finish set loop, if only flushing one entry */
+	}
+	bdm_setspr(SPR_DC_ADR,OldDCacheAdr); /* restore DC_ADR */
+}
+
+/*****************************************************************/
+static void mpcbdm_dcache_info(u_int Adr, int bAll)
+{
+	u_int CacheAdr; /* DC_ADR value for reading cache content */
+	u_int CacheDat; /* DC_DAT value for reading cache content */
+	u_int OldDCacheAdr; /* DC_ADR value for restoring */
+	u_int DC_CST; /* DC_CST value*/
+	u_int adr; /* cached adr */
+	u_int LRU; /* Last Recently Used Code: 1 bit for 860 data cache*/
+
+	int set;
+	int way;
+
+	OldDCacheAdr = bdm_getspr(SPR_DC_ADR); /* for restauration */
+
+	if (bAll) /* total dcache info */
+	{
+		DC_CST = bdm_getspr(SPR_DC_CST);
+		printf_filtered("dcache: ");
+		if (DC_CST & MPC_DC_CST_DEN)
+		{
+			printf_filtered(" enabled");
+		}
+		else
+		{
+			printf_filtered("disabled");
+		}
+		if (DC_CST & MPC_DC_CST_DFWT)
+		{
+			printf_filtered(", DFWT");
+		}
+		if (DC_CST & MPC_DC_CST_LES)
+		{
+			printf_filtered(", LES");
+		}
+		if (DC_CST & MPC_DC_CST_CCER1)
+		{
+			printf_filtered(", CCER1");
+		}
+		if (DC_CST & MPC_DC_CST_CCER2)
+		{
+			printf_filtered(", CCER2");
+		}
+		if (DC_CST & MPC_DC_CST_CCER3)
+		{
+			printf_filtered(", CCER3");
+		}
+		printf_filtered(", data MMU: MSR[DR]");
+		if (LastMSR & MSR_DR) /* data mmu on*/
+			printf_filtered(" enabled");
+		else
+		{
+			printf_filtered(" disabled");
+		}
+		printf_filtered("\n");
+
+		CacheAdr = (1<<(31-18)) | (4 << (31-27)); /* read last copy back address */
+		bdm_setspr(SPR_DC_ADR, CacheAdr);
+		CacheDat = bdm_getspr(SPR_DC_DAT);
+		printf_filtered("last copyback adr=0x%08x:",CacheDat);
+
+		for (set=0; set < MPC_DCACHE_SIZE/4; set++)
+		{
+			CacheAdr = (1<<(31-18)) | (set << (31-27)); /* read last copy back buffer */
+			bdm_setspr(SPR_DC_ADR, CacheAdr);
+			CacheDat = bdm_getspr(SPR_DC_DAT);
+			printf_filtered(" 0x%08x",CacheDat);
+		}
+		printf_filtered("\n");
+
+		set = 0;
+	}
+	else /* specific address */
+	{
+		if ((LastMSR & MSR_DR)&&(mpcbdm_mmu)) /*mmu on and option activated*/
+		{
+			Adr = ppc_bdm_tablewalk(Adr);
+		}
+		Adr = (Adr & (~(MPC_DCACHE_SIZE-1))); /* align to cache block start */
+		set = (Adr & MPC_DCACHE_SETMASK) >> MPC_DCACHE_SETSHIFT;
+	}
+
+
+	for (; set < MPC_DCACHE_SETS; set++)
+	{
+		for (way=0; way < MPC_DCACHE_WAYS; way++)
+		{
+/* read tags */
+			CacheAdr = (way<<(31-19)) | (set << (31-27));
+			bdm_setspr(SPR_DC_ADR, CacheAdr);
+			CacheDat = bdm_getspr(SPR_DC_DAT);
+			adr = (CacheDat & MPC_DC_DAT_TAG) | (set << (31-27));
+
+			if ((!bAll) && (adr != (Adr & (~(MPC_DCACHE_SIZE-1)))))
+				continue; /* skip not matching entry */
+
+			if ((!bAll) || (way == 0)) /* show LRU code only once */
+			{
+				LRU = (CacheDat & MPC_DC_DAT_LRU) >> MPC_DC_DAT_LRU_SHIFT;
+				printf_filtered("set0x%02x: LRU=0x%1x ",set,LRU);
+			}
+
+			if (bAll)
+			{
+				if (way) /* need separator ?*/
+					printf_filtered(", ");
+				printf_filtered("way%1x:0x%08x..%1x",way,adr,MPC_DCACHE_SIZE-1);
+			}
+			else /* show only specified way */
+			{
+				printf_filtered("way%1x:0x%08x..%1x",way,Adr,MPC_DCACHE_SIZE-1);
+			}
+			if (CacheDat & MPC_DC_DAT_VALID)
+			{
+				printf_filtered(" val");
+			}
+			else
+			{
+				printf_filtered("    ");
+			}
+			if (CacheDat & MPC_DC_DAT_LOCKED)
+			{
+				printf_filtered(" lck");
+			}
+			else
+			{
+				printf_filtered("    ");
+			}
+			if (CacheDat & MPC_DC_DAT_MOD)
+			{
+				printf_filtered(" mod");
+			}
+			else
+			{
+				printf_filtered("    ");
+			}
+
+			if (!bAll)
+			{
+				printf_filtered("\n");
+				break;
+			}
+		}
+		if (!bAll) break;
+		printf_filtered("\n");
+	}
+	bdm_setspr(SPR_DC_ADR,OldDCacheAdr);
+}
+
+/*****************************************************************/
+static void mpcbdm_dcache(char *args, int from_tty)
+{
+	u_int adr; /* cached adr */
+
+	int bAll;
+
+	char * OsParse;
+	char * sParse;
+
+	sParse = args;
+	if (sParse == 0) /* no arguments ?*/
+	{
+		mpcbdm_dcache_info(0,1); /* display all data cache contents */
+	}
+	else if (strncmp(sParse,"flush",5) == 0)
+	{
+		sParse +=5;
+		adr = strtoul(sParse,&OsParse,0);
+		if (sParse != OsParse) /* digits found? */
+		{
+			bAll = 0;
+		}
+		else
+		{
+			bAll = 1;
+		}
+		mpcbdm_dcache_flush(adr,bAll);
+	}
+	else
+	{
+		adr = strtoul(sParse,&OsParse,0);
+		if (sParse != OsParse) /* digits found? */
+		{
+			mpcbdm_dcache_info(adr,0); /* display only specific data cache entry */
+		}
+		else
+		{
+			printf_filtered("try 'help mpcbdm dcache' for a list of supported commands\n");
+		}
+	}
+}
+
+/*****************************************************************
+* MMU routines                                                   *
+*****************************************************************/
+static void mpcbdm_cmd_mmu(char *args, int from_tty)
+{
+	u_int vAddr;
+	u_int pAddr;
+
+	u_int Mx_CTR;
+
+	char * OsParse;
+	char * sParse;
+
+	int i;
+
+	sParse = args;
+	if (sParse == 0) /* no arguments ?*/
+	{
+		printf_filtered("IMMU:");
+		if (LastMSR & MSR_IR) /* instruction mmu activated? */
+		{
+			printf_filtered(" enabled");
+		}
+		else
+		{
+			printf_filtered(" disabled");
+		}
+
+		printf_filtered(", DMMU:");
+		if (LastMSR & MSR_DR) /* data mmu activated? */
+		{
+			printf_filtered(" enabled");
+		}
+		else
+		{
+			printf_filtered(" disabled");
+		}
+
+		printf_filtered(", mpcbdm_mmu tablewalk:");
+		if (mpcbdm_mmu) /*mmu option activated*/
+		{
+			printf_filtered(" enabled");
+		}
+		else
+		{
+			printf_filtered(" disabled");
+		}
+		printf_filtered("\n");
+	}
+	else if (strncmp(sParse,"on",2) == 0)
+	{
+		mpcbdm_mmu = 1;
+	}
+	else if (strncmp(sParse,"off",3) == 0)
+	{
+		mpcbdm_mmu = 0;
+	}
+	else if (strncmp(sParse,"inst",4) == 0)
+	{
+		Mx_CTR = bdm_getspr(SPR_MI_CTR);
+		print_spr_info(SPR_MI_CTR, Mx_CTR,1,0,0,1);
+		printf_filtered("\n");
+		for (i = 0; i < MPC_IMMU_ENTRIES; i++)
+		{
+			bdm_setspr(SPR_MI_CTR, ((Mx_CTR & MPC_MI_CTR_MASK) | (i << MPC_MI_CTR_SHIFT)) );
+			bdm_setspr(SPR_MI_CAM, 0); /* perform mtspr CAM for CAM,RAM0,RAM1 update */
+			printf_filtered("IMMU%2d:",i);
+			print_spr_info(SPR_MI_CAM,bdm_getspr(SPR_MI_CAM),1,0,0,1);
+			printf_filtered("\n       ");
+			print_spr_info(SPR_MI_RAM0,bdm_getspr(SPR_MI_RAM0),1,0,0,1);
+			printf_filtered("\n       ");
+			print_spr_info(SPR_MI_RAM1,bdm_getspr(SPR_MI_RAM1),1,0,0,1);
+			printf_filtered("\n");
+		}
+		bdm_setspr(SPR_MI_CTR,Mx_CTR); /* restore */
+	}
+	else if (strncmp(sParse,"data",4) == 0)
+	{
+		Mx_CTR = bdm_getspr(SPR_MD_CTR);
+		print_spr_info(SPR_MD_CTR, Mx_CTR,1,0,0,1);
+		printf_filtered("\n");
+		for (i = 0; i < MPC_DMMU_ENTRIES; i++)
+		{
+			bdm_setspr(SPR_MD_CTR, ((Mx_CTR & MPC_MD_CTR_MASK) | (i << MPC_MD_CTR_SHIFT)) );
+			bdm_setspr(SPR_MD_CAM, 0); /* perform mtspr CAM for CAM,RAM0,RAM1 update */
+			printf_filtered("DMMU%2d:",i);
+			print_spr_info(SPR_MD_CAM,bdm_getspr(SPR_MD_CAM),1,0,0,1);
+			printf_filtered("\n       ");
+			print_spr_info(SPR_MD_RAM0,bdm_getspr(SPR_MD_RAM0),1,0,0,1);
+			printf_filtered("\n       ");
+			print_spr_info(SPR_MD_RAM1,bdm_getspr(SPR_MD_RAM1),1,0,0,1);
+			printf_filtered("\n");
+		}
+		bdm_setspr(SPR_MD_CTR,Mx_CTR); /* restore */
+	}
+	else if (strncmp(sParse,"kbase",5) == 0)
+	{
+		sParse +=5;
+		vAddr = strtoul(sParse,&OsParse,0);
+		if (sParse != OsParse) /* digits found? */
+		{
+			mpcbdm_kbase = vAddr;
+		}
+		else
+		{
+			printf_filtered("mmu kbase = 0x%08x\n",mpcbdm_kbase);
+		}
+	}
+	else if (strncmp(sParse,"pgdir",5) == 0)
+	{
+		sParse +=5;
+		vAddr = strtoul(sParse,&OsParse,0);
+		if (sParse != OsParse) /* digits found? */
+		{
+			mpcbdm_pgdir = vAddr;
+		}
+		else
+		{
+			printf_filtered("mmu pgdir = 0x%08x\n",mpcbdm_pgdir);
+		}
+	}
+	else
+	{
+		vAddr = strtoul(sParse,&OsParse,0);
+		if (sParse != OsParse) /* digits found? */
+		{
+			if (LastMSR & MSR_IR) /* instruction mmu activated? */
+			{
+				pAddr = ppc_bdm_tablewalk(vAddr); /* FIXME: necessary to check if enabled?*/
+				printf_filtered("MMU translates virtual 0x%08x to physical 0x%08x\n",vAddr,pAddr);
+			}
+			else
+			{
+				printf_filtered("MMU disabled virtual = physical 0x%08x\n",vAddr);
+			}
+		}
+		else
+		{
+			printf_filtered("try 'help mpcbdm mmu' for a list of supported commands\n");
+		}
+	}
+}
+/*****************************************************************
+* remote target execution helpers                                *
+*****************************************************************/
+unsigned int remote_restore(void)
+{
+	unsigned int temp;
+	int i;
+
+	for (i = 0; i < 32; i++)
+	{
+		if (pramlen != 0)
+			temp = bdm_getreg(i); /* save registers */
+		bdm_setreg(i, RegBuffer[i]); /* restore GPR0..31 */
+		if (pramlen != 0)
+			RegBuffer[i] = temp; /* store into register buffers for return values */
+	}
+
+	if (pramlen != 0)
+	{
+/* restore original control registers content, if any program loaded before */
+		temp = bdm_getspr(SPR_CTR); /*save CTR*/
+		bdm_setspr(SPR_CTR, RegBuffer[i]); /*restore CTR*/
+		RegBuffer[i++] = temp;
+		temp = bdm_getspr(SPR_SRR0); /*save srr0*/
+		bdm_setspr(SPR_SRR0, RegBuffer[i++]); /*restore srr0*/
+		RegBuffer[i++] = temp;
+		temp = bdm_getspr(SPR_SRR1); /*save srr1*/
+		bdm_setspr(SPR_SRR1, RegBuffer[i++]); /*restore srr1*/
+		RegBuffer[i++] = temp;
+		temp = bdm_getspr(SPR_DER); /*save DER*/
+		bdm_setspr(SPR_DER, RegBuffer[i++]); /*restore DER*/
+		RegBuffer[i++] = temp;
+
+/* restore original memory content, if any program loaded before */
+		for (i = 0; i< pramlen; i++)
+		{
+			ppc_bdm_setword(mpcbdm_pram+i*4,membuf[i]);
+		}
+		pramlen = 0; /* program removed from target */
+
+	}
+
+	return RegBuffer[0]; /* default return value is r0 */
+}
+
+/*****************************************************************/
+unsigned int remote_execute(void)
+{
+	if (pramlen == 0)
+	{
+		printf_filtered("remote_execute: pramlen == 0, no program loaded\n");
+		return 0;
+	}
+	ppc_bdm_resume(); /* start remote target NIP = preloaded SRR0 = mpxbdm_pram */
+	ppc_bdm_wait(); /* wait until remote target reaches 0x0 -> SEI */
+
+	return remote_restore();
+}
+
+/*****************************************************************/
+unsigned int remote_prepare(unsigned int * pPrg, int nPrg)
+{
+	int i;
+
+	for (i = 0; i < 32; i++)
+	{
+		RegBuffer[i] = bdm_getreg(i); /* save GPR0..31 */
+	}
+
+	RegBuffer[i++] = bdm_getspr(SPR_CTR); /*save CTR*/
+	RegBuffer[i++] = bdm_getspr(SPR_SRR0); /*save srr0*/
+	RegBuffer[i++] = bdm_getspr(SPR_SRR1); /*save srr1*/
+	RegBuffer[i++] = bdm_getspr(SPR_DER); /*save DER*/
+
+/*copy ram content into buffer, and remote program into ram, if any*/
+	for (i = 0; i< nPrg; i++)
+	{
+		membuf[i] = ppc_bdm_getword(mpcbdm_pram+i*4);
+		ppc_bdm_setword(mpcbdm_pram+i*4,pPrg[i]);
+	}
+	pramlen = i;
+
+/*verify, that ram holds program, if any */
+	for (i = 0; i< pramlen; i++)
+	{
+		if (ppc_bdm_getword(mpcbdm_pram+i*4) != pPrg[i])
+		{
+			printf_filtered("remote_execute_init: RAM doesn't hold prg at addr 0x%08x\n",mpcbdm_pram+i*4);
+			pramlen = 0;
+			remote_restore(); /* at least restore registers */
+			return pramlen;
+		}
+	}
+
+/* setup processor for program, if any */
+	if (pramlen)
+	{
+		bdm_setspr(SPR_SRR0,mpcbdm_pram); /*start address*/
+		bdm_setspr(SPR_SRR1,0x1000); /* new MSR:enable only ME*/
+		bdm_setspr(SPR_DER,0x7002400f); /* allow SEIE, to return to gdb*/
+	}
+
+/* target processor is now ready to execute program with remote_execute() */
+
+	return pramlen; /* return len of program, 0 for fail */
+}
+
+/*****************************************************************
+* FLASH routines                                                 *
+*****************************************************************/
+unsigned int flash_addr(unsigned int Addr)
+{
+	unsigned int Val;
+
+	if (!pFB) return 0; /* no bank selected */
+
+	Val = (Addr << pFB->shift) + pFB->start;
+	return Val;
+}
+
+/*****************************************************************/
+unsigned int flash_data(unsigned int Data)
+{
+	unsigned int Val;
+	int i;
+
+	if (!pFB) return 0; /* no bank selected */
+
+	Val = pFB->mask & Data;
+	for (i = 1; i < pFB->devices; i++) /* copy data for all parallel devices */
+	{
+		Val |= (Val<<pFB->bits);
+	}
+	return Val;
+}
+
+/*****************************************************************/
+int flash_erase(unsigned int Addr)
+{
+	int i;
+	int nResult;
+
+	flash_find_bank(Addr,1);
+	if (!pFB) return;
+
+/*check if sector is protected*/
+/*	Data = FBS.getword(flash_addr((FBS.pDevice->ADDR_VERIFYPROTECT)+((secID)<<FBS.IDshift)));
+*/
+	if (mpcbdm_fquery)
+	{
+		i = query("erase FLASH bank %d sector %d [0x%08x,0x%08x] ?", FBank, FSec, pFB->Sector[FSec].Start, pFB->Sector[FSec].End);
+		if (i != 1) return 0;
+	}
+	else
+	{
+		printf_filtered("erasing FLASH bank %d sector %d [0x%08x,0x%08x]\n", FBank, FSec, pFB->Sector[FSec].Start, pFB->Sector[FSec].End);
+	}
+
+	remote_prepare(NULL,0); /*save GPRs*/
+	flash_load_sequence(pFB->cErase,Addr,0,1);
+	nResult = flash_execute_sequence(pFB->cErase,Addr,0);
+	remote_restore(); /*restore GPRs*/
+
+	return nResult;
+}
+/*****************************************************************/
+int flash_clear(unsigned int Addr)
+{
+	int i;
+	int nResult;
+
+	flash_find_bank(Addr,1);
+	if (!pFB) return;
+
+	if (mpcbdm_fquery)
+	{
+		i = query("clear FLASH bank %d [0x%08x,0x%08x] ?", FBank, pFB->start, pFB->end);
+		if (i != 1) return 0;
+	}
+	else
+	{
+		printf_filtered("clearing FLASH bank %d [0x%08x,0x%08x]\n", FBank, pFB->start, pFB->end);
+	}
+
+	remote_prepare(NULL,0); /*save GPRs*/
+	flash_load_sequence(pFB->cClear,Addr,0,1);
+	nResult = flash_execute_sequence(pFB->cClear,Addr,0);
+	remote_restore(); /*restore GPRs*/
+
+	return nResult;
+}
+/*****************************************************************/
+int flash_write_word(unsigned int Addr, unsigned int Word, int bLoadSeq)
+{
+/* have to be check for zero to ones before, destroys target register content */
+	int nResult;
+	int i;
+
+	flash_find_bank(Addr,0);
+	if (!pFB) return 0; /* no valid bank configuration found */
+
+	for (i = pFB->EWA-1; i >=0; i--) /* loop elementar accesses for one 32 word, turn endianess */
+	{
+		nResult = flash_load_sequence(pFB->cWrite,Addr+(i<<pFB->shift),Word & pFB->mask,(i == pFB->EWA-1)&&(bLoadSeq));
+		if (!nResult) break;
+		nResult = flash_execute_sequence(pFB->cWrite,Addr+(i<<pFB->shift),Word & pFB->mask);
+		if (!nResult) break;
+		Word = Word >> pFB->width;
+	}
+	if (!nResult) /* write reset commando, if errors occured */
+	{
+		flash_load_sequence(pFB->cReset,Addr,Word,1);
+		flash_execute_sequence(pFB->cReset,Addr,Word);
+	}
+	return nResult;
+}
+
+/*****************************************************************/
+int flash_write(unsigned int Addr, unsigned int Word)
+{
+	int nResult;
+	int i;
+	unsigned int Data;
+	unsigned int hData;
+
+	flash_find_bank(Addr,1);
+	if (!pFB) return 0; /* no valid bank configuration found */
+
+	if (mpcbdm_fquery)
+	{
+		i = query("write 0x%08x to FLASH at 0x%08x (bank %d sector %d [0x%08x,0x%08x]) ?", Word, Addr, FBank, FSec, pFB->Sector[FSec].Start, pFB->Sector[FSec].End);
+		if (i != 1) return 0;
+	}
+	else
+	{
+		printf_filtered("writing 0x%08x to FLASH at 0x%08x (bank %d sector %d [0x%08x,0x%08x])\n", Word, Addr, FBank, FSec, pFB->Sector[FSec].Start, pFB->Sector[FSec].End);
+	}
+
+	Data = ppc_bdm_getword(Addr); /*Word found in FLASH*/
+	hData = Word & ~Data; /* find ones to be written into zeros*/
+	if (hData)
+	{
+		printf_filtered("0x%08x: unable to write 0->1 : need to erase sector\n",Addr);
+		return 0; /* failure */
+	}
+
+	remote_prepare(NULL,0); /*save GPRs*/
+	nResult = flash_write_word(Addr,Word,1);
+	remote_restore(); /*restore GPRs*/
+	if (!nResult)
+	{
+		printf_filtered("0x%08x: flash_write: failed to write 0x%08x to 0x%08x\n",Word,Addr);
+	}
+	return nResult;
+}
+/*****************************************************************/
+int flash_check_zeros_host(unsigned int *Buffer, unsigned int len, unsigned int Destination, unsigned int * Adr)
+{
+	int i;
+	int nResult;
+	unsigned int r0;
+	unsigned int r1;
+	unsigned int Data;
+	unsigned int hData;
+	unsigned int Word;
+	int wlen;
+
+	nResult = 0;
+
+	r0 = bdm_getreg(0); /* save scratch registers */
+	r1 = bdm_getreg(1);
+
+	bdm_setreg(1,Destination-4);
+	wlen = (len + 3)>>2; /* word len */
+	if ((wlen << 2) != len)
+	{
+		printf_filtered("flash_check_zeros_host: assert warning: len not divisible by 4");
+	}
+
+	*Adr = Destination;
+	for (i=0; i<wlen; i++)
+	{
+/* Buffer ist in host byte order, so we have to convert... */
+		Word = extract_unsigned_integer(&(Buffer[i]),sizeof(Word));
+		ser_clkinstr(0x84010004, 0); /*lwzu    r0,4(r1)*/
+		Data = bdm_getreg(0);
+
+		hData = Word & ~Data; /* find ones to be written into zeros*/
+		if (hData)
+		{
+			nResult = 1;
+			break; /* failure, Destination Adr in *Adr */
+		}
+		(*Adr) += 4;
+	}
+	bdm_setreg(0,r0); /* restore registers */
+	bdm_setreg(1,r1);
+
+	return nResult;
+}
+/*****************************************************************/
+unsigned int flash_check_zeros(unsigned int SourceStart, unsigned int SourceEnd, unsigned int Destination, unsigned int * Adr)
+{
+	int i;
+	unsigned int h, len;
+	unsigned int prg[5]=
+	{
+		0x84010004,	/*lwzu    r0,4(r1)*/
+		0x84820004,	/*lwzu    r4,4(r2)*/
+		0x7c002079,	/*andc.   r0,r0,r4*/
+		0x4102fff4,	/*bdnzt   eq,-16*/
+		0x00000000	/*.long 0x0*/
+	};
+
+	if (mpcbdm_fflash) /* using fast remote routines?*/
+	{
+/* prepare remote execution */
+		h = remote_prepare(&(prg[0]),5);
+		if (h != 5)
+		{
+			*Adr = 0;
+			return 1; /* !=0 for failure */
+		}
+
+/* parameters for program */
+		bdm_setreg(1,SourceStart-4);
+		bdm_setreg(2,Destination-4);
+		len = (SourceEnd-SourceStart+4)/4;
+		bdm_setspr(SPR_CTR,len); /*len*/
+
+/* check for zeros needed to be programmed to 1 */
+		h = remote_execute(); /* last result, should be 0 */
+
+		*Adr = RegBuffer[2]; /*return value last postion*/
+
+		return h;
+	}
+/* slow host side routines:*/
+	remote_prepare(NULL,0); /* save GPRs*/
+	bdm_setreg(1,SourceStart-4);
+	bdm_setreg(2,Destination-4);
+	len = (SourceEnd-SourceStart+4)/4;
+	for (i=len; i>0; i--)
+	{
+		ser_clkinstr(prg[0], 0);
+		ser_clkinstr(prg[1], 0);
+		ser_clkinstr(prg[2], 0);
+		h = bdm_getreg(0);
+		if (h)
+		{
+			*Adr = bdm_getreg(2);
+			break;
+		}
+	}
+	remote_restore(); /* restore GPRs*/
+	return h;
+}
+
+/*****************************************************************/
+unsigned int flash_fast_program(
+	unsigned int SourceStart,
+	unsigned int SourceEnd,
+	unsigned int Destination,
+	unsigned int *Adr)
+{
+	int i;
+	int nResult;
+	unsigned int h,len;
+
+	flash_find_bank(Destination,1);
+
+	if (!pFB) return -1; /* no bank found for destination address */
+
+	if ((!pFB->fflash) || (pFB->nfflash<=0)) return -2; /* no fast routine configured */
+
+	h = remote_prepare(pFB->fflash,pFB->nfflash);
+	if (h != pFB->nfflash) return -3;
+
+/* preload registers for fast cycle */
+	nResult = 	flash_load_sequence(pFB->cFast,Destination,0,1);
+
+/*parameters for program*/
+	bdm_setreg(28,SourceStart-pFB->align);
+	bdm_setreg(29,Destination-pFB->align);
+	len = (SourceEnd-SourceStart+pFB->align)/pFB->align;
+	bdm_setspr(SPR_CTR,len); /*len*/
+
+	remote_execute(); /* implicite remote_restore() */
+
+	(*Adr) = RegBuffer[29]; /*last written to FLASH adr*/
+	h = RegBuffer[32]; /* in case of no error, CTR should be equal to 0 */
+
+	return h;
+}
+
+/*****************************************************************/
+int flash_copy(unsigned int SourceStart, unsigned int SourceEnd, unsigned int Destination)
+{
+	int i;
+	int K,L;
+	unsigned int Source,Dest,len;
+	unsigned int nResult, Adr;
+	unsigned int Pos;
+	u_int Word,Data,hData ; /*for read operations*/
+
+	if (SourceStart > SourceEnd)
+	{
+		printf_filtered("error: source start > source end\n");
+		return 0; /* failure */
+	}
+	len = SourceEnd - SourceStart;
+
+	flash_find_bank(Destination,1);
+	if (!pFB) return 0; /* no bank found for address */
+
+	if (pFB->end < Destination+len)
+	{
+		printf_filtered("error: destination range [0x%08x,0x%08x] exceeds bank range [0x%08x,0x%08x]\n",
+				Destination, Destination+len, pFB->start, pFB->end);
+		return 0;
+	}
+	if (((Destination>=SourceStart) && (Destination <=SourceEnd))||
+		((Destination+len>=SourceStart) && (Destination+len <=SourceEnd)))
+	{
+		printf_filtered("error: destination range [0x%08x,0x%08x] within source range [0x%08x,0x%08x]\n",
+				Destination, Destination+len, SourceStart, SourceEnd);
+		return 0;
+	}
+	if (SourceStart%pFB->align !=0)
+	{
+		printf_filtered("error: start address has to be %d bytes aligned\n",pFB->align);
+		return 0;
+	}
+	if (Destination%pFB->align !=0)
+	{
+		printf_filtered("error: destination address has to be %d bytes aligned\n",pFB->align);
+		return 0;
+	}
+
+   	printf_filtered(" checking, if data can be written without erasing FLASH...\n");
+
+	for (Pos = 0; Pos <= SourceEnd-SourceStart;)
+	{
+		/*search for zeros to be written to ones: sector needs erasure*/
+		nResult = flash_check_zeros(SourceStart+Pos,SourceEnd,Destination+Pos,&Adr);
+		if (nResult == 0) break; /*ok to write data to flash*/
+
+		if (Adr == 0) /* flash_check_zeros failed to setup remote*/
+		{
+			printf_filtered(" range not copied\n");
+			return 0;
+		}
+		printf_filtered("0x%08x: need to erase sector\n",Adr);
+		i = flash_erase(Adr); /*try to erase sector*/
+		if (i == 0)
+		{
+			printf_filtered(" range not copied\n");
+			return 0;
+		}
+		Pos = Adr - Destination; /* retry checking at last position */
+		if (mpcbdm_verbose&VERBOSE_FLS)
+		{
+			printf_filtered("flash_copy Pos = 0x%08x\n",Pos);
+		}
+	}
+	if (Pos > SourceEnd-SourceStart)
+	{
+		printf_filtered("assert warning:  flash_copy Pos > SourceEnd-SourceStart 0x%08x\n",Pos);
+	}
+   	printf_filtered("\nFLASH checked successfully!\n");
+
+	if (mpcbdm_fquery)
+	{
+		i = query("Copy memory [0x%08x,0x%08x] to FLASH at [0x%08x,0x%08x] ?", SourceStart, SourceEnd, Destination, Destination +len);
+		if (i!=1) return 0;
+	}
+	else
+	{
+		printf_filtered("Copying memory [0x%08x,0x%08x] to FLASH at [0x%08x,0x%08x]\n", SourceStart, SourceEnd, Destination, Destination +len);
+	}
+
+/* use fast flash ppc subroutines? */
+	if ((mpcbdm_fflash) && (pFB->fflash) && (pFB->nfflash>0) && (pFB->cFast))
+	{
+		nResult = flash_fast_program(SourceStart,SourceEnd,Destination,&Adr);
+		if (nResult !=0)
+		{
+			printf_filtered("error: FLASH failure at 0x%08x: nResult=0x%08x\n",Adr,nResult);
+			return 0; /* failure */
+		}
+		return 1; /* success*/
+	}
+	if (mpcbdm_fflash)
+	{
+		if ((!(pFB->fflash)) || (pFB->nfflash<=0))
+		{
+			printf_filtered("no fast flash routine configured, using slow host routine\n");
+		}
+		else if (!(pFB->cFast))
+		{
+			printf_filtered("no fast flash routine register preload (cfast) configured, using slow host routine\n");
+		}
+	}
+/* use host controlled flash routine, very slow! */
+	remote_prepare(NULL,0); /*save GPRs*/
+	bdm_setreg(28,SourceStart-4); /**/
+	len = 0;
+	K = 0;
+	L = 0;
+	for (Source = SourceStart; Source <= SourceEnd; Destination+=4,Source+=4)
+	{
+		ser_clkinstr(0x877c0004, 0);//   lwzu	 r27,4(r28)
+		Word = bdm_getreg(27);
+
+		i = flash_write_word(Destination,Word,(Source==SourceStart));
+		if (!i)
+		{
+			remote_restore(); /*restore GPRs*/
+			return 0;/*stop if failed writing data to FLASH*/
+		}
+		len+=4;
+		K+=4; /*count bytes*/
+		if (K >= 4096) /*4KByte*/
+		{
+			printf_unfiltered(".");
+			gdb_flush (gdb_stdout);
+			K-=4096;
+			L++;
+			if (L == 32) /*32*4K = 128KByte*/
+			{
+				printf_unfiltered("%dK\n",len/1024);
+				gdb_flush (gdb_stdout);
+				L = 0;
+			}
+		}
+	}
+	remote_restore(); /*restore GPRs*/
+	printf_filtered("\n copying finished.\n");
+	return 1; /* success */
+}
+
+/*****************************************************************/
+void flash_info(void)
+{
+	int i;
+	int bank;
+	int nResult;
+
+	for(bank=0; bank < mpcbdm_nBank; bank++) /*for all configured flash banks*/
+	{
+		flash_find_bank(FB[bank].start,1);
+		if (!pFB) continue;  /* misconfigured, should never happen*/
+
+		printf_filtered("FLASH bank %d %dx %d bit %s: %x-%x, adr align %d\n",
+						bank,pFB->devices,pFB->bits,pFB->sName,
+						pFB->start, pFB->end, pFB->align);
+		nResult = flash_ident(pFB->start); /* test if device is responding */
+
+/* 		for (i = 0; i< FBS.pDevice->nSectors; i++)
+		{
+			Data = FBS.getword(flash_addr((FBS.pDevice->ADDR_VERIFYPROTECT)
+								+((FBS.pDevice->Sector[i].ID)<<FBS.IDshift)));
+			printf_filtered(" SA%02d Protect:%x",i,Data);
+			printf_filtered(" Start:%08x",flash_addr(FBS.pDevice->Sector[i].Start));
+			printf_filtered(" End:%08x\n",flash_addr(FBS.pDevice->Sector[i].End)+(FBS.width)/8-1);
+		}
+*/
+	}
+}
+
+/*****************************************************************/
+int flash_find_bank(unsigned int Addr, int bVerbose)
+{
+	int nResult;
+
+	for (FBank = 0; FBank < mpcbdm_nBank; FBank++)
+	{
+		if ((FB[FBank].start <= Addr) && (FB[FBank].end >= Addr))
+			break; /*found bank for addr*/
+	}
+	if (FBank >= mpcbdm_nBank)
+	{
+		if (bVerbose)
+		{
+			printf_filtered("no FLASH bank found for Addr:0x%08x\n",Addr);
+		}
+		pFB = NULL;
+		return 0;
+	}
+	if (pFB == &(FB[FBank]))
+	{
+		nResult = 1; /* same bank selected previously */
+	}
+	else
+	{
+		nResult = 0; /* new bank selected */
+		pFB = &(FB[FBank]);
+	}
+
+	for (FSec = 0; FSec < pFB->nSectors; FSec++)
+	{
+		if ((pFB->Sector[FSec].Start <= Addr) && (pFB->Sector[FSec].End >= Addr))
+			break; /*found sector for addr*/
+	}
+	if (FSec >= pFB->nSectors)
+	{
+		if (bVerbose)
+		{
+			printf_filtered("no FLASH sector found for Addr:0x%08x in bank %d\n",Addr,FBank);
+		}
+		pFB = NULL;
+		return 0;
+	}
+	return nResult;
+}
+/*****************************************************************/
+int flash_load_sequence(FlashCycle *pCycle,unsigned int Addr,unsigned int Data,int bFirstTime)
+{
+	int bAdr;
+	int bData;
+	int bID;
+	int cyc;
+
+	if ((!pCycle) || (!pFB)) return 0;
+
+	cyc = 0;
+	bAdr = 0;	/* actual address used at least once, loaded into r31*/
+	bData = 0;	/* actual data used at least once, loaded into r0 */
+	bID = 0;	/* actual id used at least once, loaded into r30 */
+
+	while ((cyc < MAXFLASHCYCLES) && (pCycle[cyc].cType != 0))
+	{
+		switch (pCycle[cyc].cAdrType)
+		{
+		case 'a':
+			if (!bAdr)
+			{
+				bdm_setreg(31,Addr);
+				bAdr = 1;
+			}
+			pCycle[cyc].Adr = Addr; /* for debugging, insert actual address */
+			break;
+		case 'i':
+			if (!bID)
+			{
+				bdm_setreg(30,flash_addr(pFB->Sector[FSec].ID<<pFB->IDshift));
+				bID = 1;
+			}
+			pCycle[cyc].Adr = flash_addr(pFB->Sector[FSec].ID<<pFB->IDshift); /* for debugging, insert actual id address */
+			break;
+		default:
+			if (bFirstTime) /* load immediate data only once */
+			{
+				bdm_setreg((cyc<<1)+1,pCycle[cyc].Adr);
+			}
+			break;
+		}
+/* only for write cycles data has to be placed into registers*/
+/* the rest is to load actual cycle data for debug purposes*/
+		switch (pCycle[cyc].cDataType)
+		{
+		case 'd':
+			if (pCycle[cyc].cType == 'w')
+			{
+				if (!bData)
+				{
+					bdm_setreg(0,Data);
+					bData = 1;
+				}
+			}
+			pCycle[cyc].Data = Data; /* for debugging, insert actual Data */
+			break;
+		case 'i':
+			if (pCycle[cyc].cType == 'w')
+			{
+				if (!bID)
+				{
+					bdm_setreg(30,flash_data(pFB->Sector[FSec].ID<<pFB->IDshift));
+					bID = 1;
+				}
+			}
+ /* for debugging, insert actual Data */
+			pCycle[cyc].Data = flash_data(pFB->Sector[FSec].ID<<pFB->IDshift);
+			break;
+		default:
+			if (pCycle[cyc].cType == 'w')
+			{
+				if (bFirstTime) /* load immediate data only once */
+				{
+					bdm_setreg((cyc<<1)+2,pCycle[cyc].Data);
+				}
+			}
+			break;
+		}
+		cyc++;
+	}
+	return 1;
+}
+/*****************************************************************/
+int flash_execute_sequence(FlashCycle *pCycle, unsigned int Addr, unsigned int Data)
+{
+	int cyc;
+	u_int val;
+	u_int com;
+	u_int comload;
+	u_int comstore;
+	u_int rD; /* number of register holding data for cycle */
+	u_int rA; /* number of register holding address for cycle */
+	u_int comp = 0; /* for load related cycles value to compare with */
+	u_int dgbRA; /* for debug printouts*/
+	u_int dgbRD;
+	unsigned int i;
+
+	if ((!pCycle) || (!pFB)) return 0;
+
+	switch (pFB->width)
+	{
+/*		com = (OP << 26) | (rD << 21) | (rA << 16) | d;*/ /* l/s w/h/b z rD,d(rA)*/
+	case 8:
+		comload = (34 << 26); /*lbz rD,d(rA)*/
+		comstore =(38 << 26); /*stb rS,d(rA)*/
+		break;
+	case 16:
+		comload = (40 << 26); /*lhz rD,d(rA)*/
+		comstore =(44 << 26); /*sth rS,d(rA)*/
+		break;
+	case 32:
+		comload = (32 << 26); /*lwz rD,d(rA)*/
+		comstore =(36 << 26); /*stw rS,d(rA)*/
+		break;
+	default:
+		printf_filtered("flash_execute_sequence: config error bank %d width %d\n",FBank,pFB->width);
+		return 0;
+		break;
+	}
+
+	cyc = 0;
+
+	while ((cyc < MAXFLASHCYCLES) && (pCycle[cyc].cType != 0))
+	{
+		switch (pCycle[cyc].cAdrType)
+		{
+		case 'a':
+			rA = 31;
+			break;
+		case 'i':
+			rA = 30;
+			break;
+		default:
+			rA = (cyc<<1)+1;
+			break;
+		}
+
+		if (pCycle[cyc].cType == 'w')
+		{
+			switch (pCycle[cyc].cDataType)
+			{
+			case 'd':
+				rD = 0;
+				break;
+			case 'i':
+				rD = 30;
+				break;
+			default:
+				rD = (cyc<<1)+2;
+				break;
+			}
+		}
+		else /* for read related cycles store data in cycle data reg */
+		{
+			rD = (cyc<<1)+2;
+
+			switch (pCycle[cyc].cDataType)
+			{
+			case 'd':
+				comp = Data;
+				break;
+			case 'i':
+				comp = flash_data(pFB->Sector[FSec].ID<<pFB->IDshift);
+				break;
+			default:
+				comp = pCycle[cyc].Data;
+				break;
+			}
+		}
+
+		if (mpcbdm_verbose&VERBOSE_FLS)
+		{
+			printf_filtered("flash_execute_sequence: Cyc%d %c%c 0x%x:%c 0x%x\n",
+				cyc,pCycle[cyc].cType,pCycle[cyc].cAdrType,
+				pCycle[cyc].Adr,pCycle[cyc].cDataType,pCycle[cyc].Data);
+		}
+
+		switch (pCycle[cyc].cType)
+		{
+		case 'w':
+			com = comstore | (rD << 21) | (rA << 16); /*st[width] rS,0(rA)*/
+			ser_clkinstr(com, 0);
+			break;
+		case 'r':
+			com = comload | (rD << 21) | (rA << 16); /*l[width]w rD,0(rA)*/
+			ser_clkinstr(com, 0);
+			val = bdm_getreg(rD);
+			if (comp != val)
+			{
+				printf_filtered("flash_execute_cycle: read 0x%x got 0x%x\n",comp,val);
+			}
+			break;
+		case 'c':
+			com = comload | (rD << 21) | (rA << 16); /*l[width]z rD,0(rA)*/
+			ser_clkinstr(com, 0);
+			val = bdm_getreg(rD);
+			if (comp != val)
+			{
+				printf_filtered("flash_execute_cycle: compare 0x%x got 0x%x\n",comp,val);
+				return 0;
+			}
+			break;
+		case 'p':
+			com = comload | (rD << 21) | (rA << 16); /*l[width]z rD,0(rA)*/
+			for (i = 0; i < mpcbdm_toggle; i++)
+			{
+				ser_clkinstr(com, 0);
+				val = bdm_getreg(rD) & pCycle[cyc].Data; /*poll only valid with immediate data*/
+				if (!val) break;
+			}
+			if (i == mpcbdm_toggle)
+			{
+				printf_filtered("flash_execute_cycle: poll timed out\n");
+				return 0;
+			}
+			break;
+		case 't':
+			com = comload | (rD << 21) | (rA << 16); /*l[width]z rD,0(rA)*/
+			ser_clkinstr(com, 0);
+			val = bdm_getreg(rD) & pCycle[cyc].Data; /* toggle only valid with immediate data*/
+			for (i = 0; i < mpcbdm_toggle; i++)
+			{
+				ser_clkinstr(com, 0);
+				comp = bdm_getreg(rD) & pCycle[cyc].Data;
+				if (!(val ^ comp)) break; /* toggling stopped?*/
+				val = comp;
+			}
+			if (i == mpcbdm_toggle)
+			{
+				printf_filtered("flash_execute_cycle: toggle timed out\n");
+				return 0;
+			}
+			break;
+		default:
+			break;
+		}
+		cyc++;
+	}
+	return 1; /* success */
+}
+/*****************************************************************/
+int flash_file_skipspace(FILE *f,char cChar, unsigned int * Start)
+{
+	int nResult;
+
+	while (!feof(f) && !ferror(f))
+	{
+		nResult = fgetc(f);
+		if (nResult == cChar)
+		{
+			if (Start!=0) *Start = ftell(f);
+			return 1;
+		}
+		if (! isspace(nResult))
+		{
+			ungetc(nResult,f);
+			return 0;
+		}
+	}
+	if (ferror(f))
+	{
+		printf_filtered("file error while skipping whitespace for '%c'\n",cChar);
+	}
+	return 0;
+}
+/*****************************************************************/
+int flash_file_find(FILE *f,char * sString,unsigned int * Start)
+{
+	int pos;
+	int len;
+	int nResult;
+
+	pos = 0;
+	len = strlen(sString);
+	while (!feof(f) && !ferror(f))
+	{
+		nResult = fgetc(f);
+		if (nResult != sString[pos])
+		{
+			pos = 0;
+			continue;
+		}
+		pos++;
+		if (pos == len)
+		{
+			if (Start!=0) *Start = ftell(f);
+			return 1;
+		}
+	}
+	if (ferror(f))
+	{
+		printf_filtered("file error while searching for '%s'\n",sString);
+	}
+	return 0;
+}
+/*****************************************************************/
+int flash_file_node(FILE *f,char * sString,unsigned int * Start)
+{
+	int nResult;
+
+	do
+	{
+		nResult = flash_file_find(f,sString,Start);
+		if (!nResult)
+		{
+			printf_filtered("error: '%s' not found inside '%s'.\n",sString,mpcbdm_flashdev);
+			return 0;
+		}
+		nResult = flash_file_skipspace(f,'{',Start);
+	} while (!nResult && !feof(f) && ! ferror(f));
+	if (feof(f) || ferror(f)) return 0;
+	return 1;
+}
+/*****************************************************************/
+void flash_free_bank()
+{
+	if ((mpcbdm_nBank >= 0) && (mpcbdm_nBank < MAXFLASHBANKS))
+	{
+		if (FB[mpcbdm_nBank].sName)
+		{
+			free(FB[mpcbdm_nBank].sName);
+			FB[mpcbdm_nBank].sName=NULL;
+		}
+		if (FB[mpcbdm_nBank].Sector)
+		{
+			free(FB[mpcbdm_nBank].Sector);
+			FB[mpcbdm_nBank].Sector=NULL;
+		}
+		if (FB[mpcbdm_nBank].cReset)
+		{
+			free(FB[mpcbdm_nBank].cReset);
+			FB[mpcbdm_nBank].cReset=NULL;
+		}
+		if (FB[mpcbdm_nBank].cIdent)
+		{
+			free(FB[mpcbdm_nBank].cIdent);
+			FB[mpcbdm_nBank].cIdent=NULL;
+		}
+		if (FB[mpcbdm_nBank].cWrite)
+		{
+			free(FB[mpcbdm_nBank].cWrite);
+			FB[mpcbdm_nBank].cWrite=NULL;
+		}
+		if (FB[mpcbdm_nBank].cErase)
+		{
+			free(FB[mpcbdm_nBank].cErase);
+			FB[mpcbdm_nBank].cErase=NULL;
+		}
+		if (FB[mpcbdm_nBank].cClear)
+		{
+			free(FB[mpcbdm_nBank].cClear);
+			FB[mpcbdm_nBank].cClear=NULL;
+		}
+		if (FB[mpcbdm_nBank].cFast)
+		{
+			free(FB[mpcbdm_nBank].cFast);
+			FB[mpcbdm_nBank].cFast=NULL;
+		}
+		if (FB[mpcbdm_nBank].fflash)
+		{
+			free(FB[mpcbdm_nBank].fflash);
+			FB[mpcbdm_nBank].fflash=NULL;
+			FB[mpcbdm_nBank].nfflash=0;
+		}
+	}
+}
+/*****************************************************************/
+int flash_parse_cycle(FlashCycle **pCycle)
+{
+	int len;
+	int i;
+	int j;
+	int p;
+	int cyc;
+	int data;
+	unsigned int val;
+	char cType;
+
+	*pCycle = malloc(sizeof(FlashCycle)*MAXFLASHCYCLES);
+	if (!*pCycle)
+	{
+		printf_filtered("flash_parse_cycle:unable to allocate mem\n");
+		return 0;
+	}
+
+	for(cyc = 0; cyc < MAXFLASHCYCLES; cyc++)
+	{
+		len = strlen(pParse);
+		for(i = 0;(i<len) && (isspace(pParse[i]));i++);
+		if (i >= len) return 0;
+
+		cType = tolower(pParse[i]);
+		switch(cType)
+		{
+		case 'w':
+		case 'r':
+		case 'c':
+		case 't':
+		case 'p':
+			break;
+		default:
+			printf_filtered("flash_parse_cycle: incorrect cycle #%d '%s'\n",cyc,pParse);
+			return 0;
+			break;
+		}
+		(*pCycle)[cyc].cType = cType;
+		if ((i+1<len) && (pParse[i+1]=='%')) /* special ADR? */
+		{
+			if (i+2>=len)
+			{
+				printf_filtered("flash_parse_cycle: incorrect cycle #%d, missing adr '%s'\n",cyc,pParse);
+				return 0;
+			}
+			cType = tolower(pParse[i+2]);
+			switch(cType)
+			{
+			case 'a':
+				break;
+			case 'i':
+				break;
+			default:
+				printf_filtered("flash_parse_cycle: incorrect cycle #%d, special adr '%s'\n",cyc,pParse);
+				return 0;
+				break;
+			}
+			(*pCycle)[cyc].cAdrType = cType;
+			i+=3;
+		}
+		else
+		{
+			(*pCycle)[cyc].cAdrType = ' ';
+			sscanf(pParse+i+1,"%i%n",&data,&p);
+			if (p==0)
+			{
+				printf_filtered("flash_parse_cycle: incorrect cycle #%d, adr '%s'\n",cyc,pParse);
+				return 0;
+			}
+			(*pCycle)[cyc].Adr = (((unsigned int)data)<<FB[mpcbdm_nBank].shift) + FB[mpcbdm_nBank].start;
+			i+=p+1;
+		}
+		if (i >= len)
+		{
+			printf_filtered("flash_parse_cycle: incorrect cycle #%d, missing ':' '%s'\n",cyc,pParse);
+			return 0;
+		}
+		if (pParse[i] != ':')
+		{
+			printf_filtered("flash_parse_cycle: incorrect cycle #%d, missing ':' '%s'\n",cyc,pParse);
+			return 0;
+		}
+		i++;
+		if (i >= len)
+		{
+			printf_filtered("flash_parse_cycle: incorrect cycle #%d, missing data '%s'\n",cyc,pParse);
+			return 0;
+		}
+		if (pParse[i]=='%') /* special DATA? */
+		{
+			if (i+1>=len)
+			{
+				printf_filtered("flash_parse_cycle: incorrect cycle #%d, missing data '%s'\n",cyc,pParse);
+				return 0;
+			}
+			cType = tolower(pParse[i+1]);
+			switch(cType)
+			{
+			case 'd':
+				break;
+			case 'i':
+				break;
+			default:
+				printf_filtered("flash_parse_cycle: incorrect cycle #%d, special data '%s'\n",cyc,pParse);
+				return 0;
+				break;
+			}
+			(*pCycle)[cyc].cDataType = cType;
+			i+=2;
+		}
+		else
+		{
+			(*pCycle)[cyc].cDataType = ' ';
+			sscanf(pParse+i,"%i%n",&data,&p);
+			if (p==0)
+			{
+				printf_filtered("flash_parse_cycle: incorrect cycle #%d, data '%s'\n",cyc,pParse);
+				return 0;
+			}
+			val = FB[mpcbdm_nBank].mask & (unsigned int)data;
+			for (j = 1; j < FB[mpcbdm_nBank].devices; j++) /* copy data for all parallel devices */
+			{
+				val |= (val<<FB[mpcbdm_nBank].bits);
+			}
+			(*pCycle)[cyc].Data = val;
+			i+=p;
+		}
+		if (mpcbdm_verbose&VERBOSE_FLS)
+		{
+			printf_filtered("flash_parse_cycle: Cyc %d %c%c0x%x:%c0x%x\n",cyc,(*pCycle)[cyc].cType,(*pCycle)[cyc].cAdrType,(*pCycle)[cyc].Adr,(*pCycle)[cyc].cDataType,(*pCycle)[cyc].Data);
+		}
+		pParse+=i;
+		len = strlen(pParse);
+		for(i = 0;(i<len) && (isspace(pParse[i]));i++);
+		if (i >= len) /* end of line, no ',' -> end of cycles */
+		{
+			cyc++;
+			break;
+		}
+		if (pParse[i] == ',')
+		{
+			pParse++;
+		}
+		len = strlen(pParse);
+		for(i = 0;(i<len) && (isspace(pParse[i]));i++);
+		if (i >= len) /* ',' + eol -> read next line */
+		{
+			fgets(FileBuffer,MAXBUFFERLEN,f);
+			pParse = FileBuffer;
+		}
+	}
+	if (cyc < MAXFLASHCYCLES)
+	{
+		(*pCycle)[cyc].cType = 0; /* mark end of cycles */
+	}
+	return 1; /* successfully parsed cycles */
+}
+/*****************************************************************/
+void flash_configure(u_int Addr,u_int Num,char * sDevice)
+{
+	char Buffer[MAXBUFFERLEN];
+	char sSector[MAXBUFFERLEN];
+	char sAlgo[MAXBUFFERLEN];
+	char sFast[MAXBUFFERLEN];
+	int len;
+	int i;
+	int nResult;
+	int nComma = 0;
+	u_int nStart;
+	u_int adr;
+	u_int prg;
+
+	sFast[0]=0;
+
+	if (mpcbdm_nBank >= MAXFLASHBANKS)
+	{
+		printf_filtered("unable to configure bank: too many banks %d\n",mpcbdm_nBank);
+		return;
+	}
+
+	flash_find_bank(Addr,0);
+	if (pFB)
+	{
+		printf_filtered("bank %d already defined for 0x%08x\n",FBank,Addr);
+		return;
+	}
+
+	for(;isspace(*sDevice);sDevice++);
+	len = strlen(sDevice);
+
+	if (mpcbdm_verbose&VERBOSE_FLS)
+	{
+		printf_filtered("configuring bank %d 0x%08x as %u * %s\n",mpcbdm_nBank,Addr,Num,sDevice);
+	}
+
+	if (!mpcbdm_flashdev)
+	{
+		error("no flash configuration file path given: set mpcbdm_flashdev.");
+		return;
+	}
+
+	FB[mpcbdm_nBank].sName = malloc(len+1);
+	if (!FB[mpcbdm_nBank].sName)
+	{
+		printf_filtered("flash_configure:unable to allocate mem for Name\n");
+		flash_free_bank();
+		return;
+	}
+
+	strncpy(FB[mpcbdm_nBank].sName,sDevice,len+1);
+	FB[mpcbdm_nBank].start = Addr;
+	FB[mpcbdm_nBank].devices = Num;
+
+	f = fopen(mpcbdm_flashdev, "rb");
+
+	if(!f)
+	{
+		error("failed to open flash configuration file.");
+		return;
+	}
+
+	sprintf(Buffer,".device %s",sDevice);
+	nResult = flash_file_node(f,Buffer,&nStart);
+
+	if (!nResult)
+	{
+		flash_free_bank();
+		if (f) fclose(f);
+		return;
+	}
+	do
+	{
+		nResult = flash_file_skipspace(f,'}',NULL);
+		if (nResult)
+		{
+			break;
+		}
+		nResult = flash_file_skipspace(f,'.',NULL);
+		if (nResult)
+		{
+			fgets(Buffer,sizeof(Buffer),f);
+			pParse=Buffer;
+			if (strncmp(pParse,"size",4) == 0)
+			{
+				pParse+=4;
+				FB[mpcbdm_nBank].size = strtoul(pParse,&pParse,0);
+				if (pParse[0]== 'M')
+				{
+					FB[mpcbdm_nBank].size *= 1048576;
+				}
+				else if (pParse[0]== 'K')
+				{
+					FB[mpcbdm_nBank].size *= 1024;
+				}
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("%s.size %u\n",FB[mpcbdm_nBank].sName,FB[mpcbdm_nBank].size);
+				}
+			}
+			else if (strncmp(pParse,"width",5) == 0)
+			{
+				pParse+=5;
+				FB[mpcbdm_nBank].bits = strtoul(pParse,&pParse,0);
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("%s.width %u\n",FB[mpcbdm_nBank].sName,FB[mpcbdm_nBank].bits);
+				}
+			}
+			else if (strncmp(pParse,"sector",6) == 0)
+			{
+				pParse+=6;
+				sscanf(pParse,"%s",sSector);
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("%s.sector %s\n",FB[mpcbdm_nBank].sName,sSector);
+				}
+			}
+			else if (strncmp(pParse,"idoffset",8) == 0)
+			{
+				pParse+=8;
+				FB[mpcbdm_nBank].IDshift = strtoul(pParse,&pParse,0);
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("%s.idoffset %u\n",FB[mpcbdm_nBank].sName,FB[mpcbdm_nBank].IDshift);
+				}
+			}
+			else if (strncmp(pParse,"algorithm",9) == 0)
+			{
+				pParse+=9;
+				sscanf(pParse,"%s",sAlgo);
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("%s.algorithm %s\n",FB[mpcbdm_nBank].sName,sAlgo);
+				}
+			}
+			else
+			{
+				printf_filtered("wrong syntax: %s",Buffer);
+			}
+		}
+	} while (!feof(f) && !ferror(f));
+	if (ferror(f))
+	{
+		printf_filtered("file error while parsing .device %s",mpcbdm_flashdev);
+		flash_free_bank();
+		if (f) fclose(f);
+		return;
+	}
+
+	FB[mpcbdm_nBank].width = FB[mpcbdm_nBank].devices * FB[mpcbdm_nBank].bits;
+	FB[mpcbdm_nBank].EWA = 32 / FB[mpcbdm_nBank].width; /* number of elementar accesses needed for a 32 bit word */
+	FB[mpcbdm_nBank].fflash = NULL;
+	FB[mpcbdm_nBank].nfflash = 0;
+
+	switch (FB[mpcbdm_nBank].width)
+	{
+	case 8:
+		FB[mpcbdm_nBank].mask = 0xff;
+		FB[mpcbdm_nBank].align = 1;
+		FB[mpcbdm_nBank].shift = 0;
+		FB[mpcbdm_nBank].getword = ppc_bdm_getbyte;
+		FB[mpcbdm_nBank].setword = ppc_bdm_setbyte;
+		break;
+	case 16:
+		FB[mpcbdm_nBank].mask = 0xffff;
+		FB[mpcbdm_nBank].align = 2;
+		FB[mpcbdm_nBank].shift = 1;
+		FB[mpcbdm_nBank].getword = ppc_bdm_gethalfword;
+		FB[mpcbdm_nBank].setword = ppc_bdm_sethalfword;
+		break;
+	case 32:
+		FB[mpcbdm_nBank].mask = 0xffffffff;
+		FB[mpcbdm_nBank].align = 4;
+		FB[mpcbdm_nBank].shift = 2;
+		FB[mpcbdm_nBank].getword = ppc_bdm_getword; /* set default routines to 32 bit */
+		FB[mpcbdm_nBank].setword = ppc_bdm_setword; /* set default routines to 32 bit */
+		break;
+	default:
+		printf_filtered("FLASH bank %d misconfigured: found width %d for Addr:0x%08x\n",mpcbdm_nBank,FB[mpcbdm_nBank].width,Addr);
+		flash_free_bank();
+		if (f) fclose(f);
+		return;
+		break;
+	}
+
+	FB[mpcbdm_nBank].end = FB[mpcbdm_nBank].start + FB[mpcbdm_nBank].devices * FB[mpcbdm_nBank].size -1;
+	if (mpcbdm_verbose&VERBOSE_FLS)
+	{
+		printf_filtered("%s.end 0x%08x\n",FB[mpcbdm_nBank].sName,FB[mpcbdm_nBank].end);
+	}
+
+	sprintf(Buffer,".sector %s",sSector);
+	nResult = flash_file_node(f,Buffer,&nStart);
+	if (!nResult)
+	{
+		flash_free_bank();
+		if (f) fclose(f);
+		return;
+	}
+
+	FB[mpcbdm_nBank].Sector = malloc(sizeof(FlashSector)*MAXFLASHSECTORS);
+	if (!FB[mpcbdm_nBank].Sector)
+	{
+		printf_filtered("flash_configure:unable to allocate mem for sectors\n");
+		flash_free_bank();
+		if (f) fclose(f);
+		return;
+	}
+
+	FB[mpcbdm_nBank].nSectors = 0;
+	for (i = 0; (i < MAXFLASHSECTORS)&&(!feof(f) && !ferror(f)); i++)
+	{
+		nResult = flash_file_skipspace(f,'}',NULL);
+		if (nResult)
+		{
+			if (nComma)
+			{
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("flash_configure: unnecessary ',' in .sector %s\n",sSector);
+				}
+			}
+			break;
+		}
+		if ((i !=0 ) && (!nComma))
+		{
+			if (mpcbdm_verbose&VERBOSE_FLS)
+			{
+				printf_filtered("flash_configure: missing ',' in .sector %s entry %d\n",sSector,i);
+			}
+			break;
+		}
+
+		nResult = fscanf(f,"%i",&adr);
+		if (nResult != 1) break;
+		FB[mpcbdm_nBank].Sector[i].ID = adr;
+		nResult = flash_file_skipspace(f,',',NULL);
+		if (nResult != 1) break;
+		nResult = fscanf(f,"%i",&adr);
+		if (nResult != 1) break;
+		FB[mpcbdm_nBank].Sector[i].Start = (adr<<FB[mpcbdm_nBank].shift) + FB[mpcbdm_nBank].start;
+		nResult = flash_file_skipspace(f,',',NULL);
+		if (nResult != 1) break;
+		nResult = fscanf(f,"%i",&adr);
+		if (nResult != 1) break;
+		FB[mpcbdm_nBank].Sector[i].End = (adr<<FB[mpcbdm_nBank].shift) + FB[mpcbdm_nBank].start +(FB[mpcbdm_nBank].width)/8-1;
+		nComma = flash_file_skipspace(f,',',NULL);
+		if (!nResult)
+		{
+			nResult = flash_file_skipspace(f,'}',NULL);
+			break;
+		}
+	}
+	if (ferror(f) || (nResult != 1))
+	{
+		printf_filtered("flash_configure: error while parsing .sector %s\n",sSector);
+		flash_free_bank();
+		if (f) fclose(f);
+		return;
+	}
+	FB[mpcbdm_nBank].nSectors = i;
+	if ( (i>0) && (FB[mpcbdm_nBank].Sector[i-1].End != FB[mpcbdm_nBank].end) )
+	{
+		if (mpcbdm_verbose&VERBOSE_FLS)
+		{
+			printf_filtered("end of last sector not equal to end of bank?\n");
+		}
+	}
+
+	sprintf(Buffer,".algorithm %s",sAlgo);
+	nResult = flash_file_node(f,Buffer,&nStart);
+
+	if (!nResult)
+	{
+		flash_free_bank();
+		if (f) fclose(f);
+		return;
+	}
+	do
+	{
+		nResult = flash_file_skipspace(f,'}',NULL);
+		if (nResult)
+		{
+			break;
+		}
+		nResult = flash_file_find(f,".",NULL);
+		if (nResult)
+		{
+			fgets(FileBuffer,sizeof(FileBuffer),f);
+			pParse=FileBuffer;
+			if (strncmp(pParse,"reset",5) == 0)
+			{
+				pParse+=5;
+
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("flash_configure: %s.reset\n",FB[mpcbdm_nBank].sName);
+				}
+
+				nResult = flash_parse_cycle(&FB[mpcbdm_nBank].cReset);
+				if (!nResult)
+				{
+					printf_filtered("error in .algorithm %s .reset\n",sAlgo);
+					flash_free_bank();
+					if (f) fclose(f);
+					return;
+				}
+			}
+			else if (strncmp(pParse,"ident",5) == 0)
+			{
+				pParse+=5;
+
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("flash_configure: %s.ident\n",FB[mpcbdm_nBank].sName);
+				}
+
+				nResult = flash_parse_cycle(&FB[mpcbdm_nBank].cIdent);
+				if (!nResult)
+				{
+					printf_filtered("error in .algorithm %s .ident\n",sAlgo);
+					flash_free_bank();
+					if (f) fclose(f);
+					return;
+				}
+			}
+			else if (strncmp(pParse,"write",5) == 0)
+			{
+				pParse+=5;
+
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("flash_configure: %s.write\n",FB[mpcbdm_nBank].sName);
+				}
+
+				nResult = flash_parse_cycle(&FB[mpcbdm_nBank].cWrite);
+				if (!nResult)
+				{
+					printf_filtered("error in .algorithm %s .write\n",sAlgo);
+					flash_free_bank();
+					if (f) fclose(f);
+					return;
+				}
+			}
+			else if (strncmp(pParse,"erase",5) == 0)
+			{
+				pParse+=5;
+
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("flash_configure: %s.erase\n",FB[mpcbdm_nBank].sName);
+				}
+
+				nResult = flash_parse_cycle(&FB[mpcbdm_nBank].cErase);
+				if (!nResult)
+				{
+					printf_filtered("error in .algorithm %s .erase\n",sAlgo);
+					flash_free_bank();
+					if (f) fclose(f);
+					return;
+				}
+			}
+			else if (strncmp(pParse,"clear",5) == 0)
+			{
+				pParse+=5;
+
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("flash_configure: %s.clear\n",FB[mpcbdm_nBank].sName);
+				}
+
+				nResult = flash_parse_cycle(&FB[mpcbdm_nBank].cClear);
+				if (!nResult)
+				{
+					printf_filtered("error in .algorithm %s .clear\n",sAlgo);
+					flash_free_bank();
+					if (f) fclose(f);
+					return;
+				}
+			}
+			else if (strncmp(pParse,"cfast",5) == 0)
+			{
+				pParse+=5;
+
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("flash_configure: %s.cfast\n",FB[mpcbdm_nBank].sName);
+				}
+
+				nResult = flash_parse_cycle(&FB[mpcbdm_nBank].cFast);
+				if (!nResult)
+				{
+					printf_filtered("error in .algorithm %s .cfast\n",sAlgo);
+					flash_free_bank();
+					if (f) fclose(f);
+					return;
+				}
+			}
+			else if (strncmp(pParse,"fast",4) == 0)
+			{
+				pParse+=4;
+				sscanf(pParse,"%s",sFast);
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("%s.fast%d %s\n",FB[mpcbdm_nBank].sName,FB[mpcbdm_nBank].width,sFast);
+				}
+			}
+			else
+			{
+				printf_filtered("wrong syntax: %s",FileBuffer);
+			}
+		}
+	} while (!feof(f) && !ferror(f));
+
+	if (ferror(f))
+	{
+		printf_filtered("file error while parsing .device %s",mpcbdm_flashdev);
+		flash_free_bank();
+		if (f) fclose(f);
+		return;
+	}
+
+	if (sFast[0]!= 0)
+	{
+		sprintf(Buffer,".fast%d %s",FB[mpcbdm_nBank].width,sFast);
+		nResult = flash_file_node(f,Buffer,&nStart);
+
+		if (!nResult)
+		{
+			flash_free_bank();
+			if (f) fclose(f);
+			return;
+		}
+
+		FB[mpcbdm_nBank].fflash = malloc(sizeof(unsigned int)*MAXFLASHPRG);
+		if (!FB[mpcbdm_nBank].fflash)
+		{
+			printf_filtered("flash_configure:unable to allocate mem for fast flash routine\n");
+			flash_free_bank();
+			if (f) fclose(f);
+			return;
+		}
+
+		nComma = 0;
+		i = 0;
+		do
+		{
+			nResult = flash_file_skipspace(f,'}',NULL);
+			if (nResult)
+			{
+				if (nComma)
+				{
+					if (mpcbdm_verbose&VERBOSE_FLS)
+					{
+						printf_filtered("flash_configure: unnecessary comma...\n");
+					}
+				}
+				break;
+			}
+			nResult = flash_file_skipspace(f,'/',NULL); /* comment sign?*/
+			if (!nResult)
+			{
+				nResult = fscanf(f,"%x",&prg);
+				if (!nResult)
+				{
+					printf_filtered("flash_configure: %s expected instruction\n",Buffer);
+					flash_free_bank();
+					if (f) fclose(f);
+					return;
+				}
+				if (i >= MAXFLASHPRG)
+				{
+					printf_filtered("flash_configure: %s too many instructions\n",Buffer);
+					flash_free_bank();
+					if (f) fclose(f);
+					return;
+				}
+				FB[mpcbdm_nBank].fflash[i] = prg;
+				if (mpcbdm_verbose&VERBOSE_FLS)
+				{
+					printf_filtered("flash_configure: fflash[%d] =0x%08x\n",i,FB[mpcbdm_nBank].fflash[i]);
+				}
+				i++;
+				nComma=flash_file_skipspace(f,',',NULL);
+			}
+			else /* comment, skip end of row */
+			{
+				fgets(FileBuffer,sizeof(FileBuffer),f);
+			}
+
+		} while (!feof(f) && !ferror(f));
+		if (ferror(f))
+		{
+			printf_filtered("file error while parsing .device %s\n",mpcbdm_flashdev);
+			flash_free_bank();
+			if (f) fclose(f);
+			return;
+		}
+		FB[mpcbdm_nBank].nfflash = i;
+	}
+	mpcbdm_nBank++;
+	if (mpcbdm_verbose&VERBOSE_FLS)
+	{
+		printf_filtered("flash bank %d configured.\n",mpcbdm_nBank);
+	}
+
+	if (f) fclose(f);
+}
+/*****************************************************************/
+void flash_bank_reset(u_int Adr)
+{
+	int nResult;
+
+	flash_find_bank(Adr,1);
+	if (!pFB) return; /* no valid bank configuration found */
+	remote_prepare(NULL,0);
+	flash_load_sequence(pFB->cReset,Adr,0,1);
+	flash_execute_sequence(pFB->cReset,Adr,0);
+	remote_restore();
+}
+
+/*****************************************************************/
+int flash_ident(u_int Adr)
+{
+	int nResult;
+
+	flash_find_bank(Adr,1);
+	if (!pFB) return 0; /* no valid bank configuration found */
+	remote_prepare(NULL,0);
+	flash_load_sequence(pFB->cIdent,Adr,0,1);
+	nResult = flash_execute_sequence(pFB->cIdent,Adr,0);
+	remote_restore();
+	if (nResult)
+	{
+		printf_filtered("Ident Sequence: Ok!\n");
+	}
+	else
+	{
+		printf_filtered("Ident Sequence: failure?\n");
+	}
+	return nResult;
+}
+/*****************************************************************/
+void flash_program_file(char* sFilename,unsigned int destaddr)
+{
+	int i;
+	unsigned int len;
+	FILE * pf;
+	int nResult;
+	int bUseFast;
+	unsigned int Adr;
+	unsigned int Data;
+
+	unsigned int	nTotal;
+	unsigned int	nBuffer;
+	unsigned int	nLeft;
+
+	u_char * buffer = NULL;
+	u_char * rbuffer = NULL;
+
+	nResult = flash_find_bank(destaddr,0);
+	if (!pFB) return;
+
+	if (mpcbdm_fbuf % 4)
+	{
+		printf_filtered("mpcbdm_fbuf must be divisible by 4.\n");
+		return;
+	}
+	if (mpcbdm_fsizebuf % 4)
+	{
+		printf_filtered("mpcbdm_fsizebuf must be divisible by 4.\n");
+		return;
+	}
+
+	if (destaddr%pFB->align !=0)
+	{
+		printf_filtered("error: destination address has to be %d bytes aligned\n",pFB->align);
+		return; /* failure */
+	}
+
+	buffer = (u_char*)malloc(mpcbdm_fsizebuf);
+	if (!buffer)
+	{
+		printf_filtered("flash_program_file: unable to alloc host mem for buffer\n");
+		return;
+	}
+
+/* can we use fast flash ppc subroutines? */
+	bUseFast = 0;
+	if ((mpcbdm_fflash) && (pFB->fflash) && (pFB->nfflash>0) && (pFB->cFast))
+	{
+/* so it's faster to copy bufferwise into target and execute remote flashing per buffer */
+/* this mode seems only usefull, if using DPRAM and no other properly configured RAM is available*/
+/* else using 'mem load' and then 'flash copy' is more efficient */
+		rbuffer = (u_char*)malloc(mpcbdm_fsizebuf);
+		if (rbuffer)
+		{
+/* save target buffer content*/
+			ppc_bdm_read_block(mpcbdm_fbuf, rbuffer, mpcbdm_fsizebuf);
+			bUseFast = 1;
+			printf_filtered("Copying to flash with remote routines using buffer[0x%08x,0x%08x]...\n",mpcbdm_fbuf,mpcbdm_fbuf+mpcbdm_fsizebuf-1);
+		}
+		else
+		{
+			printf_filtered("flash_program_file: unable to alloc host mem for rbuffer\n");
+		}
+	}
+	else if (mpcbdm_fflash)
+	{
+		if ((!(pFB->fflash)) || (pFB->nfflash<=0))
+		{
+			printf_filtered("no fast flash routine configured\n");
+		}
+		else if (!(pFB->cFast))
+		{
+			printf_filtered("no fflash register preload (cfast) configured\n");
+		}
+	}
+
+	do /* for freeing resources on error, break */
+	{
+		pf=fopen(sFilename,"rb");
+		if(pf==NULL) /* could not open the file */
+		{
+			printf_filtered("Could not open the file\"%s\"\n",sFilename);
+			break;
+		}
+
+		nResult = fseek(pf, 0, SEEK_END);
+		if (nResult)
+		{
+			error("fseek error.");
+			break;
+		}
+		len = (unsigned int)ftell(pf);
+		rewind(pf);
+
+		if (destaddr+len > pFB->end)
+		{
+			printf_filtered("error: destination end 0x%08x exceeds bank border 0x%08x\n",destaddr+len,pFB->end);
+			break; /* failure */
+		}
+
+		i = query("Copy file \"%s\" len 0x%08x to FLASH at [0x%08x,0x%08x] ?",sFilename, len, destaddr, destaddr+len-1);
+    	if (i!=1) break;
+
+/* checking if we have to erase */
+		for (nTotal = 0, nLeft = len; nLeft > 0; nTotal += nBuffer, nLeft -= nBuffer)
+		{
+			if(nLeft > mpcbdm_fsizebuf)
+			{
+				nBuffer = mpcbdm_fsizebuf;
+			}
+			else
+			{
+				nBuffer = nLeft;
+			}
+			nResult = fread(buffer, 1, nBuffer, pf);
+			if (nResult != nBuffer)
+			{
+				error("read error.");
+				nResult = 0;
+				break;
+			}
+/* check buffer for zero writing to ones */
+			printf_filtered("checking FLASH [0x%08x,0x%08x]...\n",destaddr+nTotal,destaddr+nTotal+nBuffer-1);
+			if (bUseFast)
+			{
+				ppc_bdm_write_block(mpcbdm_fbuf, buffer, nBuffer);
+				nResult = flash_check_zeros(mpcbdm_fbuf,mpcbdm_fbuf+nBuffer-1, destaddr+nTotal, &Adr);
+			}
+			else
+			{
+				nResult = flash_check_zeros_host((unsigned int *)buffer, nBuffer, destaddr + nTotal,&Adr);
+			}
+			if (nResult)
+			{
+				printf_filtered("need to erase sector for 0x%08x\n",Adr);
+				nResult = flash_erase(Adr); /*try to erase sector*/
+				if (!nResult)
+				{
+					printf_filtered(" range not copied\n");
+					break; /* failure, exit for loop */
+				}
+			}
+			else /* no need to erase sector belonging to this buffer*/
+			{
+				nResult = 1; /* success for this buffer, set nResult not to break, if last sector */
+			}
+		}
+		if (!nResult) break; /* for loop failure */
+
+		rewind(pf);
+
+		if (bUseFast)
+		{
+			printf_filtered("Copying to Flash using remote routines...\n");
+		}
+		else
+		{
+			printf_filtered("Copying to Flash using host routines...\n");
+			remote_prepare(NULL,0); /*save GPRs*/
+		}
+		for (nTotal = 0, nLeft = len; nLeft > 0; nTotal += nBuffer, nLeft -= nBuffer)
+		{
+			if(nLeft > mpcbdm_fsizebuf)
+			{
+				nBuffer = mpcbdm_fsizebuf;
+			}
+			else
+			{
+				nBuffer = nLeft;
+			}
+			nResult = fread(buffer, 1, nBuffer, pf);
+			if (nResult != nBuffer)
+			{
+				error("read error.");
+				nResult = 0;
+				break;
+			}
+			printf_filtered("writing FLASH [0x%08x,0x%08x]...\n",destaddr+nTotal,destaddr+nTotal+nBuffer-1);
+			if (bUseFast)
+			{
+				ppc_bdm_write_block(mpcbdm_fbuf, buffer, nBuffer);
+				nResult = flash_fast_program(mpcbdm_fbuf,mpcbdm_fbuf+nBuffer-1, destaddr+nTotal, &Adr);
+				if (nResult !=0)
+				{
+					printf_filtered("error: FLASH failure at 0x%08x: nResult=0x%08x\n",Adr,nResult);
+					nResult = 0; /* failure */
+					break;
+				}
+				else
+				{
+					nResult = 1; /* we have to invert nResult since flash_fast_program uses 0 for success*/
+				}
+			}
+			else
+			{
+				for (i = 0; i < nBuffer; i+=4)
+				{
+					if (i+3 >= nBuffer)
+					{
+						printf_filtered("buffer len not divisible by 4, ommiting last subword\n");
+						nResult = 0;
+						break;
+					}
+/* we have to correct endianess here:*/
+					Data = extract_unsigned_integer(buffer+i, sizeof(Data));
+//					Data = *(unsigned int *)&(buffer[i]);
+					nResult = flash_write_word(destaddr+nTotal+i,Data,(nTotal == 0)&&(i == 0));
+					if (!nResult)
+					{
+						printf_filtered("error: FLASH failure at 0x%08x: nResult=0x%08x\n",Adr,nResult);
+						break;
+					}
+				}
+			}
+			if (!nResult) break;
+		}
+		if (!bUseFast)
+		{
+			remote_restore(); /*restore GPRs*/
+		}
+		break;
+	} while (1); /* for freeing resources on error, break */
+
+	if (rbuffer)
+	{
+/* restore target buffer content, if any */
+		ppc_bdm_write_block(mpcbdm_fbuf, rbuffer, mpcbdm_fsizebuf);
+		free(rbuffer);
+		rbuffer = NULL;
+	}
+
+	if (buffer)
+	{
+		free(buffer);
+		buffer = NULL;
+	}
+	if (nResult)
+	{
+		printf_filtered("FLASH writing completed\n");
+	}
+
+	if (ferror(pf))
+	{
+		printf_filtered(" file error while reading \"%s\" \n",sFilename);
+	}
+	if (pf)
+	{
+		fclose(pf);
+		pf = NULL;
+	}
+}
+/*****************************************************************/
+static void mpcbdm_flash(char *args, int from_tty)
+{
+	u_int Data,Addr; /* for single word write */
+	u_int Num;
+	u_int SourceStart,Source,SourceEnd,Destination; /* copy range and destination*/
+	char *sParse;
+	char *sFilename;
+
+	if (args == 0) /*no arguments, print info*/
+	{
+		flash_info();
+	}
+	else /* parsing conf, write, copy and erase */
+	{
+		sParse = args;
+		if (strncmp(sParse,"conf ",5) == 0)
+		{
+			sParse +=5;
+
+			if (strncmp(sParse,"clear",5) == 0)
+			{
+				for (;mpcbdm_nBank > 0;)
+				{
+					mpcbdm_nBank--;
+					flash_free_bank();
+				}
+				printf_filtered("flash config cleared\n");
+				return;
+			}
+			Addr = strtoul(sParse,&sParse,0); /* start ADDR of bank */
+			Num = strtoul(sParse,&sParse,0);  /* number of devices in parallel */
+			flash_configure(Addr,Num,sParse);
+		}
+		else if (strncmp(sParse,"ident",5) == 0)
+		{
+			sParse +=5;
+
+			Addr = strtoul(sParse,&sParse,0); /* ADDR of bank */
+			flash_ident(Addr);
+		}
+		else if (strncmp(sParse,"reset",5) == 0)
+		{
+			sParse +=5;
+
+			Addr = strtoul(sParse,&sParse,0); /* ADDR of bank */
+			flash_bank_reset(Addr);
+		}
+		else if (strncmp(sParse,"write ",6) == 0)
+		{
+			sParse +=6;
+
+			Addr = strtoul(sParse,&sParse,0); /*for testing Write ADDR*/
+			Data = strtoul(sParse,&sParse,0);  /*for testing write DATA*/
+
+			flash_write(Addr,Data);
+		}
+		else if (strncmp(sParse,"copy ",5) == 0)
+		{
+			sParse +=5;
+
+			SourceStart = strtoul(sParse,&sParse,0); /*source start addr*/
+			SourceEnd = strtoul(sParse,&sParse,0); /*source end addr*/
+			Destination = strtoul(sParse,&sParse,0);  /*for testing write DATA*/
+
+			flash_copy(SourceStart, SourceEnd, Destination);
+		}
+		else if (strncmp(sParse,"erase ",6) == 0)
+		{
+			sParse +=6;
+
+			Addr = strtoul(sParse,&sParse,0);
+
+			flash_erase(Addr);
+		}
+		else if (strncmp(sParse,"clear ",6) == 0)
+		{
+			sParse +=6;
+
+			Addr = strtoul(sParse,&sParse,0);
+
+			flash_clear(Addr);
+		}
+		else  if(strncmp(sParse,"file ",5)==0)
+		{
+			sParse+=5;
+
+			sFilename = parse_filename(&sParse);
+			if (!sFilename)
+			{
+				printf_filtered("error while parsing filename\n");
+				return;
+			}
+			if (*sParse=='\0') //no flash destination
+			{
+				printf_filtered("try 'help mpcbdm flash' for a list of supported commands\n");
+				return;
+			}
+			Destination = strtoul(sParse,&sParse,0);
+
+			flash_program_file(sFilename,Destination);
+
+		}
+		else
+		{
+			printf_filtered("try 'help mpcbdm flash' for a list of supported commands\n");
+		}
+	}
+}
+
+/***************************************************************
+* Automatic initialization from init.c to add target to gdb.   *
+* IMPORTANT: '_initialize_mpcbdm' have to be at the beginning  *
+* of the line, therefore the 'void' one line above. If not,    *
+* the target will not be initialized. So DO NOT touch the      *
+* following four lines !!!                                     *
+****************************************************************/
+void
+_initialize_mpcbdm (void)
+{
+	static struct cmd_list_element *mpcbdm_cmd_list = NULL;
+
+	init_mpcbdm_ops() ; /*init target operation structure*/
+	add_target (&mpcbdm_ops); /*add target to gdb*/
+
+	mpcbdm_flashdev = malloc(MAXBUFFERLEN);
+	if (mpcbdm_flashdev) strncpy(mpcbdm_flashdev,"Flash.dev",MAXBUFFERLEN);
+
+/* customizing target by adding obscure commands*/
+
+	add_show_from_set (add_set_cmd ("mpcbdm_adapter", no_class,
+		var_zinteger, (char *)&mpcbdm_adapter,
+		"Set adapter version.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_delay", no_class,
+		var_zinteger, (char *)&mpcbdm_delay,
+		"Set delay value for mpcbdm signals.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_power", no_class,
+		var_boolean, (char *)&mpcbdm_power,
+		"Set powering adapter from port.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_verbose", no_class,
+		var_zinteger, (char *)&mpcbdm_verbose,
+		"Set mask of verbosity for mpcbdm.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_mmu", no_class,
+		var_boolean, (char *)&mpcbdm_mmu,
+		"Set translating virtual addresses over mpcbdm.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_reattach", no_class,
+		var_boolean, (char *)&mpcbdm_reattach,
+		"Set reattach mode for resume.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_hwbrk", no_class,
+		var_boolean, (char *)&mpcbdm_hwbrk,
+		"Set using hardware registers for breakpoints.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_fflash", no_class,
+		var_boolean, (char *)&mpcbdm_fflash,
+		"Set using fast flashing routines.\n", &setlist),
+		&showlist);
+
+
+	add_show_from_set (add_set_cmd ("mpcbdm_flashdev", no_class,
+		var_filename, (char *)&mpcbdm_flashdev,
+		"Set flash device description file.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_dflush", no_class,
+		var_boolean, (char *)&mpcbdm_dflush,
+		"Set automatic data cache flushing on returning into mpcbdm .\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_relaxed", no_class,
+		var_boolean, (char *)&mpcbdm_relaxed,
+		"Set relaxed BDM port timing.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_wait", no_class,
+		var_zinteger, (char *)&mpcbdm_wait,
+		"Set number of wait-for-DSDO-goes-low cycles.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_toggle", no_class,
+		var_zinteger, (char *)&mpcbdm_toggle,
+		"Set number of wait-FLASH-toggle cycles.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_fquery", no_class,
+		var_boolean, (char *)&mpcbdm_fquery,
+		"Set confirm query for erases and writes to flash.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_fbuf", no_class,
+		var_zinteger, (char *)&mpcbdm_fbuf,
+		"Set address of buffer for FLASH file.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_fsizebuf", no_class,
+		var_zinteger, (char *)&mpcbdm_fsizebuf,
+		"Set size of buffer for FLASH file.\n", &setlist),
+		&showlist);
+
+	add_show_from_set (add_set_cmd ("mpcbdm_pram", no_class,
+		var_zinteger, (char *)&mpcbdm_pram,
+		"Set pointer to RAM where to load the fast remote routines to.\n", &setlist),
+		&showlist);
+
+	add_prefix_cmd ("mpcbdm", class_obscure, bdm_command,
+  		"Use On-Chip Debugging on MPC's via parallel port BDM interface",
+		&mpcbdm_cmd_list, "mpcbdm ",	0, &cmdlist);
+
+	add_cmd ("reset", class_obscure, mpcbdm_reset_command,
+		"send /HRESET signal to MPC", &mpcbdm_cmd_list);
+
+	add_cmd ("restart", class_obscure, mpcbdm_restart_command,
+		"resetting and stopping target MPC", &mpcbdm_cmd_list);
+
+	add_cmd ("spr", class_obscure, mpcbdm_spr_command,
+	  "show or set value of MPC's spr, give number or name", &mpcbdm_cmd_list);
+
+	add_cmd ("sprs", class_obscure, show_spr,
+	  "show important sprs", &mpcbdm_cmd_list);
+
+	add_cmd ("upms", class_obscure, mpcbdm_obscure_upms,
+	  "show settings of upms", &mpcbdm_cmd_list);
+
+	add_cmd ("flash", class_obscure, mpcbdm_flash,
+	"program and erase flash memory\n\
+without arguments to get info about banks\n\
+'conf ADR NUM NAME' to configure next bank from ADR, NUM devices of type NAME\n\
+'conf clear' to empty all flash configurations\n\
+'ident ADR' to run an ident cycle on FLASH\n\
+'reset ADR' to run an reset cycle on FLASH\n\
+'write ADR DATA' to write single word to FLASH\n\
+'copy SOURCESTART SOURCEEND DESTINATION' for writing to FLASH\n\
+'erase ADR' to erase FLASH sector containing address\n\
+'clear ADR' to clear FLASH bank containing address\n\
+'file \"FILE\" DESTINATION' to write a file to FLASH\n "\
+, &mpcbdm_cmd_list);
+
+	add_cmd ("port", class_obscure, mpcbdm_port,
+	  "show settings of adapter port", &mpcbdm_cmd_list);
+
+	add_cmd ("mem", class_obscure, mpcbdm_mem,
+	"load/save memory contents from/to file\n\
+'load \"FILE\" DESTINATION [LEN]'\n\
+'save \"FILE\" SOURCE LEN'\n"\
+, &mpcbdm_cmd_list);
+
+	add_cmd ("icache", class_obscure, mpcbdm_icache,
+	"show instruction cache entries\n"\
+, &mpcbdm_cmd_list);
+
+	add_cmd ("dcache", class_obscure, mpcbdm_dcache,
+	"data cache commands\n\
+'[ADR]' without subcommand display whole data cache, or specific [ADR] entry\n\
+'flush [ADR]' to flush all or selected blocks\n"\
+, &mpcbdm_cmd_list);
+
+	add_cmd ("mmu", class_obscure, mpcbdm_cmd_mmu,
+	"mmu commands\n\
+without subcommand display mmu status and mpcbdm mmu settings\n\
+'ADR' display address translation if mmu is enabled\n\
+'data' display dmmu register contents\n\
+'inst' display immu register contents\n\
+'kbase [ADR]' display [or set] kernel base address\n\
+'pgdir [ADR]' display [or set] kernel swapper_pg_dir address\n\
+'on|off' enable|disable mpcbdm tablewalk\n"\
+, &mpcbdm_cmd_list);
+
+	PP.Power = PortError;
+	PP.Write = PortError;
+	PP.Reset = PortError;
+	PP.Status = PortErrorV;
+	PP.port = -1;
+}
diff -urN gdb-5.2.1/gdb/mpcbdm.h gdb-5.2.1-mpcbdm/gdb/mpcbdm.h
--- gdb-5.2.1/gdb/mpcbdm.h	Wed Dec 31 19:00:00 1969
+++ gdb-5.2.1-mpcbdm/gdb/mpcbdm.h	Mon Jan 27 21:15:33 2003
@@ -0,0 +1,578 @@
+
+#ifndef _MPCBDM_H_
+#define _MPCBDM_H_
+
+#define MAXBUFFERLEN 256		/* needs to be at least word aligned!*/
+#define MAXFLASHBANKS 4
+#define MAXFLASHSECTORS 1024
+#define MAXFLASHCYCLES 10		/* using maximum 2*10 ppc registers for flash preload*/
+#define MAXFLASHPRG 100
+
+#define PPC_BITS	32
+#define PPC_BIT(x) (1 << (PPC_BITS-1-(x)))
+
+// Commands of Development Port Shift Register
+
+#define DSDI_PREF3_CORE_INSTRUCTION	0x4	// +32 bits
+#define DSDI_PREF3_CORE_DATA		0x5	// +32 bits
+#define DSDI_PREF3_TECR			0x6	// +7 bits
+#define DSDI_PREF3_DPC			0x7	// +7 bits
+
+#define DSDI_DPC_NOP 			0
+#define DSDI_DPC_HRESET			0x1
+#define DSDI_DPC_SRESET			0x2
+#define DSDI_DPC_END_DOWNLOAD		0x43
+#define DSDI_DPC_START_DOWNLOAD		0x63
+#define DSDI_DPC_NEGATE_MASK_BREAK	0x1f
+#define DSDI_DPC_ASSERT_MASK_BREAK	0x3f
+#define DSDI_DPC_NEGATE_NMASK_BREAK	0x1f
+#define DSDI_DPC_ASSERT_NMASK_BREAK	0x7f
+
+#define DSDO_CORE_DATA		0x0	// +32 bits
+#define DSDO_SEQ_ERROR		0x1	// +2 bits + xx
+#define DSDO_CORE_INTERRUPT	0x2	// +2 bits + xx
+#define DSDO_NULL		0x3	// +2 bits + xx
+
+
+#define DSDI_COM_NOP  	0x60000000
+#define DSDI_COM_RFI  	0x4C000064
+#define DSDI_COM_ICR  	0x7C1422A6
+#define DSDI_COM_DER  	0x7C1522A6
+#define DSDI_COM_MFMSR  0x7C0000A6
+#define DSDI_COM_MTSPR  0x7C169BA6
+
+#define GPR_REG_MASK	0x2000
+
+#define SPR_XER		1
+#define SPR_LR		8
+#define SPR_CTR		9
+#define SPR_TBLR	268
+#define SPR_TBUR	269
+#define SPR_DSISR	18
+#define SPR_DAR		19
+#define SPR_DEC		22
+#define SPR_SRR0	26
+#define SPR_SRR1	27
+#define SPR_SPRG0	272
+#define SPR_SPRG1	273
+#define SPR_SPRG2	274
+#define SPR_SPRG3	275
+#define SPR_TBLW	284
+#define SPR_TBUW	285
+#define SPR_PVR		287
+#define SPR_EIE		80
+#define SPR_EID		81
+#define SPR_NRI		82
+#define SPR_DPIR	631
+#define SPR_IMMR	638
+#define SPR_IC_CST	560
+#define SPR_IC_ADR	561
+#define SPR_IC_DAT	562
+#define SPR_DC_CST	568
+#define SPR_DC_ADR	569
+#define SPR_DC_DAT	570
+#define SPR_MI_CTR	784
+#define SPR_MI_AP	786
+#define SPR_MI_EPN	787
+#define SPR_MI_TWC	789
+#define SPR_MI_RPN	790
+#define SPR_MI_CAM	816
+#define SPR_MI_RAM0	817
+#define SPR_MI_RAM1	818
+#define SPR_MD_CTR	792
+#define SPR_M_CASID	793
+#define SPR_MD_AP	794
+#define SPR_MD_EPN	795
+#define SPR_M_TWB	796
+#define SPR_MD_TWC	797
+#define SPR_MD_RPN	798
+#define SPR_M_TW	799
+#define SPR_MD_CAM	824
+#define SPR_MD_RAM0	825
+#define SPR_MD_RAM1	826
+#define SPR_CMPA	144
+#define SPR_CMPB	145
+#define SPR_CMPC	146
+#define SPR_CMPD	147
+#define SPR_ICR		148
+#define SPR_DER		149
+#define SPR_COUNTA	150
+#define SPR_COUNTB	151
+#define SPR_CMPE	152
+#define SPR_CMPF	153
+#define SPR_CMPG	154
+#define SPR_CMPH	155
+#define SPR_LCTRL1	156
+#define SPR_LCTRL2	157
+#define SPR_ICTRL	158
+#define SPR_BAR		159
+#define SPR_DPDR	630
+
+#define SPRI_REV_NUM 0x3cb0
+
+#define SPRI_MASK	0x10000
+#define SPRI_SIUMCR	(SPRI_MASK | 0x000)
+#define SPRI_SYPCR	(SPRI_MASK | 0x004)
+#define SPRI_SWSR	(SPRI_MASK | 0x00E)  /* 16 bit 556C AA39 */
+#define SPRI_SCCR	(SPRI_MASK | 0x280)
+#define SPRI_PLPRCR	(SPRI_MASK | 0x284)
+#define SPRI_RSR	(SPRI_MASK | 0x288)
+#define SPRI_BRx(x)	(SPRI_MASK | (0x100 + (x)*8))
+#define SPRI_ORx(x)	(SPRI_MASK | (0x104 + (x)*8))
+#define SPRI_MAMR	(SPRI_MASK | 0x170)
+#define SPRI_MBMR	(SPRI_MASK | 0x174)
+#define SPRI_MCR	(SPRI_MASK | 0x168)
+#define SPRI_MAR	(SPRI_MASK | 0x164)
+#define SPRI_MDR	(SPRI_MASK | 0x17C)
+#define SPRI_MSTAT	(SPRI_MASK | 0x178)    /* MSTAT MPTPR */
+
+#define SPR_MASK	0x20000
+
+#define SPR_MSR		(SPR_MASK | 0x1)
+#define SPR_CR		(SPR_MASK | 0x2)
+
+
+#define PPC_I_R0R1   0x90010000   /* stw 0,0(1) # mov r0,@r1 */
+#define PPC_I_R0R1hw 0xB0010000    /* stw 0,0(1) # movh r0,@r1 */
+#define PPC_I_R1R0   0x80010000   /* lwz 0,0(1) # mov @r1,r0 */
+
+/* from ppc_sprnames.h*/
+
+typedef struct
+{
+  char *name;	/*motorola name for spr*/
+  int num;		/*spr number*/
+  char *Namefield; /*(Na|Nb..|Ne) Acronyms of bitfield plus start and end*/
+  char *Longname; /*no acronym*/
+  char *Reference; /*where to find documentation*/
+} SPRNAME;
+
+SPRNAME sprnames[] =
+{
+{"XER",		1 ,"SO|OV|CA||25BCNT","","UM141"},
+{"LR",		8 ,"","Link Register"},
+{"CTR",		9 ,"","Counter Register"},
+{"DSISR",	18 },
+{"DAR",		19 },
+{"DEC",		22 ,"","Decrementer Register","UM297"},
+{"SRR0",	26 },
+{"SRR1",	27 ,"||16EE|PR|FP|ME||SE|BE||26IR|DR||30RI|LE","Machine Status Save/Restore Register1","UM145"},
+{"EIE",		80 },
+{"EID",		81 },
+{"NRI",		82 },
+{"CMPA",	144 ,"","Comparator A Value Register (instr)","UM987"},
+{"CMPB",	145 ,"","Comparator B Value Register (instr)","UM987"},
+{"CMPC",	146 ,"","Comparator C Value Register (instr)","UM987"},
+{"CMPD",	147 ,"","Comparator D Value Register (instr)","UM987"},
+{"ICR",		148 ,"|RST|CHSTP|MCI||6EXTI|ALI|PRI|FPUVI|DECI||13SYSI|TR||17SEI|ITLBMS|DTBLMS|ITLBER|DTLBER||28LBRK|IBRK|EBRK|DPI","Interrupt Cause Register","UM994"},
+{"DER",		149 ,"|RSTE|CHSTPE|MCIE||6EXTIE|ALIE|PRIE|FPUVIE|DECIE||13SYSIE|TRE||17SEIE|ITLBMSE|DTLBMSE|ITLBERE|DTBLERE||28LBRKE|IBRKE|EBRKE|DPIE","Debug Enable Register","UM996"},
+{"COUNTA",	150 ,"CNTCV|16|30CNTC","Breakpoint Counter Value and Control A Register","UM994"},
+{"COUNTB",	151 ,"CNTCV|16|30CNTC","Breakpoint Counter Value and Control B Register","UM994"},
+{"CMPE",	152 ,"","Comparator E Value Register (addr)","UM987"},
+{"CMPF",	153 ,"","Comparator F Value Register (addr)","UM987"},
+{"CMPG",	154 ,"","Comparator G Value Register (data)","UM987"},
+{"CMPH",	155 ,"","Comparator H Value Register (data)","UM987"},
+{"LCTRL1",	156 ,"CTE|3CTF|6CTG|9CTH|12CRWE|14CRWF|16CSG|18CSH|20SUSG|SUSH|CGBMSK|26CHBMSK|30","Load/Store Support Comparators Control Register","UM990"},
+{"LCTRL2",	157 ,"LW0EN|LW0IA|3LW0IADC|LW0LA|6LW0LADC|LW0LD|9LW0LDDC|LW1EN|LW1IA|13LW1IADC|LW1LA|16LW1LADC|LW1LD|19LW1LDDC|BRKNOMSK||28DLW0EN|DLW1EN|SLW0EN|SLW1EN","Load/Store Support AND-OR Control Register","UM991"},
+{"ICTRL",	158 ,"CTA|3CTB|6CTC|9CTD|12IW0|14IW1|16IW2|18IW3|20SIW0EN|SIW1EN|SIW2EN|SIW3EN|DIW0EN|DIW1EN|DIW2EN|DIW3EN|IFM|ISCT_SER","Instruction Support Control Register","UM989"},
+{"BAR",		159 },
+{"TBLR",	268 },
+{"TBUR",	269 },
+{"SPRG0",	272 },
+{"SPRG1",	273 },
+{"SPRG2",	274 },
+{"SPRG3",	275 },
+{"TBLW",	284 },
+{"TBUW",	285 },
+{"PVR",		287 },
+{"IC_CST",	560 ,"IEN||4CMD|7|10CCER1|CCER2|CCER3|","Instruction Cache Control and Status Register","UM200"},
+{"IC_ADR",	561 ,"|18Data|Way1||Set|28Word|30","Instruction Cache Address Register","UM202"},
+{"IC_DAT",	562 ,"Tag|21|Valid|Locked|LRU|","Instruction Cache Data Port Register","UM202"},
+{"DC_CST",	568 ,"DEN|DFWT|LES||CMD|8|10CCER1|CCER2|CCER3|","Data Cache Control an Status Register","UM205"},
+{"DC_ADR",	569 ,"|18Cbb|Way1||Set|28","Data Cache Address Register","UM208"},
+{"DC_DAT",	570 ,"Tag|21|Valid|Locked|LRU|Modified|","Data Cache Data Port Register","UM209"},
+{"DPDR",	630 },
+{"DPIR",	631 },
+{"IMMR",	638 ,"ISB|16PARTNUM|24MASKNUM","Internal Memory Map Register","UM279"},
+{"MI_CTR",	784 ,"GPM|PPM|CIDEF||RSV4I||PPCS||19ITLB_INDX|24","IMMU Control Register","UM242"},
+{"MI_AP",	786 ,"GP0|2GP1|4GP2|6GP3|8GP4|10GP5|12GP6|14GP7|16GP8|18GP9|20GP10|22GP11|24GP12|26GP13|28GP14|30GP15","IMMU Access Protection Register","UM250"},
+{"MI_EPN",	787 ,"EPN|20|22EV||28ASID", "IMMU Effective Page Number Register","UM244"},
+{"MI_TWC",	789 ,"|23APG|G|PS|30|V","IMMU Tablewalk Control Register","UM244"},
+{"MI_RPN",	790 ,"RPN|20|PP|28SPS|SH|CI|V","IMMU Real Page Number Register","UM246"},
+{"MD_CTR",	792 ,"GPM|PPM|CIDEF|WTDEF|RSV4D|TWAM|PPCS||19DTLB_INDX|24","DMMU Control Register","UM243"},
+{"M_CASID",	793 ,"|28CASID","MMU Current Address Space ID Register","UM249"},
+{"MD_AP",	794 ,"GP0|2GP1|4GP2|6GP3|8GP4|10GP5|12GP6|14GP7|16GP8|18GP9|20GP10|22GP11|24GP12|26GP13|28GP14|30GP15","DMMU Access Protection Register","UM250"},
+{"MD_EPN",	795 ,"EPN|20|22EV||28ASID", "IMMU Effective Page Number Register","UM244"},
+{"M_TWB",	796 ,"L1TB|20L1INDX|30","MMU Tablewalk Base Register","UM249"},
+{"MD_TWC",	797 ,"L2TB|20|23APG|27G|PS|30WT|V","DMMU Tablewalk Control Register","UM245"},
+{"MD_RPN",	798 ,"RPN|20PP|28SPS|SH|CI|V","DMMU Real Page Number Register","UM248"},
+{"M_TW",	799 ,0,"MMU Tablewalk Special Register","UM250"},
+{"MI_CAM",	816 ,"EPN|20PS|23ASID|27SH|SPV","IMMU CAM Entry Read Register","UM251"},
+{"MI_RAM0",	817 ,"RPN|20PS_B|23CI|APG|28SFP","IMMU RAM Entry Read Register 0","UM252"},
+{"MI_RAM1",	818 ,"|26UFP|30PV|G","IMMU RAM Entry Read Register 1","UM253"},
+{"MD_CAM",	824 ,"EPN|20SPVF|24PS|27SH|ASID","DMMU CAM Entry Read Register","UM254"},
+{"MD_RAM0",	825 ,"RPN|20PS|23APGI|27G|WT|CI|","DMMU RAM Entry Read Register 0","UM255"},
+{"MD_RAM1",	826 ,"|16RES|C|EVF|SA|23SAT|URP0|UWP0|URP1|UWP1|URP2|UWP2|URP3|UWP3","DMMU RAM Entry Read Register 1","UM256"},
+//{"",		(SPRI_MASK|0x0), "","",""},
+{"SIUMCR",	(SPRI_MASK|0x000) ,"EARB|EARP|4|8DSHW|DBGC|11DBPC|13|FRC|DLK|OPAR|PNCS|DPC|MPRE|MLRC|22AEME|SEME|BSC|GB5E|B2DD|B3DD|","SIU Module Configuration Register","UM280"},
+{"SYPCR",	(SPRI_MASK|0x004), "SWTC|16BMT|24BME||28SWF|SWE|SWRI|SWP","System Protection Control Register","UM283"},
+{"SWSR",	(SPRI_MASK|0x00E), "","Software Service Register","UM296"}, /*16bit556CAA39*/
+{"SIPEND",	(SPRI_MASK|0x010), "IRQ0|LVL0|IRQ1|LVL1|IRQ2|LVL2|IRQ3|LVL3|IRQ4|LVL4|IRQ5|LVL5|IRQ6|LVL6|IRQ7|LVL7|","SIU Interrupt Pending Register","UM291"},
+{"SIMASK",	(SPRI_MASK|0x014), "IRM0|LVM0|IRM1|LVM1|IRM2|LVM2|IRM3|LVM3|IRM4|LVM4|IRM5|LVM5|IRM6|LVM6|IRM7|LVM7|","SIU Interrupt Mask Register","UM291"},
+{"SIEL",	(SPRI_MASK|0x018), "ED0|WM0|ED1|WM1|ED2|WM2|ED3|WM3|ED4|WM4|ED5|WM5|ED6|WM6|ED7|WM7|","SIU Interrupt Edge/Level Register","UM292"},
+{"SIVEC",	(SPRI_MASK|0x01c), "INTC|8","SIU Interrupt Vector Register","UM293"},
+{"TESR",	(SPRI_MASK|0x020), "|18IEXT|ITMT|IPB0|IPB1|IPB2|IPB3||26DEXT|DTMT|DPB0|DPB1|DPB2|DPB3","Transfer Error Status Register","UM284"},
+{"SDCR",	(SPRI_MASK|0x032), "|17FRZ|19|25AM||30RAID","SDMA Configuration Register","UM570"},
+{"PBR0",	(SPRI_MASK|0x080), "","PCMCIA Base Register 0","UM516"},
+{"POR0",	(SPRI_MASK|0x084), "BSIZE|5|12PSHT|16PSST|20PSL|25PPS|PRS|29PSLOT|WP|PV","PCMCIA Option Register 0","UM517"},
+{"PBR1",	(SPRI_MASK|0x088), "","PCMCIA Base Register 1","UM516"},
+{"POR1",	(SPRI_MASK|0x08C), "BSIZE|5|12PSHT|16PSST|20PSL|25PPS|PRS|29PSLOT|WP|PV","PCMCIA Option Register 1","UM517"},
+{"PBR2",	(SPRI_MASK|0x090), "","PCMCIA Base Register 2","UM516"},
+{"POR2",	(SPRI_MASK|0x094), "BSIZE|5|12PSHT|16PSST|20PSL|25PPS|PRS|29PSLOT|WP|PV","PCMCIA Option Register 2","UM517"},
+{"PBR3",	(SPRI_MASK|0x098), "","PCMCIA Base Register 3","UM516"},
+{"POR3",	(SPRI_MASK|0x09C), "BSIZE|5|12PSHT|16PSST|20PSL|25PPS|PRS|29PSLOT|WP|PV","PCMCIA Option Register 3","UM517"},
+{"PBR4",	(SPRI_MASK|0x0A0), "","PCMCIA Base Register 4","UM516"},
+{"POR4",	(SPRI_MASK|0x0A4), "BSIZE|5|12PSHT|16PSST|20PSL|25PPS|PRS|29PSLOT|WP|PV","PCMCIA Option Register 4","UM517"},
+{"PBR5",	(SPRI_MASK|0x0A8), "","PCMCIA Base Register 5","UM516"},
+{"POR5",	(SPRI_MASK|0x0AC), "BSIZE|5|12PSHT|16PSST|20PSL|25PPS|PRS|29PSLOT|WP|PV","PCMCIA Option Register 5","UM517"},
+{"PBR6",	(SPRI_MASK|0x0B0), "","PCMCIA Base Register 6","UM516"},
+{"POR6",	(SPRI_MASK|0x0B4), "BSIZE|5|12PSHT|16PSST|20PSL|25PPS|PRS|29PSLOT|WP|PV","PCMCIA Option Register 6","UM517"},
+{"PBR7",	(SPRI_MASK|0x0B8), "","PCMCIA Base Register 7","UM516"},
+{"POR7",	(SPRI_MASK|0x0BC), "BSIZE|5|12PSHT|16PSST|20PSL|25PPS|PRS|29PSLOT|WP|PV","PCMCIA Option Register 7","UM517"},
+{"PGCRA",	(SPRI_MASK|0x0E0), "CxIREQLVL|8CxSCHLVL|16CxDREQ|18|24CxOE|CxReset|","PCMCIA Interface General Control Register","UM516"},
+{"PGCRB",	(SPRI_MASK|0x0E4), "CxIREQLVL|8CxSCHLVL|16CxDREQ|18|24CxOE|CxReset|","PCMCIA Interface General Control Register","UM516"},
+{"PSCR",	(SPRI_MASK|0x0E8), "CAVS1_C|CAVS2_C|CAWP_C|CACD2_C|CACD1_C|CABVD2_C|CABVD1_C||CARDY_L|CARDY_H|CARDY_R|CARDY_F||16CBVS1_C|CBVS2_C|CBWP_C|CBCD2_C|CBCD1_C|CBBVD2_C|CBBVD1_C||CBRDY_L|CBRDY_H|CBRDY_R|CBRDY_F|","PCMCIA Interface Status Changed Register","UM513"},
+{"PIPR",	(SPRI_MASK|0x0F0), "CAVS1|CAVS2|CAWP|CACD2|CACD1|CABVD2|CABVD1|CARDY||16CBVS1|CBVS2|CBWP|CBCD2|CBCD1|CBBVD2|CBBVD1|CBRDY|","PCMCIA Interface Input Pins Register","UM512"},
+{"PER",		(SPRI_MASK|0x0F8), "CA_EVS1_C|CA_EVS2_C|CA_EWP_C|CA_ECD2_C|CA_ECD1_C|CA_EBVD2_C|CA_EBVD1_C||CA_ERDY_L|CA_ERDY_H|CA_ERDY_R|CA_ERDY_F||16CB_EVS1_C|CB_EVS2_C|CB_EWP_C|CB_ECD2_C|CB_ECD1_C|CB_EBVD2_C|CB_EBVD1_C||CB_ERDY_L|CB_ERDY_H|CB_ERDY_R|CB_ERDY_F|","PCMCIA Interface Enable Register","UM514"},
+{"BR0",		(SPRI_MASK|0x100), "BA|17AT|20PS|22PARE|WP|MS|26|31V","Base Register 0","UM435"},
+{"OR0", 	(SPRI_MASK|0x104), "AM|17ATM|20CSNT/SAM|ACS/G5LA,G5LS|23BIH|SCY|28SETA|TRLX|EHTR|","Option Register 0","UM437"},
+{"BR1",		(SPRI_MASK|0x108), "BA|17AT|20PS|22PARE|WP|MS|26|31V","Base Register 1","UM435"},
+{"OR1", 	(SPRI_MASK|0x10c), "AM|17ATM|20CSNT/SAM|ACS/G5LA,G5LS|23BIH|SCY|28SETA|TRLX|EHTR|","Option Register 1","UM437"},
+{"BR2",		(SPRI_MASK|0x110), "BA|17AT|20PS|22PARE|WP|MS|26|31V","Base Register 2","UM435"},
+{"OR2", 	(SPRI_MASK|0x114), "AM|17ATM|20CSNT/SAM|ACS/G5LA,G5LS|23BIH|SCY|28SETA|TRLX|EHTR|","Option Register 2","UM437"},
+{"BR3",		(SPRI_MASK|0x118), "BA|17AT|20PS|22PARE|WP|MS|26|31V","Base Register 3","UM435"},
+{"OR3", 	(SPRI_MASK|0x11c), "AM|17ATM|20CSNT/SAM|ACS/G5LA,G5LS|23BIH|SCY|28SETA|TRLX|EHTR|","Option Register 3","UM437"},
+{"BR4",		(SPRI_MASK|0x120), "BA|17AT|20PS|22PARE|WP|MS|26|31V","Base Register 4","UM435"},
+{"OR4", 	(SPRI_MASK|0x124), "AM|17ATM|20CSNT/SAM|ACS/G5LA,G5LS|23BIH|SCY|28SETA|TRLX|EHTR|","Option Register 4","UM437"},
+{"BR5",		(SPRI_MASK|0x128), "BA|17AT|20PS|22PARE|WP|MS|26|31V","Base Register 5","UM435"},
+{"OR5", 	(SPRI_MASK|0x12c), "AM|17ATM|20CSNT/SAM|ACS/G5LA,G5LS|23BIH|SCY|28SETA|TRLX|EHTR|","Option Register 5","UM437"},
+{"BR6",		(SPRI_MASK|0x130), "BA|17AT|20PS|22PARE|WP|MS|26|31V","Base Register 6","UM435"},
+{"OR6", 	(SPRI_MASK|0x134), "AM|17ATM|20CSNT/SAM|ACS/G5LA,G5LS|23BIH|SCY|28SETA|TRLX|EHTR|","Option Register 6","UM437"},
+{"BR7",		(SPRI_MASK|0x138), "BA|17AT|20PS|22PARE|WP|MS|26|31V","Base Register 7","UM435"},
+{"OR7", 	(SPRI_MASK|0x13c), "AM|17ATM|20CSNT/SAM|ACS/G5LA,G5LS|23BIH|SCY|28SETA|TRLX|EHTR|","Option Register 7","UM437"},
+{"MAR",		(SPRI_MASK|0x164), "", "Memory Address Register","UM443"},
+{"MCR",		(SPRI_MASK|0x168), "OP|2|8UM||16MB|19|MCLF|24|26MAD","Memory Command Register","UM441"},
+{"MAMR",	(SPRI_MASK|0x170), "PTA|8PTAE|AMA|12|DSA|15|G0CLA|19GPLA4DIS|RLFA|24WLFA|28TLFA","Machine A Mode Register","UM440"},
+{"MBMR",	(SPRI_MASK|0x174), "PTB|8PTBE|AMB|12|DSB|15|G0CLB|19GPLB4DIS|RLFB|24WLFB|28TLFB","Machine B Mode Register","UM440"},
+{"MSTAT",	(SPRI_MASK|0x178), "PER0|PER1|PER2|PER3|PER4|PER5|PER6|PER7|WPER||16PTP|24","Memory Status Register & Periodic Timer","UM439"}, /*contains both MSTAT,MPTPR*/
+{"MDR",		(SPRI_MASK|0x17C), "CST4|CST1|CST2|CST3|BST4|BST1|BST2|BST3|G0L|10G0H|12G1T4|G1T3|G2T4|G2T3|G3T4|G3T3|G4T4/DLT3|G4T3/WAEN|G5T4|G5T3||24LOOP|EXEN|AMX|28NA|UTA|TODT|LAST", "Memory Data Register", "UM442"},
+{"TBSCR",	(SPRI_MASK|0x200), "TBIRQ|8REFA|REFB||12REFAE|REFBE|TBF|TBE|","Timebase Status and Control Register","UM300"}, /*16bit!*/
+{"TBREFA",	(SPRI_MASK|0x204), "","Timebase Reference Register A","UM299"},
+{"TBREFB",	(SPRI_MASK|0x208), "","Timebase Reference Register B","UM299"},
+{"RTCSC",	(SPRI_MASK|0x220), "RTCIRQ|8SEC|ALR||teK|SIE|ALE|RTF|RTE|","Real-Time Clock Status and Control Register","UM301"}, /*16bit!, teK = 38K*/
+{"RTC",		(SPRI_MASK|0x224), "","Real-Time Clock Register","UM302"},
+{"RTSEC",	(SPRI_MASK|0x228), "COUNTER|14","Real-Time Clock Alarm Seconds Register","UM304"},
+{"RTCAL",	(SPRI_MASK|0x22C), "","Real-Time Clock Alarm Register","UM303"},
+{"PISCR",	(SPRI_MASK|0x240), "PIRQ|8PS||13PIE|PITF|PTE|","Periodic Interrupt Status and Control Register","UM305"}, /*16bit!*/
+{"PITC",	(SPRI_MASK|0x244), "PITC|16","PIT Count Register","UM306"},
+{"PITR",	(SPRI_MASK|0x248), "PIT|16","PIT Register","UM307"},
+{"SCCR",	(SPRI_MASK|0x280), "|COM|3|6TBS|RTDIV|RTSEL|CRQEN|PRQEN||13EBDF|15|17DFSYNC|19DFBRG|21DFNL|24DFNH|27","System Clock and Reset Control Register","UM421"},
+{"PLPRCR",	(SPRI_MASK|0x284), "MF|12|16SPLSS|TEXPS||TMIST||CSRC|LPM|24CSR|LOLRE|FIOPD|","PLL, Low-Power and Reset Control Register","UM423"},
+{"RSR",		(SPRI_MASK|0x288), "EHRS|ESRS|LLRS|SWRS|CSRS|DBHRS|DBSRS|JTRS|","Reset Status Register","UM313"},
+{"TBSCRK",	(SPRI_MASK|0x300), "","Timebase Status and Control Register Key","UM285"},
+{"CIVR",	(SPRI_MASK|0x930), "VN|5|15IACK|","CPM Interrupt Vector Register 16 bit","UM912"}, /*16bit!*/
+{"CICR",	(SPRI_MASK|0x940), "|8SCdP|10SCcP|12SCbP|14SCaP|16IRL|19HP|24IEN||31SPS","CPM Interrupt Configuration Register","UM909"},
+{"CIPR",	(SPRI_MASK|0x944), "PC15|SCC1|SCC2|SCC3|SCC4|PC14|TIMER1|PC13|PC12|SDMA|IDMA1|IDMA2||TIMER2|RTT|I2C|PC11|PC10||TIMER3|PC9|PC8|PC7||TIMER4|PC6|SPI|SMC1|SMC2|PC5|PC4|","CPM Interrupt Pending Register","UM910"},
+{"CIMR",	(SPRI_MASK|0x948), "PC15|SCC1|SCC2|SCC3|SCC4|PC14|TIMER1|PC13|PC12|SDMA|IDMA1|IDMA2||TIMER2|RTT|I2C|PC11|PC10||TIMER3|PC9|PC8|PC7||TIMER4|PC6|SPI|SMC1|SMC2|PC5|PC4|","CPM Interrupt Mask Register","UM910"},
+{"CISR",	(SPRI_MASK|0x94C), "PC15|SCC1|SCC2|SCC3|SCC4|PC14|TIMER1|PC13|PC12|SDMA|IDMA1|IDMA2||TIMER2|RTT|I2C|PC11|PC10||TIMER3|PC9|PC8|PC7||TIMER4|PC6|SPI|SMC1|SMC2|PC5|PC4|","CPM Interrupt In-Service Register","UM910"},
+{"PADIR",	(SPRI_MASK|0x950), "DIR|16PAR","Port A Data Direction Register 16 bit",""}, /*16bit! PAPAR*/
+{"PAODR",	(SPRI_MASK|0x954), "ODR|16DAT","Port A Open-Drain Register 16 bit",""}, /*16bit! PADAT*/
+{"PCDIR",	(SPRI_MASK|0x960), "DIR|16PAR","Port C Data Direction Register 16 bit",""}, /*16bit! PCPAR*/
+{"PCSO",	(SPRI_MASK|0x964), "SO|16DAT","Port C Special Option Register 16 bit",""}, /*16bit! PCDAT*/
+{"PCINT",	(SPRI_MASK|0x968), "INT|16","Port C Interrupt Control Register 16 bit",""}, /*16bit!*/
+{"PDDIR",	(SPRI_MASK|0x970), "DIR|16PAR","Port C Data Direction Register 16 bit",""}, /*16bit! PDPAR*/
+{"PDDAT",	(SPRI_MASK|0x976), "ODR|16","Port C Data Register 16 bit",""}, /*16bit!*/
+{"PBDIR",	(SPRI_MASK|0xAB8), "","Port B Data Direction Register","UM893"},
+{"PBPAR",	(SPRI_MASK|0xABC), "","Port B Pin Assignment Register","UM893"},
+{"PBODR",	(SPRI_MASK|0xAC0), "","Port B Open-Drain Register","UM891"},
+{"PBDAT",	(SPRI_MASK|0xAC4), "","Port B Data Register","UM892"},
+{"SIMODE",	(SPRI_MASK|0xAE0), "SMC2|SMC2CS|4SDMb|6RFSDb|8DSCb|CRTb|STZb|CEb|FEb|GMb|TFSDb|16SMC1|SMC1CS|20SDMa|22RFSDa|24DSCa|CRTa|STZa|CEa|FEa|GMa|TFSDa","SI mode register","UM606"},
+{"SIGMR",	(SPRI_MASK|0xAE4), "|4ENb|ENa|RDM|8|16CRORa|CROTa|CRORb|CROTb||24CSRRa|CSRTa|CSRRb|CSRTb|","SI global mode register 8 bit","UM605"}, /*8bit! res, SISTR, SICMR*/
+{"SICR",	(SPRI_MASK|0xAEC), "GR4|SC4|R4CS|5T4CS|8GR3|SC3|R3CS|13T3CS|16GR2|SC2|R2CS|21T2CS|24GR1|SC1|R1CS|28T1CS","SI clock route register","UM612"},
+{"SIRP",	(SPRI_MASK|0xAF0), "|2VTb|TbPTR|8|10VTa|TaPTR|16|18VRb|RbPTR|24|26VRa|RaPTR","SI RAM pointer register","UM614"},
+{"MSR",		(SPR_MASK|0x1), "|13POW||ILE|EE|PR|FP|ME||SE|BE||25IP|IR|DR||30RI|LE","Machine State Register","UM145"},
+{"CR",		(SPR_MASK|0x2), "CR0|4CR1|8CR2|12CR3|16CR4|20CR5|24CR6|28CR7","Condition Register","UM140"},
+{0 /*last entry for sprnames*/}
+};
+
+#define SRR1_MASK 0x9002
+
+#define BDM_NUM_REGS 24
+
+#define BDM_REGMAP \
+	GPR_REG_MASK|0,  GPR_REG_MASK|1,  GPR_REG_MASK|2,  GPR_REG_MASK|3,  GPR_REG_MASK|4,  GPR_REG_MASK|5,  GPR_REG_MASK|6,  GPR_REG_MASK|7,  /* r0-r7 */ \
+	GPR_REG_MASK|8,  GPR_REG_MASK|9,  GPR_REG_MASK|10, GPR_REG_MASK|11, GPR_REG_MASK|12, GPR_REG_MASK|13, GPR_REG_MASK|14, GPR_REG_MASK|15, /* r8-r15 */ \
+	GPR_REG_MASK|16, GPR_REG_MASK|17, GPR_REG_MASK|18, GPR_REG_MASK|19, GPR_REG_MASK|20, GPR_REG_MASK|21, GPR_REG_MASK|22, GPR_REG_MASK|23, /* r16-r23 */ \
+	GPR_REG_MASK|24, GPR_REG_MASK|25, GPR_REG_MASK|26, GPR_REG_MASK|27, GPR_REG_MASK|28, GPR_REG_MASK|29, GPR_REG_MASK|30, GPR_REG_MASK|31, /* r24-r31 */ \
+\
+	2080, 2082, 2084, 2086, 2088, 2090, 2092, 2094, /* fp0->fp8 */ \
+	2096, 2098, 2100, 2102, 2104, 2106, 2108, 2110, /* fp0->fp8 */ \
+	2112, 2114, 2116, 2118, 2120, 2122, 2124, 2126, /* fp0->fp8 */ \
+	2128, 2130, 2132, 2134, 2136, 2138, 2140, 2142, /* fp0->fp8 */ \
+\
+	SPR_SRR0,     /* pc (SRR0 (SPR 26)) */ \
+	SPR_MSR,      /* ps (MSR) */ \
+	SPR_CR,       /* cnd (CR) */ \
+	SPR_LR,       /* lr (SPR 8) */ \
+	SPR_CTR,      /* cnt (CTR (SPR 9)) */ \
+	SPR_XER,      /* xer (SPR 1) */ \
+	0,            /* mq (SPR 0) */
+
+/*
+
+i86 parallel port registers and pin connections:
+
+|Funct.| Addr.|Access|Bit 7 |Bit 6 |Bit 5 |Bit 4 |Bit 3 |Bit 2 |Bit 1 |Bit 0 |
++------+------+------+------+------+------+------+------+------+------+------+
+| DATA |0x378 | R/W  |D7    |D6    |D5    |D4    |D3    |D2    |D1    |D0    |
+|      |      |      |Pin 9 |Pin 8 |Pin 7 |Pin 6 |Pin 5 |Pin 4 |Pin 3 |Pin 2 |
+|      |      |      |      |      |      |      |      |      |      |      |
++------+------+------+------+------+------+------+------+------+------+------+
+| STAT |0x379 |  R   |~Busy | Ack  |PapErr|Select|Error |  1   |  1   |Time- |
+|      |      |      |Pin 11|Pin 10|Pin 12| -In  |Pin 15|      |      | out  |
+|      |      |      |      |      |      |Pin 13|      |      |      |      |
++------+------+------+------+------+------+------+------+------+------+------+
+| CTRL |0x37A |  W   |  1   |   1  |DATDIR|IRQEna|~Se­  | Init |~Auto-|~Stro-|
+|      |      |      |      |      | 1=I  |      | lect |Pin 16| feed |  be  |
+|      |      |      |      |      | 0=O  |      |Pin 17|      |Pin 14|Pin 1 |
++------+------+------+------+------+------+------+------+------+------+------+
+
+mapping of adapter V1 and V2:
+
+DATA	7		6		5		4		3		2		1		0
+V1		V5V		V5V		V5V		V5V		V5V		V5V		V5V		V5V
+V2		V5V		V5V		V5V		V5V		V5V		TMS		DSDI	DSCK
+
+STAT	7		6		5		4		3		2		1		0
+V1		-		VDD		DSDO	-		FRZ		-		-		-
+V2		VFLS1	VDD1	DSDO	VDD2	VFLS0	-		-		-
+
+CTRL	7		6		5		4		3		2		1		0
+V1		-		-		DATDIR	IRQEna	HRESET#	DSDI	SRESET#	DSCK
+V2		-		-		DATDIR	IRQEna	HRESET#	-		sRESET#	TRST#
+
+JTAG/COP (I/O direction as seen from host):
+
++------------------+-------------------+
+|1  TDO         (I)|2  QACK         (I)|
++------------------+-------------------+
+|3  TDI         (O)|4  TRST#        (O)|
++------------------+-------------------+
+|5  QREQ        (I)|6  VDD          (I)|
++------------------+-------------------+
+|7  TCLK        (O)|8  NC              |
++------------------+-------------------+
+|9  TMS         (O)|10 NC              |
++------------------+-------------------+
+|11 SRESET#     (O)|12 GND             |
++------------------+-------------------+
+|13 HRESET#     (O)|14 NC              |
++------------------+-------------------+
+|15 CHKSTOP     (I)|16 GND             |
++------------------+-------------------+
+
+BDM Connector (I/O direction as seen from host):
+
++------------------+-------------------+
+|1 VFLS0/FREEZE (I)| 2 SRESET#      (O)|
++------------------+-------------------+
+|3 GND             | 4 DSCK         (O)|
++------------------+-------------------+
+|5 GND             | 6 VFLS1/FREEZE (I)|
++------------------+-------------------+
+|7 HRESET#      (O)| 8 DSDI         (O)|
++------------------+-------------------+
+|9 VDD          (I)| 10 DSDO        (I)|
++------------------+-------------------+
+
+(HRESET#, SRESET#, and TRST# are implemented as open collector signals)
+
+*/
+
+/* abstraction of parallel port layer */
+typedef struct
+{
+/* pointer to function to read input lines : DSDO,VFLS0..1,VDD1..2*/
+	int (*Read)(void);
+/* pointer to function to enable/disable powering adapter from port */
+	void (*Power)(unsigned char Data);
+/* pointer to function to output DSCK,DSDI*/
+	void (*Write)(unsigned char Data);
+/* pointer to function to output HRESET,SRESET,TRST*/
+	void (*Reset)(unsigned char Data);
+	void (*Status)(void);
+	short DATAAddr;
+	short STATAddr;
+	short CTRLAddr;
+	unsigned char DATA;
+	unsigned char DATAMask;
+	unsigned char STAT;
+	unsigned char CTRL;
+	unsigned char CTRLMask;
+	unsigned char DSCK;
+	unsigned char DSDI;
+	unsigned char TMS;
+	unsigned char POWER;
+	unsigned char VFLS0;
+	unsigned char VDD2;
+	unsigned char DSDO;
+	unsigned char VDD1;
+	unsigned char VFLS1;
+	unsigned char TRST;
+	unsigned char SRESET;
+	unsigned char HRESET;
+	unsigned char FREEZE;
+	char sStatus[MAXBUFFERLEN];
+	int port;
+} Port;
+
+/* processor idenfication */
+
+typedef struct
+{
+	unsigned int pvr;
+	unsigned short partmask;
+	unsigned short revnum;
+	char * name;
+	char * regfile;
+	unsigned int flags;
+} Processor;
+
+Processor CPU[]=
+{
+	{ 0x00500000, 0x0502, 0x0000,"XPC860 Rev. D.4",0,0},
+	{ 0x00500000, 0x0501, 0x0000,"XPC860 Rev. D.3",0,0},
+	{ 0x00500000, 0x0031, 0x0065,"XPC860SR Rev. C.1",0,0},
+	{ 0x00500000, 0x0031, 0x0004,"XPC860 Rev. C.1",0,0},
+	{ 0x00500000, 0x0030, 0x0065,"XPC860SR Rev. C.0",0,0},
+	{ 0x00500000, 0x0030, 0x0004,"XPC860 Rev. C.0",0,0},
+	{ 0x00500000, 0x0020, 0x0064,"XPC860SR Rev. B.1",0,0},
+	{ 0x00500000, 0x0020, 0x0004,"XPC860 Rev. B",0,0},
+	{ 0x00500000, 0x0013, 0x0003,"XPC860 Rev. A.3",0,0},
+	{ 0x00500000, 0x0012, 0x0003,"XPC860 Rev. A.2",0,0},
+	{ 0x00500000, 0x0010, 0x0003,"XPC860 Rev. A.1",0,0},
+	{ 0x00500000, 0x0002, 0x0001,"XPC860 Rev. 0",0,0},
+	{ 0x00500000, 0x2101, 0x0067,"XPC850 Rev. B","XPC850.reg",0},
+	{ 0x00500000, 0x2100, 0x0065,"XPC850 Rev. A","XPC850.reg",0},
+	{ 0x00500000, 0x2002, 0x0001,"XPC850 Rev. 0","XPC850.reg",0},
+	{ 0x00000000, 0x0000, 0x0000,0,0,0} /* last entry for processor*/
+};
+
+/* FLASH device sector description */
+
+typedef struct
+{
+	unsigned int ID;
+	unsigned int Start;
+	unsigned int End;
+} FlashSector;
+
+/* FlashCycle: an action paired with a adr:data tupel */
+typedef struct
+{
+	char cType; /* cycle action : one of W R C T P */
+	unsigned int Adr;
+	char cAdrType;
+	unsigned int Data;
+	char cDataType;
+} FlashCycle;
+
+typedef struct
+{
+	char *sName; /* name of FLASH device*/
+	FlashSector *Sector; /* array of sectors*/
+	int nSectors; /* number of sectors*/
+	unsigned int bits;		/* number of bits per device */
+	unsigned int devices;	/* number of devices parallel in bank */
+	unsigned int start;		/* physical start address of bank */
+	unsigned int size;		/* size per device */
+	unsigned int end;		/* physical end address*/
+	unsigned int IDshift;	/* bit offset for sector id*/
+	unsigned int width;		/* number of data lines connected to data bus for total bank */
+	unsigned int mask;		/* (1<<width)-1, bit mask for elementar access */
+	unsigned int EWA;		/* number of elementar accesses needed per word = 32/width */
+	unsigned int align;		/* align  = width/8 , one address increase results in 'align' bytes increase */
+	unsigned int shift;		/* ld(align) = bit shift left to get physical mapping */
+	FlashCycle *cReset;		/* pointer to reset flash cycles */
+	FlashCycle *cIdent;		/* pointer to ident flash cycles */
+	FlashCycle *cWrite;		/* pointer to write flash cycles */
+	FlashCycle *cErase;		/* pointer to erase flash cycles */
+	FlashCycle *cClear;		/* pointer to clear chip flash cycles */
+	FlashCycle *cFast;		/* pointer to fast flash cycles for register preloading */
+	unsigned int *fflash;	/* pointer to fast flash ppc subroutine array */
+	int nfflash;			/* number of instructions of fast flash subroutine */
+	unsigned int (*getword)(unsigned int addr); /* pointer to lowlevel communication routine */
+	void (*setword)(unsigned int addr, unsigned int val); /* pointer to lowlevel communication routine */
+} FlashBank;
+
+#define MSR_IR	0x00000020	/*IMMU enabled*/
+#define MSR_DR	0x00000010	/*DMMU enabled*/
+
+#define MPC_IMMU_ENTRIES	32	/* number of instruction mmu tlb entries */
+#define MPC_MI_CTR_MASK	0xfe000000	/* bits other than index */
+#define MPC_MI_CTR_SHIFT	8	/* start bit for index from right (PC# not PPC;-)*/
+#define MPC_DMMU_ENTRIES	32	/* number of instruction mmu tlb entries */
+#define MPC_MD_CTR_SHIFT		8	/* start bit for index from right (PC# not PPC;-)*/
+#define MPC_MD_CTR_MASK	0xfe000000	/* bits other than index */
+
+#define MPC_ICACHE_SETS		128	/* number of sets in one way of the instruction cache */
+/* FIXME:  changes needed for 860P/DP , as icache has 4 ways */
+/* and 6 bit LRU encoding */
+#define MPC_ICACHE_WAYS		2	/* number of associative ways of the instruction cache */
+#define MPC_ICACHE_SIZE		16	/* number of bytes in instruction cache */
+#define MPC_IC_CST_IEN		0x80000000	/* instruction cache enable in IC_CST */
+#define MPC_IC_DAT_TAG		0xfffff800	/* instruction cache tag field in IC_DAT */
+#define MPC_IC_DAT_VALID	0x00000200	/* instruction cache valid in IC_DAT */
+#define MPC_IC_DAT_LOCKED	0x00000100	/* instruction cache locked in IC_DAT */
+#define MPC_IC_DAT_LRU		0x00000080	/* instruction cache LRU in IC_DAT */
+#define MPC_IC_DAT_LRU_SHIFT 7	/* data cache LRU shift */
+#define MPC_DCACHE_SETS		128	/* number of sets in one way of the data cache */
+#define MPC_DCACHE_SETSHIFT	4	/* set adr start bit */
+#define MPC_DCACHE_SETMASK	0x000007f0	/* set adr mask = (SETS-1)<<SHIFT */
+#define MPC_DCACHE_WAYS		2	/* number of associative ways of the data cache */
+#define MPC_DCACHE_SIZE		16	/* number of bytes in data cache */
+#define MPC_DC_CST_DEN		0x80000000	/* data cache enable in DC_CST */
+#define MPC_DC_CST_DFWT		0x40000000	/* data cache force write through in DC_CST */
+#define MPC_DC_CST_LES		0x20000000	/* data cache little endian swap in DC_CST */
+#define MPC_DC_CST_CCER1	0x00200000	/* data cache error (dcbf dcbst)in DC_CST */
+#define MPC_DC_CST_CCER2	0x00100000	/* data cache error (DC_CST cmd)in DC_CST */
+#define MPC_DC_CST_CCER3	0x00080000	/* data cache error (reserved)in DC_CST */
+#define MPC_DC_CST_FLUSH	0x0e000000	/* data cache CMD = Flush block with phys. adr in DC_ADR */
+#define MPC_DC_CST_UNLOCK	0x08000000	/* data cache CMD = unlock block with phys. adr in DC_ADR */
+#define MPC_DC_CST_LOCK		0x06000000	/* data cache CMD = load and lock block with phys. adr in DC_ADR */
+#define MPC_DC_DAT_TAG		0xfffff800	/* data cache tag field in DC_DAT */
+#define MPC_DC_DAT_VALID	0x00000200	/* data cache valid in DC_DAT */
+#define MPC_DC_DAT_LOCKED	0x00000100	/* data cache locked in DC_DAT */
+#define MPC_DC_DAT_LRU		0x00000080	/* data cache LRU in DC_DAT */
+#define MPC_DC_DAT_LRU_SHIFT 7	/* data cache LRU shift */
+#define MPC_DC_DAT_MOD		0x00000040	/* data cache modified in DC_DAT */
+
+#define MAX_HWBRK	4 /*number of hardware breakpoint registers to use*/
+
+#define BDM_BREAKPOINT {0x0,0x0,0x0,0x0} /* For ppc 8xx */
+/* #define BDM_BREAKPOINT {0x4a,0xfa} *//* BGND insn used for CPU32 */
+
+/* masks for mpcbdm_verbose, produces more output for selected subroutines*/
+#define VERBOSE_BDM	0x01
+#define VERBOSE_SER	0x02
+#define VERBOSE_BRK	0x04
+#define VERBOSE_MMU	0x08
+#define VERBOSE_TAR	0x10
+#define VERBOSE_DCA	0x20
+#define VERBOSE_FLS	0x40
+#define VERBOSE_SRR1	0x80
+
+#define RETURN_FAIL		-1
+#define RETURN_OK		0
+
+#endif /*_MPCBDM_H_*/
