From adf4a4390d41becac3d406e57b40115c31e5d962 Mon Sep 17 00:00:00 2001
From: Jiri Gaisler <jiri@gaisler.se>
Date: Sun, 9 Dec 2018 10:56:14 +0100
Subject: [PATCH] sim/erc32: SMP support for leon3

---
 sim/erc32/README.leon3 |  18 +-
 sim/erc32/README.run   |  17 ++
 sim/erc32/README.sis   |  11 +-
 sim/erc32/erc32.c      |  51 ++--
 sim/erc32/exec.c       | 345 ++++++++--------------
 sim/erc32/func.c       | 655 +++++++++++++++++++++++++++++------------
 sim/erc32/help.c       |   2 +-
 sim/erc32/interf.c     | 201 ++++++-------
 sim/erc32/leon2.c      |  37 +--
 sim/erc32/leon3.c      | 272 +++++++++++------
 sim/erc32/run.c        |  22 +-
 sim/erc32/sis.c        | 126 ++------
 sim/erc32/sis.h        |  81 +++--
 13 files changed, 1003 insertions(+), 835 deletions(-)
 create mode 100644 sim/erc32/README.run

diff --git a/sim/erc32/README.leon3 b/sim/erc32/README.leon3
index e6d5f5e57e..80fff5f46c 100644
--- a/sim/erc32/README.leon3
+++ b/sim/erc32/README.leon3
@@ -10,7 +10,15 @@ MMU.
 To start sis in Leon3 mode, add the -leon3 switch. In gdb,
 use 'target sim -leon3' .
 
-1.1 UART
+1.1 Multiprocessing
+
+It is possible to emulate an SMP leon3 system with up to 4 cores.
+Add the switch -m <n> when starting the simulator, where n can be 
+2 - 4. The cores are simulated in a round-robin fashion with a time-
+slice of 50 clocks. Shorter or longer time-slices can be selected
+using -d <clocks>/
+
+1.2 UART
 
 The UART emulates an APBUART and is located at address 0x80000100.
 The following registers are implemented:
@@ -20,13 +28,13 @@ The following registers are implemented:
 
 The UART generates interrupt 3.
 
-1.2 Timer unit (GPTIMER)
+1.3 Timer unit (GPTIMER)
 
 The GPTIMER programmable counter is emulated and located at
 address 0x80000300. It is configured with two timers and separate
 interrupts (8 and 9).
 
-1.3 Interrupt controller
+1.4 Interrupt controller
 
 The IRQMP interrupt controller is implemented as described in the
 GRLIB IP manual, with the exception of the interrupt level register.
@@ -44,10 +52,8 @@ The following memory areas are valid for the Leon3 simulator:
 
 Access to non-existing memory will result in a memory exception trap.
 
-1.8 Power-down mode
+1.6 Power-down mode
 
 The Leon3 power-down feature (%asr19) is supported. When power-down is
 entered, time is skipped forward until the next event in the event queue.
-However, if the simulator event queue is empty, power-down mode is not
-entered since no interrupt would be generated to exit from the mode. A
 Ctrl-C in the simulator window will exit the power-down mode.
diff --git a/sim/erc32/README.run b/sim/erc32/README.run
new file mode 100644
index 0000000000..555231cb64
--- /dev/null
+++ b/sim/erc32/README.run
@@ -0,0 +1,17 @@
+
+The 'run' application allows to execute a binary directly without starting sis.
+Nota that sis now also have this feature included through the -r switch.
+
+The following options are useful for erc32/leon2/3 simulation:
+
+-a -leon2	Emulate a leon2 system (erc32 is default)
+
+-a -leon3	Emulate a leon3 system (erc32 is default)
+
+-m <n>		Enable SMP emulation with n cores
+
+-t <n>		Set a simulator time-out for n seconds
+
+-v <n>		Set debug level to n
+
+It is not possible to pass other sis options to the simulator.
diff --git a/sim/erc32/README.sis b/sim/erc32/README.sis
index bf2f7a7f90..7e687e41b0 100644
--- a/sim/erc32/README.sis
+++ b/sim/erc32/README.sis
@@ -13,8 +13,8 @@ and peripherals.
 
 The simulator is started as follows:
 
-sis [-leon2] [-leon3] [-uart1 uart_device1] [-uart2 uart_device2]
-    [-nfp] [-freq frequency] [-c batch_file] [-v] [-r] [-tlim time] [files]
+sis [-leon2] [-leon3] [-uart1 uart_device1] [-uart2 uart_device2] [-m cores]
+[-d clocks] [-nfp] [-freq freq] [-c batch_file] [-v] [-r] [-tlim time] [files]
 
 By default, SIS emulates an ERC32 system. The -leon2 switch enables
 LEON2 emulation, while the -leon3 switch enables emulation of a
@@ -40,7 +40,12 @@ for automated testing of large number of binaries.
 -tlim can be used together with -r to limit the amount of simulated time that
 the simulator runs for before exiting. The following units are recognized:
 us, ms and s. To limit simulated time to 100 seconds, it should thus be
-started with -r -tlim 100s .
+started with -r -tlim 100 s .
+
+-m sets the number of cores (2 - 4) in a leon3 multi-processor system.
+
+-d set the the number of clocks in each time-slice for multi-processor
+simulation. Default is 50, set lower for higher accuracy.
 
 Files to be loaded must be in one of the formats supported by the BFD library.
 This inlude elf, a.out, srec and binary. On start-up, the files will be
diff --git a/sim/erc32/erc32.c b/sim/erc32/erc32.c
index d2b9194591..085d215a45 100644
--- a/sim/erc32/erc32.c
+++ b/sim/erc32/erc32.c
@@ -307,6 +307,7 @@ reset()
     mec_reset();
     uart_irq_start();
     wdog_start();
+    sregs[0].intack = mec_intack;
 }
 
 static void
@@ -559,18 +560,17 @@ chk_irq()
     uint32          itmp;
     int		    old_irl;
 
-    old_irl = ext_irl;
+    old_irl = ext_irl[0];
     if (mec_tcr & 0x80000) itmp = mec_ifr;
     else itmp  = 0;
     itmp = ((mec_ipr | itmp) & ~mec_imr) & 0x0fffe;
-    ext_irl = 0;
+    ext_irl[0] = 0;
     if (itmp != 0) {
 	for (i = 15; i > 0; i--) {
 	    if (((itmp >> i) & 1) != 0) {
 		if ((sis_verbose) && (i > old_irl)) 
 		    printf("IU irl: %d\n", i);
-		ext_irl = i;
-	        set_int(i, mec_intack, i);
+		ext_irl[0] = i;
 		break;
 	    }
 	}
@@ -905,7 +905,8 @@ mec_write(addr, data)
 
     case MEC_PWDR:
 	if (mec_mcr & 1)
-	    wait_for_irq();
+	    sregs->pwd_mode = 1;
+            sregs->pwdstart = sregs->simtime;
 	break;
 
     default:
@@ -1618,7 +1619,7 @@ memory_iread (uint32 addr, uint32 *data, int32 *ws)
 
     if (sis_verbose)
 	printf ("Memory exception at %x (illegal address)\n", addr);
-    if (sregs.psr & 0x080)
+    if (sregs->psr & 0x080)
         asi = 9;
     else
         asi = 8;
@@ -1637,7 +1638,7 @@ memory_read (uint32 addr, uint32 *data, int32 sz, int32 *ws)
     if (errmec) {
 	if (sis_verbose)
 	    printf("Inserted MEC error %d\n",errmec);
-	asi = (sregs.psr & 0x080) ? 11 : 10;
+	asi = (sregs->psr & 0x080) ? 11 : 10;
 	set_sfsr(errmec, addr, asi, 1);
 	if (errmec == 5) mecparerror();
 	if (errmec == 6) iucomperr();
@@ -1651,7 +1652,7 @@ memory_read (uint32 addr, uint32 *data, int32 sz, int32 *ws)
 	*ws = mem_ramr_ws;
 	return 0;
     } else if ((addr >= MEC_START) && (addr < MEC_END)) {
-	asi = (sregs.psr & 0x080) ? 11 : 10;
+	asi = (sregs->psr & 0x080) ? 11 : 10;
 	mexc = mec_read(addr, asi, data);
 	if (mexc) {
 	    set_sfsr(MEC_ACC, addr, asi, 1);
@@ -1691,18 +1692,12 @@ memory_read (uint32 addr, uint32 *data, int32 sz, int32 *ws)
 
     if (sis_verbose)
 	printf ("Memory exception at %x (illegal address)\n", addr);
-    asi = (sregs.psr & 0x080) ? 11 : 10;
+    asi = (sregs->psr & 0x080) ? 11 : 10;
     set_sfsr(UIMP_ACC, addr, asi, 1);
     *ws = MEM_EX_WS;
     return 1;
 }
 
-static int
-memory_read_asi (int32 asi, uint32 addr, uint32 *data, int32 sz, int32 *ws)
-{
-  return memory_read (addr, data, sz, ws);
-}
-
 static int
 memory_write (uint32 addr, uint32 *data, int32 sz, int32 *ws)
 {
@@ -1719,7 +1714,7 @@ memory_write (uint32 addr, uint32 *data, int32 sz, int32 *ws)
     if (errmec) {
 	if (sis_verbose)
 	    printf("Inserted MEC error %d\n",errmec);
-	asi = (sregs.psr & 0x080) ? 11 : 10;
+	asi = (sregs->psr & 0x080) ? 11 : 10;
 	set_sfsr(errmec, addr, asi, 0);
 	if (errmec == 5) mecparerror();
 	if (errmec == 6) iucomperr();
@@ -1732,7 +1727,7 @@ memory_write (uint32 addr, uint32 *data, int32 sz, int32 *ws)
 	if (mem_accprot) {
 
 	    waddr = (addr & 0x7fffff) >> 2;
-	    asi = (sregs.psr & 0x080) ? 11 : 10;
+	    asi = (sregs->psr & 0x080) ? 11 : 10;
 	    for (i = 0; i < 2; i++)
 		wphit[i] =
 		    (((asi == 0xa) && (mec_wpr[i] & 1)) ||
@@ -1754,7 +1749,7 @@ memory_write (uint32 addr, uint32 *data, int32 sz, int32 *ws)
 	store_bytes (ramb, waddr, data, sz, ws);
 	return 0;
     } else if ((addr >= MEC_START) && (addr < MEC_END)) {
-	asi = (sregs.psr & 0x080) ? 11 : 10;
+	asi = (sregs->psr & 0x080) ? 11 : 10;
 	if ((sz != 2) || (asi != 0xb)) {
 	    set_sfsr(MEC_ACC, addr, asi, 0);
 	    *ws = MEM_EX_WS;
@@ -1811,17 +1806,11 @@ memory_write (uint32 addr, uint32 *data, int32 sz, int32 *ws)
     }
 	
     *ws = MEM_EX_WS;
-    asi = (sregs.psr & 0x080) ? 11 : 10;
+    asi = (sregs->psr & 0x080) ? 11 : 10;
     set_sfsr(UIMP_ACC, addr, asi, 0);
     return 1;
 }
 
-static int
-memory_write_asi (int32 asi, uint32 addr, uint32 *data, int32 sz, int32 *ws)
-{
-  return memory_write (addr, data, sz, ws);
-}
-
 static unsigned char  *
 get_mem_ptr(addr, size)
     uint32          addr;
@@ -1886,12 +1875,12 @@ boot_init (void)
 {
     mec_write(MEC_WCR, 0);	/* zero waitstates */
     mec_write(MEC_TRAPD, 0);	/* turn off watch-dog */
-    mec_write(MEC_RTC_SCALER, sregs.freq - 1); /* generate 1 MHz RTC tick */
+    mec_write(MEC_RTC_SCALER, ebase.freq - 1); /* generate 1 MHz RTC tick */
     mec_write(MEC_MEMCFG, (3 << 18) | (4 << 10)); /* 1 MB ROM, 4 MB RAM */
-    sregs.wim = 2;
-    sregs.psr = 0x110010e0;
-    sregs.r[30] = RAM_END;
-    sregs.r[14] = sregs.r[30] - 96 * 4;
+    sregs->wim = 2;
+    sregs->psr = 0x110010e0;
+    sregs->r[30] = RAM_END;
+    sregs->r[14] = sregs->r[30] - 96 * 4;
     mec_mcr |= 1;		/* power-down enabled */
 }
 
@@ -1905,9 +1894,7 @@ const struct memsys erc32sys = {
     restore_stdio,
     memory_iread,
     memory_read,
-    memory_read_asi,
     memory_write,
-    memory_write_asi,
     sis_memory_write,
     sis_memory_read,
     boot_init
diff --git a/sim/erc32/exec.c b/sim/erc32/exec.c
index ce5a72978b..085193e84f 100644
--- a/sim/erc32/exec.c
+++ b/sim/erc32/exec.c
@@ -21,7 +21,7 @@
 #include <math.h>
 #include <stdio.h>
 
-int ext_irl = 0;
+int ext_irl[NCPU];
 
 /* Load/store interlock delay */
 #define FLSTHOLD 1
@@ -417,7 +417,7 @@ dispatch_instruction(sregs)
     uint32          ldep, icc;
     int32           operand1, operand2, *rdd, result, eicc,
                     new_cwp;
-    int32           pc, npc, data, address, ws, mexc, fcc;
+    int32           pc, npc, data, address, ws, mexc, fcc, annul;
     int32	    ddata[2];
 
     sregs->ninst++;
@@ -427,6 +427,8 @@ dispatch_instruction(sregs)
     npc = sregs->npc + 4;
     op3 = rd = rs1 = operand2 = eicc = 0;
     rdd = 0;
+    annul = 0;
+
     if (op & 2) {
 
 	op3 = (sregs->inst >> 19) & 0x3f;
@@ -436,7 +438,7 @@ dispatch_instruction(sregs)
 #ifdef LOAD_DEL
 
 	/* Check if load dependecy is possible */
-	if (ebase.simtime <= sregs->ildtime)
+	if (sregs->simtime <= sregs->ildtime)
 	    ldep = (((op3 & 0x38) != 0x28) && ((op3 & 0x3e) != 0x34) && (sregs->ildreg != 0));
         else
 	    ldep = 0;
@@ -522,7 +524,7 @@ dispatch_instruction(sregs)
 	    case BICC_BA:
 		eicc = 1;
 		if (sregs->inst & 0x20000000)
-		    sregs->annul = 1;
+		    annul = 1;
 		break;
 	    case BICC_BNE:
 		eicc = ~(ICC_Z);
@@ -552,7 +554,7 @@ dispatch_instruction(sregs)
 		npc = sregs->pc + operand1;
 	    } else {
 		if (sregs->inst & 0x20000000)
-		    sregs->annul = 1;
+		    annul = 1;
 	    }
 	    break;
 	case FPBCC:
@@ -563,8 +565,8 @@ dispatch_instruction(sregs)
 		sregs->trap = TRAP_FPDIS;
 		break;
 	    }
-	    if (ebase.simtime < sregs->ftime) {
-		sregs->ftime = ebase.simtime + sregs->hold;
+	    if (sregs->simtime < sregs->ftime) {
+		sregs->ftime = sregs->simtime + sregs->hold;
 	    }
 	    cond = ((sregs->inst >> 25) & 0x0f);
 	    fcc = (sregs->fsr >> 10) & 0x3;
@@ -596,7 +598,7 @@ dispatch_instruction(sregs)
 	    case FBA:
 		eicc = 1;
 		if (sregs->inst & 0x20000000)
-		    sregs->annul = 1;
+		    annul = 1;
 		break;
 	    case FBE:
 		eicc = !(fcc != FCC_E);
@@ -626,7 +628,7 @@ dispatch_instruction(sregs)
 		npc = sregs->pc + operand1;
 	    } else {
 		if (sregs->inst & 0x20000000)
-		    sregs->annul = 1;
+		    annul = 1;
 	    }
 	    break;
 
@@ -714,7 +716,7 @@ dispatch_instruction(sregs)
 				(sregs->inst == 0x91d02001))
 		    {
 			sregs->trap = WPT_TRAP;
-			sregs->bphit = 1;
+			ebase.bphit = 1;
 		    }
 		}
 		break;
@@ -1141,12 +1143,13 @@ dispatch_instruction(sregs)
                     if ( 0 == rd )
                         sregs->y = (rs1 ^ operand2);
                     else if ( 17 == rd ) {
-                        if (sparclite)
-                            sregs->asr17 = (rs1 ^ operand2);
+                        sregs->asr17 &= ~0x0FFFE000;
+                        sregs->asr17 |= 0x0FFFE000 & (rs1 ^ operand2);
                     }
                     else if ( 19 == rd ) {
-                        if (cputype == CPU_LEON3)
-                            wait_for_irq();
+                        if (cputype == CPU_LEON3) {
+			    pwd_enter(sregs);
+			}
                     }
                 }
 		break;
@@ -1223,8 +1226,8 @@ dispatch_instruction(sregs)
 
 	if (op3 & 4) {
 	    sregs->icnt = T_ST;	/* Set store instruction count */
-	    if (sregs->wpwnum) {
-	       if (sregs->wphit = check_wpw(sregs, address, wpmask(op3))) {
+	    if (ebase.wpwnum) {
+	       if (ebase.wphit = check_wpw(sregs, address, wpmask(op3))) {
 	           sregs->trap = WPT_TRAP;
 		   break;
 	       }
@@ -1234,8 +1237,8 @@ dispatch_instruction(sregs)
 #endif
 	} else {
 	    sregs->icnt = T_LD;	/* Set load instruction count */
-	    if (sregs->wprnum) {
-	       if (sregs->wphit = check_wpr(sregs, address, wpmask(op3))) {
+	    if (ebase.wprnum) {
+	       if (ebase.wphit = check_wpr(sregs, address, wpmask(op3))) {
 	           sregs->trap = WPT_TRAP;
 		   break;
 	       }
@@ -1250,32 +1253,6 @@ dispatch_instruction(sregs)
 	switch (op3) {
 	case LDDA:
 	    if (!chk_asi(sregs, &asi, op3)) break;
-	    if (address & 0x7) {
-		sregs->trap = TRAP_UNALI;
-		break;
-	    }
-	    if (rd & 1) {
-		rd &= 0x1e;
-		if (rd > 7)
-		    rdd = &(sregs->r[(cwp + rd) & 0x7f]);
-		else
-		    rdd = &(sregs->g[rd]);
-	    }
-	    mexc = ms->memory_read_asi (asi, address, ddata, 2, &ws);
-	    sregs->hold += ws;
-	    mexc |= ms->memory_read_asi (asi, address+4, &ddata[1], 2, &ws);
-	    sregs->hold += ws;
-	    sregs->icnt = T_LDD;
-	    if (mexc)
-		sregs->trap = TRAP_DEXC;
-	    else {
-		rdd[0] = ddata[0];
-		rdd[1] = ddata[1];
-#ifdef STAT
-		sregs->nload++;	/* Double load counts twice */
-#endif
-	    }
-	    break;
 	case LDD:
 	    if (address & 0x7) {
 		sregs->trap = TRAP_UNALI;
@@ -1310,13 +1287,11 @@ dispatch_instruction(sregs)
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    mexc = ms->memory_read_asi (asi, address, &data, 2, &ws);
-	    sregs->hold += ws;
-	    if (mexc)
-		sregs->trap = TRAP_DEXC;
-	    else
-		*rdd = data;
-	    break;
+	    if ((cputype == CPU_LEON3) && (asi == 2)) {
+		if (address == 0) *rdd = sregs->cache_ctrl;
+		else *rdd = 1 << 27;
+		break;
+	    }
 	case LD:
 	    if (address & 0x3) {
 		sregs->trap = TRAP_UNALI;
@@ -1332,24 +1307,7 @@ dispatch_instruction(sregs)
 	    break;
 	case LDSTUBA:
 	    if (!chk_asi(sregs, &asi, op3)) break;
-	    mexc = ms->memory_read_asi (asi, address, &data, 0, &ws);
-	    sregs->hold += ws;
-	    sregs->icnt = T_LDST;
-	    if (mexc) {
-		sregs->trap = TRAP_DEXC;
-		break;
-	    }
-	    data = extract_byte (data, address);
-	    *rdd = data;
-	    data = 0x0ff;
-	    mexc = ms->memory_write_asi (asi, address, &data, 0, &ws);
-	    sregs->hold += ws;
-	    if (mexc)
-		sregs->trap = TRAP_DEXC;
-#ifdef STAT
-	    sregs->nload++;
-#endif
-	    break;
+	    /* fall through to LDSTUB */
 	case LDSTUB:
 	    mexc = ms->memory_read (address, &data, 0, &ws);
 	    sregs->hold += ws;
@@ -1373,18 +1331,7 @@ dispatch_instruction(sregs)
 	case LDSBA:
 	case LDUBA:
 	    if (!chk_asi(sregs, &asi, op3)) break;
-	    mexc = ms->memory_read_asi (asi, address, &data, 0, &ws);
-	    sregs->hold += ws;
-	    if (mexc) {
-		sregs->trap = TRAP_DEXC;
-		break;
-	    }
-	    if (op3 == LDSB)
-	        data = extract_byte_signed (data, address);
-	    else
-	        data = extract_byte (data, address);
-	    *rdd = data;
-	    break;
+	    /* fall through to LDSB */
 	case LDSB:
 	case LDUB:
 	    mexc = ms->memory_read (address, &data, 0, &ws);
@@ -1402,22 +1349,7 @@ dispatch_instruction(sregs)
 	case LDSHA:
 	case LDUHA:
 	    if (!chk_asi(sregs, &asi, op3)) break;
-	    if (address & 0x1) {
-		sregs->trap = TRAP_UNALI;
-		break;
-	    }
-	    mexc = ms->memory_read_asi (asi, address, &data, 1, &ws);
-	    sregs->hold += ws;
-	    if (mexc) {
-		sregs->trap = TRAP_DEXC;
-		break;
-	    }
-	    if (op3 == LDSH)
-	        data = extract_short_signed (data, address);
-	    else
-	        data = extract_short (data, address);
-	    *rdd = data;
-	    break;
+	    /* fall through to LDSB */
 	case LDSH:
 	case LDUH:
 	    if (address & 0x1) {
@@ -1445,15 +1377,15 @@ dispatch_instruction(sregs)
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    if (ebase.simtime < sregs->ftime) {
+	    if (sregs->simtime < sregs->ftime) {
 		if ((sregs->frd == rd) || (sregs->frs1 == rd) ||
 		    (sregs->frs2 == rd))
-		    sregs->fhold += (sregs->ftime - ebase.simtime);
+		    sregs->fhold += (sregs->ftime - sregs->simtime);
 	    }
 	    mexc = ms->memory_read (address, &data, 2, &ws);
 	    sregs->hold += ws;
 	    sregs->flrd = rd;
-	    sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD +
+	    sregs->ltime = sregs->simtime + sregs->icnt + FLSTHOLD +
 		sregs->hold + sregs->fhold;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1470,11 +1402,11 @@ dispatch_instruction(sregs)
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    if (ebase.simtime < sregs->ftime) {
+	    if (sregs->simtime < sregs->ftime) {
 		if (((sregs->frd >> 1) == (rd >> 1)) ||
 		    ((sregs->frs1 >> 1) == (rd >> 1)) ||
 		    ((sregs->frs2 >> 1) == (rd >> 1)))
-		    sregs->fhold += (sregs->ftime - ebase.simtime);
+		    sregs->fhold += (sregs->ftime - sregs->simtime);
 	    }
 	    mexc = ms->memory_read (address, ddata, 2, &ws);
 	    sregs->hold += ws;
@@ -1491,13 +1423,13 @@ dispatch_instruction(sregs)
 		sregs->nload++;	/* Double load counts twice */
 #endif
 		sregs->fs[rd + 1] = *((float32 *) & ddata[1]);
-		sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD +
+		sregs->ltime = sregs->simtime + sregs->icnt + FLSTHOLD +
 			       sregs->hold + sregs->fhold;
 	    }
 	    break;
 	case LDFSR:
-	    if (ebase.simtime < sregs->ftime) {
-		sregs->fhold += (sregs->ftime - ebase.simtime);
+	    if (sregs->simtime < sregs->ftime) {
+		sregs->fhold += (sregs->ftime - sregs->simtime);
 	    }
 	    if (!((sregs->psr & PSR_EF) && FP_PRES)) {
 		sregs->trap = TRAP_FPDIS;
@@ -1526,8 +1458,8 @@ dispatch_instruction(sregs)
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    if (ebase.simtime < sregs->ftime) {
-		sregs->fhold += (sregs->ftime - ebase.simtime);
+	    if (sregs->simtime < sregs->ftime) {
+		sregs->fhold += (sregs->ftime - sregs->simtime);
 	    }
 	    mexc = ms->memory_write (address, &sregs->fsr, 2, &ws);
 	    sregs->hold += ws;
@@ -1542,11 +1474,10 @@ dispatch_instruction(sregs)
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    mexc = ms->memory_write_asi (asi, address, rdd, 2, &ws);
-	    sregs->hold += ws;
-	    if (mexc)
-		sregs->trap = TRAP_DEXC;
-	    break;
+	    if ((cputype == CPU_LEON3) && (asi == 2)) {
+		sregs->cache_ctrl = *rdd;
+		break;
+	    }
 	case ST:
 	    if (address & 0x3) {
 		sregs->trap = TRAP_UNALI;
@@ -1560,11 +1491,7 @@ dispatch_instruction(sregs)
 	    break;
 	case STBA:
 	    if (!chk_asi(sregs, &asi, op3)) break;
-	    mexc = ms->memory_write_asi (asi, address, rdd, 0, &ws);
-	    sregs->hold += ws;
-	    if (mexc)
-		sregs->trap = TRAP_DEXC;
-	    break;
+	    /* fall through to STB */
 	case STB:
 	    mexc = ms->memory_write (address, rdd, 0, &ws);
 	    sregs->hold += ws;
@@ -1574,28 +1501,6 @@ dispatch_instruction(sregs)
 	    break;
 	case STDA:
 	    if (!chk_asi(sregs, &asi, op3)) break;
-	    if (address & 0x7) {
-		sregs->trap = TRAP_UNALI;
-		break;
-	    }
-	    if (rd & 1) {
-		rd &= 0x1e;
-		if (rd > 7)
-		    rdd = &(sregs->r[(cwp + rd) & 0x7f]);
-		else
-		    rdd = &(sregs->g[rd]);
-	    }
-	    mexc = ms->memory_write_asi (asi, address, rdd, 3, &ws);
-	    sregs->hold += ws;
-	    sregs->icnt = T_STD;
-#ifdef STAT
-	    sregs->nstore++;	/* Double store counts twice */
-#endif
-	    if (mexc) {
-		sregs->trap = TRAP_DEXC;
-		break;
-	    }
-	    break;
 	case STD:
 	    if (address & 0x7) {
 		sregs->trap = TRAP_UNALI;
@@ -1653,15 +1558,6 @@ dispatch_instruction(sregs)
 	    break;
 	case STHA:
 	    if (!chk_asi(sregs, &asi, op3)) break;
-	    if (address & 0x1) {
-		sregs->trap = TRAP_UNALI;
-		break;
-	    }
-	    mexc = ms->memory_write_asi (asi, address, rdd, 1, &ws);
-	    sregs->hold += ws;
-	    if (mexc)
-		sregs->trap = TRAP_DEXC;
-	    break;
 	case STH:
 	    if (address & 0x1) {
 		sregs->trap = TRAP_UNALI;
@@ -1682,9 +1578,9 @@ dispatch_instruction(sregs)
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    if (ebase.simtime < sregs->ftime) {
+	    if (sregs->simtime < sregs->ftime) {
 		if (sregs->frd == rd)
-		    sregs->fhold += (sregs->ftime - ebase.simtime);
+		    sregs->fhold += (sregs->ftime - sregs->simtime);
 	    }
 	    mexc = ms->memory_write (address, &sregs->fsi[rd], 2, &ws);
 	    sregs->hold += ws;
@@ -1702,9 +1598,9 @@ dispatch_instruction(sregs)
 		break;
 	    }
 	    rd &= 0x1E;
-	    if (ebase.simtime < sregs->ftime) {
+	    if (sregs->simtime < sregs->ftime) {
 		if ((sregs->frd == rd) || (sregs->frd + 1 == rd))
-		    sregs->fhold += (sregs->ftime - ebase.simtime);
+		    sregs->fhold += (sregs->ftime - sregs->simtime);
 	    }
 	    mexc = ms->memory_write (address, &sregs->fsi[rd], 3, &ws);
 	    sregs->hold += ws;
@@ -1718,28 +1614,6 @@ dispatch_instruction(sregs)
 	    break;
 	case SWAPA:
 	    if (!chk_asi(sregs, &asi, op3)) break;
-	    if (address & 0x3) {
-		sregs->trap = TRAP_UNALI;
-		break;
-	    }
-	    mexc = ms->memory_read_asi (asi, address, &data, 2, &ws);
-	    sregs->hold += ws;
-	    if (mexc) {
-		sregs->trap = TRAP_DEXC;
-		break;
-	    }
-	    mexc = ms->memory_write_asi (asi, address, rdd, 2, &ws);
-	    sregs->hold += ws;
-	    sregs->icnt = T_LDST;
-	    if (mexc) {
-		sregs->trap = TRAP_DEXC;
-		break;
-	    } else
-		*rdd = data;
-#ifdef STAT
-	    sregs->nload++;
-#endif
-	    break;
 	case SWAP:
 	    if (address & 0x3) {
 		sregs->trap = TRAP_UNALI;
@@ -1772,14 +1646,14 @@ dispatch_instruction(sregs)
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    mexc = ms->memory_read_asi (asi, address, &data, 2, &ws);
+	    mexc = ms->memory_read (address, &data, 2, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
 		break;
 	    }
 	    if (data == operand2) {
-		mexc = ms->memory_write_asi (asi, address, rdd, 2, &ws);
+		mexc = ms->memory_write (address, rdd, 2, &ws);
 		if (mexc) {
 		    sregs->trap = TRAP_DEXC;
 		    break;
@@ -1800,7 +1674,7 @@ dispatch_instruction(sregs)
 #ifdef LOAD_DEL
 
 	if (!(op3 & 4)) {
-	    sregs->ildtime = ebase.simtime + sregs->hold + sregs->icnt;
+	    sregs->ildtime = sregs->simtime + sregs->hold + sregs->icnt;
 	    sregs->ildreg = rd;
 	    if ((op3 | 0x10) == 0x13)
 		sregs->ildreg |= 1;	/* Double load, odd register loaded
@@ -1817,6 +1691,11 @@ dispatch_instruction(sregs)
     if (!sregs->trap) {
 	sregs->pc = pc;
 	sregs->npc = npc;
+	if (annul) {
+	    sregs->pc = sregs->npc;
+	    sregs->npc = sregs->npc + 4;
+	    sregs->icnt += 1;
+	}
     }
     return 0;
 }
@@ -1894,14 +1773,14 @@ fpexec(op3, rd, rs1, rs2, sregs)
      * finished by incrementing fhold with the remaining execution time
      */
 
-    if (ebase.simtime < sregs->ftime) {
-	sregs->fhold = (sregs->ftime - ebase.simtime);
+    if (sregs->simtime < sregs->ftime) {
+	sregs->fhold = (sregs->ftime - sregs->simtime);
     } else {
 	sregs->fhold = 0;
 
 	/* Check load dependencies. */
 
-	if (ebase.simtime < sregs->ltime) {
+	if (sregs->simtime < sregs->ltime) {
 
 	    /* Don't check rs1 if single operand instructions */
 
@@ -1922,7 +1801,7 @@ fpexec(op3, rd, rs1, rs2, sregs)
     sregs->frs2 = rs2;
     sregs->frd = rd;
 
-    sregs->ftime = ebase.simtime + sregs->hold + sregs->fhold;
+    sregs->ftime = sregs->simtime + sregs->hold + sregs->fhold;
 
     /* SPARC is big-endian - swap double floats if host is little-endian */
     /* This is ugly - I know ... */
@@ -2198,12 +2077,13 @@ execute_trap(sregs)
 
 	if ((sregs->psr & PSR_ET) == 0)
 	    return ERROR;
+	if ((sregs->trap > 16) && (sregs->trap < 32))
+	    sregs->intack(sregs->trap - 16, sregs->cpu);
 
 	sregs->tbr = (sregs->tbr & 0xfffff000) | (sregs->trap << 4);
 	sregs->trap = 0;
 	sregs->psr &= ~PSR_ET;
 	sregs->psr |= ((sregs->psr & PSR_S) >> 1);
-	sregs->annul = 0;
 	sregs->psr = (((sregs->psr & PSR_CWP) - 1) & 0x7) | (sregs->psr & ~PSR_CWP);
 	cwp = ((sregs->psr & PSR_CWP) << 4);
 	sregs->r[(cwp + 17) & 0x7f] = sregs->pc;
@@ -2232,20 +2112,14 @@ int
 check_interrupts(sregs)
     struct pstate  *sregs;
 {
-#ifdef ERRINJ
-    if (errtt) {
-	sregs->trap = errtt;
-	if (sis_verbose) printf("Inserted error trap 0x%02X\n",errtt);
-	errtt = 0;
-    }
-#endif
-
-    if ((ext_irl) && (sregs->psr & PSR_ET) &&
-	((ext_irl == 15) || (ext_irl > (int) ((sregs->psr & PSR_PIL) >> 8)))) {
+    if ((ext_irl[sregs->cpu]) && (sregs->psr & PSR_ET) &&
+	((ext_irl[sregs->cpu] == 15) || (ext_irl[sregs->cpu] > (int) ((sregs->psr & PSR_PIL) >> 8)))) {
+	if (sregs->pwd_mode) {
+            sregs->pwdtime += sregs->simtime -sregs->pwdstart;
+	    sregs->pwd_mode = 0;
+	}
 	if (sregs->trap == 0) {
-	    sregs->trap = 16 + ext_irl;
-	    irqarr[ext_irl & 0x0f].callback(irqarr[ext_irl & 0x0f].arg);
-	    return 1;
+	    return ext_irl[sregs->cpu];
 	}
     }
     return 0;
@@ -2255,48 +2129,59 @@ void
 init_regs(sregs)
     struct pstate  *sregs;
 {
-    sregs->pc = 0;
-    sregs->npc = 4;
-    sregs->trap = 0;
-    sregs->psr &= 0x00f03fdf;
+  int i;
+
+  for (i=0; i<NCPU; i++) {  
+    sregs[i].pc = 0;
+    sregs[i].npc = 4;
+    sregs[i].trap = 0;
+    sregs[i].psr &= 0x00f03fdf;
     if (cputype == CPU_LEON3)
-      sregs->psr |= 0xF3000080;	/* Set supervisor bit */
+      sregs[i].psr |= 0xF3000080;	/* Set supervisor bit */
     else
     if (cputype == CPU_LEON2)
-      sregs->psr |= 0x00000080;	/* Set supervisor bit */
+      sregs[i].psr |= 0x00000080;	/* Set supervisor bit */
     else
-      sregs->psr |= 0x11000080;	/* Set supervisor bit */
-    sregs->breakpoint = 0;
-    sregs->annul = 0;
-    sregs->fpstate = FP_EXE_MODE;
-    sregs->fpqn = 0;
-    sregs->ftime = 0;
-    sregs->ltime = 0;
-    sregs->err_mode = 0;
-    ext_irl = 0;
-    sregs->g[0] = 0;
+      sregs[i].psr |= 0x11000080;	/* Set supervisor bit */
+    sregs[i].breakpoint = 0;
+    sregs[i].fpstate = FP_EXE_MODE;
+    sregs[i].fpqn = 0;
+    sregs[i].ftime = 0;
+    sregs[i].ltime = 0;
+    sregs[i].err_mode = 0;
+    ext_irl[i] = 0;
+    sregs[i].g[0] = 0;
 #ifdef HOST_LITTLE_ENDIAN
-    sregs->fdp = (float32 *) sregs->fd;
-    sregs->fsi = (int32 *) sregs->fs;
+    sregs[i].fdp = (float32 *) sregs[i].fd;
+    sregs[i].fsi = (int32 *) sregs[i].fs;
 #else
-    sregs->fs = (float32 *) sregs->fd;
-    sregs->fsi = (int32 *) sregs->fd;
+    sregs[i].fs = (float32 *) sregs[i].fd;
+    sregs[i].fsi = (int32 *) sregs[i].fd;
 #endif
-    sregs->fsr = 0;
-    sregs->fpu_pres = !nfp;
-    set_fsr(sregs->fsr);
-    sregs->bphit = 0;
-    sregs->wphit = 0;
-    sregs->ildreg = 0;
-    sregs->ildtime = 0;
-
-    sregs->y = 0;
-    sregs->asr17 = 0;
-
-    sregs->rett_err = 0;
-    sregs->jmpltime = 0;
+    sregs[i].fsr = 0;
+    sregs[i].fpu_pres = !nfp;
+    set_fsr(sregs[i].fsr);
+    ebase.bphit = 0;
+    ebase.wphit = 0;
+    sregs[i].ildreg = 0;
+    sregs[i].ildtime = 0;
+
+    sregs[i].y = 0;
+    sregs[i].asr17 = 0;
+
+    sregs[i].rett_err = 0;
+    sregs[i].jmpltime = 0;
     if (cputype == CPU_LEON3) {
-        sregs->asr17 = 0x107;
-        if (!nfp) sregs->asr17 |= (3 << 10);  /* Meiko FPU */
+        sregs[i].asr17 = 0x04000107 | (i << 28);
+        if (!nfp) sregs[i].asr17 |= (3 << 10);  /* Meiko FPU */
     }
+    sregs[i].cpu = i;
+    sregs[i].simtime = 0;
+    sregs[i].pwdtime = 0;
+    sregs[i].pwdstart = 0;
+    if (i == 0)
+        sregs[i].pwd_mode = 0;
+    else
+        sregs[i].pwd_mode = 1;
+  }
 }
diff --git a/sim/erc32/func.c b/sim/erc32/func.c
index 1cf7e451bb..b1a56d75bb 100644
--- a/sim/erc32/func.c
+++ b/sim/erc32/func.c
@@ -37,14 +37,13 @@ int dumbio = 0;
 int tty_setup = 1;
 
 struct disassemble_info dinfo;
-struct pstate   sregs;
+struct pstate   sregs[NCPU];
 struct estate   ebase;
 struct evcell   evbuf[EVENT_MAX];
-struct irqcell  irqarr[16];
 
 int             ctrl_c = 0;
 int             sis_verbose = 0;
-char           *sis_version = "2.8";
+char           *sis_version = "2.9";
 int             nfp = 0;
 int             ift = 0;
 int             wrp = 0;
@@ -61,6 +60,9 @@ host_callback 	*sim_callback;
 const struct memsys *ms = &erc32sys;
 int		cputype = 0;		/* 0 = erc32, 2 = leon2,3 = leon3 */
 int             sis_gdb_break;
+int             cpu = 0;		/* active cpu */
+int             ncpu = 1;		/* number of cpus to emulate */
+int             delta = 50;		/* time slice for MP simulation */
 
 #ifdef ERRINJ
 uint32		errcnt = 0;
@@ -103,7 +105,7 @@ batch(sregs, fname)
 	if (slen && (lbuf[slen - 1] == '\n')) {
 	    lbuf[slen - 1] = 0;
 	    printf("sis> %s\n", lbuf);
-	    exec_cmd(sregs, lbuf);
+	    exec_cmd(lbuf);
 	}
     }
     free(lbuf);
@@ -374,14 +376,14 @@ limcalc (freq)
             lim = (uint64) flim;
         } else  {
             printf("error in expression\n");
-            lim = -1;
+            lim = 0;
         }
     }
     return lim;
 }
 
 int
-exec_cmd(struct pstate *sregs, const char *cmd)
+exec_cmd(const char *cmd)
 {
     char           *cmd1, *cmd2;
     int32           stat;
@@ -395,26 +397,26 @@ exec_cmd(struct pstate *sregs, const char *cmd)
     if ((cmd1 = strtok (cmdsave2, " \t")) != NULL) {
 	clen = strlen(cmd1);
 	if (strncmp(cmd1, "bp", clen) == 0) {
-	    for (i = 0; i < sregs->bptnum; i++) {
-		printf("  %d : 0x%08x\n", i + 1, sregs->bpts[i]);
+	    for (i = 0; i < ebase.bptnum; i++) {
+		printf("  %d : 0x%08x\n", i + 1, ebase.bpts[i]);
 	    }
 	} else if (strncmp(cmd1, "+bp", clen) == 0) {
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
-		sregs->bpts[sregs->bptnum] = VAL(cmd1) & ~0x3;
+		ebase.bpts[ebase.bptnum] = VAL(cmd1) & ~0x3;
 		printf("added breakpoint %d at 0x%08x\n",
-		       sregs->bptnum + 1, sregs->bpts[sregs->bptnum]);
-		sregs->bptnum += 1;
+		       ebase.bptnum + 1, ebase.bpts[ebase.bptnum]);
+		ebase.bptnum += 1;
 	    }
 	} else if (strncmp(cmd1, "-bp", clen) == 0) {
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
 		i = VAL(cmd1) - 1;
-		if ((i >= 0) && (i < sregs->bptnum)) {
+		if ((i >= 0) && (i < ebase.bptnum)) {
 		    printf("deleted breakpoint %d at 0x%08x\n", i + 1,
-			   sregs->bpts[i]);
-		    for (; i < sregs->bptnum - 1; i++) {
-			sregs->bpts[i] = sregs->bpts[i + 1];
+			   ebase.bpts[i]);
+		    for (; i < ebase.bptnum - 1; i++) {
+			ebase.bpts[i] = ebase.bpts[i + 1];
 		    }
-		    sregs->bptnum -= 1;
+		    ebase.bptnum -= 1;
 		}
 	    }
 	} else if (strncmp(cmd1, "batch", clen) == 0) {
@@ -425,9 +427,9 @@ exec_cmd(struct pstate *sregs, const char *cmd)
 	    }
 	} else if (strncmp(cmd1, "cont", clen) == 0) {
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) {
-		stat = run_sim(sregs, UINT64_MAX, 0);
+		stat = run_sim(UINT64_MAX/2, 0);
 	    } else {
-		stat = run_sim(sregs, VAL(cmd1), 0);
+		stat = run_sim(VAL(cmd1), 0);
 	    }
 	    daddr = sregs->pc;
 	    ms->sim_halt ();
@@ -470,15 +472,17 @@ exec_cmd(struct pstate *sregs, const char *cmd)
 	    } else {
 		len = VAL(cmd1);
 	    }
-	    sregs->pc = len & ~3;
-	    sregs->npc = sregs->pc + 4;
+	    for (i=0; i<ncpu; i++) {
+	        sregs[i].pc = len & ~3;
+	        sregs[i].npc = sregs->pc + 4;
+	    }
 	    if ((sregs->pc != 0) && (ebase.simtime == 0))
 	        ms->boot_init ();
 	    printf("resuming at 0x%08x\n",sregs->pc);
 	    if ((cmd2 = strtok(NULL, " \t\n\r")) != NULL) {
-		stat = run_sim(sregs, VAL(cmd2), 0);
+		stat = run_sim(VAL(cmd2), 0);
 	    } else {
-		stat = run_sim(sregs, UINT64_MAX, 0);
+		stat = run_sim(UINT64_MAX/2, 0);
 	    }
 	    daddr = sregs->pc;
 	    ms->sim_halt ();
@@ -486,20 +490,22 @@ exec_cmd(struct pstate *sregs, const char *cmd)
 	    gen_help();
 	} else if (strncmp(cmd1, "history", clen) == 0) {
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
-		sregs->histlen = VAL(cmd1);
-		if (sregs->histbuf != NULL)
-		    free(sregs->histbuf);
-		sregs->histbuf = (struct histype *) calloc(sregs->histlen, sizeof(struct histype));
-		printf("trace history length = %d\n\r", sregs->histlen);
-		sregs->histind = 0;
+		ebase.histlen = VAL(cmd1);
+		for (i=0; i<ncpu; i++) {
+		    if (sregs[i].histbuf != NULL)
+		        free(sregs[i].histbuf);
+		        sregs[i].histbuf = (struct histype *) calloc(ebase.histlen, sizeof(struct histype));
+			sregs[i].histind = 0;
+		}
+		printf("trace history length = %d\n\r", ebase.histlen);
 
 	    } else {
-		j = sregs->histind;
-		for (i = 0; i < sregs->histlen; i++) {
-		    if (j >= sregs->histlen)
+		j = sregs[cpu].histind;
+		for (i = 0; i < ebase.histlen; i++) {
+		    if (j >= ebase.histlen)
 			j = 0;
-		    printf(" %8d ", sregs->histbuf[j].time);
-		    dis_mem(sregs->histbuf[j].addr, 1, &dinfo);
+		    printf(" %8d ", sregs[cpu].histbuf[j].time);
+		    dis_mem(sregs[cpu].histbuf[j].addr, 1, &dinfo);
 		    j++;
 		}
 	    }
@@ -521,6 +527,18 @@ exec_cmd(struct pstate *sregs, const char *cmd)
 		len = 64;
 	    disp_mem(daddr, len);
 	    daddr += len;
+	} else if (strncmp(cmd1, "cpu", clen) == 0) {
+	    if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
+		cpu = VAL(cmd1);
+		if (cpu > NCPU) cpu = NCPU;
+	    }
+	    printf("active cpu: %d\n", cpu);
+	} else if (strncmp(cmd1, "ncpu", clen) == 0) {
+	    if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
+		ncpu = VAL(cmd1);
+		if (ncpu > NCPU) ncpu = NCPU;
+	    }
+	    printf("number of online cpus: %d\n", ncpu);
 	} else if (strncmp(cmd1, "wmem", clen) == 0) {
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL)
 		daddr = VAL(cmd1);
@@ -540,30 +558,34 @@ exec_cmd(struct pstate *sregs, const char *cmd)
 	    cmd1 = strtok(NULL, " \t\n\r");
 	    cmd2 = strtok(NULL, " \t\n\r");
 	    if (cmd2 != NULL)
-		set_rega(sregs, cmd1, VAL(cmd2));
+		set_rega(&sregs[cpu], cmd1, VAL(cmd2));
 	    else if (cmd1 != NULL)
-		disp_reg(sregs, cmd1);
+		disp_reg(&sregs[cpu], cmd1);
 	    else {
-		disp_regs(sregs,sregs->psr);
-		disp_ctrl(sregs);
+		disp_regs(&sregs[cpu], sregs[cpu].psr);
+		disp_ctrl(&sregs[cpu]);
 	    }
 	} else if (strncmp(cmd1, "reset", clen) == 0) {
 	    ebase.simtime = 0;
+	    ebase.simstart = 0;
 	    reset_all();
 	    reset_stat(sregs);
 	} else if (strncmp(cmd1, "run", clen) == 0) {
 	    ebase.simtime = 0;
+	    ebase.simstart = 0;
 	    reset_all();
 	    reset_stat(sregs);
             if (last_load_addr != 0) {
-	        sregs->pc = last_load_addr & ~3;
-	        sregs->npc = sregs->pc + 4;
+		for (i=0; i<ncpu; i++) {
+	          sregs[i].pc = last_load_addr & ~3;
+	          sregs[i].npc = sregs[i].pc + 4;
+		}
             }
 	    if ((sregs->pc != 0) && (ebase.simtime == 0)) ms->boot_init ();
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) {
-		stat = run_sim(sregs, UINT64_MAX, 0);
+		stat = run_sim(UINT64_MAX/2, 0);
 	    } else {
-		stat = run_sim(sregs, VAL(cmd1), 0);
+		stat = run_sim(VAL(cmd1), 0);
 	    }
 	    daddr = sregs->pc;
 	    ms->sim_halt ();
@@ -574,12 +596,12 @@ exec_cmd(struct pstate *sregs, const char *cmd)
 		}
 	    }
 	} else if (strncmp(cmd1, "step", clen) == 0) {
-	    stat = run_sim(sregs, 1, 1);
+	    stat = run_sim(1, 1);
 	    daddr = sregs->pc;
 	    ms->sim_halt ();
 	} else if (strncmp(cmd1, "tcont", clen) == 0) {
-	    sregs->tlimit = limcalc(sregs->freq);
-	    stat = run_sim(sregs, UINT64_MAX, 0);
+	    ebase.tlimit = limcalc(ebase.freq);
+	    stat = run_sim(UINT64_MAX/2, 0);
 	    daddr = sregs->pc;
 	    ms->sim_halt ();
 	} else if (strncmp(cmd1, "tgo", clen) == 0) {
@@ -587,30 +609,32 @@ exec_cmd(struct pstate *sregs, const char *cmd)
 		len = last_load_addr;
 	    } else {
 		len = VAL(cmd1);
-	        sregs->tlimit = limcalc(sregs->freq);
+	        ebase.tlimit = limcalc(ebase.freq);
 	    }
 	    sregs->pc = len & ~3;
 	    sregs->npc = sregs->pc + 4;
 	    printf("resuming at 0x%08x\n",sregs->pc);
-	    stat = run_sim(sregs, UINT64_MAX, 0);
+	    stat = run_sim(UINT64_MAX/2, 0);
 	    daddr = sregs->pc;
 	    ms->sim_halt ();
 	} else if (strncmp(cmd1, "tlimit", clen) == 0) {
-	   sregs->tlimit = limcalc(sregs->freq);
-	   if (sregs->tlimit != (uint32) -1)
-              printf("simulation limit = %u (%.3f ms)\n",(uint32) sregs->tlimit,
-		sregs->tlimit / sregs->freq / 1000);
+	   ebase.tlimit = limcalc(ebase.freq);
+	   if (ebase.tlimit != (uint32) -1)
+	      if (sis_verbose)
+                  printf("simulation limit = %u (%.3f ms)\n",
+		      (uint32) ebase.tlimit, ebase.tlimit / ebase.freq / 1000);
 	} else if (strncmp(cmd1, "tra", clen) == 0) {
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) {
-		stat = run_sim(sregs, UINT64_MAX, 1);
+		stat = run_sim(UINT64_MAX/2, 1);
 	    } else {
-		stat = run_sim(sregs, VAL(cmd1), 1);
+		stat = run_sim(VAL(cmd1), 1);
 	    }
 	    printf("\n");
 	    daddr = sregs->pc;
 	    ms->sim_halt ();
 	} else if (strncmp(cmd1, "trun", clen) == 0) {
 	    ebase.simtime = 0;
+	    ebase.simstart = 0;
 	    reset_all();
 	    reset_stat(sregs);
             if (last_load_addr != 0) {
@@ -618,55 +642,55 @@ exec_cmd(struct pstate *sregs, const char *cmd)
 	        sregs->npc = sregs->pc + 4;
             }
 	    if ((sregs->pc != 0) && (ebase.simtime == 0)) ms->boot_init ();
-	    sregs->tlimit = limcalc(sregs->freq);
-	    stat = run_sim(sregs, UINT64_MAX, 0);
+	    ebase.tlimit = limcalc(ebase.freq);
+	    stat = run_sim(UINT64_MAX/2, 0);
 	    daddr = sregs->pc;
 	    ms->sim_halt ();
 	} else if (strncmp(cmd1, "wp", clen) == 0) {
-	    for (i = 0; i < sregs->wprnum; i++) {
-		printf("  %d : 0x%08x (read)\n", i + 1, sregs->wprs[i]);
+	    for (i = 0; i < ebase.wprnum; i++) {
+		printf("  %d : 0x%08x (read)\n", i + 1, ebase.wprs[i]);
 	    }
-	    for (i = 0; i < sregs->wpwnum; i++) {
-		printf("  %d : 0x%08x (write)\n", i + 1, sregs->wpws[i]);
+	    for (i = 0; i < ebase.wpwnum; i++) {
+		printf("  %d : 0x%08x (write)\n", i + 1, ebase.wpws[i]);
 	    }
 	} else if (strncmp(cmd1, "+wpr", clen) == 0) {
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
-		sregs->wprs[sregs->wprnum] = VAL(cmd1) & ~0x3;
-		sregs->wprm[sregs->wprnum] = 3;
+		ebase.wprs[ebase.wprnum] = VAL(cmd1) & ~0x3;
+		ebase.wprm[ebase.wprnum] = 3;
 		printf("added read watchpoint %d at 0x%08x\n",
-		       sregs->wprnum + 1, sregs->wprs[sregs->wprnum]);
-		sregs->wprnum += 1;
+		       ebase.wprnum + 1, ebase.wprs[ebase.wprnum]);
+		ebase.wprnum += 1;
 	    }
 	} else if (strncmp(cmd1, "-wpr", clen) == 0) {
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
 		i = VAL(cmd1) - 1;
-		if ((i >= 0) && (i < sregs->wprnum)) {
+		if ((i >= 0) && (i < ebase.wprnum)) {
 		    printf("deleted read watchpoint %d at 0x%08x\n", i + 1,
-			   sregs->wprs[i]);
-		    for (; i < sregs->wprnum - 1; i++) {
-			sregs->wprs[i] = sregs->wprs[i + 1];
+			   ebase.wprs[i]);
+		    for (; i < ebase.wprnum - 1; i++) {
+			ebase.wprs[i] = ebase.wprs[i + 1];
 		    }
-		    sregs->wprnum -= 1;
+		    ebase.wprnum -= 1;
 		}
 	    }
 	} else if (strncmp(cmd1, "+wpw", clen) == 0) {
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
-		sregs->wpws[sregs->wpwnum] = VAL(cmd1) & ~0x3;
-		sregs->wpwm[sregs->wpwnum] = 3;
+		ebase.wpws[ebase.wpwnum] = VAL(cmd1) & ~0x3;
+		ebase.wpwm[ebase.wpwnum] = 3;
 		printf("added write watchpoint %d at 0x%08x\n",
-		       sregs->wpwnum + 1, sregs->wpws[sregs->wpwnum]);
-		sregs->wpwnum += 1;
+		       ebase.wpwnum + 1, ebase.wpws[ebase.wpwnum]);
+		ebase.wpwnum += 1;
 	    }
 	} else if (strncmp(cmd1, "-wpw", clen) == 0) {
 	    if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) {
 		i = VAL(cmd1) - 1;
-		if ((i >= 0) && (i < sregs->wpwnum)) {
+		if ((i >= 0) && (i < ebase.wpwnum)) {
 		    printf("deleted write watchpoint %d at 0x%08x\n", i + 1,
-			   sregs->wpws[i]);
-		    for (; i < sregs->wpwnum - 1; i++) {
-			sregs->wpws[i] = sregs->wpws[i + 1];
+			   ebase.wpws[i]);
+		    for (; i < ebase.wpwnum - 1; i++) {
+			ebase.wpws[i] = ebase.wpws[i + 1];
 		    }
-		    sregs->wpwnum -= 1;
+		    ebase.wpwnum -= 1;
 		}
 	    }
 	} else
@@ -684,7 +708,7 @@ void
 reset_stat(sregs)
     struct pstate  *sregs;
 {
-    sregs->tottime = 0.0;
+    ebase.tottime = 0.0;
     sregs->pwdtime = 0;
     sregs->ninst = 0;
     sregs->fholdt = 0;
@@ -694,7 +718,7 @@ reset_stat(sregs)
     sregs->nstore = 0;
     sregs->nload = 0;
     sregs->nbranch = 0;
-    sregs->simstart = ebase.simtime;
+    ebase.simstart = ebase.simtime;
 
 }
 
@@ -702,54 +726,70 @@ void
 show_stat(sregs)
     struct pstate  *sregs;
 {
-    uint64          iinst;
-    uint64          stime;
-
-    if (sregs->tottime == 0.0)
-        sregs->tottime += 1E-6;
-    stime = ebase.simtime - sregs->simstart;	/* Total simulated time */
+    uint64          iinst, ninst, pwdtime;
+    uint64          stime, atime;
+    int		i;
+
+    ninst = 0;
+    pwdtime = 0;
+    atime = 0;
+    if (ebase.tottime == 0.0)
+        ebase.tottime += 1E-6;
+    for (i=0; i<ncpu; i++) {
+	if (sregs[i].pwd_mode) {
+	    sregs[i].pwdtime += sregs[i].simtime - sregs[i].pwdstart;
+	    sregs[i].pwdstart = sregs[i].simtime;
+	}
+        ninst += sregs[i].ninst;
+	pwdtime += sregs[i].pwdtime;
+    }
+    stime = ebase.simtime - ebase.simstart; /* Total simulated time */
+    printf ("\n Frequency       : %4.1f MHz\n", ebase.freq);
+    printf(" Cycles          : %" PRIu64 "\n", stime);
+    printf(" Instructions    : %" PRIu64 "\n", ninst);
+    printf(" Simulated time  : %.2f s\n",
+        (double) (stime) / 1000000.0 / ebase.freq);
+    printf(" System perf.    : %.2f MOPS\n",
+        (double) ninst / ((double) (stime) / ebase.freq));
+    printf(" Real-time perf. : %.2f %%\n",
+	100.0 / (ebase.tottime / ((double) (stime) / (ebase.freq * 1.0E6))));
+    printf(" Simulator perf. : %.2f MIPS\n",
+	(double)(ninst / ebase.tottime / 1E6));
+    printf(" Wall time       : %.2f s\n\n", ebase.tottime);
+    printf (" Core   MIPS   MFLOPS     CPI     Util\n");
+    for (i=0; i<ncpu; i++) {
 #ifdef STAT
-
-    iinst = sregs->ninst - sregs->finst - sregs->nload - sregs->nstore -
-	sregs->nbranch;
+        iinst = sregs[i].ninst - sregs[i].finst - sregs[i].nload - sregs[i].nstore -
+	    sregs[i].nbranch;
 #endif
 
-    printf("\n Cycles       : %9" PRIu64 "\n\r", ebase.simtime - sregs->simstart);
-    printf(" Instructions : %9" PRIu64 "\n", sregs->ninst);
+        stime = sregs[i].simtime - ebase.simstart + 1; /* Core simulated time */
+        printf ("  %d    %5.2f    %5.2f    %5.2f    %5.2f %%\n", i,
+	  ebase.freq * (double) (sregs[i].ninst - sregs[i].finst) /
+	  (double) (stime - sregs[i].pwdtime),
+          ebase.freq * (double) sregs[i].finst / (double) (stime - sregs[i].pwdtime),
+	  (double) (stime - sregs[i].pwdtime) / (double) (sregs[i].ninst + 1),
+	 100.0 * (1.0 - ((double) sregs[i].pwdtime / (double) stime)));
+    }
 
 #ifdef STAT
-    printf ("   integer    : %9.2f %%\n", 100.0 * (double) iinst / (double) sregs->ninst);
+    printf ("   integer    : %9.2f %%\n", 100.0 * (double) iinst / (double) sregs[i].ninst);
     printf("   load       : %9.2f %%\n",
-	   100.0 * (double) sregs->nload / (double) sregs->ninst);
+	   100.0 * (double) sregs->nload / (double) sregs[i].ninst);
     printf("   store      : %9.2f %%\n",
-	   100.0 * (double) sregs->nstore / (double) sregs->ninst);
+	   100.0 * (double) sregs->nstore / (double) sregs[i].ninst);
     printf("   branch     : %9.2f %%\n",
-	   100.0 * (double) sregs->nbranch / (double) sregs->ninst);
+	   100.0 * (double) sregs->nbranch / (double) sregs[i].ninst);
     printf("   float      : %9.2f %%\n",
-	   100.0 * (double) sregs->finst / (double) sregs->ninst);
+	   100.0 * (double) sregs->finst / (double) sregs[i].ninst);
     printf(" Integer CPI  : %9.2f\n",
-	   ((double) (stime - sregs->pwdtime - sregs->fholdt - sregs->finst))
+	   ((double) (stime - sregs[i].pwdtime - sregs[i].fholdt - sregs[i].finst))
 	   /
-	   (double) (sregs->ninst - sregs->finst));
+	   (double) (sregs[i].ninst - sregs[i].finst));
     printf(" Float CPI    : %9.2f\n",
-	   ((double) sregs->fholdt / (double) sregs->finst) + 1.0);
+	   ((double) sregs[i].fholdt / (double) sregs[i].finst) + 1.0);
 #endif
-    printf(" Overall CPI  : %9.2f\n",
-	  (double) (stime - sregs->pwdtime) / (double) sregs->ninst);
-    printf ("\n CPU performance (%4.1f MHz)  : %5.2f MOPS (%5.2f MIPS, %5.2f MFLOPS)\n",
-	  sregs->freq, sregs->freq * (double) sregs->ninst / (double) (stime - sregs->pwdtime),
-	  sregs->freq * (double) (sregs->ninst - sregs->finst) /
-	  (double) (stime - sregs->pwdtime),
-     sregs->freq * (double) sregs->finst / (double) (stime - sregs->pwdtime));
-    printf (" Simulated CPU time          : %.2f s\n",
-	(double) (ebase.simtime - sregs->simstart) / 1000000.0 / sregs->freq);
-    printf(" Processor utilisation       : %.2f %%\n",
-	100.0 * (1.0 - ((double) sregs->pwdtime / (double) stime)));
-    printf(" Real-time performance       : %.2f %%\n",
-	100.0 / (sregs->tottime / ((double) (stime) / (sregs->freq * 1.0E6))));
-    printf(" Simulator performance       : %.2f MIPS\n",
-	(double)(sregs->ninst) / sregs->tottime / 1E6);
-    printf(" Used time (sys + user)      : %.2f s\n\n", sregs->tottime);
+    printf("\n");
 }
 
 
@@ -758,13 +798,17 @@ void
 init_bpt(sregs)
     struct pstate  *sregs;
 {
-    sregs->bptnum = 0;
-    sregs->wprnum = 0;
-    sregs->wpwnum = 0;
-    sregs->histlen = 0;
-    sregs->histind = 0;
-    sregs->histbuf = NULL;
-    sregs->tlimit = -1;
+    int i;
+
+    ebase.bptnum = 0;
+    ebase.wprnum = 0;
+    ebase.wpwnum = 0;
+    ebase.histlen = 0;
+    for (i=0; i<ncpu; i++) {
+	sregs[i].histind = 0;
+	sregs[i].histbuf = NULL;
+    }
+    ebase.tlimit = 0;
 }
 
 static void
@@ -852,6 +896,8 @@ disp_ctrl(sregs)
 
     printf("\n psr: %08X   wim: %08X   tbr: %08X   y: %08X\n",
 	   sregs->psr, sregs->wim, sregs->tbr, sregs->y);
+    printf(" cc: %08X   asr17: %08X\n",
+	   sregs->cache_ctrl, sregs->asr17);
     ms->sis_memory_read (sregs->pc, (char *) &i, 4);
     printf ("\n  pc: %08X = %08X    ", sregs->pc, i);
     print_insn_sparc_sis(sregs->pc, &dinfo);
@@ -860,6 +906,8 @@ disp_ctrl(sregs)
     print_insn_sparc_sis(sregs->npc, &dinfo);
     if (sregs->err_mode)
 	printf("\n IU in error mode");
+    else if (sregs->pwd_mode)
+	printf("\n IU in power-down mode");
     printf("\n\n");
 }
 
@@ -949,14 +997,35 @@ event(cfunc, arg, delta)
     ev1->nxt->time = delta;
     ev1->nxt->cfunc = cfunc;
     ev1->nxt->arg = arg;
+    ebase.evtime = ebase.eq.nxt->time;
 }
 
-#if 0	/* apparently not used */
+/* remove event from event queue */
 void
-stop_event()
+remove_event(cfunc)
+    void            (*cfunc) ();
+{
+    struct evcell  *ev1, *evdel;
+
+    ev1 = &ebase.eq;
+    while (ev1->nxt != NULL) {
+        if (ev1->nxt->cfunc == cfunc) {
+	    evdel = ev1->nxt;
+	    ev1->nxt = ev1->nxt->nxt;
+	    evdel->nxt = ebase.freeq;
+	    ebase.freeq = evdel;
+	}
+	ev1 = ev1->nxt;
+    }
+    ebase.evtime = ebase.eq.nxt->time;
+}
+
+static void
+last_event (int32 arg)
 {
+    printf("Warning: end of time ... exiting!\n");
+    exit(0);
 }
-#endif
 
 void
 init_event()
@@ -969,44 +1038,27 @@ init_event()
 	evbuf[i].nxt = &evbuf[i + 1];
     }
     evbuf[EVENT_MAX - 1].nxt = NULL;
-}
-
-void
-set_int(level, callback, arg)
-    int32           level;
-    void            (*callback) ();
-    int32           arg;
-{
-    irqarr[level & 0x0f].callback = callback;
-    irqarr[level & 0x0f].arg = arg;
+    event(last_event, 0, UINT64_MAX);
 }
 
 /* Advance simulator time */
 
 void
-advance_time(sregs)
-    struct pstate  *sregs;
+advance_time(endtime)
+    uint64          endtime;
 {
 
     struct evcell  *evrem;
     void            (*cfunc) ();
     uint32          arg;
-    uint64          endtime;
 
-#ifdef STAT
-    sregs->fholdt += sregs->fhold;
-    sregs->holdt += sregs->hold;
-    sregs->icntt += sregs->icnt;
-#endif
-
-    endtime = ebase.simtime + sregs->icnt + sregs->hold + sregs->fhold;
-
-    while ((ebase.eq.nxt->time <= (endtime)) && (ebase.eq.nxt != NULL)) {
+    while (ebase.evtime <= endtime) {
 	ebase.simtime = ebase.eq.nxt->time;
 	cfunc = ebase.eq.nxt->cfunc;
 	arg = ebase.eq.nxt->arg;
 	evrem = ebase.eq.nxt;
 	ebase.eq.nxt = ebase.eq.nxt->nxt;
+        ebase.evtime = ebase.eq.nxt->time;
 	evrem->nxt = ebase.freeq;
 	ebase.freeq = evrem;
 	cfunc(arg);
@@ -1018,39 +1070,15 @@ advance_time(sregs)
 uint32
 now()
 {
-    return ebase.simtime;
+    return (uint32) ebase.simtime;
 }
 
-
-/* Advance time until an external interrupt is seen */
-
-int
-wait_for_irq()
+void
+pwd_enter(struct pstate *sregs)
 {
-    struct evcell  *evrem;
-    void            (*cfunc) ();
-    int32           arg;
-    uint64          endtime;
-
-    if (ebase.eq.nxt == NULL)
-	printf("Warning: event queue empty - power-down mode not entered\n");
-    endtime = ebase.simtime;
-    while (!ext_irl && (ebase.eq.nxt != NULL)) {
-	ebase.simtime = ebase.eq.nxt->time;
-	cfunc = ebase.eq.nxt->cfunc;
-	arg = ebase.eq.nxt->arg;
-	evrem = ebase.eq.nxt;
-	ebase.eq.nxt = ebase.eq.nxt->nxt;
-	evrem->nxt = ebase.freeq;
-	ebase.freeq = evrem;
-	cfunc(arg);
-	if (ctrl_c) {
-	    printf("\bwarning: power-down mode interrupted\n");
-	    break;
-	}
-    }
-    sregs.pwdtime += ebase.simtime - endtime;
-    return ebase.simtime - endtime;
+    sregs->pwd_mode = 1;
+    sregs->pwdstart = sregs->simtime;
+    sregs->hold += delta;
 }
 
 int
@@ -1059,10 +1087,10 @@ check_bpt(sregs)
 {
     int32           i;
 
-    if ((sregs->bphit) || (sregs->annul))
+    if (ebase.bphit)
 	return 0;
-    for (i = 0; i < (int32) sregs->bptnum; i++) {
-	if (sregs->pc == sregs->bpts[i])
+    for (i = 0; i < (int32) ebase.bptnum; i++) {
+	if (sregs->pc == ebase.bpts[i])
 	    return BPT_HIT;
     }
     return 0;
@@ -1076,11 +1104,11 @@ check_wpr(sregs, address, mask)
 {
     int32           i, msk;
 
-    for (i = 0; i < sregs->wprnum; i++) {
-	msk = ~(mask | sregs->wprm[i]);
-	if (((address ^ sregs->wprs[i]) & msk) == 0) {
-	    sregs->wpaddress = address;
-            if (sregs->wphit) return (0);
+    for (i = 0; i < ebase.wprnum; i++) {
+	msk = ~(mask | ebase.wprm[i]);
+	if (((address ^ ebase.wprs[i]) & msk) == 0) {
+	    ebase.wpaddress = address;
+            if (ebase.wphit) return (0);
 	    return (WPT_HIT);
 	}
     }
@@ -1095,11 +1123,11 @@ check_wpw(sregs, address, mask)
 {
     int32           i, msk;
 
-    for (i = 0; i < sregs->wpwnum; i++) {
-	msk = ~(mask | sregs->wpwm[i]);
-	if (((address ^ sregs->wpws[i]) & msk) == 0) {
-	    sregs->wpaddress = address;
-            if (sregs->wphit) return (0);
+    for (i = 0; i < ebase.wpwnum; i++) {
+	msk = ~(mask | ebase.wpwm[i]);
+	if (((address ^ ebase.wpws[i]) & msk) == 0) {
+	    ebase.wpaddress = ebase.wpws[i];
+            if (ebase.wphit) return (0);
 	    return (WPT_HIT);
 	}
     }
@@ -1110,7 +1138,7 @@ void
 reset_all()
 {
     init_event();		/* Clear event queue */
-    init_regs(&sregs);
+    init_regs(sregs);
     ms->reset ();
 #ifdef ERRINJ
     errinjstart();
@@ -1121,13 +1149,258 @@ void
 sys_reset()
 {
     reset_all();
-    sregs.trap = 256;		/* Force fake reset trap */
+    sregs[0].trap = 256;		/* Force fake reset trap */
 }
 
 void
 sys_halt()
 {
-    sregs.trap = 257;           /* Force fake halt trap */
+    sregs[0].trap = 257;           /* Force fake halt trap */
+}
+
+/* simulate uni-processor system */
+
+static int
+run_sim_un(icount, dis)
+    uint64          icount;
+    int             dis;
+{
+    int             irq, mexc, deb;
+
+    if (sregs->err_mode) icount = 0;
+    deb = dis || ebase.histlen || ebase.bptnum;
+    irq = 0;
+    while (icount > 0) {
+	if (sregs->pwd_mode) {
+	    sregs->simtime = ebase.evtime; /* skip forward to next event */
+	    if (ext_irl[0]) irq = check_interrupts(sregs);
+	} else {
+	    sregs->icnt = 1;
+	    sregs->fhold = 0;
+	    if (ext_irl[0]) irq = check_interrupts(sregs);
+	    if (!irq) {
+		mexc = ms->memory_iread (sregs->pc, &sregs->inst, &sregs->hold);
+		if (mexc) {
+		    sregs->trap = I_ACC_EXC;
+		} else {
+		    if (deb) {
+			if (ebase.histlen) {
+			    sregs->histbuf[sregs->histind].addr = sregs->pc;
+			    sregs->histbuf[sregs->histind].time = ebase.simtime;
+			    sregs->histind++;
+			    if (sregs->histind >= ebase.histlen)
+				sregs->histind = 0;
+			}
+			if (dis) {
+			    printf(" %8" PRIu64 " ", ebase.simtime);
+			    dis_mem(sregs->pc, 1, &dinfo);
+			}
+			if ((ebase.bptnum) && (ebase.bphit = check_bpt(sregs)))
+			    icount = 0;
+			else {
+			    dispatch_instruction(sregs);
+			    icount--;
+			}
+		    } else {
+			dispatch_instruction(sregs);
+			icount--;
+		    }
+		}
+	    } else
+		sregs->trap = irq + 16;
+	    if (sregs->trap) {
+		irq = 0;
+		if ((sregs->err_mode = execute_trap(sregs)) == WPT_HIT) {
+		    sregs->err_mode = 0;
+		    sregs->trap = 0;
+		    icount = 0;
+		}
+		if (sregs->err_mode) {
+		    ms->error_mode (sregs->pc);
+		    icount = 0;
+		}
+	    }
+#ifdef STAT
+	    sregs->fholdt += sregs->fhold;
+	    sregs->holdt += sregs->hold;
+	    sregs->icntt += sregs->icnt;
+#endif
+    	    sregs->simtime += sregs->icnt + sregs->hold + sregs->fhold;
+	}
+	advance_time(sregs->simtime);
+	if (ctrl_c) {
+	    icount = 0;
+	}
+    }
+    if (sregs->err_mode)
+	return ERROR;
+    if (ebase.bphit)
+	return (BPT_HIT);
+    if (ebase.wphit)
+	return (WPT_HIT);
+    if (ctrl_c) {
+	return CTRL_C;
+    }
+    return TIME_OUT;
+}
+
+/* stop simulation after specified time */
+
+static void
+sim_timeout(int32 arg)
+{
+    ctrl_c = arg;
+}
+
+/* simulate one core in an mp system */
+
+static int
+run_sim_core(sregs, ntime, deb, dis)
+    struct pstate  *sregs;
+    uint64 ntime;
+    int deb;
+    int dis;
+{
+    int mexc, irq;
+        irq = 0;
+	if (sregs->pwd_mode == 0)
+	  while (ntime > sregs->simtime) {
+	    if (ext_irl[sregs->cpu])
+		irq = check_interrupts(sregs);
+	    else
+		irq = 0;
+	    sregs->icnt = 1;
+	    mexc = ms->memory_iread (sregs->pc, &sregs->inst, &sregs->hold);
+	    sregs->fhold = 0;
+	    if (!irq) {
+		if (mexc) {
+		    sregs->trap = I_ACC_EXC;
+		} else {
+		    if (deb) {
+			if (ebase.histlen) {
+			    sregs->histbuf[sregs->histind].addr = sregs->pc;
+			    sregs->histbuf[sregs->histind].time = sregs->simtime;
+			    sregs->histind++;
+			    if (sregs->histind >= ebase.histlen)
+				sregs->histind = 0;
+			}
+			if (dis) {
+			    printf("cpu %d  %8" PRIu64 " ", sregs->cpu, sregs->simtime);
+			    dis_mem(sregs->pc, 1, &dinfo);
+			}
+			if ((ebase.bptnum) && (ebase.bphit = check_bpt(sregs))) {
+			    ntime = sregs->simtime;
+		        } else {
+			    dispatch_instruction(sregs);
+			}
+		    } else {
+			dispatch_instruction(sregs);
+		    }
+		}
+	    } else
+		sregs->trap = irq + 16;
+	    if (sregs->trap) {
+		irq = 0;
+		if ((sregs->err_mode = execute_trap(sregs)) == WPT_HIT) {
+		    sregs->err_mode = 0;
+		    sregs->trap = 0;
+		    ntime = sregs->simtime;
+		    ctrl_c = 1;
+		    break;
+		}
+		if (sregs->err_mode) {
+		    ms->error_mode (sregs->pc);
+		    sregs->pwd_mode = 1;
+		    sregs->pwdstart = sregs->simtime;
+	    	    sregs->simtime = ntime;
+		    ctrl_c = 1;
+		    break;
+		}
+	    }
+#ifdef STAT
+	    sregs->fholdt += sregs->fhold;
+	    sregs->holdt += sregs->hold;
+	    sregs->icntt += sregs->icnt;
+#endif
+    	    sregs->simtime += sregs->icnt + sregs->hold + sregs->fhold;
+	  }
+	else
+	    sregs->simtime = ntime;
+	    if (ext_irl[sregs->cpu]) irq = check_interrupts(sregs);
+}
+
+/* time slice simulation of cpu cores in MP system */
+
+static int
+run_sim_mp(icount, dis)
+    uint64          icount;
+    int             dis;
+{
+    uint64          ntime;
+    int             deb, i;
+    int             err_mode, bphit, wphit;
+
+    err_mode = bphit = wphit = 0;
+    icount += ebase.simtime;
+    for(i=0; i<ncpu; i++) {
+      if (sregs[i].err_mode) {
+	  icount = 0;
+	  err_mode = 1;
+      }
+    }
+    while (icount > ebase.simtime) {
+      ntime = ebase.simtime + delta;
+      if (ntime > icount) ntime = icount;
+      for(i=0; i<ncpu; i++) {
+        deb = dis || ebase.histlen || ebase.bptnum;
+	run_sim_core(&sregs[i], ntime, deb, dis);
+	err_mode |= sregs[i].err_mode;
+	bphit |= ebase.bphit;
+	wphit |= ebase.wphit;
+      }
+      advance_time(ntime);
+      if (ctrl_c) {
+	  icount = 0;
+      }
+    }
+    /* align time of all cores to allow single stepping */
+    for(i=0; i<ncpu; i++) {
+	sregs[i].simtime = ebase.simtime;
+    }
+    if (err_mode)
+	return ERROR;
+    if (bphit)
+	return (BPT_HIT);
+    if (wphit)
+	return (WPT_HIT);
+    if (ctrl_c) {
+	return CTRL_C;
+    }
+    return TIME_OUT;
+}
+
+int
+run_sim(icount, dis)
+    uint64          icount;
+    int             dis;
+{
+    int res;
+
+    ctrl_c = 0;
+    ebase.starttime = get_time();
+    ms->init_stdio ();
+    if (ebase.tlimit > ebase.simtime)
+	event(sim_timeout, 2, ebase.tlimit - ebase.simtime);
+    if (ncpu > 1)
+	res = run_sim_mp(icount, dis);
+    else
+	res = run_sim_un(icount, dis);
+    remove_event(sim_timeout);
+    ebase.tottime += get_time() - ebase.starttime;
+    ms->restore_stdio ();
+    if ((res == CTRL_C) && (ctrl_c == 2))
+	printf("\nTime-out limit reached\n");	
+    return res;
 }
 
 #include "ansidecl.h"
diff --git a/sim/erc32/help.c b/sim/erc32/help.c
index 1e1339e1c7..60496cdb23 100644
--- a/sim/erc32/help.c
+++ b/sim/erc32/help.c
@@ -21,7 +21,7 @@
 #include "sis.h"
 
 void
-usage()
+sis_usage()
 {
 
     printf("usage: sis [-uart1 uart_device1] [-uart2 uart_device2]\n");
diff --git a/sim/erc32/interf.c b/sim/erc32/interf.c
index da0e7c3e66..0a756f6e35 100644
--- a/sim/erc32/interf.c
+++ b/sim/erc32/interf.c
@@ -35,72 +35,23 @@
 #include "gdb/common/break-common.h"
 
 #define PSR_CWP 0x7
+#define	VAL(x)	strtol(x,(char **)NULL,0)
 
-int
-run_sim(sregs, icount, dis)
-    struct pstate  *sregs;
+static int
+run_sim_gdb(icount, dis)
     uint64          icount;
     int             dis;
 {
-    int             mexc, irq;
+    int             res;
 
     if (sis_verbose)
 	(*sim_callback->printf_filtered) (sim_callback, "resuming at %x\n",
 					  sregs->pc);
-   ms->init_stdio ();
-   sregs->starttime = get_time();
-   irq = 0;
-   if (sregs->err_mode) icount = 0;
-   if ((sregs->pc != 0) && (ebase.simtime == 0))
+    if ((sregs->pc != 0) && (ebase.simtime == 0))
 	ms->boot_init ();
-   while (icount > 0) {
-	sregs->fhold = 0;
-	sregs->icnt = 1;
-        mexc = ms->memory_iread (sregs->pc, &sregs->inst, &sregs->hold);
-        if (sregs->annul) {
-            sregs->annul = 0;
-            sregs->pc = sregs->npc;
-            sregs->npc = sregs->npc + 4;
-        } else {
-	    if (ext_irl) irq = check_interrupts(sregs);
-	    if (!irq) {
-		if (mexc) {
-		    sregs->trap = I_ACC_EXC;
-		} else {
-		    dispatch_instruction(sregs);
-		    icount--;
-		}
-	    }
-	    if (sregs->trap) {
-                irq = 0;
-		if ((sregs->err_mode = execute_trap(sregs)) == WPT_HIT) {
-		    sregs->err_mode = 0;
-		    sregs->trap = 0;
-		    icount = 0;
-		}
-		if (sregs->err_mode) icount = 0;
-	    }
-	}
-	advance_time(sregs);
-	if (ctrl_c)
-	    icount = 0;
-    }
-    ms->sim_halt ();
-    sregs->tottime += get_time() - sregs->starttime;
-    ms->restore_stdio ();
+    res = run_sim(icount, dis);
     clearerr(stdin);
-    if (sregs->err_mode) {
-	ms->error_mode (sregs->pc);
-	return ERROR;
-    }
-    if (ctrl_c) {
-	ctrl_c = 0;
-	sregs->wphit = sregs->bphit = 0;
-	return CTRL_C;
-    }
-    if ((sregs->bphit) || (sregs->wphit))
-	return (BPT_HIT);
-    return TIME_OUT;
+    return res;
 }
 
 SIM_DESC
@@ -113,11 +64,10 @@ sim_open (kind, callback, abfd, argv)
 
     int             argc = 0;
     int             stat = 1;
-    int             freq = 0;
 
     sim_callback = callback;
-    sis_gdb_break = 1;
 
+    if (!ebase.freq) ebase.freq = 14;
     sis_gdb_break = 1;
     argc = countargv (argv);
     while (stat < argc) {
@@ -146,10 +96,12 @@ sim_open (kind, callback, abfd, argv)
 	    if (strcmp (argv[stat], "-leon2") == 0) {
 		ms = &leon2;
 		cputype = CPU_LEON2;
+		ebase.freq = 50;
 	    } else
             if (strcmp (argv[stat], "-leon3") == 0) {
 		ms = &leon3;
                 cputype = CPU_LEON3;
+		ebase.freq = 50;
             } else
             if (strcmp(argv[stat], "-wrp") == 0) {
                 wrp = 1;
@@ -173,8 +125,16 @@ sim_open (kind, callback, abfd, argv)
 	    } else
 	    if (strcmp(argv[stat], "-freq") == 0) {
 		if ((stat + 1) < argc) {
-		    freq = strtol(argv[++stat], (char **)NULL, 0);
+		    ebase.freq = strtol(argv[++stat], (char **)NULL, 0);
 		}
+	    } else if (strcmp(argv[stat], "-m") == 0) {
+		if ((stat + 1) < argc)
+		    ncpu = VAL(argv[++stat]);
+		    if ((ncpu < 1) || (ncpu > NCPU)) ncpu = 1;
+	    } else if (strcmp(argv[stat], "-d") == 0) {
+		if ((stat + 1) < argc)
+		    delta = VAL(argv[++stat]);
+		    if (delta <= 0) delta = 25;
 	    } else
 	    if (strncmp(argv[stat], "--sysroot=", sizeof("--sysroot=") - 1) == 0) {
 		/* Ignore until we start to support this.  */
@@ -188,11 +148,6 @@ sim_open (kind, callback, abfd, argv)
 	stat++;
     }
 
-    if ((cputype == CPU_LEON3) || (cputype == CPU_LEON2))
-        sregs.freq = freq ? freq : 50;
-    else
-        sregs.freq = freq ? freq : 14;
-
     if (sis_verbose) {
 	(*sim_callback->printf_filtered) (sim_callback, "\n SIS - SPARC instruction simulator %s\n", sis_version);
 	(*sim_callback->printf_filtered) (sim_callback, " Bug-reports to Jiri Gaisler (jiri@gaisler.se)\n\n");
@@ -201,7 +156,7 @@ sim_open (kind, callback, abfd, argv)
             (*sim_callback->printf_filtered) (sim_callback, "LEON2 emulation enabled\n");
             break;
         case CPU_LEON3:
-            (*sim_callback->printf_filtered) (sim_callback, "LEON3 emulation enabled\n");
+            (*sim_callback->printf_filtered) (sim_callback, "LEON3 emulation enabled, %d core(s)\n", ncpu);
             break;
         default:
             (*sim_callback->printf_filtered) (sim_callback, "ERC32 emulation enabled\n");
@@ -214,7 +169,7 @@ sim_open (kind, callback, abfd, argv)
 	  (*sim_callback->printf_filtered) (sim_callback, "dumb IO (no input, dumb output)\n");
 	if (sis_gdb_break == 0)
 	  (*sim_callback->printf_filtered) (sim_callback, "disabling GDB trap handling for breakpoints\n");
-	  (*sim_callback->printf_filtered) (sim_callback, "CPU freq %3.1f MHz\n", sregs.freq);
+	  (*sim_callback->printf_filtered) (sim_callback, "CPU freq %3.1f MHz\n", ebase.freq);
     }
 
 #ifdef F_GETFL
@@ -228,9 +183,10 @@ sim_open (kind, callback, abfd, argv)
 #endif
     reset_all();
     ebase.simtime = 0;
+    ebase.simstart = 0;
     ms->init_sim ();
-    init_bpt(&sregs);
-    reset_stat(&sregs);
+    init_bpt(sregs);
+    reset_stat(sregs);
 
     /* Fudge our descriptor for now.  */
     return (SIM_DESC) 1;
@@ -267,15 +223,20 @@ sim_create_inferior(sd, abfd, argv, env)
      char * const *argv;
      char * const *env;
 {
+    int i;
+
     bfd_vma start_address = 0;
     if (abfd != NULL)
       start_address = bfd_get_start_address (abfd);
 
     ebase.simtime = 0;
+    ebase.simstart = 0;
     reset_all();
-    reset_stat(&sregs);
-    sregs.pc = start_address & ~3;
-    sregs.npc = sregs.pc + 4;
+    reset_stat(sregs);
+    for (i=0; i<ncpu; i++){
+        sregs[i].pc = start_address & ~3;
+        sregs[i].npc = sregs[cpu].pc + 4;
+    }
     return SIM_RC_OK;
 }
 
@@ -290,7 +251,7 @@ sim_store_register(sd, regno, value, length)
 
     regval = (value[0] << 24) | (value[1] << 16)
 		 | (value[2] << 8) | value[3];
-    set_regi(&sregs, regno, regval);
+    set_regi(sregs, regno, regval);
     return length;
 }
 
@@ -302,7 +263,7 @@ sim_fetch_register(sd, regno, buf, length)
     unsigned char  *buf;
      int length;
 {
-    get_regi(&sregs, regno, buf);
+    get_regi(sregs, regno, buf);
     return -1;
 }
 
@@ -333,7 +294,7 @@ sim_info(sd, verbose)
      SIM_DESC sd;
      int verbose;
 {
-    show_stat(&sregs);
+    show_stat(sregs);
 }
 
 int             simstat = OK;
@@ -356,6 +317,7 @@ sim_stop_reason(sd, reason, sigrc)
 	*sigrc = 0;
 	break;
     case BPT_HIT:
+    case WPT_HIT:
 	*reason = sim_stopped;
 	*sigrc = GDB_SIGNAL_TRAP;
 	break;
@@ -381,7 +343,7 @@ sim_stop_reason(sd, reason, sigrc)
 */
 
 static void
-flush_windows ()
+flush_windows (struct pstate *sregs)
 {
   int invwin;
   int cwp;
@@ -390,12 +352,12 @@ flush_windows ()
 
   /* Keep current window handy */
 
-  cwp = sregs.psr & PSR_CWP;
+  cwp = sregs->psr & PSR_CWP;
 
   /* Calculate the invalid window from the wim. */
 
   for (invwin = 0; invwin <= PSR_CWP; invwin++)
-    if ((sregs.wim >> invwin) & 1)
+    if ((sregs->wim >> invwin) & 1)
       break;
 
   /* Start saving with the window after the invalid window. */
@@ -407,16 +369,16 @@ flush_windows ()
       uint32 sp;
       int i;
 
-      sp = sregs.r[(win * 16 + 14) & 0x7f];
+      sp = sregs->r[(win * 16 + 14) & 0x7f];
 #if 1
       if (sis_verbose > 2) {
-	uint32 fp = sregs.r[(win * 16 + 30) & 0x7f];
+	uint32 fp = sregs->r[(win * 16 + 30) & 0x7f];
 	printf("flush_window: win %d, sp %x, fp %x\n", win, sp, fp);
       }
 #endif
 
       for (i = 0; i < 16; i++)
-	ms->memory_write (sp + 4 * i, &sregs.r[(win * 16 + 16 + i) & 0x7f], 2,
+	ms->memory_write (sp + 4 * i, &sregs->r[(win * 16 + 16 + i) & 0x7f], 2,
 		      &ws);
 
       if (win == cwp)
@@ -429,25 +391,28 @@ sim_resume(SIM_DESC sd, int step, int siggnal)
 {
     if (sis_verbose)
 	(*sim_callback->printf_filtered) (sim_callback,
-	    "sim_resume %x : %x : %x : %x : 0x%08x\n", step, siggnal, sregs.bphit, sregs.wphit, sregs.pc);
+	    "sim_resume_start %x : %x : %x : %x : 0x%08x\n", step, siggnal, ebase.bphit, ebase.wphit, sregs[cpu].pc);
     if (step) {
-	sregs.bphit = 0;
-	sregs.wphit = 1;
-        simstat = run_sim(&sregs, 1, 0);
-	sregs.bphit = 0;
-	sregs.wphit = 0;
-    } else if (sregs.bphit || sregs.wphit) {
-	sregs.bphit = 0;
-	sregs.wphit = 1;
-        simstat = run_sim(&sregs, 1, 0);
-	sregs.bphit = sregs.wphit = 0;
-        simstat = run_sim(&sregs, UINT64_MAX, 0);
-	sregs.bphit = 0;
+	ebase.bphit = 0;
+	ebase.wphit = 1;
+        simstat = run_sim_gdb(1, 0);
+	ebase.bphit = 0;
+	ebase.wphit = 0;
+    } else if (ebase.bphit || ebase.wphit) {
+	ebase.bphit = 0;
+	ebase.wphit = 1;
+        simstat = run_sim_gdb(1, 0);
+	ebase.bphit = ebase.wphit = 0;
+        simstat = run_sim_gdb(UINT64_MAX/2, 0);
+	ebase.bphit = 0;
     }
     else
-        simstat = run_sim(&sregs, UINT64_MAX, 0);
+        simstat = run_sim_gdb(UINT64_MAX/2, 0);
 
-    if (sis_gdb_break) flush_windows ();
+    if (sis_verbose)
+	(*sim_callback->printf_filtered) (sim_callback,
+	    "sim_resume_end %x : %x : %x : %x : %x : 0x%08x\n", step, siggnal, ebase.bphit, ebase.wphit, simstat, sregs[cpu].pc);
+    if (sis_gdb_break) flush_windows (sregs);
 }
 
 void
@@ -455,7 +420,7 @@ sim_do_command(sd, cmd)
      SIM_DESC sd;
      const char *cmd;
 {
-    exec_cmd(&sregs, cmd);
+    exec_cmd(cmd);
 }
 
 char **
@@ -474,10 +439,10 @@ sim_stop (SIM_DESC sd)
 static int
 sis_insert_watchpoint_read(int addr, unsigned char mask)
 {
-    if (sregs.wprnum < WPR_MAX) {
-	sregs.wprs[sregs.wprnum] = addr;
-	sregs.wprm[sregs.wprnum] = mask;
-	sregs.wprnum++;
+    if (ebase.wprnum < WPR_MAX) {
+	ebase.wprs[ebase.wprnum] = addr;
+	ebase.wprm[ebase.wprnum] = mask;
+	ebase.wprnum++;
 	if (sis_verbose)
 	    (*sim_callback->printf_filtered) (sim_callback, "inserted read watchpoint at %x\n", addr);
 	return SIM_RC_OK;
@@ -490,12 +455,12 @@ sis_remove_watchpoint_read(int addr)
 {
     int             i = 0;
 
-    while ((i < sregs.wprnum) && (sregs.wprs[i] != addr))
+    while ((i < ebase.wprnum) && (ebase.wprs[i] != addr))
 	i++;
-    if (addr == sregs.wprs[i]) {
-	for (; i < sregs.wprnum - 1; i++)
-	    sregs.wprs[i] = sregs.wprs[i + 1];
-	sregs.wprnum -= 1;
+    if (addr == ebase.wprs[i]) {
+	for (; i < ebase.wprnum - 1; i++)
+	    ebase.wprs[i] = ebase.wprs[i + 1];
+	ebase.wprnum -= 1;
 	if (sis_verbose)
 	    (*sim_callback->printf_filtered) (sim_callback, "removed read watchpoint at %x\n", addr);
 	return 0;
@@ -506,10 +471,10 @@ sis_remove_watchpoint_read(int addr)
 static int
 sis_insert_watchpoint_write(int32 addr, unsigned char mask)
 {
-    if (sregs.wpwnum < WPR_MAX) {
-	sregs.wpws[sregs.wpwnum] = addr;
-	sregs.wpwm[sregs.wpwnum] = mask;
-	sregs.wpwnum++;
+    if (ebase.wpwnum < WPR_MAX) {
+	ebase.wpws[ebase.wpwnum] = addr;
+	ebase.wpwm[ebase.wpwnum] = mask;
+	ebase.wpwnum++;
 	if (sis_verbose)
 	    (*sim_callback->printf_filtered) (sim_callback, "sim_insert_watchpoint_write: 0x%08x : %x\n", addr, mask);
 	return SIM_RC_OK;
@@ -522,12 +487,12 @@ sis_remove_watchpoint_write(int addr)
 {
     int             i = 0;
 
-    while ((i < sregs.wpwnum) && (sregs.wpws[i] != addr))
+    while ((i < ebase.wpwnum) && (ebase.wpws[i] != addr))
 	i++;
-    if (addr == sregs.wpws[i]) {
-	for (; i < sregs.wpwnum - 1; i++)
-	    sregs.wpws[i] = sregs.wpws[i + 1];
-	sregs.wpwnum -= 1;
+    if (addr == ebase.wpws[i]) {
+	for (; i < ebase.wpwnum - 1; i++)
+	    ebase.wpws[i] = ebase.wpws[i + 1];
+	ebase.wpwnum -= 1;
 	if (sis_verbose)
 	    (*sim_callback->printf_filtered) (sim_callback, "removed write watchpoint at %x\n", addr);
 	return SIM_RC_OK;
@@ -601,13 +566,15 @@ int sim_clear_watchpoint (SIM_DESC sd, SIM_ADDR mem, int length, int type)
 int sim_stopped_by_watchpoint (SIM_DESC sd)
 {
     if (sis_verbose)
-       (*sim_callback->printf_filtered) (sim_callback, "sim_stopped_by_watchpoint %x\n", sregs.wphit);
-    return((sregs.wphit != 0));
+       (*sim_callback->printf_filtered) (sim_callback, "sim_stopped_by_watchpoint %x\n", ebase.wphit);
+    return((ebase.wphit != 0));
 }
 
 int sim_watchpoint_address (SIM_DESC sd)
 {
-    return(sregs.wpaddress);
+    if (sis_verbose)
+       (*sim_callback->printf_filtered) (sim_callback, "sim__watchpoint_address %x\n", ebase.wpaddress);
+    return(ebase.wpaddress);
 }
 
 #if 0 /* FIXME: These shouldn't exist.  */
diff --git a/sim/erc32/leon2.c b/sim/erc32/leon2.c
index 09402f7fff..90cae3bd5d 100644
--- a/sim/erc32/leon2.c
+++ b/sim/erc32/leon2.c
@@ -191,6 +191,8 @@ reset (void)
   leon2_reset ();
   uart_irq_start ();
   gpt_reset ();
+  sregs[0].intack = irqctrl_intack;
+
 }
 
 /* IU error mode manager. */
@@ -277,9 +279,9 @@ chk_irq (void)
   uint32 itmp;
   int old_irl;
 
-  old_irl = ext_irl;
+  old_irl = ext_irl[0];
   itmp = ((irqctrl_ipr | irqctrl_ifr) & irqctrl_imr) & 0x0fffe;
-  ext_irl = 0;
+  ext_irl[0] = 0;
   if (itmp != 0)
     {
       for (i = 15; i > 0; i--)
@@ -288,8 +290,7 @@ chk_irq (void)
 	    {
 	      if ((sis_verbose > 2) && (i > old_irl))
 		printf ("IU irl: %d\n", i);
-	      ext_irl = i;
-	      set_int (i, irqctrl_intack, i);
+	      ext_irl[0] = i;
 	      break;
 	    }
 	}
@@ -435,7 +436,7 @@ apb_write (uint32 addr, uint32 data)
       break;
 
     case POWER_DOWN:		/* 0x328 */
-      wait_for_irq ();
+      pwd_enter(sregs);
       break;
 
     case CACHE_CTRL:		/* 0x328 */
@@ -908,12 +909,6 @@ memory_read (uint32 addr, uint32 * data, int32 sz, int32 * ws)
   return 1;
 }
 
-static int
-memory_read_asi (int32 asi, uint32 addr, uint32 * data, int32 sz, int32 * ws)
-{
-  return memory_read (addr, data, sz, ws);
-}
-
 static int
 memory_write (uint32 addr, uint32 * data, int32 sz, int32 * ws)
 {
@@ -953,12 +948,6 @@ memory_write (uint32 addr, uint32 * data, int32 sz, int32 * ws)
   return 1;
 }
 
-static int
-memory_write_asi (int32 asi, uint32 addr, uint32 * data, int32 sz, int32 * ws)
-{
-  return memory_write (addr, data, sz, ws);
-}
-
 static unsigned char *
 get_mem_ptr (uint32 addr, uint32 size)
 {
@@ -1011,16 +1000,16 @@ static void
 boot_init (void)
 {
   /* Generate 1 MHz RTC tick.  */
-  apb_write (TIMER_SCALER, sregs.freq - 1);
-  apb_write (TIMER_SCLOAD, sregs.freq - 1);
+  apb_write (TIMER_SCALER, ebase.freq - 1);
+  apb_write (TIMER_SCLOAD, ebase.freq - 1);
   apb_write (TIMER_TIMER1, -1);
   apb_write (TIMER_RELOAD1, -1);
   apb_write (TIMER_CTRL1, 0x7);
 
-  sregs.wim = 2;
-  sregs.psr = 0x000010e0;
-  sregs.r[30] = RAM_END;
-  sregs.r[14] = sregs.r[30] - 96 * 4;
+  sregs->wim = 2;
+  sregs->psr = 0x000010e0;
+  sregs->r[30] = RAM_END;
+  sregs->r[14] = sregs->r[30] - 96 * 4;
   cache_ctrl = 0x01000f;
 }
 
@@ -1034,9 +1023,7 @@ const struct memsys leon2 = {
   restore_stdio,
   memory_iread,
   memory_read,
-  memory_read_asi,
   memory_write,
-  memory_write_asi,
   sis_memory_write,
   sis_memory_read,
   boot_init
diff --git a/sim/erc32/leon3.c b/sim/erc32/leon3.c
index 05234115f3..9f8fba222f 100644
--- a/sim/erc32/leon3.c
+++ b/sim/erc32/leon3.c
@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include <stdio.h>
 #include <string.h>
+#include <inttypes.h>
 #ifdef HAVE_TERMIOS_H
 #include <termios.h>
 #endif
@@ -47,10 +48,19 @@
 
 /* LEON3 APB register addresses.  */
 
-#define IRQMP_IPR		0x204
-#define IRQMP_IMR 	0x240
-#define IRQMP_ICR 	0x20C
+#define IRQMP_IPR	0x204
 #define IRQMP_IFR 	0x208
+#define IRQMP_ICR 	0x20C
+#define IRQMP_ISR 	0x210
+#define IRQMP_IBR 	0x214
+#define IRQMP_IMR 	0x240
+#define IRQMP_IMR1	0x244
+#define IRQMP_IMR2	0x248
+#define IRQMP_IMR3	0x24C
+#define IRQMP_IFR0 	0x280
+#define IRQMP_IFR1 	0x284
+#define IRQMP_IFR2 	0x288
+#define IRQMP_IFR3 	0x28C
 #define GPTIMER_SCALER  0x300
 #define GPTIMER_SCLOAD  0x304
 #define GPTIMER_CONFIG  0x308
@@ -63,6 +73,7 @@
 
 #define APBUART_RXTX	0x100
 #define APBUART_STATUS  0x104
+#define APBUART_CTRL    0x108
 
 /* Size of UART buffers (bytes).  */
 #define UARTBUF	1024
@@ -82,8 +93,9 @@
 /* IRQMP registers.  */
 
 static uint32 irqmp_ipr;
-static uint32 irqmp_imr;
-static uint32 irqmp_ifr;
+static uint32 irqmp_ibr;
+static uint32 irqmp_imr[NCPU];
+static uint32 irqmp_ifr[NCPU];
 
 /* GPTIMER registers.  */
 
@@ -109,8 +121,6 @@ static uint32 gpt_ctrl[NGPTIMERS];
 /* Memory.  */
 static unsigned char romb[ROM_END - ROM_START];
 static unsigned char ramb[RAM_END - RAM_START];
-static uint32 cache_ctrl;
-
 
 /* UART support variables.  */
 
@@ -139,13 +149,14 @@ static int f1open = 0;
 static char uarta_sreg, uarta_hreg;
 static uint32 uart_stat_reg;
 static uint32 uarta_data;
+static uint xcpu;
 
 /* Forward declarations. */
 
 static void mem_init (void);
 static void close_port (void);
 static void leon3_reset (void);
-static void irqmp_intack (int32 level);
+static void irqmp_intack (int level, int cpu);
 static void chk_irq (void);
 static void set_irq (int32 level);
 static int32 apb_read (uint32 addr, uint32 * data);
@@ -246,9 +257,11 @@ leon3_reset (void)
   int i;
 
   irqmp_ipr = 0;
-  irqmp_imr = 0;
-  irqmp_ifr = 0;
-
+  for (i=0; i<NCPU; i++) {
+    irqmp_imr[i] = 0;
+    irqmp_ifr[i] = 0;
+    sregs[i].intack = irqmp_intack;
+  }
   wnuma = wnumb = 0;
   anum = aind = bnum = bind = 0;
 
@@ -263,55 +276,65 @@ leon3_reset (void)
 }
 
 static void
-irqmp_intack (int32 level)
+irqmp_intack (int level, int cpu)
 {
   int irq_test;
 
-  if (sis_verbose > 2)
-    printf ("interrupt %d acknowledged\n", level);
-  if (irqmp_ifr & (1 << level))
-    irqmp_ifr &= ~(1 << level);
+  if ((sis_verbose > 2) && (level != 10))
+          printf ("%8" PRIu64 " cpu %d interrupt %d acknowledged\n", 
+			  ebase.simtime, cpu, level);
+  if (irqmp_ifr[cpu] & (1 << level))
+    irqmp_ifr[cpu] &= ~(1 << level);
   else
     irqmp_ipr &= ~(1 << level);
   chk_irq ();
 }
 
 static void
-chk_irq (void)
+chk_irq ()
 {
-  int32 i;
+  int32 i, cpu;
   uint32 itmp;
   int old_irl;
 
-  old_irl = ext_irl;
-  itmp = ((irqmp_ipr | irqmp_ifr) & irqmp_imr) & 0x0fffe;
-  ext_irl = 0;
-  if (itmp != 0)
+  for (cpu = 0; cpu<ncpu; cpu++) {
+    old_irl = ext_irl[cpu];
+    itmp = ((irqmp_ipr | irqmp_ifr[cpu]) & irqmp_imr[cpu]) & 0x0fffe;
+    ext_irl[cpu] = 0;
+    if (itmp != 0)
     {
       for (i = 15; i > 0; i--)
 	{
 	  if (((itmp >> i) & 1) != 0)
 	    {
-	      if ((sis_verbose > 2) && (i > old_irl))
-		printf ("IU irl: %d\n", i);
-	      ext_irl = i;
-	      set_int (i, irqmp_intack, i);
+	      if ((sis_verbose > 2) && (i != old_irl))
+                printf ("%8" PRIu64 " cpu %d irl: %d\n",
+				ebase.simtime, cpu, i);
+	      ext_irl[cpu] = i;
 	      break;
 	    }
 	}
     }
+  }
 }
 
 static void
 set_irq (int32 level)
 {
-  irqmp_ipr |= (1 << level);
+  int i;
+
+  if ((irqmp_ibr >> level) & 1)
+    for (i=0; i<ncpu; i++)
+      irqmp_ifr[i] |= (1 << level);
+  else
+    irqmp_ipr |= (1 << level);
   chk_irq ();
 }
 
 static int32
 apb_read (uint32 addr, uint32 * data)
 {
+  int i;
 
   switch (addr & 0xfff)
     {
@@ -320,17 +343,58 @@ apb_read (uint32 addr, uint32 * data)
     case APBUART_STATUS:	/* 0x104 */
       *data = grlib_read_uart (addr);
       break;
+    case APBUART_CTRL:		/* 0x108 */
+      *data = 3;
+      break;
 
     case IRQMP_IPR:		/* 0x204 */
       *data = irqmp_ipr;
       break;
 
     case IRQMP_IFR:		/* 0x208 */
-      *data = irqmp_ifr;
+      *data = irqmp_ifr[0];
+      break;
+
+    case IRQMP_ISR:		/* 0x210 */
+      *data = ((ncpu - 1) << 28);
+      for (i=0;i<ncpu;i++)
+	  *data |= (sregs[i].pwd_mode << i);
+      break;
+
+    case IRQMP_IBR:		/* 0x214 */
+      *data = irqmp_ibr;
       break;
 
     case IRQMP_IMR:		/* 0x240 */
-      *data = irqmp_imr;
+      *data = irqmp_imr[0];
+      break;
+
+    case IRQMP_IMR1:		/* 0x244 */
+      *data = irqmp_imr[1];
+      break;
+
+    case IRQMP_IMR2:		/* 0x248 */
+      *data = irqmp_imr[2];
+      break;
+
+    case IRQMP_IMR3:		/* 0x24C */
+      *data = irqmp_imr[3];
+      break;
+
+    case IRQMP_IFR0:		/* 0x280 */
+      *data = irqmp_ifr[0];
+      break;
+
+    case IRQMP_IFR1:		/* 0x284 */
+      *data = irqmp_ifr[1];
+      break;
+
+    case IRQMP_IFR2:		/* 0x288 */
+      *data = irqmp_ifr[2];
+      break;
+
+    case IRQMP_IFR3:		/* 0x28C */
+      *data = irqmp_ifr[3];
       break;
 
     case GPTIMER_SCALER:	/* 0x300 */
@@ -371,11 +435,16 @@ apb_read (uint32 addr, uint32 * data)
 
     default:
       *data = 0;
+      if (sis_verbose > 1)
+          printf ("%8" PRIu64 " cpu %d APB read  a: %08x, d: %08x  unimplemented!\n",
+			  ebase.simtime, xcpu, addr, *data);
       break;
     }
 
   if (sis_verbose > 1)
-    printf ("APB read  a: %08x, d: %08x\n", addr, *data);
+      if ((addr & 0xF00) != 0x100)
+          printf ("%8" PRIu64 " cpu %d APB read  a: %08x, d: %08x\n",
+			  ebase.simtime, xcpu, addr, *data);
 
   return MOK;
 }
@@ -383,8 +452,12 @@ apb_read (uint32 addr, uint32 * data)
 static int
 apb_write (uint32 addr, uint32 data)
 {
+  int i;
+
   if (sis_verbose > 1)
-    printf ("APB write a: %08x, d: %08x\n", addr, data);
+      if ((addr & 0xF00) != 0x100)
+          printf ("%8" PRIu64 " cpu %d APB write a: %08x, d: %08x\n",
+			  ebase.simtime, xcpu, addr, data);
   switch (addr & 0xfff)
     {
 
@@ -392,9 +465,11 @@ apb_write (uint32 addr, uint32 data)
     case APBUART_STATUS:	/* 0x104 */
       grlib_write_uart (addr, data);
       break;
+    case APBUART_CTRL:		/* 0x108 */
+      break;
 
     case IRQMP_IFR:		/* 0x208 */
-      irqmp_ifr = data & 0xfffe;
+      irqmp_ifr[0] = data & 0xfffe;
       chk_irq ();
       break;
 
@@ -403,8 +478,61 @@ apb_write (uint32 addr, uint32 data)
       chk_irq ();
       break;
 
+    case IRQMP_ISR:		/* 0x210 */
+      for (i=0;i<ncpu;i++) {
+	  if ((data >> i) & 1) {
+	      if (sregs[i].pwd_mode) {
+		  sregs[i].simtime = ebase.simtime;
+  		  if (sis_verbose > 1)
+                      printf ("%8" PRIu64 " cpu %d starting\n", ebase.simtime, i);
+	          sregs[i].pwdtime += ebase.simtime - sregs[i].pwdstart;
+	      }
+	      sregs[i].pwd_mode = 0;
+	  }
+      }
+      break;
+
+    case IRQMP_IBR:		/* 0x214 */
+      irqmp_ibr = data & 0xfffe;
+      break;
+
     case IRQMP_IMR:		/* 0x240 */
-      irqmp_imr = data & 0x7ffe;
+      irqmp_imr[0] = data & 0x7ffe;
+      chk_irq ();
+      break;
+
+    case IRQMP_IMR1:		/* 0x244 */
+      irqmp_imr[1] = data & 0x7ffe;
+      chk_irq ();
+      break;
+
+    case IRQMP_IMR2:		/* 0x248 */
+      irqmp_imr[2] = data & 0x7ffe;
+      chk_irq ();
+      break;
+
+    case IRQMP_IMR3:		/* 0x24C */
+      irqmp_imr[3] = data & 0x7ffe;
+      chk_irq ();
+      break;
+
+    case IRQMP_IFR0:		/* 0x280 */
+      irqmp_ifr[0] = data & 0xfffe;
+      chk_irq ();
+      break;
+
+    case IRQMP_IFR1:		/* 0x284 */
+      irqmp_ifr[1] = data & 0xfffe;
+      chk_irq ();
+      break;
+
+    case IRQMP_IFR2:		/* 0x288 */
+      irqmp_ifr[2] = data & 0xfffe;
+      chk_irq ();
+      break;
+
+    case IRQMP_IFR3:		/* 0x28C */
+      irqmp_ifr[3] = data & 0xfffe;
       chk_irq ();
       break;
 
@@ -437,6 +565,9 @@ apb_write (uint32 addr, uint32 data)
       break;
 
     default:
+      if (sis_verbose)
+          printf ("%8" PRIu64 " cpu %d APB write a: %08x, d: %08x  unimplemented!\n",
+			  ebase.simtime, xcpu, addr, data);
       break;
     }
   return MOK;
@@ -828,31 +959,28 @@ static void
 store_bytes (unsigned char *mem, uint32 waddr, uint32 * data, int32 sz,
 	     int32 * ws)
 {
-  switch (sz)
+  if (sz == 2)
+      memcpy (&mem[waddr], data, 4);
+  else
+    switch (sz)
     {
     case 0:
 #ifdef HOST_LITTLE_ENDIAN
       waddr ^= EBT;
 #endif
       mem[waddr] = *data & 0x0ff;
-      *ws = 0;
       break;
     case 1:
 #ifdef HOST_LITTLE_ENDIAN
       waddr ^= 2;
 #endif
       memcpy (&mem[waddr], data, 2);
-      *ws = 0;
-      break;
-    case 2:
-      memcpy (&mem[waddr], data, 4);
-      *ws = 0;
       break;
     case 3:
       memcpy (&mem[waddr], data, 8);
-      *ws = 0;
       break;
     }
+    *ws = 0;
 }
 
 
@@ -929,21 +1057,6 @@ memory_read (uint32 addr, uint32 * data, int32 sz, int32 * ws)
   return 1;
 }
 
-static int
-memory_read_asi (int32 asi, uint32 addr, uint32 * data, int32 sz, int32 * ws)
-{
-  if (asi == 2)
-    {
-      if (addr == 0)
-	*data = cache_ctrl;
-      else
-	*data = 0;
-      return MOK;
-    }
-  else
-    return memory_read (addr, data, sz, ws);
-}
-
 static int
 memory_write (uint32 addr, uint32 * data, int32 sz, int32 * ws)
 {
@@ -984,20 +1097,6 @@ memory_write (uint32 addr, uint32 * data, int32 sz, int32 * ws)
   return 1;
 }
 
-static int
-memory_write_asi (int32 asi, uint32 addr, uint32 * data, int32 sz, int32 * ws)
-{
-  if (asi == 2)
-    {
-      cache_ctrl = *data & 0x81000f;
-      if (sis_verbose)
-	printf ("cache ctrl reg : 0x%08x\n", cache_ctrl);
-      return MOK;
-    }
-  else
-    return (memory_write (addr, data, sz, ws));
-}
-
 static unsigned char *
 get_mem_ptr (uint32 addr, uint32 size)
 {
@@ -1017,12 +1116,14 @@ static int
 sis_memory_write (uint32 addr, const unsigned char *data, uint32 length)
 {
   char *mem;
+  int32 ws;
 
-  if ((mem = get_mem_ptr (addr, length)) == ((char *) -1))
-    return 0;
-
-  memcpy (mem, data, length);
-  return length;
+  if ((mem = get_mem_ptr (addr, length)) != ((char *) -1)) {
+    memcpy (mem, data, length);
+    return length;
+  } else if (length == 4)
+    memory_write (addr, (uint32 *) data, 2, &ws);
+  return 0;
 }
 
 static int
@@ -1047,18 +1148,23 @@ sis_memory_read (uint32 addr, char *data, uint32 length)
 static void
 boot_init (void)
 {
+
+  int i;
+
   /* Generate 1 MHz RTC tick.  */
-  apb_write (GPTIMER_SCALER, sregs.freq - 1);
-  apb_write (GPTIMER_SCLOAD, sregs.freq - 1);
+//  apb_write (GPTIMER_SCALER, ebase.freq - 1);
+  apb_write (GPTIMER_SCLOAD, ebase.freq - 1);
   apb_write (GPTIMER_TIMER1, -1);
   apb_write (GPTIMER_RELOAD1, -1);
   apb_write (GPTIMER_CTRL1, 0x7);
 
-  sregs.wim = 2;
-  sregs.psr = 0xF30010e0;
-  sregs.r[30] = RAM_END;
-  sregs.r[14] = sregs.r[30] - 96 * 4;
-  cache_ctrl = 0x81000f;
+  for (i=0;i<NCPU;i++) {
+    sregs[i].wim = 2;
+    sregs[i].psr = 0xF30010e0;
+    sregs[i].r[30] = RAM_END - (i * 0x20000);
+    sregs[i].r[14] = sregs[i].r[30] - 96 * 4;
+    sregs[i].cache_ctrl = 0x81000f;
+  }
 }
 
 const struct memsys leon3 = {
@@ -1071,9 +1177,7 @@ const struct memsys leon3 = {
   restore_stdio,
   memory_iread,
   memory_read,
-  memory_read_asi,
   memory_write,
-  memory_write_asi,
   sis_memory_write,
   sis_memory_read,
   boot_init
diff --git a/sim/erc32/run.c b/sim/erc32/run.c
index 70ae411fc6..a3e3a69519 100644
--- a/sim/erc32/run.c
+++ b/sim/erc32/run.c
@@ -46,6 +46,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "ansidecl.h"
 #include "run-sim.h"
 #include "version.h"
+#include "sis.h"
 
 static void usage (int help);
 static void print_version (void);
@@ -94,6 +95,8 @@ main (ac, av)
   char **prog_args;
   enum sim_stop reason;
   int sigrc;
+  char tlim[64] = "";
+
 
   myname = av[0] + strlen (av[0]);
   while (myname > av[0] && myname[-1] != '/')
@@ -132,7 +135,7 @@ main (ac, av)
   /* FIXME: This is currently being rewritten to have each simulator
      do all argv processing.  */
 
-  while ((i = getopt (ac, av, "a:c:m:op:s:tv")) != EOF)
+  while ((i = getopt (ac, av, "a:c:m:op:s:t:v:")) != EOF)
     switch (i)
       {
       case 'a':
@@ -155,9 +158,13 @@ main (ac, av)
 	sim_set_simcache_size (atoi (optarg));
 	break;
 #endif
+      case 'd':
+	delta = (atoi (optarg));
+	break;
       case 'm':
 	/* FIXME: Rename to sim_set_mem_size.  */
 	//sim_size (atoi (optarg));
+	ncpu = (atoi (optarg));
 	break;
 #ifdef SIM_HAVE_ENVIRONMENT
       case 'o':
@@ -175,13 +182,16 @@ main (ac, av)
 	break;
 #endif
       case 't':
-	trace = 1;
+//	trace = 1;
+	strcpy(tlim, "tlim ");
+	strcat(tlim, optarg);
+	strcat(tlim, " s");
 	break;
       case 'v':
 	/* Things that are printed with -v are the kinds of things that
 	   gcc -v prints.  This is not meant to include detailed tracing
 	   or debugging information, just summaries.  */
-	verbose = 1;
+	sis_verbose = atoi(optarg);
 	/* sim_set_verbose (1); */
 	break;
 	/* FIXME: Quick hack, to be replaced by more general facility.  */
@@ -243,6 +253,10 @@ main (ac, av)
   if (sim_create_inferior (sd, abfd, prog_args, NULL) == SIM_RC_FAIL)
     exit (1);
 
+  if (tlim[0]) {
+    exec_cmd(tlim);
+  }
+
 #ifdef SIM_HAVE_ENVIRONMENT
   /* NOTE: An old simulator supporting the operating environment MUST
      provide sim_set_trace() and not sim_trace(). That way
@@ -275,6 +289,8 @@ main (ac, av)
       prev_sigint = signal (SIGINT, cntrl_c);
       sigrc = 0;
       sim_resume (sd, 0, sigrc);
+      if (sis_verbose)
+	  exec_cmd("per");
       signal (SIGINT, prev_sigint);
       sim_stop_reason (sd, &reason, &sigrc);
     }
diff --git a/sim/erc32/sis.c b/sim/erc32/sis.c
index f78986e2e4..f311e14908 100644
--- a/sim/erc32/sis.c
+++ b/sim/erc32/sis.c
@@ -43,92 +43,6 @@
 extern int era;
 #endif
 
-int
-run_sim(sregs, icount, dis)
-    struct pstate  *sregs;
-    uint64          icount;
-    int             dis;
-{
-    int             irq, mexc, deb;
-
-    sregs->starttime = get_time();
-    ms->init_stdio ();
-    if (sregs->err_mode) icount = 0;
-    deb = dis || sregs->histlen || sregs->bptnum;
-    irq = 0;
-    while (icount > 0) {
-
-	mexc = ms->memory_iread (sregs->pc, &sregs->inst, &sregs->hold);
-	sregs->icnt = 1;
-	if (sregs->annul) {
-	    sregs->annul = 0;
-	    sregs->pc = sregs->npc;
-	    sregs->npc = sregs->npc + 4;
-	} else {
-	    sregs->fhold = 0;
-	    if (ext_irl) irq = check_interrupts(sregs);
-	    if (!irq) {
-		if (mexc) {
-		    sregs->trap = I_ACC_EXC;
-		} else {
-		    if (deb) {
-			if (sregs->histlen) {
-			    sregs->histbuf[sregs->histind].addr = sregs->pc;
-			    sregs->histbuf[sregs->histind].time = ebase.simtime;
-			    sregs->histind++;
-			    if (sregs->histind >= sregs->histlen)
-				sregs->histind = 0;
-			}
-			if (dis) {
-			    printf(" %8" PRIu64 " ", ebase.simtime);
-			    dis_mem(sregs->pc, 1, &dinfo);
-			}
-			if ((sregs->bptnum) && (sregs->bphit = check_bpt(sregs)))
-			    icount = 0;
-			else {
-			    dispatch_instruction(sregs);
-			    icount--;
-			}
-		    } else {
-			dispatch_instruction(sregs);
-			icount--;
-		    }
-		}
-	    }
-	    if (sregs->trap) {
-		irq = 0;
-		if ((sregs->err_mode = execute_trap(sregs)) == WPT_HIT) {
-		    sregs->err_mode = 0;
-		    sregs->trap = 0;
-		    icount = 0;
-		}
-		if (sregs->err_mode) {
-		    ms->error_mode (sregs->pc);
-		    icount = 0;
-		}
-	    }
-	}
-	advance_time(sregs);
-	if (ctrl_c || (sregs->tlimit <= ebase.simtime)) {
-	    icount = 0;
-	    if (sregs->tlimit <= ebase.simtime) sregs->tlimit = -1;
-	}
-    }
-    sregs->tottime += get_time() - sregs->starttime;
-    ms->restore_stdio ();
-    if (sregs->err_mode)
-	return ERROR;
-    if (ctrl_c) {
-	ctrl_c = 0;
-	return CTRL_C;
-    }
-    if (sregs->bphit)
-	return (BPT_HIT);
-    if (sregs->wphit)
-	return (WPT_HIT);
-    return TIME_OUT;
-}
-
 int
 main(argc, argv)
     int             argc;
@@ -208,9 +122,17 @@ main(argc, argv)
 		    strcat(tlim, " ");
 		    strcat(tlim, argv[++stat]);
 		}
+	    } else if (strcmp(argv[stat], "-m") == 0) {
+		if ((stat + 1) < argc)
+		    ncpu = VAL(argv[++stat]);
+		    if ((ncpu < 1) || (ncpu > NCPU)) ncpu = 1;
+	    } else if (strcmp(argv[stat], "-d") == 0) {
+		if ((stat + 1) < argc)
+		    delta = VAL(argv[++stat]);
+		    if (delta <= 0) delta = 25;
 	    } else {
 		printf("unknown option %s\n", argv[stat]);
-		usage();
+		sis_usage();
 		exit(1);
 	    }
 	} else {
@@ -224,7 +146,8 @@ main(argc, argv)
 	printf (" LEON2 emulation enabled\n");
 	break;
     case CPU_LEON3:
-	printf (" LEON3 emulation enabled\n");
+	printf (" LEON3 emulation enabled, %d cpus online, delta %d clocks\n",
+			ncpu, delta);
 	break;
     default:
 	printf (" ERC32 emulation enabled\n");
@@ -232,7 +155,7 @@ main(argc, argv)
 
     if (nfp)
 	printf(" FPU disabled\n");
-    sregs.freq = freq;
+    ebase.freq = freq;
     printf("\n");
 
     INIT_DISASSEMBLE_INFO(dinfo, stdout, (fprintf_ftype) fprintf);
@@ -248,8 +171,9 @@ main(argc, argv)
     using_history();
     init_signals();
     ebase.simtime = 0;
+    ebase.simstart = 0;
     reset_all();
-    init_bpt(&sregs);
+    init_bpt(sregs);
     ms->init_sim ();
     if (lfile)
         last_load_addr = bfd_load(argv[lfile]);
@@ -261,10 +185,10 @@ main(argc, argv)
 	bacmd = (char *) malloc(256);
 	strcpy(bacmd, "batch ");
 	strcat(bacmd, cfile);
-	exec_cmd(&sregs, bacmd);
+	exec_cmd(bacmd);
     }
     if (tlim[0]) {
-	exec_cmd(&sregs, tlim);
+	exec_cmd(tlim);
     }
 
     while (cont) {
@@ -279,7 +203,7 @@ main(argc, argv)
 	    cmdq[cmdi] = 0;
 	}
 	if (run) {
-	    stat = exec_cmd(&sregs, "run");
+	    stat = exec_cmd("run");
 	    cont = 0;
 	}
 	else {
@@ -287,7 +211,7 @@ main(argc, argv)
 	    if (cmdq[cmdi] && *cmdq[cmdi])
 		add_history(cmdq[cmdi]);
 	    if (cmdq[cmdi])
-		stat = exec_cmd(&sregs, cmdq[cmdi]);
+		stat = exec_cmd(cmdq[cmdi]);
 	    else {
 		puts("\n");
 		exit(0);
@@ -300,22 +224,22 @@ main(argc, argv)
 	    printf("\b\bInterrupt!\n");
 	case TIME_OUT:
 	    printf(" Stopped at time %" PRIu64 " (%.3f ms)\n", ebase.simtime,
-	      ((double) ebase.simtime / (double) sregs.freq) / 1000.0);
+	      ((double) ebase.simtime / (double) ebase.freq) / 1000.0);
 	    break;
 	case BPT_HIT:
-	    printf("breakpoint at 0x%08x reached\n", sregs.pc);
-	    sregs.bphit = 1;
+	    printf("breakpoint at 0x%08x reached\n", sregs[cpu].pc);
+	    ebase.bphit = 1;
 	    break;
 	case ERROR:
-	    printf("IU in error mode (%d)\n", sregs.trap);
+	    printf("IU in error mode (%d)\n", sregs[cpu].trap);
 	    stat = 0;
 	    printf(" %8" PRIu64 " ", ebase.simtime);
-	    dis_mem(sregs.pc, 1, &dinfo);
+	    dis_mem(sregs[cpu].pc, 1, &dinfo);
 	    break;
 	case WPT_HIT:
 	    printf("watchpoint at 0x%08x reached, pc = 0x%08x\n",
-	        sregs.wpaddress, sregs.pc);
-	    sregs.wphit = 1;
+	        ebase.wpaddress, sregs[cpu].pc);
+	    ebase.wphit = 1;
 	    break;
 	default:
 	    break;
diff --git a/sim/erc32/sis.h b/sim/erc32/sis.h
index f046d5c718..274422893b 100644
--- a/sim/erc32/sis.h
+++ b/sim/erc32/sis.h
@@ -41,6 +41,9 @@
 #define WPR_MAX	256
 #define WPW_MAX	256
 
+/* Maximum number of cpus */
+#define NCPU 4
+
 struct histype {
     unsigned        addr;
     unsigned        time;
@@ -90,45 +93,29 @@ struct pstate {
 
 
     uint32          trap;	/* Current trap type */
-    uint32          annul;	/* Instruction annul */
     uint32          data;	/* Loaded data	     */
     uint32          inst;	/* Current instruction */
     uint32          asi;	/* Current ASI */
     uint32          err_mode;	/* IU error mode */
+    uint32          pwd_mode;	/* IU in power-down mode */
     uint32          breakpoint;
-    uint32          bptnum;
-    uint32          bphit;
-    uint32          bpts[BPT_MAX];	/* Breakpoints */
-    uint32          wprnum;
-    uint32          wphit;
-    uint32          wprs[WPR_MAX];	/* Read Watchpoints */
-    unsigned char   wprm[WPR_MAX];	/* Read Watchpoint masks*/
-    uint32          wpwnum;
-    uint32          wpws[WPW_MAX];	/* Write Watchpoints */
-    unsigned char   wpwm[WPW_MAX];	/* Write Watchpoint masks */
-    uint32          wpaddress;
 
     uint32          ltime;	/* Load interlock time */
     uint32          hold;	/* IU hold cycles in current inst */
     uint32          fhold;	/* FPU hold cycles in current inst */
     uint32          icnt;	/* Instruction cycles in curr inst */
 
-    uint32          histlen;	/* Trace history management */
     uint32          histind;
     struct histype *histbuf;
-    float32         freq;	/* Simulated processor frequency */
 
 
-    double          tottime;
     uint64          ninst;
     uint64          fholdt;
     uint64          holdt;
     uint64          icntt;
     uint64          finst;
-    uint64          simstart;
-    double          starttime;
-    uint64          tlimit;	/* Simulation time limit */
     uint64          pwdtime;	/* Cycles in power-down mode */
+    uint64          pwdstart;	/* Start of power-down mode */
     uint64          nstore;	/* Number of load instructions */
     uint64          nload;	/* Number of store instructions */
     uint64          nannul;	/* Number of annuled instructions */
@@ -138,6 +125,10 @@ struct pstate {
 
     int             rett_err;	/* IU in jmpl/restore error state (Rev.0) */
     int             jmpltime;
+    int             cpu;
+    uint64          simtime;	/* local processor time */
+    uint32          cache_ctrl;	/* Leon3 cache control register */
+    void            (*intack) (); /* interrupt ack. callback */
 };
 
 struct evcell {
@@ -150,12 +141,25 @@ struct evcell {
 struct estate {
     struct evcell   eq;
     struct evcell  *freeq;
-    uint64          simtime;
-};
-
-struct irqcell {
-    void            (*callback) ();
-    int32           arg;
+    uint64          simtime;	/* timestamp of last access to event queue */
+    uint64          evtime;	/* timestamp of next event */
+    float32         freq;	/* Simulated processor frequency */
+    double          starttime;
+    double          tottime;
+    uint64          simstart;
+    uint64          tlimit;	/* Simulation time limit */
+    uint32          bptnum;
+    uint32          bphit;
+    uint32          bpts[BPT_MAX];	/* Breakpoints */
+    uint32          wprnum;
+    uint32          wphit;
+    uint32          wprs[WPR_MAX];	/* Read Watchpoints */
+    unsigned char   wprm[WPR_MAX];	/* Read Watchpoint masks*/
+    uint32          wpwnum;
+    uint32          wpws[WPW_MAX];	/* Write Watchpoints */
+    unsigned char   wpwm[WPW_MAX];	/* Write Watchpoint masks */
+    uint32          wpaddress;
+    uint32          histlen;
 };
 
 /* return values for run_sim */
@@ -180,10 +184,9 @@ struct irqcell {
 extern const struct memsys erc32sys;
 
 /* func.c */
-extern struct	pstate  sregs;
+extern struct	pstate  sregs[];
 extern struct   estate ebase;
 extern struct   evcell evbuf[];
-extern struct   irqcell irqarr[];
 extern int      nfp;
 extern int      ift;
 extern int      ctrl_c;
@@ -196,14 +199,14 @@ extern int      wrp;
 extern int      rom8;
 extern int      uben;
 extern int      irqpend;
-extern int      ext_irl;
+extern int      ext_irl[];
 extern int      termsave;
 extern char     uart_dev1[];
 extern char     uart_dev2[];
 extern void	set_regi (struct pstate *sregs, int32 reg,
 			  uint32 rval);
 extern void	get_regi (struct pstate *sregs, int32 reg, char *buf);
-extern int	exec_cmd (struct pstate *sregs, const char *cmd);
+extern int	exec_cmd (const char *cmd);
 extern void	reset_stat (struct pstate  *sregs);
 extern void	show_stat (struct pstate  *sregs);
 extern void	init_bpt (struct pstate  *sregs);
@@ -214,10 +217,7 @@ extern struct   disassemble_info dinfo;
 extern void	dis_mem (uint32 addr, uint32 len,
 			 struct disassemble_info *info);
 extern void	event (void (*cfunc) (), int32 arg, uint64 delta);
-extern void	set_int (int32 level, void (*callback) (), int32 arg);
-extern void	advance_time (struct pstate  *sregs);
 extern uint32	now (void);
-extern int	wait_for_irq (void);
 extern int	check_bpt (struct pstate *sregs);
 extern int 	check_wpr(struct pstate *sregs, int32 address, unsigned char mask);
 extern int 	check_wpw(struct pstate *sregs, int32 address, unsigned char mask);
@@ -233,25 +233,26 @@ extern int	dumbio;
 extern int	tty_setup;
 extern int      cputype;
 extern int	sis_gdb_break;
-
+extern int	cpu;	/* active cpu */
+extern int	ncpu;	/* number of online cpus */
+extern int	delta;	/* time slice for MP simulation */
+extern void	pwd_enter(struct pstate *sregs);
+extern void 	remove_event(void (*cfunc) ());
+extern int	run_sim (uint64 icount, int dis);
 
 /* exec.c */
 extern int	dispatch_instruction (struct pstate *sregs);
 extern int	execute_trap (struct pstate *sregs);
-extern int	check_interrupts (struct pstate  *sregs);
+extern int	check_interrupts (struct pstate *sregs);
 extern void	init_regs (struct pstate *sregs);
 
-/* interf.c */
-extern int	run_sim (struct pstate *sregs,
-			 uint64 icount, int dis);
-
 /* float.c */
 extern int	get_accex (void);
 extern void	clear_accex (void);
 extern void	set_fsr (uint32 fsr);
 
 /* help.c */
-extern void	usage (void);
+extern void	sis_usage (void);
 extern void	gen_help (void);
 
 struct memsys {
@@ -264,11 +265,7 @@ struct memsys {
     void	(*restore_stdio) (void);
     int	        (*memory_iread) (uint32 addr, uint32 *data, int32 *ws);
     int	        (*memory_read) (uint32 addr, uint32 *data, int32 sz, int32 *ws);
-    int	        (*memory_read_asi) (int32 asi, uint32 addr, uint32 *data,
-			     int32 sz, int32 *ws);
     int	        (*memory_write) (uint32 addr, uint32 *data, int32 sz, int32 *ws);
-    int	        (*memory_write_asi) (int32 asi, uint32 addr, uint32 *data,
-			     int32 sz, int32 *ws);
     int	        (*sis_memory_write) (uint32 addr,
 				  const unsigned char *data, uint32 length);
     int	        (*sis_memory_read) (uint32 addr, char *data,
-- 
2.17.1

