Patchwork [v5,5/9] sim/erc32: Add support for LEON3 processor emulation.

login
register
mail settings
Submitter Jiri Gaisler
Date April 3, 2015, 8:35 p.m.
Message ID <1428093356-7296-6-git-send-email-jiri@gaisler.se>
Download mbox | patch
Permalink /patch/6007/
State Changes Requested
Delegated to: Mike Frysinger
Headers show

Comments

Jiri Gaisler - April 3, 2015, 8:35 p.m.
Added memory and I/O sub-system to emulate a LEON3 processor.
	The cache and MMU are not emulated but enough functionallity
	is provided to run any RTEMS and BCC compiled application.
	The code is based on erc32.c and modified to emulate the
	LEON3 address space and peripheral operations.

	* Makefile.in : Added new object files
	* README.leon3 : New file, documentation for leon3 emulation
	* README.sis : Updated documentation for simulator commands
	* grlib.c : New file, emulates leon3/grlib peripheral devices
	* grlib.h : New file, definition of grlib plug&play values
	* leon3.c : New file, emulation of leon3 memory and interrupt controller
	* erc32.c (memory_read, memory_write): Remove asi from parameters, compute locally
	(memory_read_asi, memory_write_asi): new memory function with asi parameter
	(get_mem_ptr): allow reading of I/O registers if access has exactly 4 byte size.
	(boot_init): mark as static.
	* exec.c (dispatch_instruction): emulate leon3 V8 mul/div and asr17 register.
	Emulate LDA/LDDA/LDUBA/LDUHA/LDSTA/SWAPA/STA/STBA/SHA/STDA instructions separately.
	(fpexec): Use integer operations to implement FMOV to avoid FPU traps on x86.
	(execute_trap): support single vector trapping for leon3
	(init_regs): add leon3 vendor/device ID to %psr.
	* func.c (sis_version): bump version to 2.8 to indicate support of leon3.
	(exec_cmd): call boot_init through memsys structure. Set PC to start address
	of last loaded binary, and initialize registers if not 0.
	(show_stat): use 64-bit floats when calculating simulator statistics.
	* interf.c (run_sim): call boot_init through memsys struct. Add -leon3 option.
	(sim_open): set leon3 default frequency to 50 MHz. Print out current
	emulation mode (erc32/leon3). (flush_windows): skip asi when flushing windows.
	* sis.c (main): update maintainer email. Add -leon3 switch. Set default leon3
	frequency to 50 MHz. Print out current emulation mode (erc32/leon3).
	* sis.h: add memsys struct for leon3.
---
 sim/erc32/Makefile.in  |    8 +-
 sim/erc32/README.leon3 |   53 +++
 sim/erc32/README.sis   |   81 ++--
 sim/erc32/erc32.c      |   50 ++-
 sim/erc32/exec.c       |  223 +++++++++--
 sim/erc32/func.c       |   57 +--
 sim/erc32/grlib.c      |  101 +++++
 sim/erc32/grlib.h      |   57 +++
 sim/erc32/interf.c     |   26 +-
 sim/erc32/leon3.c      | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++
 sim/erc32/sis.c        |   22 +-
 sim/erc32/sis.h        |   49 ++-
 12 files changed, 1586 insertions(+), 141 deletions(-)
 create mode 100644 sim/erc32/README.leon3
 create mode 100644 sim/erc32/grlib.c
 create mode 100644 sim/erc32/grlib.h
 create mode 100644 sim/erc32/leon3.c
Mike Frysinger - April 19, 2015, 6:54 a.m.
On 03 Apr 2015 22:35, Jiri Gaisler wrote:
> --- /dev/null
> +++ b/sim/erc32/README.leon3
>
> +The following registers are implemeted:

"implemented"

might want to run a spell checker over the whole file

 +Cypress C601 and C602. The simulator is cycle true, i.e a simulator time is

"cycle accurate" ?

> --- a/sim/erc32/erc32.c
> +++ b/sim/erc32/erc32.c
>
> +memory_read_asi (int32 asi, uint32 addr, uint32 *data, int32 sz, int32 *ws)
> +{
> +   return memory_read (addr, data, sz, ws);

correct indentation level is 2 spaces here

> +static int
> +memory_write_asi (int32 asi, uint32 addr, uint32 *data, int32 sz, int32 *ws)
> +{
> +    return memory_write (addr, data, sz, ws);

2 spaces

> +    if (length == 4) {
> +	memory_read (addr, &w4, length, &ws);
> +	memcpy(data, &w4, length);

can you scan your patches and make sure you're using space before the (

> +                    else if ( 17 == rd ) {
> +                        if (sparclite)
> +                            sregs->asr17 = (rs1 ^ operand2);
> +                    }
> +                    else if ( 19 == rd ) {

drop the spaces with these if statements:
	else if (17 == rd) {

> +/* Vendors */

please scan all the new code to make sure the comment style is GNU

> --- a/sim/erc32/sis.h
> +++ b/sim/erc32/sis.h
> @@ -154,6 +154,29 @@ struct irqcell {
>      int32           arg;
>  };
>  
> +struct memsys {
> +    void	(*init_sim) (void);
> +    void	(*reset) (void);
> +    void	(*error_mode) (uint32 pc);
> +    void	(*sim_halt) (void);
> +    void	(*exit_sim) (void);
> +    void	(*init_stdio) (void);
> +    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,
> +				 uint32 length);
> +    void	(*boot_init) (void);
> +};
>  
>  #define OK 0
>  #define TIME_OUT 1
> @@ -235,23 +260,7 @@ extern void	set_fsr (uint32 fsr);
>  extern void	usage (void);
>  extern void	gen_help (void);
>  
> -struct memsys {
> -    void	(*init_sim) (void);
> -    void	(*reset) (void);
> -    void	(*error_mode) (uint32 pc);
> -    void	(*sim_halt) (void);
> -    void	(*exit_sim) (void);
> -    void	(*init_stdio) (void);
> -    void	(*restore_stdio) (void);
> -    int	        (*memory_iread) (uint32 addr, uint32 *data, int32 *ws);
> -    int	        (*memory_read) (int32 asi, uint32 addr, uint32 *data,
> -			     int32 sz, int32 *ws);
> -    int	        (*memory_write) (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,
> -				 uint32 length);
> -};

you just added this struct in a previous patch.  if it wasn't in the right 
place, then please squash this move into that patch instead.
-mike

Patch

diff --git a/sim/erc32/Makefile.in b/sim/erc32/Makefile.in
index 108e8b6..d2579a4 100644
--- a/sim/erc32/Makefile.in
+++ b/sim/erc32/Makefile.in
@@ -21,7 +21,10 @@ 
 TERMCAP_LIB = @TERMCAP@
 READLINE_LIB = @READLINE@
 
-SIM_OBJS = exec.o erc32.o func.o help.o float.o interf.o
+# `sis' doesn't need interf.o.
+SIS_OFILES = exec.o erc32.o func.o help.o float.o grlib.o leon3.o
+
+SIM_OBJS = $(SIS_OFILES) interf.o
 SIM_RUN_OBJS = sis.o
 SIM_EXTRA_LIBS = $(READLINE_LIB) $(TERMCAP_LIB) -lm
 SIM_EXTRA_ALL = sis
@@ -35,9 +38,6 @@  SIM_EXTRA_CFLAGS = -DFAST_UART -I$(srcroot)
 
 ## COMMON_POST_CONFIG_FRAG
 
-# `sis' doesn't need interf.o.
-SIS_OFILES = exec.o erc32.o func.o help.o float.o
-
 sis: sis.o $(SIS_OFILES) $(COMMON_OBJS) $(LIBDEPS)
 	$(CC) $(ALL_CFLAGS) -o sis \
 	  sis.o $(SIS_OFILES) $(COMMON_OBJS) $(EXTRA_LIBS)
diff --git a/sim/erc32/README.leon3 b/sim/erc32/README.leon3
new file mode 100644
index 0000000..f6701a5
--- /dev/null
+++ b/sim/erc32/README.leon3
@@ -0,0 +1,53 @@ 
+
+1. LEON3 emulation
+
+The file 'leon3.c' contains a model of simple LEON3 sub-system. It
+contains 16 Mbyte ROM and 16 Mbyte RAM. Standard peripherals
+such as interrupt controller, UART and timer are provided.
+The model can execute leon3 binaries that do not require an
+MMU.
+
+To start sis in Leon3 mode, add the -leon3 switch. In gdb,
+use 'target sim -leon3' .
+
+1.1 UART
+
+The UART emulates an APBUART and is located at address 0x80000100.
+The following registers are implemeted:
+
+- UART RX and TX register	(0x80000100)
+- UART status register		(0x80000104)
+
+The UART generates interrupt 3.
+
+1.2 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
+
+The IRQMP interrupt controller is implemented as described in the
+GRLIB IP manual, with the exception of the interrupt level register.
+Extended interrupts are not supported. The registers are located
+at address 0x80000200.
+
+1.5 Memory interface
+
+The following memory areas are valid for the Leon3 simulator:
+
+0x00000000 - 0x01000000		ROM (16 Mbyte, loaded at start-up)
+0x40000000 - 0x41000000		RAM (16 Mbyte, loaded at start-up)
+0x80000000 - 0x81000000		APB bus, including plug&play
+0xFFFFF000 - 0xFFFFFFFF		AHB plug&play area
+
+Access to non-existing memory will result in a memory exception trap.
+
+1.8 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.sis b/sim/erc32/README.sis
index b119f03..124e577 100644
--- a/sim/erc32/README.sis
+++ b/sim/erc32/README.sis
@@ -1,10 +1,10 @@ 
 
-SIS - Sparc Instruction Simulator README file  (v2.0, 05-02-1996)
+SIS - Sparc Instruction Simulator README file  (v2.8, 10-11-2014)
 -------------------------------------------------------------------
 
 1. Introduction
 
-The SIS is a SPARC V7 architecture simulator. It consist of two parts,
+The SIS is a SPARC V7/V8 architecture simulator. It consist of two parts,
 the simulator core and a user defined memory module. The simulator
 core executes the instructions while the memory module emulates memory
 and peripherals. 
@@ -13,28 +13,28 @@  and peripherals.
 
 The simulator is started as follows: 
 
-sis [-uart1 uart_device1] [-uart2 uart_device2] 
+sis [-leon3] [-uart1 uart_device1] [-uart2 uart_device2]
     [-nfp] [-freq frequency] [-c batch_file] [files] 
 
-The default uart devices for SIS are /dev/ptypc and /dev/ptypd. The
--uart[1,2] switch can be used to connect the uarts to other devices.
-Use 'tip /dev/ttypc'  to connect a terminal emulator to the uarts.
+By default, SIS emulates an ERC32 system. The -leon3 switch
+enables emulation of a LEON3 SOC system.
+
+The emulated console uart is connected to stdin/stdout. The -uart[1,2]
+switch can be used to connect the uarts to other devices.
+
 The '-nfp' will disable the simulated FPU, so each FPU instruction will
 generate a FPU disabled trap. The '-freq' switch can be used to define
 which "frequency" the simulator runs at. This is used by the 'perf'
 command to calculated the MIPS figure for a particular configuration.
-The give frequency must be an integer indicating the frequency in MHz.
+The frequency must be an integer indicating the frequency in MHz.
 
 The -c option indicates that sis commands should be read from 'batch_file' 
 at startup.
 
-Files to be loaded must be in one of the supported formats (see INSTALLATION),
-and will be loaded into the simulated memory. The file formats are
-automatically recognised.
+Files to be loaded must be in one of the supported formats (elf, a.out, srec),
+and will be loaded into the simulated memory.
 
-The script 'startsim' will start the simulator in one xterm window and
-open a terminal emulator (tip) connected to the UART A in a second
-xterm window. Below is description of commands  that are recognized by 
+Below is description of commands  that are recognized by
 the simulator. The command-line is parsed using GNU readline. A command
 history of 64 commands is maintained. Use the up/down arrows to recall
 previous commands. For more details, see the readline documentation.
@@ -77,8 +77,8 @@  Prints the FPU registers
 go <address> [inst_count]
 
 The go command will set pc to <address> and npc to <address> + 4, and start
-execution. No other initialisation will be done. If inst_count is given, 
-execution will stop after the specified number of instructions.
+execution. If inst_count is given, execution will stop after the specified
+number of instructions.
 
 help
 
@@ -146,14 +146,20 @@  interpreted as 'cont'.
 
 3. Simulator core
 
-The SIS emulates the behavior of the 90C601E and 90C602E sparc IU and
-FPU from Matra MHS. These are roughly equivalent to the Cypress C601
-and C602.  The simulator is cycle true, i.e a simulator time is
-maintained and inremented according the IU and FPU instruction timing.
+In ERC32 mode, SIS emulates the behavior of the 90C601E and 90C602E
+sparc IU and FPU from Matra MHS. These are roughly equivalent to the
+Cypress C601 and C602. The simulator is cycle true, i.e a simulator time is
+maintained and incremented according the IU and FPU instruction timing.
 The parallel execution between the IU and FPU is modelled, as well as
-stalls due to operand dependencies (FPU). The core interacts with the
-user-defined memory modules through a number of functions. The memory
-module must provide the following functions:
+stalls due to operand dependencies (FPU).
+
+In Leon3 mode, the core emulates the Leon3 SPARC V8 core from
+Gaisler Research. All SPARC V8 instructions are supported but
+emulation is not fully cycle-true as the cache is not emulated.
+
+The core interacts with the user-defined memory modules through
+a number of functions. The memory module must provide the following
+functions:
 
 int memory_read(asi,addr,data,ws)
 int asi;
@@ -272,7 +278,7 @@  See 'erc32.c' for examples on how to use events and interrupts.
 
 5. Memory module
 
-The supplied memory module (erc32.c) emulates the functions of memory and
+The ERC32 memory module (erc32.c) emulates the functions of memory and
 the MEC asic developed for the 90C601/2. It includes the following functions:
 
 * UART A & B
@@ -284,28 +290,27 @@  the MEC asic developed for the 90C601/2. It includes the following functions:
 * 512 Kbyte ROM
 * 4 Mbyte RAM
 
-See README.erc32 on how the MEC functions are emulated.  For a detailed MEC
-specification, look at the ERC32 home page at URL:
+See README.erc32 on how the MEC functions are emulated.
 
-http://www.estec.esa.nl/wsmwww/erc32
+The Leon3 memory module (leon3.c) emulates on-chip peripherals and
+external memory for a simple Leon3 system. The modules includes the
+following functions:
 
-6. Compile and linking programs
+* AHB and APB buses with plug&play
+* UART (APBUART)
+* Interrupt controller (IRQMP)
+* Timer unit with two timers (GPTIMER)
+* PROM/SRAM memory controller (SRCTRL)
+* 16 Mbyte PROM, 16 Mbyte SRAM
 
-The directory 'examples' contain some code fragments for SIS.
-The script gccx indicates how the native sunos gcc and linker can be used
-to produce executables for the simulator. To compile and link the provided
-'hello.c', type 'gccx hello.c'. This will build the executable 'hello'.
-Start the simulator by running 'startsim hello', and issue the command 'run.
-After the program is terminated, the IU will be force to error mode through
-a software trap and halt. 
+See README.leon3 for further details on Leon3 emulation.
 
-The programs are linked with a start-up file, srt0.S. This file includes
-the traptable and window underflow/overflow trap routines.
+6. Compile and linking programs
 
 7. IU and FPU instruction timing.
 
-The simulator provides cycle true simulation. The following table shows
-the emulated instruction timing for 90C601E & 90C602E:
+The simulator provides cycle true simulation for ERC32. The following table
+shows the emulated instruction timing for 90C601E & 90C602E:
 
 Instructions	      Cycles
 
diff --git a/sim/erc32/erc32.c b/sim/erc32/erc32.c
index 01bbab8..9bf710a 100644
--- a/sim/erc32/erc32.c
+++ b/sim/erc32/erc32.c
@@ -1620,19 +1620,16 @@  memory_iread (uint32 addr, uint32 *data, int32 *ws)
 }
 
 static int
-memory_read(asi, addr, data, sz, ws)
-    int32           asi;
-    uint32          addr;
-    uint32         *data;
-    int32           sz;
-    int32          *ws;
+memory_read (uint32 addr, uint32 *data, int32 sz, int32 *ws)
 {
     int32           mexc;
+    int32           asi;
 
 #ifdef ERRINJ
     if (errmec) {
 	if (sis_verbose)
 	    printf("Inserted MEC error %d\n",errmec);
+	asi = (sregs.psr & 0x080) ? 11 : 10;
 	set_sfsr(errmec, addr, asi, 1);
 	if (errmec == 5) mecparerror();
 	if (errmec == 6) iucomperr();
@@ -1646,6 +1643,7 @@  memory_read(asi, addr, data, sz, ws)
 	*ws = mem_ramr_ws;
 	return 0;
     } else if ((addr >= MEC_START) && (addr < MEC_END)) {
+	asi = (sregs.psr & 0x080) ? 11 : 10;
 	mexc = mec_read(addr, asi, data);
 	if (mexc) {
 	    set_sfsr(MEC_ACC, addr, asi, 1);
@@ -1685,18 +1683,20 @@  memory_read(asi, addr, data, sz, ws)
 
     if (sis_verbose)
 	printf ("Memory exception at %x (illegal address)\n", addr);
+    asi = (sregs.psr & 0x080) ? 11 : 10;
     set_sfsr(UIMP_ACC, addr, asi, 1);
     *ws = MEM_EX_WS;
     return 1;
 }
 
 static int
-memory_write(asi, addr, data, sz, ws)
-    int32           asi;
-    uint32          addr;
-    uint32         *data;
-    int32           sz;
-    int32          *ws;
+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)
 {
     uint32          byte_addr;
     uint32          byte_mask;
@@ -1705,11 +1705,13 @@  memory_write(asi, addr, data, sz, ws)
     int32           mexc;
     int             i;
     int             wphit[2];
+    int             asi;
 
 #ifdef ERRINJ
     if (errmec) {
 	if (sis_verbose)
 	    printf("Inserted MEC error %d\n",errmec);
+	asi = (sregs.psr & 0x080) ? 11 : 10;
 	set_sfsr(errmec, addr, asi, 0);
 	if (errmec == 5) mecparerror();
 	if (errmec == 6) iucomperr();
@@ -1722,6 +1724,7 @@  memory_write(asi, addr, data, sz, ws)
 	if (mem_accprot) {
 
 	    waddr = (addr & 0x7fffff) >> 2;
+	    asi = (sregs.psr & 0x080) ? 11 : 10;
 	    for (i = 0; i < 2; i++)
 		wphit[i] =
 		    (((asi == 0xa) && (mec_wpr[i] & 1)) ||
@@ -1743,6 +1746,7 @@  memory_write(asi, addr, data, sz, ws)
 	store_bytes (ramb, waddr, data, sz, ws);
 	return 0;
     } else if ((addr >= MEC_START) && (addr < MEC_END)) {
+	asi = (sregs.psr & 0x080) ? 11 : 10;
 	if ((sz != 2) || (asi != 0xb)) {
 	    set_sfsr(MEC_ACC, addr, asi, 0);
 	    *ws = MEM_EX_WS;
@@ -1799,10 +1803,17 @@  memory_write(asi, addr, data, sz, ws)
     }
 	
     *ws = MEM_EX_WS;
+    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;
@@ -1846,6 +1857,14 @@  sis_memory_read(addr, data, length)
     uint32          length;
 {
     char           *mem;
+    int            ws;
+    int            w4;
+
+    if (length == 4) {
+	memory_read (addr, &w4, length, &ws);
+	memcpy(data, &w4, length);
+	return 4;
+    }
 
     if ((mem = get_mem_ptr(addr, length)) == ((char *) -1))
 	return 0;
@@ -1854,7 +1873,7 @@  sis_memory_read(addr, data, length)
     return length;
 }
 
-void
+static void
 boot_init (void)
 {
     mec_write(MEC_WCR, 0);	/* zero waitstates */
@@ -1878,7 +1897,10 @@  const struct memsys erc32sys = {
     restore_stdio,
     memory_iread,
     memory_read,
+    memory_read_asi,
     memory_write,
+    memory_write_asi,
     sis_memory_write,
-    sis_memory_read
+    sis_memory_read,
+    boot_init
 };
diff --git a/sim/erc32/exec.c b/sim/erc32/exec.c
index 000e939..27bceef 100644
--- a/sim/erc32/exec.c
+++ b/sim/erc32/exec.c
@@ -1065,17 +1065,17 @@  dispatch_instruction(sregs)
 		*rdd = sregs->psr;
 		break;
 	    case RDY:
-                if (!sparclite)
+                if ((!sparclite) && (cputype != CPU_LEON3))
                     *rdd = sregs->y;
                 else {
                     int rs1_is_asr = (sregs->inst >> 14) & 0x1f;
                     if ( 0 == rs1_is_asr )
                         *rdd = sregs->y;
-                    else if ( 17 == rs1_is_asr )
+                    else if ( 17 == rs1_is_asr ) {
                         *rdd = sregs->asr17;
+                    }
                     else {
                         sregs->trap = TRAP_UNIMP;
-                        break;
                     }
                 }
 		break;
@@ -1121,13 +1121,19 @@  dispatch_instruction(sregs)
 		    ((rs1 ^ operand2) & 0xfffff000);
 		break;
 	    case WRY:
-                if (!sparclite)
+                if ((!sparclite) && (cputype != CPU_LEON3))
                     sregs->y = (rs1 ^ operand2);
                 else {
                     if ( 0 == rd )
                         sregs->y = (rs1 ^ operand2);
-                    else if ( 17 == rd )
-                        sregs->asr17 = (rs1 ^ operand2);
+                    else if ( 17 == rd ) {
+                        if (sparclite)
+                            sregs->asr17 = (rs1 ^ operand2);
+                    }
+                    else if ( 19 == rd ) {
+                        if (cputype == CPU_LEON3)
+                            wait_for_irq();
+                    }
                     else {
                         sregs->trap = TRAP_UNIMP;
                         break;
@@ -1227,6 +1233,32 @@  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;
@@ -1239,9 +1271,9 @@  dispatch_instruction(sregs)
 		else
 		    rdd = &(sregs->g[rd]);
 	    }
-	    mexc = ms->memory_read (asi, address, ddata, 2, &ws);
+	    mexc = ms->memory_read (address, ddata, 2, &ws);
 	    sregs->hold += ws;
-	    mexc |= ms->memory_read (asi, address+4, &ddata[1], 2, &ws);
+	    mexc |= ms->memory_read (address+4, &ddata[1], 2, &ws);
 	    sregs->hold += ws;
 	    sregs->icnt = T_LDD;
 	    if (mexc) {
@@ -1257,12 +1289,23 @@  dispatch_instruction(sregs)
 
 	case LDA:
 	    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;
+	    else
+		*rdd = data;
+	    break;
 	case LD:
 	    if (address & 0x3) {
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    mexc = ms->memory_read (asi, address, &data, 2, &ws);
+	    mexc = ms->memory_read (address, &data, 2, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1272,8 +1315,26 @@  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;
 	case LDSTUB:
-	    mexc = ms->memory_read (asi, address, &data, 0, &ws);
+	    mexc = ms->memory_read (address, &data, 0, &ws);
 	    sregs->hold += ws;
 	    sregs->icnt = T_LDST;
 	    if (mexc) {
@@ -1283,7 +1344,7 @@  dispatch_instruction(sregs)
 	    data = extract_byte (data, address);
 	    *rdd = data;
 	    data = 0x0ff;
-	    mexc = ms->memory_write (asi, address, &data, 0, &ws);
+	    mexc = ms->memory_write (address, &data, 0, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1295,9 +1356,21 @@  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;
 	case LDSB:
 	case LDUB:
-	    mexc = ms->memory_read (asi, address, &data, 0, &ws);
+	    mexc = ms->memory_read (address, &data, 0, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1312,13 +1385,29 @@  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;
 	case LDSH:
 	case LDUH:
 	    if (address & 0x1) {
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    mexc = ms->memory_read (asi, address, &data, 1, &ws);
+	    mexc = ms->memory_read (address, &data, 1, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1344,7 +1433,7 @@  dispatch_instruction(sregs)
 		    (sregs->frs2 == rd))
 		    sregs->fhold += (sregs->ftime - ebase.simtime);
 	    }
-	    mexc = ms->memory_read (asi, address, &data, 2, &ws);
+	    mexc = ms->memory_read (address, &data, 2, &ws);
 	    sregs->hold += ws;
 	    sregs->flrd = rd;
 	    sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD +
@@ -1370,9 +1459,9 @@  dispatch_instruction(sregs)
 		    ((sregs->frs2 >> 1) == (rd >> 1)))
 		    sregs->fhold += (sregs->ftime - ebase.simtime);
 	    }
-	    mexc = ms->memory_read (asi, address, ddata, 2, &ws);
+	    mexc = ms->memory_read (address, ddata, 2, &ws);
 	    sregs->hold += ws;
-	    mexc |= ms->memory_read (asi, address+4, &ddata[1], 2, &ws);
+	    mexc |= ms->memory_read (address+4, &ddata[1], 2, &ws);
 	    sregs->hold += ws;
 	    sregs->icnt = T_LDD;
 	    if (mexc) {
@@ -1401,7 +1490,7 @@  dispatch_instruction(sregs)
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    mexc = ms->memory_read (asi, address, &data, 2, &ws);
+	    mexc = ms->memory_read (address, &data, 2, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1423,7 +1512,7 @@  dispatch_instruction(sregs)
 	    if (ebase.simtime < sregs->ftime) {
 		sregs->fhold += (sregs->ftime - ebase.simtime);
 	    }
-	    mexc = ms->memory_write (asi, address, &sregs->fsr, 2, &ws);
+	    mexc = ms->memory_write (address, &sregs->fsr, 2, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1432,12 +1521,21 @@  dispatch_instruction(sregs)
 
 	case STA:
 	    if (!chk_asi(sregs, &asi, op3)) break;
+	    if (address & 0x3) {
+		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;
 	case ST:
 	    if (address & 0x3) {
 		sregs->trap = TRAP_UNALI;
 		break;
 	    }
-	    mexc = ms->memory_write (asi, address, rdd, 2, &ws);
+	    mexc = ms->memory_write (address, rdd, 2, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1445,8 +1543,13 @@  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;
 	case STB:
-	    mexc = ms->memory_write (asi, address, rdd, 0, &ws);
+	    mexc = ms->memory_write (address, rdd, 0, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1454,6 +1557,28 @@  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;
@@ -1466,7 +1591,7 @@  dispatch_instruction(sregs)
 		else
 		    rdd = &(sregs->g[rd]);
 	    }
-	    mexc = ms->memory_write (asi, address, rdd, 3, &ws);
+	    mexc = ms->memory_write (address, rdd, 3, &ws);
 	    sregs->hold += ws;
 	    sregs->icnt = T_STD;
 #ifdef STAT
@@ -1495,7 +1620,7 @@  dispatch_instruction(sregs)
 		break;
 	    }
 	    rdd = &(sregs->fpq[0]);
-	    mexc = ms->memory_write (asi, address, rdd, 3, &ws);
+	    mexc = ms->memory_write (address, rdd, 3, &ws);
 	    sregs->hold += ws;
 	    sregs->icnt = T_STD;
 #ifdef STAT
@@ -1511,12 +1636,21 @@  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;
 		break;
 	    }
-	    mexc = ms->memory_write (asi, address, rdd, 1, &ws);
+	    mexc = ms->memory_write (address, rdd, 1, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1535,7 +1669,7 @@  dispatch_instruction(sregs)
 		if (sregs->frd == rd)
 		    sregs->fhold += (sregs->ftime - ebase.simtime);
 	    }
-	    mexc = ms->memory_write (asi, address, &sregs->fsi[rd], 2, &ws);
+	    mexc = ms->memory_write (address, &sregs->fsi[rd], 2, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
@@ -1555,7 +1689,7 @@  dispatch_instruction(sregs)
 		if ((sregs->frd == rd) || (sregs->frd + 1 == rd))
 		    sregs->fhold += (sregs->ftime - ebase.simtime);
 	    }
-	    mexc = ms->memory_write (asi, address, &sregs->fsi[rd], 3, &ws);
+	    mexc = ms->memory_write (address, &sregs->fsi[rd], 3, &ws);
 	    sregs->hold += ws;
 	    sregs->icnt = T_STD;
 #ifdef STAT
@@ -1567,18 +1701,40 @@  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;
 		break;
 	    }
-	    mexc = ms->memory_read (asi, address, &data, 2, &ws);
+	    mexc = ms->memory_read (address, &data, 2, &ws);
 	    sregs->hold += ws;
 	    if (mexc) {
 		sregs->trap = TRAP_DEXC;
 		break;
 	    }
-	    mexc = ms->memory_write (asi, address, rdd, 2, &ws);
+	    mexc = ms->memory_write (address, rdd, 2, &ws);
 	    sregs->hold += ws;
 	    sregs->icnt = T_LDST;
 	    if (mexc) {
@@ -1814,7 +1970,7 @@  fpexec(op3, rd, rs1, rs2, sregs)
 	sregs->ftime += T_FDIVd;
 	break;
     case FMOVs:
-	sregs->fs[rd] = sregs->fs[rs2];
+	sregs->fsi[rd] = sregs->fsi[rs2];
 	sregs->ftime += T_FMOVs;
 	sregs->frs1 = 32;	/* rs1 ignored */
 	break;
@@ -1996,7 +2152,7 @@  execute_trap(sregs)
 	sregs->pc = sregs->tbr;
 	sregs->npc = sregs->tbr + 4;
 
-        if ( 0 != (1 & sregs->asr17) ) {
+        if ( 0 != (1 & (sregs->asr17 >> 13)) ) {
             /* single vector trapping! */
             sregs->pc = sregs->tbr & 0xfffff000;
             sregs->npc = sregs->pc + 4;
@@ -2043,7 +2199,10 @@  init_regs(sregs)
     sregs->npc = 4;
     sregs->trap = 0;
     sregs->psr &= 0x00f03fdf;
-    sregs->psr |= 0x11000080;	/* Set supervisor bit */
+    if (cputype == CPU_LEON3)
+      sregs->psr |= 0xF3000080;	/* Set supervisor bit */
+    else
+      sregs->psr |= 0x11000080;	/* Set supervisor bit */
     sregs->breakpoint = 0;
     sregs->annul = 0;
     sregs->fpstate = FP_EXE_MODE;
@@ -2072,4 +2231,8 @@  init_regs(sregs)
 
     sregs->rett_err = 0;
     sregs->jmpltime = 0;
+    if (cputype == CPU_LEON3) {
+        sregs->asr17 = 0x107;
+        if (!nfp) sregs->asr17 |= (3 << 10);  /* Meiko FPU */
+    }
 }
diff --git a/sim/erc32/func.c b/sim/erc32/func.c
index 74c3820..86e7a0a 100644
--- a/sim/erc32/func.c
+++ b/sim/erc32/func.c
@@ -41,7 +41,7 @@  struct irqcell  irqarr[16];
 
 int             ctrl_c = 0;
 int             sis_verbose = 0;
-char           *sis_version = "2.7.5";
+char           *sis_version = "2.8";
 int             nfp = 0;
 int             ift = 0;
 int             wrp = 0;
@@ -56,6 +56,7 @@  uint32		last_load_addr = 0;
 int		nouartrx = 0;
 host_callback 	*sim_callback;
 const struct memsys *ms = &erc32sys;
+int		cputype = 0;		/* 0 = erc32, 3 = leon3 */
 
 #ifdef ERRINJ
 uint32		errcnt = 0;
@@ -467,7 +468,7 @@  exec_cmd(struct pstate *sregs, const char *cmd)
 	    sregs->pc = len & ~3;
 	    sregs->npc = sregs->pc + 4;
 	    if ((sregs->pc != 0) && (ebase.simtime == 0))
-	        boot_init();
+	        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);
@@ -543,6 +544,11 @@  exec_cmd(struct pstate *sregs, const char *cmd)
 	    ebase.simtime = 0;
 	    reset_all();
 	    reset_stat(sregs);
+            if (last_load_addr != 0) {
+	        sregs->pc = last_load_addr & ~3;
+	        sregs->npc = sregs->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);
 	    } else {
@@ -596,6 +602,11 @@  exec_cmd(struct pstate *sregs, const char *cmd)
 	    ebase.simtime = 0;
 	    reset_all();
 	    reset_stat(sregs);
+            if (last_load_addr != 0) {
+	        sregs->pc = last_load_addr & ~3;
+	        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);
 	    daddr = sregs->pc;
@@ -633,8 +644,8 @@  void
 show_stat(sregs)
     struct pstate  *sregs;
 {
-    uint32          iinst;
-    uint32          stime;
+    uint64          iinst;
+    uint64          stime;
 
     if (sregs->tottime == 0.0)
         sregs->tottime += 1E-6;
@@ -649,37 +660,37 @@  show_stat(sregs)
     printf(" Instructions : %9" PRIu64 "\n", sregs->ninst);
 
 #ifdef STAT
-    printf("   integer    : %9.2f %%\n", 100.0 * (float) iinst / (float) sregs->ninst);
+    printf ("   integer    : %9.2f %%\n", 100.0 * (double) iinst / (double) sregs->ninst);
     printf("   load       : %9.2f %%\n",
-	   100.0 * (float) sregs->nload / (float) sregs->ninst);
+	   100.0 * (double) sregs->nload / (double) sregs->ninst);
     printf("   store      : %9.2f %%\n",
-	   100.0 * (float) sregs->nstore / (float) sregs->ninst);
+	   100.0 * (double) sregs->nstore / (double) sregs->ninst);
     printf("   branch     : %9.2f %%\n",
-	   100.0 * (float) sregs->nbranch / (float) sregs->ninst);
+	   100.0 * (double) sregs->nbranch / (double) sregs->ninst);
     printf("   float      : %9.2f %%\n",
-	   100.0 * (float) sregs->finst / (float) sregs->ninst);
+	   100.0 * (double) sregs->finst / (double) sregs->ninst);
     printf(" Integer CPI  : %9.2f\n",
-	   ((float) (stime - sregs->pwdtime - sregs->fholdt - sregs->finst))
+	   ((double) (stime - sregs->pwdtime - sregs->fholdt - sregs->finst))
 	   /
-	   (float) (sregs->ninst - sregs->finst));
+	   (double) (sregs->ninst - sregs->finst));
     printf(" Float CPI    : %9.2f\n",
-	   ((float) sregs->fholdt / (float) sregs->finst) + 1.0);
+	   ((double) sregs->fholdt / (double) sregs->finst) + 1.0);
 #endif
     printf(" Overall CPI  : %9.2f\n",
-	   (float) (stime - sregs->pwdtime) / (float) sregs->ninst);
-    printf("\n ERC32 performance (%4.1f MHz): %5.2f MOPS (%5.2f MIPS, %5.2f MFLOPS)\n",
-	   sregs->freq, sregs->freq * (float) sregs->ninst / (float) (stime - sregs->pwdtime),
-	   sregs->freq * (float) (sregs->ninst - sregs->finst) /
-	   (float) (stime - sregs->pwdtime),
-     sregs->freq * (float) sregs->finst / (float) (stime - sregs->pwdtime));
-    printf(" Simulated ERC32 time        : %.2f s\n",
-        (float) (ebase.simtime - sregs->simstart) / 1000000.0 / sregs->freq);
+	  (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 - ((float) sregs->pwdtime / (float) stime)));
+	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))));
+	100.0 / (sregs->tottime / ((double) (stime) / (sregs->freq * 1.0E6))));
     printf(" Simulator performance       : %.2f MIPS\n",
-        (double)(sregs->ninst) / sregs->tottime / 1E6);
+	(double)(sregs->ninst) / sregs->tottime / 1E6);
     printf(" Used time (sys + user)      : %.2f s\n\n", sregs->tottime);
 }
 
diff --git a/sim/erc32/grlib.c b/sim/erc32/grlib.c
new file mode 100644
index 0000000..9cd3b9f
--- /dev/null
+++ b/sim/erc32/grlib.c
@@ -0,0 +1,101 @@ 
+/*
+ * This file is part of SIS.
+ *
+ * SIS, SPARC instruction simulator. Copyright (C) 2014 Jiri Gaisler
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "sis.h"
+#include "grlib.h"
+
+
+/* APB PNP */
+
+static uint32 apbppmem[32 * 2];    /* 32-entry APB PP AREA */
+static int apbppindex;
+
+int grlib_apbpp_add (uint32 id, uint32 addr)
+{
+    apbppmem[apbppindex++] = id;
+    apbppmem[apbppindex++] = addr;
+    if(apbppindex >= (32 * 2))
+	apbppindex = 0; /* prevent overflow of area */
+    return apbppindex;
+}
+
+uint32 grlib_apbpnp_read (uint32 addr)
+{
+    uint32 read_data;
+    addr &= 0xff;
+    read_data = apbppmem[addr >> 2];
+
+    return read_data;
+}
+
+/* AHB PNP */
+
+static uint32 ahbppmem[128*8];    /* 128-entry AHB PP AREA */
+static int ahbmppindex;
+static int ahbsppindex = 64*8;
+
+int grlib_ahbmpp_add (uint32 id)
+{
+    ahbppmem[ahbmppindex] = id;
+    ahbmppindex += 8;
+    if(ahbmppindex >= (64 * 8))
+	ahbmppindex = 0; /* prevent overflow of area */
+    return ahbmppindex;
+}
+
+int grlib_ahbspp_add (uint32 id, uint32 addr1, uint32 addr2,
+                     uint32 addr3, uint32 addr4)
+{
+    ahbppmem[ahbsppindex] = id;
+    ahbsppindex += 4;
+    ahbppmem[ahbsppindex++] = addr1;
+    ahbppmem[ahbsppindex++] = addr2;
+    ahbppmem[ahbsppindex++] = addr3;
+    ahbppmem[ahbsppindex++] = addr4;
+    if(ahbsppindex >= (128 * 8))
+	ahbsppindex = 64 * 8; /* prevent overflow of area */
+    return ahbsppindex;
+}
+
+uint32 grlib_ahbpnp_read (uint32 addr)
+{
+    uint32 read_data;
+
+    addr &= 0xfff;
+    read_data = ahbppmem[addr >> 2];
+    return read_data;
+
+}
+
+void grlib_init ()
+{
+    /* Add PP records for Leon3, APB bridge and interrupt controller
+       as this is not done elsewhere */
+
+    grlib_ahbmpp_add (GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_LEON3, 0, 0));
+    grlib_ahbspp_add (GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_APBMST, 0, 0),
+                     GRLIB_PP_AHBADDR(0x80000000, 0xFFF, 0, 0, 2),
+                     0, 0, 0);
+
+    grlib_apbpp_add (GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_IRQMP, 2, 0),
+                    GRLIB_PP_APBADDR(0x80000200, 0xFFF));
+
+}
diff --git a/sim/erc32/grlib.h b/sim/erc32/grlib.h
new file mode 100644
index 0000000..302f1b5
--- /dev/null
+++ b/sim/erc32/grlib.h
@@ -0,0 +1,57 @@ 
+/*
+ * This file is part of SIS.
+ *
+ * SIS, SPARC instruction simulator. Copyright (C) 2014 Jiri Gaisler
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+/* Definitions for AMBA PNP in Gaisler Research GRLIB SOC */
+
+/* Vendors */
+#define VENDOR_GAISLER	1
+#define VENDOR_PENDER	2
+#define VENDOR_ESA	4
+#define VENDOR_DLR	10
+
+/* Devices */
+#define GAISLER_LEON3	0x003
+#define GAISLER_APBMST	0x006
+#define GAISLER_SRCTRL	0x008
+#define GAISLER_APBUART	0x00C
+#define GAISLER_IRQMP	0x00D
+#define GAISLER_GPTIMER	0x011
+#define ESA_MCTRL	0x00F
+
+/* How to build entries in the plug&play area */
+#define GRLIB_PP_ID(v, d, x, i) ((v & 0xff) << 24) | ((d & 0x3ff) << 12) |\
+			((x & 0x1f) << 5) | (i & 0x1f)
+#define GRLIB_PP_AHBADDR(a, m, p, c, t) (a & 0xfff00000) | ((m & 0xfff) << 4) |\
+			((p & 1) << 17) | ((c & 1) << 16) | (t & 0x3)
+#define GRLIB_PP_APBADDR(a, m) ((a & 0xfff00)<< 12) | ((m & 0xfff) << 4) | 1
+
+#define AHBPP_START	0xFFFFF000
+#define AHBPP_END	0xFFFFFFFF
+#define APBPP_START	0x800FF000
+#define APBPP_END	0x800FFFFF
+
+int grlib_apbpp_add (uint32 id, uint32 addr);
+int grlib_ahbmpp_add (uint32 id);
+int grlib_ahbspp_add (uint32 id, uint32 addr1, uint32 addr2,
+			uint32 addr3, uint32 addr4);
+uint32 grlib_ahbpnp_read (uint32 addr);
+uint32 grlib_apbpnp_read (uint32 addr);
+void grlib_init ();
diff --git a/sim/erc32/interf.c b/sim/erc32/interf.c
index 2b465f0..ad90af2 100644
--- a/sim/erc32/interf.c
+++ b/sim/erc32/interf.c
@@ -53,7 +53,7 @@  run_sim(sregs, icount, dis)
    sregs->starttime = get_time();
    irq = 0;
    if ((sregs->pc != 0) && (ebase.simtime == 0))
-	boot_init();
+	ms->boot_init ();
    while (!sregs->err_mode & (icount > 0)) {
 
 	sregs->fhold = 0;
@@ -175,6 +175,10 @@  sim_open (kind, callback, abfd, argv)
             if (strcmp(argv[stat], "-nouartrx") == 0) {
 		nouartrx = 1;
 	    } else
+            if (strcmp (argv[stat], "-leon3") == 0) {
+		ms = &leon3;
+                cputype = CPU_LEON3;
+            } else
             if (strcmp(argv[stat], "-wrp") == 0) {
                 wrp = 1;
 	    } else
@@ -212,9 +216,21 @@  sim_open (kind, callback, abfd, argv)
 	stat++;
     }
 
+    if (cputype == CPU_LEON3)
+        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 ESA/ESTEC (jgais@wd.estec.esa.nl)\n");
+	(*sim_callback->printf_filtered) (sim_callback, " Bug-reports to Jiri Gaisler ESA/ESTEC (jiri@gaisler.se)\n\n");
+        switch (cputype) {
+        case CPU_LEON3:
+            (*sim_callback->printf_filtered) (sim_callback, "LEON3 emulation enabled\n");
+            break;
+        default:
+            (*sim_callback->printf_filtered) (sim_callback, "ERC32 emulation enabled\n");
+        }
 	if (nfp)
 	  (*sim_callback->printf_filtered) (sim_callback, "no FPU\n");
 	if (sparclite)
@@ -223,11 +239,9 @@  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");
-	if (freq)
-	  (*sim_callback->printf_filtered) (sim_callback, " ERC32 freq %d Mhz\n", freq);
+	  (*sim_callback->printf_filtered) (sim_callback, "CPU freq %3.1f MHz\n", sregs.freq);
     }
 
-    sregs.freq = freq ? freq : 15;
     termsave = fcntl(0, F_GETFL, 0);
     INIT_DISASSEMBLE_INFO(dinfo, stdout,(fprintf_ftype)fprintf);
 #ifdef HOST_LITTLE_ENDIAN
@@ -417,7 +431,7 @@  flush_windows ()
 #endif
 
       for (i = 0; i < 16; i++)
-	ms->memory_write (11, 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)
diff --git a/sim/erc32/leon3.c b/sim/erc32/leon3.c
new file mode 100644
index 0000000..da18d65
--- /dev/null
+++ b/sim/erc32/leon3.c
@@ -0,0 +1,1000 @@ 
+/*
+ * This file is part of SIS.
+ *
+ * SIS, SPARC instruction simulator V2.5 Copyright (C) 1995 Jiri Gaisler,
+ * European Space Agency
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Leon3 emulation, loosely based on erc32.c.
+ */
+
+/* The control space devices.  */
+
+#include "config.h"
+#include <errno.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <unistd.h>
+#include "sis.h"
+#include "grlib.h"
+#include "sim-config.h"
+
+static int tty_setup = 1;
+
+/* APB registers */
+#define APBSTART	0x80000000
+#define APBEND		0x80100000
+
+/* Memory exception waitstates.  */
+#define MEM_EX_WS 	1
+
+#define MOK		0
+
+/* LEON3 APB register addresses.  */
+
+#define IRQMP_IPR		0x204
+#define IRQMP_IMR 	0x240
+#define IRQMP_ICR 	0x20C
+#define IRQMP_IFR 	0x208
+#define GPTIMER_SCALER  0x300
+#define GPTIMER_SCLOAD  0x304
+#define GPTIMER_CONFIG  0x308
+#define GPTIMER_TIMER1 	0x310
+#define GPTIMER_RELOAD1	0x314
+#define GPTIMER_CTRL1 	0x318
+#define GPTIMER_TIMER2 	0x320
+#define GPTIMER_RELOAD2	0x324
+#define GPTIMER_CTRL2 	0x328
+
+#define APBUART_RXTX	0x100
+#define APBUART_STATUS  0x104
+
+/* Size of UART buffers (bytes).  */
+#define UARTBUF	1024
+
+/* Number of simulator ticks between flushing the UARTS.  */
+/* For good performance, keep above 1000.  */
+#define UART_FLUSH_TIME	  3000
+
+/* New uart defines.  */
+#define UART_TX_TIME	1000
+#define UART_RX_TIME	1000
+#define UARTA_DR	0x1
+#define UARTA_SRE	0x2
+#define UARTA_HRE	0x4
+#define UARTA_OR	0x10
+
+/* IRQMP registers.  */
+
+static uint32   irqmp_ipr;
+static uint32   irqmp_imr;
+static uint32   irqmp_ifr;
+
+/* GPTIMER registers.  */
+
+#define NGPTIMERS  2
+#define GPTIMER_IRQ 8
+
+static uint32   gpt_scaler;
+static uint32   gpt_scaler_start;
+static uint32   gpt_counter[NGPTIMERS];
+static uint32   gpt_reload[NGPTIMERS];
+static uint32   gpt_ctrl[NGPTIMERS];
+
+/* ROM size 16 Mbyte.  */
+#define ROM_START 	0x00000000
+#define ROM_MASK 	0x00ffffff
+#define ROM_END 	(ROM_START + ROM_MASK + 1)
+
+/* RAM size 16 Mbyte.  */
+#define RAM_START 	0x40000000
+#define RAM_MASK 	0x00ffffff
+#define RAM_END 	(RAM_START + RAM_MASK + 1)
+
+/* Memory.  */
+static unsigned char	romb[ROM_END - ROM_START];
+static unsigned char	ramb[RAM_END - RAM_START];
+static uint32   cache_ctrl;
+
+
+/* UART support variables.  */
+
+/* File descriptor for input file.  */
+static int32    fd1, fd2;
+
+/* UART status register */
+static int32    Ucontrol;
+
+static unsigned char aq[UARTBUF], bq[UARTBUF];
+static int32    anum, aind = 0;
+static int32    bnum, bind = 0;
+static char     wbufa[UARTBUF], wbufb[UARTBUF];
+static unsigned wnuma;
+static unsigned wnumb;
+static FILE    *f1in, *f1out;
+static struct termios ioc1, ioc2, iocold1, iocold2;
+static int      f1open = 0;
+
+static char     uarta_sreg, uarta_hreg;
+static uint32   uart_stat_reg;
+static uint32   uarta_data;
+
+/* 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	chk_irq (void);
+static void	set_irq (int32 level);
+static int32	apb_read (uint32 addr, uint32 *data);
+static int	apb_write (uint32 addr, uint32 data);
+static void	port_init (void);
+static uint32	grlib_read_uart (uint32 addr);
+static void	grlib_write_uart (uint32 addr, uint32 data);
+static void	flush_uart (void);
+static void	uarta_tx (void);
+static void	uart_rx (caddr_t arg);
+static void	uart_intr (caddr_t arg);
+static void	uart_irq_start (void);
+static void	gpt_intr (caddr_t arg);
+static void	gpt_init (void);
+static void	gpt_reset (void);
+static void	gpt_scaler_set (uint32 val);
+static void	timer_ctrl (uint32 val, int i);
+static unsigned char *
+		get_mem_ptr (uint32 addr, uint32 size);
+static void	store_bytes (unsigned char *mem, uint32 waddr,
+			uint32 *data, int sz, int32 *ws);
+
+static host_callback *callback;
+
+
+/* One-time init. */
+
+static void
+init_sim (void)
+{
+    callback = sim_callback;
+    grlib_init ();
+    mem_init ();
+    port_init ();
+    gpt_init ();
+}
+
+/* Power-on reset init. */
+
+static void
+reset (void)
+{
+    leon3_reset ();
+    uart_irq_start ();
+    gpt_reset ();
+}
+
+/* IU error mode manager. */
+
+static void
+error_mode (uint32 pc)
+{
+
+}
+
+/* Memory init. */
+
+static void
+mem_init (void)
+{
+
+/* Add AMBA P&P record for SRCTRL memory controller */
+
+    grlib_ahbspp_add (GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_SRCTRL, 0, 0),
+			GRLIB_PP_AHBADDR(0x00000000, 0xE00, 1, 1, 2),
+			GRLIB_PP_AHBADDR(0x40000000, 0xC00, 1, 1, 2),
+			GRLIB_PP_AHBADDR(0x20000000, 0xE00, 0, 0, 2),
+			0);
+    if (sis_verbose)
+	printf ("RAM start: 0x%x, RAM size: %d K, ROM size: %d K\n",
+		RAM_START, (RAM_MASK+1)/1024, (ROM_MASK+1)/1024);
+}
+
+/* Flush ports when simulator stops. */
+
+static void
+sim_halt (void)
+{
+#ifdef FAST_UART
+    flush_uart ();
+#endif
+}
+
+static void
+close_port (void)
+{
+    if (f1open && f1in != stdin)
+	fclose (f1in);
+}
+
+static void
+exit_sim (void)
+{
+    close_port ();
+}
+
+static void
+leon3_reset (void)
+{
+    int i;
+
+    irqmp_ipr = 0;
+    irqmp_imr = 0;
+    irqmp_ifr = 0;
+
+    wnuma = wnumb = 0;
+    anum = aind = bnum = bind = 0;
+
+    uart_stat_reg = UARTA_SRE | UARTA_HRE;
+
+    gpt_counter[0] = 0xffffffff;
+    gpt_reload[0] = 0xffffffff;
+    gpt_scaler = 0xffff;
+    gpt_ctrl[0] = 0;
+    gpt_ctrl[1] = 0;
+
+}
+
+static void
+irqmp_intack (int32 level)
+{
+    int irq_test;
+
+    if (sis_verbose > 2)
+	printf("interrupt %d acknowledged\n", level);
+    if (irqmp_ifr & (1 << level))
+	irqmp_ifr &= ~(1 << level);
+    else
+	irqmp_ipr &= ~(1 << level);
+   chk_irq ();
+}
+
+static void
+chk_irq (void)
+{
+    int32           i;
+    uint32          itmp;
+    int		    old_irl;
+
+    old_irl = ext_irl;
+    itmp = ((irqmp_ipr | irqmp_ifr) & irqmp_imr) & 0x0fffe;
+    ext_irl = 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);
+		break;
+	    }
+	}
+    }
+}
+
+static void
+set_irq (int32 level)
+{
+    irqmp_ipr |= (1 << level);
+    chk_irq ();
+}
+
+static int32
+apb_read (uint32 addr, uint32 *data)
+{
+
+    switch (addr & 0xfff) {
+
+    case APBUART_RXTX:		/* 0x100 */
+    case APBUART_STATUS:	/* 0x104 */
+	*data = grlib_read_uart (addr);
+	break;
+
+    case IRQMP_IPR:		/* 0x204 */
+	*data = irqmp_ipr;
+	break;
+
+    case IRQMP_IFR:		/* 0x208 */
+	*data = irqmp_ifr;
+	break;
+
+    case IRQMP_IMR:		/* 0x240 */
+	*data = irqmp_imr;
+	break;
+
+    case GPTIMER_SCALER:	/* 0x300 */
+	*data = gpt_scaler - (now () - gpt_scaler_start);
+	break;
+
+    case GPTIMER_SCLOAD:	/* 0x304 */
+	*data = gpt_scaler;
+	break;
+
+    case GPTIMER_CONFIG:	/* 0x308 */
+	*data = 0x100 | (GPTIMER_IRQ << 3) | NGPTIMERS;
+	break;
+
+    case GPTIMER_TIMER1:	/* 0x310 */
+	*data = gpt_counter[0];
+	break;
+
+    case GPTIMER_RELOAD1:	/* 0x314 */
+	*data = gpt_reload[0];
+	break;
+
+    case GPTIMER_CTRL1:		/* 0x318 */
+	*data = gpt_ctrl[0];
+	break;
+
+    case GPTIMER_TIMER2:	/* 0x320 */
+	*data = gpt_counter[1];
+	break;
+
+    case GPTIMER_RELOAD2:	/* 0x324 */
+	*data = gpt_reload[1];
+	break;
+
+    case GPTIMER_CTRL2:		/* 0x328 */
+	*data = gpt_ctrl[1];
+	break;
+
+    default:
+	*data = 0;
+	break;
+    }
+
+    if (sis_verbose > 1)
+	printf ("APB read  a: %08x, d: %08x\n", addr, *data);
+
+    return MOK;
+}
+
+static int
+apb_write (uint32 addr, uint32 data)
+{
+    if (sis_verbose > 1)
+	printf ("APB write a: %08x, d: %08x\n",addr,data);
+    switch (addr & 0xfff) {
+
+    case APBUART_RXTX:		/* 0x100 */
+    case APBUART_STATUS:	/* 0x104 */
+	grlib_write_uart (addr, data);
+	break;
+
+    case IRQMP_IFR:		/* 0x208 */
+	irqmp_ifr = data & 0xfffe;
+	chk_irq ();
+	break;
+
+    case IRQMP_ICR:		/* 0x20C */
+	irqmp_ipr &= ~data & 0x0fffe;
+	chk_irq ();
+	break;
+
+    case IRQMP_IMR:		/* 0x240 */
+	irqmp_imr = data & 0x7ffe;
+	chk_irq ();
+	break;
+
+    case GPTIMER_SCLOAD:	/* 0x304 */
+	gpt_scaler_set (data);
+	break;
+
+    case GPTIMER_TIMER1:	/* 0x310 */
+	gpt_counter[0] = data;
+	break;
+
+    case GPTIMER_RELOAD1:	/* 0x314 */
+        gpt_reload[0] = data;
+	break;
+
+    case GPTIMER_CTRL1:		/* 0x318 */
+	timer_ctrl (data, 0);
+	break;
+
+    case GPTIMER_TIMER2:	/* 0x320 */
+	gpt_counter[1] = data;
+	break;
+
+    case GPTIMER_RELOAD2:	/* 0x324 */
+        gpt_reload[1] = data;
+	break;
+
+    case GPTIMER_CTRL2:		/* 0x328 */
+	timer_ctrl (data, 1);
+	break;
+
+    default:
+	break;
+    }
+    return MOK;
+}
+
+
+/* APBUART.  */
+
+static int      ifd1 = -1, ofd1 = -1;
+
+static void
+init_stdio (void)
+{
+    if (dumbio)
+	return;
+    if (ifd1 == 0 && f1open) {
+	tcsetattr (0, TCSANOW, &ioc1);
+	tcflush (ifd1, TCIFLUSH);
+    }
+}
+
+static void
+restore_stdio (void)
+{
+    if (dumbio)
+	return;
+    if (ifd1 == 0 && f1open && tty_setup)
+	tcsetattr (0, TCSANOW, &iocold1);
+}
+
+#define DO_STDIO_READ( _fd_, _buf_, _len_ )          \
+		( dumbio || nouartrx \
+		? (0) /* no bytes read, no delay */   \
+		: (_fd_) == 1 && callback ? \
+		callback->read_stdin (callback, _buf_, _len_) :  \
+		read( _fd_, _buf_, _len_ ) )
+
+static void
+port_init (void)
+{
+    f1in = stdin;
+    f1out = stdout;
+    if (uart_dev1[0] != 0)
+	if ((fd1 = open(uart_dev1, O_RDWR | O_NONBLOCK)) < 0) {
+	    printf ("Warning, couldn't open output device %s\n", uart_dev1);
+	} else {
+	    if (sis_verbose)
+		printf ("serial port A on %s\n", uart_dev1);
+	    f1in = f1out = fdopen (fd1, "r+");
+	    setbuf (f1out, NULL);
+	    f1open = 1;
+	}
+    if (f1in)
+	ifd1 = fileno (f1in);
+    if (ifd1 == 0) {
+	if (callback && !callback->isatty (callback, ifd1))
+	    tty_setup = 0;
+	if (sis_verbose)
+	    printf ("serial port A on stdin/stdout\n");
+	if (!dumbio) {
+	    tcgetattr (ifd1, &ioc1);
+	    if (tty_setup) {
+		iocold1 = ioc1;
+		ioc1.c_lflag &= ~(ICANON | ECHO);
+		ioc1.c_cc[VMIN] = 0;
+		ioc1.c_cc[VTIME] = 0;
+	    }
+	}
+	f1open = 1;
+    }
+
+    if (f1out) {
+	ofd1 = fileno (f1out);
+	if (!dumbio && tty_setup && ofd1 == 1)
+	    setbuf (f1out, NULL);
+    }
+
+    wnuma = 0;
+
+    grlib_apbpp_add (GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_APBUART, 1, 3),
+			GRLIB_PP_APBADDR(0x80000100, 0xFFF));
+}
+
+static uint32
+grlib_read_uart (uint32 addr)
+{
+    unsigned tmp = 0;
+
+    switch (addr & 0xff) {
+
+    case 0x00:			/* UART 1 RX/TX */
+#ifndef _WIN32
+#ifdef FAST_UART
+
+	if (aind < anum) {
+	    if ((aind + 1) < anum)
+		set_irq (3);
+	    return (uint32) aq[aind++];
+	} else {
+	    if (f1open)
+		anum = DO_STDIO_READ (ifd1, aq, UARTBUF);
+	    else
+		anum = 0;
+	    if (anum > 0) {
+		aind = 0;
+		if ((aind + 1) < anum)
+		    set_irq (3);
+		return (uint32) aq[aind++];
+	    } else
+		return (uint32) aq[aind];
+	}
+#else
+	tmp = uarta_data;
+	uarta_data &= ~UART_DR;
+	uart_stat_reg &= ~UARTA_DR;
+	return tmp;
+#endif
+#else
+	return 0;
+#endif
+	break;
+
+    case 0x04:			/* UART status register	 */
+#ifndef _WIN32
+#ifdef FAST_UART
+
+	Ucontrol = 0;
+	if (aind < anum) {
+	    Ucontrol |= 0x00000001;
+	} else {
+	    if (f1open)
+		anum = DO_STDIO_READ (ifd1, aq, UARTBUF);
+	    else
+		anum = 0;
+	    if (anum > 0) {
+		Ucontrol |= 0x00000001;
+		aind = 0;
+		set_irq (3);
+	    }
+	}
+	Ucontrol |= 0x00000006;
+	return Ucontrol;
+#else
+	return uart_stat_reg;
+#endif
+#else
+	return 0x00060006;
+#endif
+	break;
+    default:
+	if (sis_verbose)
+	    printf ("Read from unimplemented UART register (%x)\n", addr);
+    }
+
+    return 0;
+}
+
+static void
+grlib_write_uart(uint32 addr, uint32 data)
+{
+    unsigned char c;
+
+    c = (unsigned char) data;
+    switch (addr & 0xff) {
+
+    case 0x00:			/* UART A */
+#ifdef FAST_UART
+	if (f1open) {
+	    if (wnuma < UARTBUF)
+		wbufa[wnuma++] = c;
+	    else {
+		while (wnuma) {
+		    if (ofd1 == 1 && callback)
+			wnuma -= callback->write_stdout(callback, wbufa, wnuma);
+		    else
+			wnuma -= fwrite (wbufa, 1, wnuma, f1out);
+		}
+		wbufa[wnuma++] = c;
+	    }
+	}
+	set_irq (3);
+#else
+	if (uart_stat_reg & UARTA_SRE) {
+	    uarta_sreg = c;
+	    uart_stat_reg &= ~UARTA_SRE;
+	    event (uarta_tx, 0, UART_TX_TIME);
+	} else {
+	    uarta_hreg = c;
+	    uart_stat_reg &= ~UARTA_HRE;
+	}
+#endif
+	break;
+
+    case 0x04:			/* UART status register */
+#ifndef FAST_UART
+        uart_stat_reg &= 1;
+#endif
+	break;
+    default:
+	if (sis_verbose)
+	    printf ("Write to unimplemented UART register (%x)\n", addr);
+    }
+}
+
+static void
+flush_uart (void)
+{
+    while (wnuma && f1open) {
+	if (ofd1 == 1 && callback) {
+	    wnuma -= callback->write_stdout (callback, wbufa, wnuma);
+	    callback->flush_stdout (callback);
+        } else
+	    wnuma -= fwrite (wbufa, 1, wnuma, f1out);
+    }
+}
+
+static void
+uarta_tx (void)
+{
+    while (f1open) {
+	if (ofd1 == 1 && callback)
+	    while (callback->write_stdout (callback, &uarta_sreg, 1) != 1)
+		continue;
+	else
+	    while (fwrite (&uarta_sreg, 1, 1, f1out) != 1)
+		continue;
+    }
+    if (uart_stat_reg & UARTA_HRE) {
+	uart_stat_reg |= UARTA_SRE;
+    } else {
+	uarta_sreg = uarta_hreg;
+	uart_stat_reg |= UARTA_HRE;
+	event (uarta_tx, 0, UART_TX_TIME);
+    }
+    set_irq (3);
+}
+
+static void
+uart_rx (caddr_t arg)
+{
+    char  rxd;
+    int32 rsize = 0;
+
+
+    if (f1open)
+	rsize = DO_STDIO_READ (ifd1, &rxd, 1);
+    else
+	rsize = 0;
+    if (rsize > 0) {
+	uarta_data = rxd;
+	if (uart_stat_reg & UARTA_DR) {
+	    uart_stat_reg |= UARTA_OR;
+	}
+	uart_stat_reg |= UARTA_DR;
+	set_irq (3);
+    }
+    event (uart_rx, 0, UART_RX_TIME);
+}
+
+static void
+uart_intr (caddr_t arg)
+{
+    /* Check for UART interrupts every 1000 clk.  */
+    grlib_read_uart (APBUART_STATUS);
+    flush_uart ();
+    event (uart_intr, 0, UART_FLUSH_TIME);
+}
+
+
+static void
+uart_irq_start (void)
+{
+#ifdef FAST_UART
+    event (uart_intr, 0, UART_FLUSH_TIME);
+#else
+#ifndef _WIN32
+    event (uart_rx, 0, UART_RX_TIME);
+#endif
+#endif
+}
+
+/* GPTIMER.  */
+
+static void
+gpt_intr (caddr_t arg)
+{
+    int i;
+
+    for (i = 0; i < NGPTIMERS; i++) {
+	if (gpt_ctrl[i] & 1) {
+	    gpt_counter[i] -= 1;
+	    if (gpt_counter[i] == -1) {
+		if (gpt_ctrl[i] & 8)
+		    set_irq (GPTIMER_IRQ + i);
+		if (gpt_ctrl[i] & 2)
+		    gpt_counter[i] = gpt_reload[i];
+	    }
+	}
+    }
+    event (gpt_intr, 0, gpt_scaler + 1);
+    gpt_scaler_start = now ();
+}
+
+static void
+gpt_init (void)
+{
+    if (sis_verbose)
+	printf ("GPT started (period %d)\n\r", gpt_scaler + 1);
+
+    grlib_apbpp_add (GRLIB_PP_ID(VENDOR_GAISLER, GAISLER_GPTIMER, 0, 8),
+			GRLIB_PP_APBADDR(0x80000300, 0xFFF));
+}
+
+static void
+gpt_reset(void)
+{
+    event(gpt_intr, 0, gpt_scaler + 1);
+    gpt_scaler_start = now();
+}
+
+static void
+gpt_scaler_set (uint32 val)
+{
+    /* Mask for 16-bit scaler. */
+    gpt_scaler = val & 0x0ffff;
+}
+
+static void
+timer_ctrl (uint32 val, int i)
+{
+    if (val & 4) {
+	/* Reload.  */
+        gpt_counter[i] = gpt_reload[i];
+    }
+    gpt_ctrl[i] = val & 0xb;
+}
+
+/* Store data in host byte order.  MEM points to the beginning of the
+   emulated memory; WADDR contains the index the emulated memory,
+   DATA points to words in host byte order to be stored.  SZ contains log(2)
+   of the number of bytes to retrieve, and can be 0 (1 byte), 1 (one half-word),
+   2 (one word), or 3 (two words); WS should return the number of wait-states. */
+
+static void
+store_bytes (unsigned char *mem, uint32	waddr, uint32 *data, int32 sz, int32 *ws)
+{
+    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;
+    }
+}
+
+
+/* Memory emulation.  */
+
+static int
+memory_iread (uint32 addr, uint32 *data, int32 *ws)
+{
+    if ((addr >= RAM_START) && (addr < RAM_END)) {
+	memcpy (data, &ramb[addr & RAM_MASK], 4);
+	*ws = 0;
+	return 0;
+    } else if (addr < ROM_END) {
+	memcpy (data, &romb[addr], 4);
+	*ws = 0;
+	return 0;
+    }
+
+    if (sis_verbose)
+	printf ("Memory exception at %x (illegal address)\n", addr);
+    *ws = MEM_EX_WS;
+    return 1;
+}
+
+static int
+memory_read (uint32 addr, uint32 *data, int32 sz, int32 *ws)
+{
+    int32 mexc;
+
+    if ((addr >= RAM_START) && (addr < RAM_END)) {
+	memcpy (data, &ramb[addr & RAM_MASK & ~3], 4);
+	*ws = 0;
+	return 0;
+    } else if ((addr >= APBPP_START) && (addr <= APBPP_END)) {
+        *data = grlib_apbpnp_read (addr);
+        if (sis_verbose > 1)
+	    printf ("APB PP read a: %08x, d: %08x\n",addr, *data);
+	*ws = 4;
+	return 0;
+    } else if ((addr >= APBSTART) && (addr < APBEND)) {
+	mexc = apb_read (addr, data);
+	if (mexc)
+	    *ws = MEM_EX_WS;
+	else
+	    *ws = 0;
+	return mexc;
+    } else if ((addr >= AHBPP_START) && (addr <= AHBPP_END)) {
+	if (sis_verbose > 1)
+	    printf ("AHB PP read a: %08x, d: %08x\n",addr, *data);
+	*data = grlib_ahbpnp_read (addr);
+	*ws = 4;
+	return 0;
+    } else if (addr < ROM_END) {
+	memcpy (data, &romb[addr & ~3], 4);
+	*ws = 0;
+	return 0;
+    }
+
+    if (sis_verbose)
+	printf ("Memory exception at %x (illegal address)\n", addr);
+    *ws = MEM_EX_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)
+{
+    uint32 byte_addr;
+    uint32 byte_mask;
+    uint32 waddr;
+    uint32 *ram;
+    int32  mexc;
+    int    i;
+    int    wphit[2];
+
+    if ((addr >= RAM_START) && (addr < RAM_END)) {
+	waddr = addr & RAM_MASK;
+	store_bytes (ramb, waddr, data, sz, ws);
+	return 0;
+    } else if ((addr >= APBSTART) && (addr < APBEND)) {
+	if (sz != 2) {
+	    *ws = MEM_EX_WS;
+	    return 1;
+	}
+	apb_write (addr, *data);
+	*ws = 0;
+	return 0;
+
+    } else if (addr < ROM_END) {
+	*ws = 0;
+	store_bytes (romb, addr, data, sz, ws);
+	return 0;
+    }
+
+    *ws = MEM_EX_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)
+{
+    if ((addr + size) < ROM_END) {
+	return &romb[addr];
+    } else if ((addr >= RAM_START) && ((addr + size) < RAM_END)) {
+	return &ramb[addr & RAM_MASK];
+    }
+
+    return (char *) -1;
+}
+
+static int
+sis_memory_write (uint32 addr, const unsigned char * data, uint32 length)
+{
+    char *mem;
+
+    if ((mem = get_mem_ptr(addr, length)) == ((char *) -1))
+	return 0;
+
+    memcpy(mem, data, length);
+    return length;
+}
+
+static int
+sis_memory_read (uint32 addr, char *data, uint32 length)
+{
+    char *mem;
+    int  ws;
+
+    if (length == 4) {
+	memory_read (addr, (uint32 *) data, length, &ws);
+	return 4;
+    }
+
+    if ((mem = get_mem_ptr (addr, length)) == ((char *) -1))
+	return 0;
+
+    memcpy (data, mem, length);
+    return length;
+}
+
+static void
+boot_init (void)
+{
+    /* Generate 1 MHz RTC tick.  */
+    apb_write (GPTIMER_SCALER, sregs.freq-1);
+    apb_write (GPTIMER_SCLOAD, sregs.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;
+}
+
+const struct memsys leon3 = {
+    init_sim,
+    reset,
+    error_mode,
+    sim_halt,
+    exit_sim,
+    init_stdio,
+    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/sis.c b/sim/erc32/sis.c
index 41b8fb0..e24cbf1 100644
--- a/sim/erc32/sis.c
+++ b/sim/erc32/sis.c
@@ -142,7 +142,7 @@  main(argc, argv)
     for (i = 0; i < 64; i++)
 	cmdq[i] = 0;
     printf("\n SIS - SPARC instruction simulator %s,  copyright Jiri Gaisler 1995\n", sis_version);
-    printf(" Bug-reports to jgais@wd.estec.esa.nl\n\n");
+    printf (" Bug-reports to jiri@gaisler.se\n\n");
     while (stat < argc) {
 	if (argv[stat][0] == '-') {
 	    if (strcmp(argv[stat], "-v") == 0) {
@@ -181,6 +181,10 @@  main(argc, argv)
 		dumbio = 1;
             } else if (strcmp(argv[stat], "-nouartrx") == 0) {
 		nouartrx = 1;
+	    } else if (strcmp (argv[stat], "-leon3") == 0) {
+		ms = &leon3;
+		if (freq == 14) freq = 50;
+		cputype = CPU_LEON3;
             } else if (strcmp(argv[stat], "-v") == 0) {
 		sis_verbose += 1;
 	    } else {
@@ -193,13 +197,19 @@  main(argc, argv)
 	}
 	stat++;
     }
+
+    switch (cputype) {
+    case CPU_LEON3:
+	printf (" LEON3 emulation enabled\n");
+	break;
+    default:
+	printf (" ERC32 emulation enabled\n");
+    }
+
     if (nfp)
-	printf("FPU disabled\n");
-#ifdef ERA
-    if (era)
-	printf("ERA ECC emulation enabled\n");
-#endif
+	printf(" FPU disabled\n");
     sregs.freq = freq;
+    printf("\n");
 
     INIT_DISASSEMBLE_INFO(dinfo, stdout, (fprintf_ftype) fprintf);
 #ifdef HOST_LITTLE_ENDIAN
diff --git a/sim/erc32/sis.h b/sim/erc32/sis.h
index 5feb1f1..39c140e 100644
--- a/sim/erc32/sis.h
+++ b/sim/erc32/sis.h
@@ -154,6 +154,29 @@  struct irqcell {
     int32           arg;
 };
 
+struct memsys {
+    void	(*init_sim) (void);
+    void	(*reset) (void);
+    void	(*error_mode) (uint32 pc);
+    void	(*sim_halt) (void);
+    void	(*exit_sim) (void);
+    void	(*init_stdio) (void);
+    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,
+				 uint32 length);
+    void	(*boot_init) (void);
+};
 
 #define OK 0
 #define TIME_OUT 1
@@ -161,6 +184,8 @@  struct irqcell {
 #define ERROR 3
 #define CTRL_C 4
 
+#define CPU_LEON3  3
+
 /* Prototypes  */
 
 /* erc32.c */
@@ -214,7 +239,7 @@  extern double	get_time (void);
 extern int	nouartrx;
 extern		host_callback *sim_callback;
 extern int	dumbio;
-
+extern int      cputype;
 
 /* exec.c */
 extern int	dispatch_instruction (struct pstate *sregs);
@@ -235,23 +260,7 @@  extern void	set_fsr (uint32 fsr);
 extern void	usage (void);
 extern void	gen_help (void);
 
-struct memsys {
-    void	(*init_sim) (void);
-    void	(*reset) (void);
-    void	(*error_mode) (uint32 pc);
-    void	(*sim_halt) (void);
-    void	(*exit_sim) (void);
-    void	(*init_stdio) (void);
-    void	(*restore_stdio) (void);
-    int	        (*memory_iread) (uint32 addr, uint32 *data, int32 *ws);
-    int	        (*memory_read) (int32 asi, uint32 addr, uint32 *data,
-			     int32 sz, int32 *ws);
-    int	        (*memory_write) (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,
-				 uint32 length);
-};
-
 extern const struct memsys *ms;
+
+/* leon3.c */
+extern const struct memsys leon3;