From f4d2ff34bef1789eef9bed93572993ee023270e2 Mon Sep 17 00:00:00 2001 From: Rob Savoye Date: Mon, 20 May 1996 02:46:07 +0000 Subject: [PATCH] New sparc simulator from the ESA. --- sim/erc32/ChangeLog | 109 +++ sim/erc32/Makefile.in | 204 +++++ sim/erc32/NEWS | 108 +++ sim/erc32/README.erc32 | 130 +++ sim/erc32/README.gdb | 67 ++ sim/erc32/README.sis | 356 ++++++++ sim/erc32/configure.in | 18 + sim/erc32/end.c | 23 + sim/erc32/examples/__main.c | 4 + sim/erc32/examples/clock.c | 8 + sim/erc32/examples/gccx | 7 + sim/erc32/examples/hello.c | 87 ++ sim/erc32/examples/srt0.S | 449 ++++++++++ sim/erc32/exec.c | 1597 +++++++++++++++++++++++++++++++++++ sim/erc32/float.c | 169 ++++ sim/erc32/func.c | 968 +++++++++++++++++++++ sim/erc32/help.c | 30 + sim/erc32/interf.c | 372 ++++++++ sim/erc32/run.c | 92 ++ sim/erc32/startsim | 4 + 20 files changed, 4802 insertions(+) create mode 100644 sim/erc32/ChangeLog create mode 100644 sim/erc32/Makefile.in create mode 100644 sim/erc32/NEWS create mode 100644 sim/erc32/README.erc32 create mode 100644 sim/erc32/README.gdb create mode 100644 sim/erc32/README.sis create mode 100644 sim/erc32/configure.in create mode 100644 sim/erc32/end.c create mode 100644 sim/erc32/examples/__main.c create mode 100644 sim/erc32/examples/clock.c create mode 100755 sim/erc32/examples/gccx create mode 100644 sim/erc32/examples/hello.c create mode 100755 sim/erc32/examples/srt0.S create mode 100644 sim/erc32/exec.c create mode 100644 sim/erc32/float.c create mode 100644 sim/erc32/func.c create mode 100644 sim/erc32/help.c create mode 100644 sim/erc32/interf.c create mode 100644 sim/erc32/run.c create mode 100644 sim/erc32/startsim diff --git a/sim/erc32/ChangeLog b/sim/erc32/ChangeLog new file mode 100644 index 00000000000..ed56438b983 --- /dev/null +++ b/sim/erc32/ChangeLog @@ -0,0 +1,109 @@ +version 2.1 26-02-96 +-------------------- + +* Fixed bug in "go" command. + +version 2.0 05-02-96 +-------------------- + +* Fixed bug in interrupt force register (erc32.c). + +* Change file load function to use bfd_openr. + +* SIS should now be endian independent. + +version 1.8 24-11-95 +-------------------- + +* Fixed FPU timing - some sequences of FPU instructions did not calculate + the resource dependencies right. + +* Corrected STDFQ when qne = 0 (again!). The ftt is set to sequence_error + but no FPU trap is generated. + +version 1.7.1 31-10-95 +-------------------- + +* Corrected STDFQ when qne = 0. Now, a trap is immidiately generated but + the FPU stays in execute mode. + +* Corrected JMPL and RETT timing (these instructions takes two cycles). + + +version 1.7 25-10-95 +-------------------- + +* Interrupt during annuled instruction corrupted return address - fixed. + + +version 1.6.2 25-10-95 +-------------------- + +* Added -DFAST_UART to Makefile + + +version 1.6.1 24-10-95 +-------------------- + +* Fixed bug in STDFQ which caused bus error + + +version 1.6 02-10-95 +-------------------- + +* Modified srt0.s to include code that initiates registers in IU and FPU + and initializes the data segment. The simulator 'load' command does not + longer initialize the data segment! + +* Corrected MEC timer operation; scalers now divide the frequency by + (scaler_value + 1). + +* MEC breakpoints are not checked during store operation + + +version 1.5 14-09-95 +-------------------- + +* Fixed some bugs in the cycle counting for IU & FPU instructions. + +* Fixed bug that allowed an annuled instruction to cause memory exception. + +* The *ws parameter in mem.c should now contain the number of waitstates + required by the memory access (was total number of cycles). + +* The supplied srt0.s now clears the BSS (thanks Joel). + +version 1.4 22-08-95 +-------------------- + +* Added a '-g' switch to enable/disable the GNU readline(), which cause +some problems on solaris 2.x machines. + +* Enabled MEC watchpoint and breakpoint function to mem.c. Performance +may suffer a bit ... + +NOTE: The UARTs are now connected to /dev/ttypc and /dev/ttypd. + +version 1.3 26-07-95 +-------------------- + +* Fixed bug in mulscc instruction (how could that ever have worked?) + +* Fixed bug in UART B (flushed characters on UART A), thanks Paul. + +version 1.2 13-07-95 +-------------------- + +* Fixed bug in interrupt handling (wrong interrupt selected when more that +one interrupt pending) + +* Fixed updating of condition codes during logical instructions (carry and +overflow were not reset) + +* Fixed bug in WRTBR (tt field was wrongly over-written) + +version 1.1 07-07-95 +-------------------- + +* Fixed several bugs in the interrupt handler and callback routines. +(reported by Paul Warren, Alsys) diff --git a/sim/erc32/Makefile.in b/sim/erc32/Makefile.in new file mode 100644 index 00000000000..5ee6db3eb0a --- /dev/null +++ b/sim/erc32/Makefile.in @@ -0,0 +1,204 @@ +# Makefile template for Configure for the erc32sim library. +# Copyright (C) 1993 Free Software Foundation, Inc. +# Written by Cygnus Support +# Modified by J.Gaisler ESA/ESTEC +# +# 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 2 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, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +VPATH = @srcdir@ +srcdir = @srcdir@ +srcroot = $(srcdir)/../../ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +host_alias = @host_alias@ +target_alias = @target_alias@ +program_transform_name = @program_transform_name@ +bindir = $(exec_prefix)/bin +libdir = $(exec_prefix)/lib +tooldir = $(exec_prefix)/$(target_alias) + +datadir = $(prefix)/lib +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = $(prefix)/info +includedir = $(prefix)/include +oldincludedir = +docdir = $(srcdir)/doc + +SHELL = /bin/sh + +INSTALL = $${srcroot}/install.sh -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) +INSTALL_XFORM = $(INSTALL) -t='$(program_transform_name)' +INSTALL_XFORM1= $(INSTALL_XFORM) -b=.1 + +AR = @AR@ +AR_FLAGS = rc +CC = @CC@ +CFLAGS = @CFLAGS@ +MAKEINFO = makeinfo +RANLIB = @RANLIB@ + +# +# UARTS run at about 115200 baud (simulator time). Add -DFAST_UART to +# CFLAGS if faster (infinite) UART speed is desired. Might affect the +# behaviour of UART interrupt routines ... +# + +AR = ar +AR_FLAGS = rc +CFLAGS2 = -g -O3 -DSTAT -DFAST_UART -DIUREV0 -DMECREV0 +BISON = bison +MAKEINFO = makeinfo +RANLIB = ranlib +CC = gcc + +INCDIR = $(srcdir)/../../include +CSEARCH = -I. -I$(srcdir) -I$(INCDIR) -I../../bfd -I$(srcdir)/../../bfd \ + -I$(srcdir)/../../gdb -I$(srcdir)/../../gdb/config +DEP = mkdep + + +TARGETLIB = libsim.a + +CFILES = sis.c exec.c erc32.c interf.c run.c help.c float.c +OFILES = exec.o erc32.o func.o help.o float.o + + +all: end.h sis run $(TARGETLIB) + +end : $(srcdir)/end.c + $(CC) $(srcdir)/end.c -o end + +end.h : end + end > end.h + +sis: sis.o $(OFILES) + $(CC) $(CFLAGS) $(CLAGS2) -o sis sis.o $(OFILES) \ + ../../opcodes/libopcodes.a ../../readline/libreadline.a \ + ../../bfd/libbfd.a ../../libiberty/libiberty.a \ + -ltermcap -lm + +run: run.o interf.o $(OFILES) + $(CC) $(CFLAGS) $(CLAGS2) -o run run.o interf.o $(OFILES) \ + ../../opcodes/libopcodes.a ../../readline/libreadline.a \ + ../../bfd/libbfd.a ../../libiberty/libiberty.a \ + -ltermcap -lm + +clean: + rm -f *.o libsim.a sis run end end.h + +distclean: clean + rm -rf Makefile config.status sysdep.h + +#### host and target dependent Makefile fragments come in here. +### + +FLAGS_TO_PASS = \ + "against=$(against)" \ + "AR=$(AR)" \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC=$(CC)" \ + "CFLAGS=$(CFLAGS)" \ + "RANLIB=$(RANLIB)" \ + "MAKEINFO=$(MAKEINFO)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "BISON=$(BISON)" + +$(OFILES) sis.o interf.o : end.h sis.h + +.c.o: + $(CC) -c $(CFLAGS) $(CFLAGS2) $(HDEFINES) $(TDEFINES) $(CSEARCH) $(CSWITCHES) $< + + +# C source files that correspond to .o's. + +STAGESTUFF = $(TARGETLIB) $(OFILES) + +all: $(TARGETLIB) + + +.NOEXPORT: + +check: + +info: +clean-info: +install-info: + +# HDEPFILES comes from the host config; TDEPFILES from the target config. + + +$(TARGETLIB): $(OFILES) interf.o + rm -f $(TARGETLIB) + $(AR) $(AR_FLAGS) $(TARGETLIB) $(OFILES) interf.o + $(RANLIB) $(TARGETLIB) + +# Circumvent Sun Make bug with VPATH. +sparc-opc.o: sparc-opc.c + +tags etags: TAGS + +TAGS: force + etags $(INCDIR)/*.h $(srcdir)/*.h $(srcdir)/*.c + + +sis.o: sis.c sis.h end.h +exec.o: exec.c sis.h end.h +erc32.o: erc32.c sis.h end.h +interf.o: interf.c sis.h end.h +run.o: run.c +help.o: help.c +float.o: float.c sis.h end.h + +# Mark everything as depending on config.status, since the timestamp on +# sysdep.h might actually move backwards if we reconfig and relink it +# to a different hosts/h-xxx.h file. This will force a recompile anyway. +RECONFIG = config.status + +# Dummy target to force execution of dependent targets. +# +force: + +# Copy the files into directories where they will be run. +install: + srcroot=`cd $(srcroot); pwd`; export srcroot; \ + $(INSTALL_XFORM) sis $(bindir)/sis ; \ + n=`echo sis | sed '$(program_transform_name)'`; \ + if [ -d $(tooldir) ] ; then \ + if [ -d $(tooldir)/bin ] ; then true ; else mkdir $(tooldir)/bin ; fi; \ + rm -f $(tooldir)/bin/sis; \ + ln $(bindir)/$$n $(bindir)/sis \ + || $(INSTALL_PROGRAM) sis $(bindir)/sis; \ + ln $(bindir)/$$n $(tooldir)/bin/sis \ + || $(INSTALL_PROGRAM) sis $(tooldir)/bin/sis; \ + true; fi + + +Makefile: $(srcdir)/Makefile.in + $(SHELL) ./config.status diff --git a/sim/erc32/NEWS b/sim/erc32/NEWS new file mode 100644 index 00000000000..dd24b7b23f7 --- /dev/null +++ b/sim/erc32/NEWS @@ -0,0 +1,108 @@ + +version 2.0 05-02-96 +-------------------- + +* Switched to bfd library. Any supported format (elf, coff, ...) can be used. +* The UART devices can be set through -uart1 and -uart2 switches. +* Switched to GNU readline. +* Added -c option to run batch files at startup +* 'reg' command can show different register windows (eg 'reg w3'). +* Use 'help' for online help on simulator commands + +version 1.8.1 20-01-96 +-------------------- + +* added -mevrev0 switch to simulate MEC rev.0 bugs in timer and uart + +* added -iurev0 switch to simulate IU rev.0 jmpl/restore bug + +* Added sis command 'batch' to run batch files + + +version 1.8 30-10-95 +-------------------- + +* Added s-record support. Use the '-s' switch with sis or the 'load' command. + +* IU load dependencies are now modelled + +version 1.7 30-10-95 +-------------------- + +* Power-down mode implemented in erc32.c. + +* Performance display shows the ratio between simulator-time and real-time. + + +version 1.6.2 25-10-95 +-------------------- + +* The UARTs can now be run at a given speed (simulator time) to better + simulate the behaviour of interrupt routines. The "true mode" is + selected through a compile switch in the makefile. + + +version 1.6 28-09-95 +-------------------- + +* Major reorganisation of the code. mec.c and mem.c merged into erc32.c. + +* The load command does NOT longer load the initialised data at an address + defined by .bdata. This is done in srt0.s using _environ. + +* Additional MEC functionallity added - software reset, memory access + protection and waitstate configuration register. + +* interf.c - a GDB interface added + +* -v switch (verbose) added + +version 1.5 14-09-95 +-------------------- + +* Added a instruction trace buffer, enabled through the 'hist' command. + +* Added a 'perf' command to display statistics such as instruction mix, + CPI, FPU holds etc. + +* Added -nfp switch to disable FPU. + +* Added -freq switch to set simulated frequency. + +version 1.4 22-08-95 +-------------------- + +* A -g is provided for those who have problems with GNU readline(). + +version 1.3 26-07-95 +-------------------- + +* No major news, just a bug fix release ... + + +version 1.2 13-07-95 +-------------------- + +* Added setting of IU registers through the 'reg' command. See README. + +* The GNU readline() function is used for command input. However, a +ctrl-D still kills the simulator ... + + +version 1.1 07-07-95 +-------------------- + + +* Added a 'go' command + +* Added cycle counting for interrupt overhead. + +* Function 'get_mem_ptr' takes one more parameter to avoid segmentation + faults if a.out files are loaded outside the simulated memory. See README. + +* Added user-defined function sim_stop(). + +* Added a reset command. See README. + +* Implemented buffered output for MEC uarts to improve output speed. + diff --git a/sim/erc32/README.erc32 b/sim/erc32/README.erc32 new file mode 100644 index 00000000000..f413599294c --- /dev/null +++ b/sim/erc32/README.erc32 @@ -0,0 +1,130 @@ + +1. MEC and ERC32 emulation + +The file 'erc32.c' contains a model of the MEC, 512 K rom and 4 M ram. + +The following paragraphs outline the implemented MEC functions. + +1.1 UARTs + +The UARTs are connected to two pseudo-devices, /dev/ttypc and /dev/ttypd. +The following registers are implemeted: + +- UART A RX and TX register (0x01f800e0) +- UART B RX and TX register (0x01f800e4) +- UART status register (0x01f800e8) + +To speed up simulation, the UARTs operate at approximately 115200 baud. +The UARTs generate interrupt 4 and 5 after each received or transmitted +character. The error interrupt is generated if overflow occurs - other +errors cannot occure. + +1.2 Real-time clock and general pupose timer A + +The following registers are implemeted: + +- Real-time clock timer (0x01f80080, read-only) +- Real-time clock scaler program register (0x01f80084, write-only) +- Real-time clock counter program register (0x01f80080, write-only) + +- Genearl pupose timer (0x01f80088, read-only) +- Real-time clock scaler program register (0x01f8008c, write-only) +- General purpose timer counter prog. register (0x01f80088, write-only) + +- Timer control register (0x01f80098, write-only) + +1.3 Interrupt controller + +The interrupt controller is implemented as in the MEC specification with +the exception of the interrupt shape register. Since external interrupts +are not possible, the interrupt shape register is not implemented. The +only internal interrupts that are generated are the real-time clock, +the general purpose timer and UARTs. However, all 15 interrupts +can be tested via the interrupt force register. + +The following registers are implemeted: + +- Interrupt pending register (0x01f80048, read-only) +- Interrupt mask register (0x01f8004c, read-write) +- Interrupt clear register (0x01f80050, write-only) +- Interrupt force register (0x01f80054, read-write) + +1.4 Breakpoint and watchpoint register + +The breakpoint and watchpoint functions are implemented as in the MEC +specification. Traps are correctly generated, and the system fault status +register is updated accordingly. Implemeted registers are: + +- Debug control register (0x01f800c0, read-write) +- Breakpoint register (0x01f800c4, write-only) +- Watchpoint register (0x01f800c8, write-only) +- System fault status register (0x01f800a0, read-write) +- Firts failing address register (0x01f800a4, read-write) + + +1.5 Memory interface + +The following memory areas are valid for the ERC32 simulator: + +0x00000000 - 0x00080000 ROM (512 Kbyte, loaded at start-up) +0x02000000 - 0x02400000 RAM (4 Mbyte, initialised to 0x0) +0x01f80000 - 0x01f800ff MEC registers + +Access to unimplemented MEC registers or non-existing memory will result +in a memory exception trap. However, access to unimplemented MEC registers +in the area 0x01f80000 - 0x01f80100 will not cause a memory exception trap. +The written value will be stored in a register and can be read back. It +does however not affect the function in any way. + +The memory configuartion register is used to define available memory +in the system. The fields RSIZ and PSIZ are used to set RAM and ROM +size, the remaining fields are not used. NOTE: after reset, the MEC +is set to decode 4 Kbyte of ROM and 256 Kbyte of RAM. The memory +configuration register has to be updated to reflect the available memory. + +The waitstate configuration register is used to generate waitstates. +This register must also be updated with the correct configuration after +reset. + +The memory protection scheme is implemented - it is enabled through bit 3 +in the MEC control register. + +The following registers are implemeted: + +- MEC control register (bit 3 only) (0x01f80000, read-write) +- Memory control register (0x01f80010, read-write) +- Waitstate configuration register (0x01f80018, read-write) +- Memory access register 0 (0x01f80020, read-write) +- Memory access register 1 (0x01f80024, read-write) + +1.6 Watchdog + +The watchdog is implemented as in the specification. The input clock is +always the system clock regardsless of WDCS bit in mec configuration +register. + +The following registers are implemeted: + +- Watchdog program and acknowledge register (0x01f80060, write-only) +- Watchdog trap door set register (0x01f80064, write-only) + +1.7 Software reset register + +Implemented as in the specification (0x01f800004, write-only). + +1.8 Power-down mode + +The power-down register (0x01f800008) is implemented as in the specification. +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. + +1.9 MEC control register + +The following bits are implemented in the MEC control register: + +Bit Name Function +0 PRD Power-down mode enable +1 SWR Soft reset enable +3 APR Access protection enable + diff --git a/sim/erc32/README.gdb b/sim/erc32/README.gdb new file mode 100644 index 00000000000..619fcb38fc9 --- /dev/null +++ b/sim/erc32/README.gdb @@ -0,0 +1,67 @@ +How to use SIS with GDB +----------------------- + +1. Building GDB with SIS + +To build GDB with the SIS/ERC32 simulator, configure with option +'--target sparc-erc32-aout' and build as usual. + +2. Attaching the simulator + +To attach GDB to the simulator, use: + +target sim [options] [files] + +The following options are supported: + + -nfp Disable FPU. FPops will cause an FPU disabled trap. + + -freq Set the simulated "system clock" to MHz. + + -v Verbose mode. + + -nogdb Disable GDB breakpoint handling (see below) + +The listed [files] are expected to be in aout format and will be +loaded in the simulator memory prior. This could be used to load +a boot block at address 0x0 if the application is linked to run +from RAM (0x2000000). + +To start debugging a program type 'load ' and debug as +usual. + +The native simulator commands can be reached using the GDB 'sim' +command: + +sim + +Direct simulator commands during a GDB session must be issued +with care not to disturb GDB's operation ... + +For info on supported ERC32 functionality, see README.sis. + + +3. Loading aout files + +The GDB load command loads an aout file into the simulator +memory with the data section starting directly after the text +section regardless of wich start address was specified for the data +at link time! This means that your applications either has to include +a routine that initialise the data segment at the proper address or +link with the data placed directly after the text section. + +A copying routine is fairly simple, just copy all data between +_etext and _data to a memory loaction starting at _environ. This +should be done at the same time as the bss is cleared (in srt0.s). + + +4. GDB breakpoint handling + +GDB inserts breakpoint in the form of the 'ta 1' instruction. The +GDB-integrated simulator will therefore recognize the breakpoint +instruction and return control to GDB. If the application uses +'ta 1', the breakpoint detection can be disabled with the -nogdb +switch. In this case however, GDB breakpoints will not work. + + +Report problems to Jiri Gaisler ESA/ESTEC (jgais@wd.estec.esa.nl) diff --git a/sim/erc32/README.sis b/sim/erc32/README.sis new file mode 100644 index 00000000000..b119f038ac2 --- /dev/null +++ b/sim/erc32/README.sis @@ -0,0 +1,356 @@ + +SIS - Sparc Instruction Simulator README file (v2.0, 05-02-1996) +------------------------------------------------------------------- + +1. Introduction + +The SIS is a SPARC V7 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. + +2. Usage + +The simulator is started as follows: + +sis [-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. +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 -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. + +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 +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. + +batch + +Execute a batch file of SIS commands. + ++bp
+ +Adds an breakpoint at address
. + +bp + +Prints all breakpoints + +-bp + +Deletes breakpoint . Use 'bp' to see which number is assigned to the +breakpoints. + +cont [inst_count] + +Continue execution at present position, optionally for [inst_count] +instructions. + +dis [addr] [count] + +Disassemble [count] instructions at address [addr]. Default values for +count is 16 and addr is the present address. + +echo + +Print to the simulator window. + +float + +Prints the FPU registers + +go
[inst_count] + +The go command will set pc to
and npc to
+ 4, and start +execution. No other initialisation will be done. If inst_count is given, +execution will stop after the specified number of instructions. + +help + +Print a small help menu for the SIS commands. + +hist [trace_length] + +Enable the instruction trace buffer. The 'trace_length' last executed +instructions will be placed in the trace buffer. A 'hist' command without +a trace_length will display the trace buffer. Specifying a zero trace +length will disable the trace buffer. + +load + +Loads a file into simulator memory. + +mem [addr] [count] + +Display memory at [addr] for [count] bytes. Same default values as above. + +quit + +Exits the simulator. + +perf [reset] + +The 'perf' command will display various execution statistics. A 'perf reset' +command will reset the statistics. This can be used if statistics shall +be calculated only over a part of the program. The 'run' and 'reset' +command also resets the statistic information. + +reg [reg_name] [value] + +Prints and sets the IU regiters. 'reg' without parameters prints the IU +registers. 'reg [reg_name] [value]' sets the corresponding register to +[value]. Valid register names are psr, tbr, wim, y, g1-g7, o0-o7 and +l0-l7. + +reset + +Performs a power-on reset. This command is equal to 'run 0'. + +run [inst_count] + +Resets the simulator and starts execution from address 0. If an instruction +count is given (inst_count), the simulator will stop after the specified +number of instructions. The event queue is emptied but any set breakpoints +remain. + +step + +Equal to 'trace 1' + +tra [inst_count] + +Starts the simulator at the present position and prints each instruction +it executes. If an instruction count is given (inst_count), the simulator +will stop after the specified number of instructions. + +Typing a 'Ctrl-C' will interrupt a running simulator. + +Short forms of the commands are allowed, e.g 'c' 'co' or 'con' are all +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. +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: + +int memory_read(asi,addr,data,ws) +int asi; +unsigned int addr; +unsigned int *data; +int *ws; + +int memory_write(asi,addr,data,sz,ws) +int asi; +unsigned int addr; +unsigned int *data; +int sz; +int *ws; + +int sis_memory_read(addr, data, length) +unsigned int addr; +char *data; +unsigned int length; + +int sis_memory_write(addr, data, length) +unsigned int addr; +char *data; +unsigned int length; + +int init_sim() + +int reset() + +int error_mode(pc) +unsigned int pc; + +memory_read() is used by the simulator to fetch instructions and +operands. The address space identifier (asi) and address is passed as +parameters. The read data should be assigned to the data pointer +(*data) and the number of waitstate to *ws. 'memory_read' should return +0 on success and 1 on failure. A failure will cause a data or +instruction fetch trap. memory_read() always reads one 32-bit word. + +sis_memory_read() is used by the simulator to display and disassemble +memory contants. The function should copy 'length' bytes of the simulated +memory starting at 'addr' to '*data'. +The sis_memory_read() should return 1 on success and 0 on failure. +Failure should only be indicated if access to unimplemented memory is attempted. + +memory_write() is used to write to memory. In addition to the asi +and address parameters, the size of the written data is given by 'sz'. +The pointer *data points to the data to be written. The 'sz' is coded +as follows: + + sz access type + 0 byte + 1 halfword + 2 word + 3 double-word + +If a double word is written, the most significant word is in data[0] and +the least significant in data[1]. + +sis_memory_write() is used by the simulator during loading of programs. +The function should copy 'length' bytes from *data to the simulated +memory starting at 'addr'. sis_memory_write() should return 1 on +success and 0 on failure. Failure should only be indicated if access +to unimplemented memory is attempted. See erc32.c for more details +on how to define the memory emulation functions. + +The 'init_sim' is called once when the simulator is started. This function +should be used to perform initialisations of user defined memory or +peripherals that only have to be done once, such as opening files etc. + +The 'reset' is called every time the simulator is reset, i.e. when a +'run' command is given. This function should be used to simulate a power +on reset of memory and peripherals. + +error_mode() is called by the simulator when the IU goes into error mode, +typically if a trap is caused when traps are disabled. The memory module +can then take actions, such as issue a reset. + +sys_reset() can be called by the memory module to reset the simulator. A +reset will empty the event queue and perform a power-on reset. + +4. Events and interrupts + +The simulator supports an event queue and the generation of processor +interrupts. The following functions are available to the user-defined +memory module: + +event(cfunc,arg,delta) +void (*cfunc)(); +int arg; +unsigned int delta; + +set_int(level,callback,arg) +int level; +void (*callback)(); +int arg; + +clear_int(level) +int level; + +sim_stop() + +The 'event' functions will schedule the execution of the function 'cfunc' +at time 'now + delta' clock cycles. The parameter 'arg' is passed as a +parameter to 'cfunc'. + +The 'set_int' function set the processor interrupt 'level'. When the interrupt +is taken, the function 'callback' is called with the argument 'arg'. This +will also clear the interrupt. An interrupt can be cleared before it is +taken by calling 'clear_int' with the appropriate interrupt level. + +The sim_stop function is called each time the simulator stops execution. +It can be used to flush buffered devices to get a clean state during +single stepping etc. + +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 MEC asic developed for the 90C601/2. It includes the following functions: + +* UART A & B +* Real-time clock +* General purpose timer +* Interrupt controller +* Breakpoint register +* Watchpoint register +* 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: + +http://www.estec.esa.nl/wsmwww/erc32 + +6. Compile and linking programs + +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. + +The programs are linked with a start-up file, srt0.S. This file includes +the traptable and window underflow/overflow trap routines. + +7. IU and FPU instruction timing. + +The simulator provides cycle true simulation. The following table shows +the emulated instruction timing for 90C601E & 90C602E: + +Instructions Cycles + +jmpl, rett 2 +load 2 +store 3 +load double 3 +store double 4 +other integer ops 1 +fabs 2 +fadds 4 +faddd 4 +fcmps 4 +fcmpd 4 +fdivs 20 +fdivd 35 +fmovs 2 +fmuls 5 +fmuld 9 +fnegs 2 +fsqrts 37 +fsqrtd 65 +fsubs 4 +fsubd 4 +fdtoi 7 +fdots 3 +fitos 6 +fitod 6 +fstoi 6 +fstod 2 + +The parallel operation between the IU and FPU is modelled. This means +that a FPU instruction will execute in parallel with other instructions as +long as no data or resource dependency is detected. See the 90C602E data +sheet for the various types of dependencies. Tracing using the 'trace' +command will display the current simulator time in the left column. This +time indicates when the instruction is fetched. If a dependency is detetected, +the following fetch will be delayed until the conflict is resolved. + +The load dependency in the 90C601E is also modelled - if the destination +register of a load instruction is used by the following instruction, an +idle cycle is inserted. + +8. FPU implementation + +The simulator maps floating-point operations on the hosts floating point +capabilities. This means that accuracy and generation of IEEE exceptions is +host dependent. diff --git a/sim/erc32/configure.in b/sim/erc32/configure.in new file mode 100644 index 00000000000..0eb7b73bf9b --- /dev/null +++ b/sim/erc32/configure.in @@ -0,0 +1,18 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.3)dnl +AC_INIT(Makefile.in) + +AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../..) +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM + +. ${srcdir}/../../bfd/configure.host + +AC_PROG_CC +AC_SUBST(CFLAGS) +AC_SUBST(HDEFINES) +AR=${AR-ar} +AC_SUBST(AR) +AC_PROG_RANLIB + +AC_OUTPUT(Makefile) diff --git a/sim/erc32/end.c b/sim/erc32/end.c new file mode 100644 index 00000000000..5cd454a42bd --- /dev/null +++ b/sim/erc32/end.c @@ -0,0 +1,23 @@ +main() +{ + + unsigned int u1; + char *c; + double d1; + float *f1; + + c = (char *) &u1; + u1 = 0x0F; + if (c[0] == 0x0F) + puts("#define HOST_LITTLE_ENDIAN\n"); + else + puts("#define HOST_BIG_ENDIAN\n"); + + d1 = 1.0; + f1 = (float *) &d1; + if (*((int *) f1) != 0x3ff00000) + puts("#define HOST_LITTLE_ENDIAN_FLOAT\n"); + else + puts("#define HOST_BIG_ENDIAN_FLOAT\n"); + exit(0); +} diff --git a/sim/erc32/examples/__main.c b/sim/erc32/examples/__main.c new file mode 100644 index 00000000000..73c52cd344a --- /dev/null +++ b/sim/erc32/examples/__main.c @@ -0,0 +1,4 @@ +/* Dummy __main for gccx compiled programs */ + +__main() +{} diff --git a/sim/erc32/examples/clock.c b/sim/erc32/examples/clock.c new file mode 100644 index 00000000000..ec23037a0c6 --- /dev/null +++ b/sim/erc32/examples/clock.c @@ -0,0 +1,8 @@ + +int clock() +{ + volatile int *t_addr; + + t_addr = (volatile int * ) 0x01F80080; /* Real-time clock address */ + return(*t_addr); +} diff --git a/sim/erc32/examples/gccx b/sim/erc32/examples/gccx new file mode 100755 index 00000000000..5fec6ece63e --- /dev/null +++ b/sim/erc32/examples/gccx @@ -0,0 +1,7 @@ +# +sparclite-aout-gcc -g \ +-Xlinker -Bstatic -Xlinker -N -Xlinker -Ttext -Xlinker 0 \ +-Xlinker -Tdata -Xlinker 02000000 -Xlinker -e -Xlinker _trap_table -Xlinker -X \ +-o $1:r -nostartfiles -nostdlib \ +srt0.S __main.c $* +size $1:r diff --git a/sim/erc32/examples/hello.c b/sim/erc32/examples/hello.c new file mode 100644 index 00000000000..02903cf214c --- /dev/null +++ b/sim/erc32/examples/hello.c @@ -0,0 +1,87 @@ +/* A small test program to demonstrate use of UARTs and clock */ + + +#define RXADATA (int *) 0x01F800E0 +#define RXBDATA (int *) 0x01F800E4 +#define RXSTAT (int *) 0x01F800E8 + +int write (fd, buf, nbyte) +int fd; +char *buf; +int nbyte; +{ + + int *rxadata; + int rxmask; + int nsave; + volatile *rxstat; + + nsave = nbyte; + + switch (fd) { + case 0 : + rxadata = RXADATA; + rxmask = 6; + break; + case 1 : + rxadata = RXBDATA; + rxmask = 0x60000; + break; + default: + return (-1); + } + rxstat = RXSTAT; + while (nbyte > 0) { + while ((*rxstat & rxmask) == 0); + *rxadata = *buf; + buf++; + nbyte--; + } + return (nsave); +} + +int read (fd, buf, nbyte) +int fd; +char *buf; +int nbyte; +{ + + int rxmask,*rxadata; + int nsave; + volatile *rxstat; + + nsave = nbyte; + switch (fd) { + case 0 : + rxadata = RXADATA; + rxmask = 1; + break; + case 1 : + rxadata = RXBDATA; + rxmask = 0x10000; + break; + default: + return (-1); + } + rxstat = RXSTAT; + while (nbyte > 0) { + while ((*rxstat & rxmask) == 0); + *buf = *rxadata; + buf++; + nbyte--; + } + return (nsave); +} + +char * +puts(s) +char *s; +{ + while (*s) write(0,s++,1); +} + +main() +{ + puts("Hello world!\n"); +} + diff --git a/sim/erc32/examples/srt0.S b/sim/erc32/examples/srt0.S new file mode 100755 index 00000000000..1e68951999e --- /dev/null +++ b/sim/erc32/examples/srt0.S @@ -0,0 +1,449 @@ +/* + * srt0.s for ERC32. This file is part of ERC32SIM. + * + * 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 2 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, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* The traptable has to be the first code in a boot PROM. */ + +/* Entry for traps which jump to a programmer-specified trap handler. */ +#define TRAP(H) mov %psr, %l0; sethi %hi(H), %l4; jmp %l4+%lo(H); nop; + +/* Unexcpected trap will halt the processor by forcing it to error state */ +#define BAD_TRAP ta 0; nop; nop; nop; + +/* Software trap. Treat as BAD_TRAP for the time being... */ +#define SOFT_TRAP BAD_TRAP + +#define PSR_INIT 0x10c0 /* Disable traps, set s and ps */ +#define WIM_INIT 2 +#define SP_INIT 0x02100000 + +WINDOWSIZE = (16 * 4) +ARGPUSHSIZE = (6 * 4) +ARGPUSH = (WINDOWSIZE + 4) +MINFRAME = (WINDOWSIZE + ARGPUSHSIZE + 4) +#define STACK_ALIGN 8 +#define SA(X) (((X)+(STACK_ALIGN-1)) & ~(STACK_ALIGN-1)) + + .seg "text" + .global _trap_table, _mecini, start + + /* Hardware traps */ +_trap_table: + TRAP(_mecini); ! 00 reset trap + BAD_TRAP; ! 01 instruction_access_exception + BAD_TRAP; ! 02 illegal_instruction + BAD_TRAP; ! 03 priveleged_instruction + BAD_TRAP; ! 04 fp_disabled + TRAP(_window_overflow); ! 05 window_overflow + TRAP(_window_underflow); ! 06 window_underflow + BAD_TRAP; ! 07 memory_address_not_aligned + BAD_TRAP; ! 08 fp_exception + BAD_TRAP; ! 09 data_access_exception + BAD_TRAP; ! 0A tag_overflow + + /* Trap levels from 0B to 0x10 are not defined (used for MEC init) */ + +_mecini: + sethi %hi(0x01f80000), %g1 ! 0B + sethi %hi(0x001C1000), %g2 + or %g1,%lo(0x001C1000),%g1 + st %g2, [%g1 + 0x10] + + st %g0, [%g1 + 0x18] ! 0C + nop + nop + nop + + TRAP(_hardreset); ! 0D + + BAD_TRAP; ! 0E undefined + BAD_TRAP; ! 0F undefined + BAD_TRAP; ! 10 undefined + + /* Interrupt entries */ + BAD_TRAP; ! 11 interrupt level 1 + BAD_TRAP; ! 12 interrupt level 2 + BAD_TRAP; ! 13 interrupt level 3 + BAD_TRAP; ! 14 interrupt level 4 + BAD_TRAP; ! 15 interrupt level 5 + BAD_TRAP; ! 16 interrupt level 6 + BAD_TRAP; ! 17 interrupt level 7 + BAD_TRAP; ! 18 interrupt level 8 + BAD_TRAP; ! 19 interrupt level 9 + BAD_TRAP; ! 1A interrupt level 1 + BAD_TRAP; ! 1B interrupt level 11 + BAD_TRAP; ! 1C interrupt level 12 + BAD_TRAP; ! 1D interrupt level 13 + BAD_TRAP; ! 1E interrupt level 14 + BAD_TRAP; ! 1F interrupt level 15 + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 20 - 23 undefined + BAD_TRAP; ! 24 cp_disabled + BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 25 - 27 undefined + BAD_TRAP; ! 28 cp_exception + BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 29 - 2B undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 2C - 2F undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 30 - 33 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 34 - 37 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 38 - 3B undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 3C - 3F undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 40 - 43 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 44 - 47 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 48 - 4B undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 4C - 4F undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 50 - 53 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 54 - 57 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 58 - 5B undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 5C - 5F undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 60 - 63 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 64 - 67 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 68 - 6B undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 6C - 6F undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 70 - 73 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 74 - 77 undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 78 - 7B undefined + BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP; ! 7C - 7F undefined + + /* Software traps */ + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 80 - 82 + TRAP(_flush_windows) ! 83 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 84 - 87 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 88 - 8B + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 8C - 8F + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 90 - 93 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 94 - 97 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 98 - 9B + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! 9C - 9F + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A0 - A3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A4 - A7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! A8 - AB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! AC - AF + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B0 - B3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B4 - B7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! B8 - BB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! BC - BF + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C0 - C3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C4 - C7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! C8 - CB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! CC - CF + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D0 - D3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D4 - D7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! D8 - DB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! DC - DF + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E0 - E3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E4 - E7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! E8 - EB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! EC - EF + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F0 - F3 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F4 - F7 + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! F8 - FB + SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; ! FC - FF + + +! +! Startup code for standalone system. Wash IU and FPU (if present) registers. +! The registers have to be written to initiate the parity bits. +! + +_hardreset: + + sethi %hi(0x01FE0),%o0 + or %o0,%lo(0x01FE0),%o0 + wr %o0, %psr ! Set valid PSR + nop + + wr %g0, %wim ! Set window invalid mask register + wr %g0, %y ! Init Y-register + nop + set _hardreset, %g1 + + wr %g1, %tbr ! Set TBR + sethi %hi(SP_INIT),%sp + or %g0, 1, %o0 + ld [%g0], %f0 ! Check if FPU is present + + tst %o0 + bz fixiu + nop + ba fixfpu + +! FPU disabled trap address + + clr %i0 + jmpl %l2, %g0 + rett %l2 + 4 + nop + + +! Wash register files (fix for 90C601E & 90C602E) + +fixfpu: + + ld [%g0], %f0 + ld [%g0], %f1 + ld [%g0], %f2 + ld [%g0], %f3 + ld [%g0], %f4 + ld [%g0], %f5 + ld [%g0], %f6 + ld [%g0], %f7 + ld [%g0], %f8 + ld [%g0], %f9 + ld [%g0], %f10 + ld [%g0], %f11 + ld [%g0], %f12 + ld [%g0], %f13 + ld [%g0], %f14 + ld [%g0], %f15 + ld [%g0], %f16 + ld [%g0], %f17 + ld [%g0], %f18 + ld [%g0], %f19 + ld [%g0], %f20 + ld [%g0], %f21 + ld [%g0], %f22 + ld [%g0], %f23 + ld [%g0], %f24 + ld [%g0], %f25 + ld [%g0], %f26 + ld [%g0], %f27 + ld [%g0], %f28 + ld [%g0], %f29 + ld [%g0], %f30 + ld [%g0], %f31 + +fixiu: + clr %g1 + clr %g2 + clr %g3 + clr %g4 + clr %g5 + clr %g6 + clr %g7 + set 8,%g1 +wl0: + clr %i0 + clr %i1 + clr %i2 + clr %i3 + clr %i4 + clr %i5 + clr %i6 + clr %i7 + clr %l0 + clr %l1 + clr %l2 + clr %l3 + clr %l4 + clr %l5 + clr %l6 + clr %l7 + save + subcc %g1, 1, %g1 + bne wl0 + nop + +! +! Start the real-time clock with a tick of 150 clocks +! + +rtc: + + set 0x1f80000, %l0 ! MEC register base + set 149, %l1 + st %l1, [%l0 + 0x84] ! RTC scaler = 149 + set 0x0d00, %l1 + st %l1, [%l0 + 0x98] ! Start RTC + + st %g0, [%l0 + 0x64] ! Disable watchdog for now + ld [%l0], %g1 + or %g1, 1, %g1 + st %g1, [%l0] ! Enable power-down mode + +! Initialise some registers + +_init: + set PSR_INIT, %g1 ! Initialize psr + wr %g1, %psr + set WIM_INIT, %g1 ! Initialize WIM + wr %g1, %wim + set _trap_table, %g1 ! Initialize TBR + wr %g1, %tbr + nop;nop;nop + + set PSR_INIT, %g1 + wr %g1, 0x20, %psr ! enable traps + nop; nop; nop; + set 0x02100000, %sp ! Set stack pointer + mov %sp, %fp + nop + +start: + /* clear the bss */ + + sethi %hi(_edata),%g2 + or %g2,%lo(_edata),%g2 ! g2 = start of bss + sethi %hi(_end),%g3 + or %g3,%lo(_end),%g3 ! g3 = end of bss + mov %g0,%g1 ! so std has two zeros +zerobss: + std %g0,[%g2] + add %g2,8,%g2 + cmp %g2,%g3 + bleu,a zerobss + nop + + /* move data segment to proper location */ + +relocd: + set (_etext),%g2 ! g2 = start of data in aout file + set (_environ),%g4 ! g4 = start of where data should go + set (_edata),%g3 ! g3 = end of where data should go + subcc %g3, %g4, %g5 ! g5 = length of data + + subcc %g4, %g2, %g0 ! need to relocate data ? + ble initok +mvdata: + subcc %g5, 8, %g5 + ldd [%g2 + %g5], %g6 + bg mvdata + std %g6, [%g4 + %g5] + +initok: + + call _main + sub %sp, 0x40, %sp ! room for main to save args + nop + + ta 0 ! Halt if _main would return ... + nop + + + +/* Number of register windows */ +#define NWINDOWS 8 + + !Window overflow trap handler. + .global _window_overflow + +_window_overflow: + + mov %wim, %l3 ! Calculate next WIM + mov %g1, %l7 + srl %l3, 1, %g1 + sll %l3, NWINDOWS-1 , %l4 + or %l4, %g1, %g1 + + save ! Get into window to be saved. + mov %g1, %wim + nop; nop; nop + st %l0, [%sp + 0]; + st %l1, [%sp + 4]; + st %l2, [%sp + 8]; + st %l3, [%sp + 12]; + st %l4, [%sp + 16]; + st %l5, [%sp + 20]; + st %l6, [%sp + 24]; + st %l7, [%sp + 28]; + st %i0, [%sp + 32]; + st %i1, [%sp + 36]; + st %i2, [%sp + 40]; + st %i3, [%sp + 44]; + st %i4, [%sp + 48]; + st %i5, [%sp + 52]; + st %i6, [%sp + 56]; + st %i7, [%sp + 60]; + restore ! Go back to trap window. + mov %l7, %g1 + jmp %l1 ! Re-execute save. + rett %l2 + + /* Window underflow trap handler. */ + + .global _window_underflow + +_window_underflow: + + mov %wim, %l3 ! Calculate next WIM + sll %l3, 1, %l4 + srl %l3, NWINDOWS-1, %l5 + or %l5, %l4, %l5 + mov %l5, %wim + nop; nop; nop + restore ! Two restores to get into the + restore ! window to restore + ld [%sp + 0], %l0; ! Restore window from the stack + ld [%sp + 4], %l1; + ld [%sp + 8], %l2; + ld [%sp + 12], %l3; + ld [%sp + 16], %l4; + ld [%sp + 20], %l5; + ld [%sp + 24], %l6; + ld [%sp + 28], %l7; + ld [%sp + 32], %i0; + ld [%sp + 36], %i1; + ld [%sp + 40], %i2; + ld [%sp + 44], %i3; + ld [%sp + 48], %i4; + ld [%sp + 52], %i5; + ld [%sp + 56], %i6; + ld [%sp + 60], %i7; + save ! Get back to the trap window. + save + jmp %l1 ! Re-execute restore. + rett %l2 + + .global _flush_windows +_flush_windows: + + mov %psr, %g1 + or %g1, 0x0f00, %g2 + restore ! enter previous frame (cannot trap) + wr %g2, 0x20, %psr ! enable traps, disable interrupts + nop; nop; nop + save ! 6 save to flush all windows + save + save + save + save + save + restore ! 5 restore to enter trapped frame + restore + restore + restore + restore + wr %g1, %psr ! restore %psr + nop; nop; nop + jmp %l2 ! Jump to nPC + rett %l2 + 4 + + + + + .seg "data" + .global .bdata +.bdata: + .align 8 + .global _environ ! first symbol in sdata +_environ: + .word 0 + .global _errno ! not defined elsewhere ..? +_errno: + .word 0 + + + diff --git a/sim/erc32/exec.c b/sim/erc32/exec.c new file mode 100644 index 00000000000..8690cea9d89 --- /dev/null +++ b/sim/erc32/exec.c @@ -0,0 +1,1597 @@ +/* + * This file is part of SIS. + * + * SIS, SPARC instruction simulator V1.8 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 2 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, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "sis.h" +#include "end.h" +#include +#include + +extern int32 ext_irl, irqpend, iurev0, sis_verbose; + +/* Load/store interlock delay */ +#define FLSTHOLD 1 + +/* Load delay (delete if unwanted - speeds up simulation) */ +#define LOAD_DEL 1 + +#define T_LD 2 +#define T_LDD 3 +#define T_ST 3 +#define T_STD 4 +#define T_LDST 4 +#define T_JMPL 2 +#define T_RETT 2 + +#define FSR_QNE 0x2000 +#define FP_EXE_MODE 0 +#define FP_EXC_PE 1 +#define FP_EXC_MODE 2 + +#define FBA 8 +#define FBN 0 +#define FBNE 1 +#define FBLG 2 +#define FBUL 3 +#define FBL 4 +#define FBUG 5 +#define FBG 6 +#define FBU 7 + +#define FCC_E 0 +#define FCC_L 1 +#define FCC_G 2 +#define FCC_U 3 + +#define PSR_ET 0x20 +#define PSR_EF 0x1000 +#define PSR_PS 0x40 +#define PSR_S 0x80 +#define PSR_N 0x0800000 +#define PSR_Z 0x0400000 +#define PSR_V 0x0200000 +#define PSR_C 0x0100000 +#define PSR_CC 0x0F00000 +#define PSR_CWP 0x7 +#define PSR_PIL 0x0f00 + +#define ICC_N sregs->psr +#define ICC_Z (sregs->psr << 1) +#define ICC_V (sregs->psr << 2) +#define ICC_C (sregs->psr << 3) + +#define TRAP_IEXC 1 +#define TRAP_UNIMP 2 +#define TRAP_PRIVI 3 +#define TRAP_FPDIS 4 +#define TRAP_WOFL 5 +#define TRAP_WUFL 6 +#define TRAP_UNALI 7 +#define TRAP_FPEXC 8 +#define TRAP_DEXC 9 +#define TRAP_TAG 10 + +#define FSR_TT 0x1C000 +#define FP_IEEE 0x04000 +#define FP_UNIMP 0x0C000 +#define FP_SEQ_ERR 0x10000 + +#define BICC_BN 0 +#define BICC_BE 1 +#define BICC_BLE 2 +#define BICC_BL 3 +#define BICC_BLEU 4 +#define BICC_BCS 5 +#define BICC_NEG 6 +#define BICC_BVS 7 +#define BICC_BA 8 + +#define INST_SIMM13 0x1fff +#define INST_RS2 0x1f +#define INST_I 0x2000 +#define ADD 0x00 +#define ADDCC 0x10 +#define ADDX 0x08 +#define ADDXCC 0x18 +#define TADDCC 0x20 +#define TADDCCTV 0x22 +#define IAND 0x01 +#define IANDCC 0x11 +#define IANDN 0x05 +#define IANDNCC 0x15 +#define MULScc 0x24 +#define IOR 0x02 +#define IORCC 0x12 +#define IORN 0x06 +#define IORNCC 0x16 +#define SLL 0x25 +#define SRA 0x27 +#define SRL 0x26 +#define SUB 0x04 +#define SUBCC 0x14 +#define SUBX 0x0C +#define SUBXCC 0x1C +#define IXNOR 0x07 +#define IXNORCC 0x17 +#define IXOR 0x03 +#define IXORCC 0x13 +#define SETHI 0x04 +#define BICC 0x02 +#define FPBCC 0x06 +#define RDY 0x28 +#define RDPSR 0x29 +#define RDWIM 0x2A +#define RDTBR 0x2B +#define WRY 0x30 +#define WRPSR 0x31 +#define WRWIM 0x32 +#define WRTBR 0x33 +#define JMPL 0x38 +#define RETT 0x39 +#define TICC 0x3A +#define SAVE 0x3C +#define RESTORE 0x3D +#define LDD 0x03 +#define LDDA 0x13 +#define LD 0x00 +#define LDA 0x10 +#define LDF 0x20 +#define LDDF 0x23 +#define LDSTUB 0x0D +#define LDSTUBA 0x1D +#define LDUB 0x01 +#define LDUBA 0x11 +#define LDSB 0x09 +#define LDSBA 0x19 +#define LDUH 0x02 +#define LDUHA 0x12 +#define LDSH 0x0A +#define LDSHA 0x1A +#define LDFSR 0x21 +#define ST 0x04 +#define STA 0x14 +#define STB 0x05 +#define STBA 0x15 +#define STD 0x07 +#define STDA 0x17 +#define STF 0x24 +#define STDFQ 0x26 +#define STDF 0x27 +#define STFSR 0x25 +#define STH 0x06 +#define STHA 0x16 +#define SWAP 0x0F +#define SWAPA 0x1F + +/* # of cycles overhead when a trap is taken */ +#define TRAP_C 3 + +int32 fpexec(); +extern struct estate ebase; +extern int32 nfp; + +sub_cc(operand1, operand2, result, sregs) + int32 operand1; + int32 operand2; + int32 result; + struct pstate *sregs; +{ + sregs->psr = ((sregs->psr & ~PSR_N) | ((result >> 8) & PSR_N)); + if (result) + sregs->psr &= ~PSR_Z; + else + sregs->psr |= PSR_Z; + sregs->psr = (sregs->psr & ~PSR_V) | (( + ((operand1 & ~operand2 & ~result) | + (~operand1 & operand2 & result)) >> 10) & PSR_V); + sregs->psr = (sregs->psr & ~PSR_C) | (( + ((~operand1 & operand2) | + ((~operand1 | operand2) & result)) >> 11) & PSR_C); +} + +add_cc(operand1, operand2, result, psr) + int32 operand1; + int32 operand2; + int32 result; + uint32 *psr; +{ + *psr = ((*psr & ~PSR_N) | ((result >> 8) & PSR_N)); + if (result) + *psr &= ~PSR_Z; + else + *psr |= PSR_Z; + *psr = (*psr & ~PSR_V) | (( + ((operand1 & operand2 & ~result) | + (~operand1 & ~operand2 & result)) >> 10) & PSR_V); + *psr = (*psr & ~PSR_C) | (( + ((operand1 & operand2) | + ((operand1 | operand2) & ~result)) >> 11) & PSR_C); +} + +log_cc(result, sregs) + int32 result; + struct pstate *sregs; +{ + sregs->psr &= ~(PSR_CC); /* Zero CC bits */ + sregs->psr = (sregs->psr | ((result >> 8) & PSR_N)); + if (result == 0) + sregs->psr |= PSR_Z; +} + +int +dispatch_instruction(sregs) + struct pstate *sregs; +{ + + uint32 cwp, op, op2, op3, opf, opc, asi, a, rd, cond, rs1, + rs2; + uint32 ldep; + int32 operand1, operand2, *rdd, result, i, disp22, eicc, + new_cwp; + int32 pc, npc, data, address, ws, mexc, fcc; + + sregs->ninst++; + sregs->icnt = 1; + cwp = ((sregs->psr & PSR_CWP) << 4); + op = sregs->inst >> 30; + pc = sregs->npc; + npc = sregs->npc + 4; + if (op > 1) { + + op3 = (sregs->inst >> 19) & 0x3f; + rs1 = (sregs->inst >> 14) & 0x1f; + rd = (sregs->inst >> 25) & 0x1f; + +#ifdef LOAD_DEL + + /* Check if load dependecy is possible */ + ldep = ((ebase.simtime <= sregs->ildtime) && ((op3 & 0x38) != 0x28) && + ((op3 & 0x3e) != 0x34) && (sregs->ildreg != 0)); + if (sregs->inst & INST_I) { + if (ldep && (sregs->ildreg == rs1)) + sregs->hold++; + operand2 = sregs->inst & INST_SIMM13; + if (operand2 > 0x0fff) + operand2 |= 0xfffff000; + } else { + rs2 = sregs->inst & INST_RS2; + if (rs2 > 7) + operand2 = sregs->r[(cwp + rs2) & 0x7f]; + else + operand2 = sregs->g[rs2]; + if (ldep && ((sregs->ildreg == rs1) || (sregs->ildreg == rs2))) + sregs->hold++; + } +#else + if (sregs->inst & INST_I) { + operand2 = sregs->inst & INST_SIMM13; + if (operand2 > 0x0fff) + operand2 |= 0xfffff000; + } else { + rs2 = sregs->inst & INST_RS2; + if (rs2 > 7) + operand2 = sregs->r[(cwp + rs2) & 0x7f]; + else + operand2 = sregs->g[rs2]; + } +#endif + + if (rd > 7) + rdd = &(sregs->r[(cwp + rd) & 0x7f]); + else + rdd = &(sregs->g[rd]); + if (rs1 > 7) + rs1 = sregs->r[(cwp + rs1) & 0x7f]; + else + rs1 = sregs->g[rs1]; + } + switch (op) { + case 0: + op2 = (sregs->inst >> 22) & 0x7; + switch (op2) { + case SETHI: + rd = (sregs->inst >> 25) & 0x1f; + if (rd > 7) + rdd = &(sregs->r[(cwp + rd) & 0x7f]); + else + rdd = &(sregs->g[rd]); + *rdd = sregs->inst << 10; + break; + case BICC: +#ifdef STAT + sregs->nbranch++; +#endif + cond = ((sregs->inst >> 25) & 0x0f); + switch (cond & 0x7) { + case BICC_BN: + eicc = 0; + break; + case BICC_BE: + eicc = ICC_Z; + break; + case BICC_BLE: + eicc = ICC_Z | (ICC_N ^ ICC_V); + break; + case BICC_BL: + eicc = (ICC_N ^ ICC_V); + break; + case BICC_BLEU: + eicc = ICC_C | ICC_Z; + break; + case BICC_BCS: + eicc = ICC_C; + break; + case BICC_NEG: + eicc = ICC_N; + break; + case BICC_BVS: + eicc = ICC_V; + break; + } + eicc &= PSR_N; + if (sregs->inst & 0x10000000) + eicc = !eicc; + a = sregs->inst & 0x20000000; + if (eicc) { + operand1 = sregs->inst & 0x3fffff; + if (sregs->inst & 0x200000) + operand1 |= 0xffc00000; + npc = sregs->pc + (operand1 << 2); + if ((cond == BICC_BA) && (a)) + sregs->annul = 1; + } else { + if (a) + sregs->annul = 1; + } + break; + case FPBCC: +#ifdef STAT + sregs->nbranch++; +#endif + if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) { + sregs->trap = TRAP_FPDIS; + break; + } + if (ebase.simtime < sregs->ftime) { + sregs->ftime = ebase.simtime + sregs->hold; + } + cond = ((sregs->inst >> 25) & 0x0f); + fcc = (sregs->fsr >> 10) & 0x3; + switch (cond & 0x7) { + case FBN: + eicc = 0; + break; + case FBNE: + eicc = (fcc != FCC_E); + break; + case FBLG: + eicc = (fcc == FCC_L) || (fcc == FCC_G); + break; + case FBUL: + eicc = (fcc == FCC_L) || (fcc == FCC_U); + break; + case FBL: + eicc = (fcc == FCC_L); + break; + case FBUG: + eicc = (fcc == FCC_G) || (fcc == FCC_U); + break; + case FBG: + eicc = (fcc == FCC_G); + break; + case FBU: + eicc = (fcc == FCC_U); + break; + } + if (sregs->inst & 0x10000000) + eicc = !eicc; + a = sregs->inst & 0x20000000; + if (eicc) { + operand1 = sregs->inst & 0x3fffff; + if (sregs->inst & 0x200000) + operand1 |= 0xffc00000; + npc = sregs->pc + (operand1 << 2); + if ((cond == FBA) && (a)) + sregs->annul = 1; + } else { + if (a) + sregs->annul = 1; + } + break; + + default: + sregs->trap = TRAP_UNIMP; + break; + } + break; + case 1: /* CALL */ +#ifdef STAT + sregs->nbranch++; +#endif + sregs->r[(cwp + 15) & 0x7f] = sregs->pc; + npc = sregs->pc + (sregs->inst << 2); + break; + + case 2: + if ((op3 >> 1) == 0x1a) { + if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) { + sregs->trap = TRAP_FPDIS; + } else { + rs1 = (sregs->inst >> 14) & 0x1f; + rs2 = sregs->inst & 0x1f; + sregs->trap = fpexec(op3, rd, rs1, rs2, sregs); + } + } else { + + switch (op3) { + case TICC: + cond = ((sregs->inst >> 25) & 0x0f); + switch (cond & 0x7) { + case BICC_BN: + eicc = 0; + break; + case BICC_BE: + eicc = ICC_Z; + break; + case BICC_BLE: + eicc = ICC_Z | (ICC_N ^ ICC_V); + break; + case BICC_BL: + eicc = (ICC_N ^ ICC_V); + break; + case BICC_BLEU: + eicc = ICC_C | ICC_Z; + break; + case BICC_BCS: + eicc = ICC_C; + break; + case BICC_NEG: + eicc = ICC_N; + break; + case BICC_BVS: + eicc = ICC_V; + break; + } + eicc &= PSR_N; + if (sregs->inst & 0x10000000) + eicc = !eicc; + if (eicc) { + sregs->trap = (0x80 | ((rs1 + operand2) & 0x7f)); + } + break; + + case MULScc: + operand1 = + (((sregs->psr & PSR_V) ^ ((sregs->psr & PSR_N) >> 2)) + << 10) | (rs1 >> 1); + if ((sregs->y & 1) == 0) + operand2 = 0; + *rdd = operand1 + operand2; + sregs->y = (rs1 << 31) | (sregs->y >> 1); + add_cc(operand1, operand2, *rdd, &sregs->psr); + break; + case IXNOR: + *rdd = rs1 ^ ~operand2; + break; + case IXNORCC: + *rdd = rs1 ^ ~operand2; + log_cc(*rdd, sregs); + break; + case IXOR: + *rdd = rs1 ^ operand2; + break; + case IXORCC: + *rdd = rs1 ^ operand2; + log_cc(*rdd, sregs); + break; + case IOR: + *rdd = rs1 | operand2; + break; + case IORCC: + *rdd = rs1 | operand2; + log_cc(*rdd, sregs); + break; + case IORN: + *rdd = rs1 | ~operand2; + break; + case IORNCC: + *rdd = rs1 | ~operand2; + log_cc(*rdd, sregs); + break; + case IANDNCC: + *rdd = rs1 & ~operand2; + log_cc(*rdd, sregs); + break; + case IANDN: + *rdd = rs1 & ~operand2; + break; + case IAND: + *rdd = rs1 & operand2; + break; + case IANDCC: + *rdd = rs1 & operand2; + log_cc(*rdd, sregs); + break; + case SUB: + *rdd = rs1 - operand2; + break; + case SUBCC: + *rdd = rs1 - operand2; + sub_cc(rs1, operand2, *rdd, sregs); + break; + case SUBX: + *rdd = rs1 - operand2 - ((sregs->psr >> 20) & 1); + break; + case SUBXCC: + *rdd = rs1 - operand2 - ((sregs->psr >> 20) & 1); + sub_cc(rs1, operand2, *rdd, sregs); + break; + case ADD: + *rdd = rs1 + operand2; + break; + case ADDCC: + *rdd = rs1 + operand2; + add_cc(rs1, operand2, *rdd, &sregs->psr); + break; + case ADDX: + *rdd = rs1 + operand2 + ((sregs->psr >> 20) & 1); + break; + case ADDXCC: + *rdd = rs1 + operand2 + ((sregs->psr >> 20) & 1); + add_cc(rs1, operand2, *rdd, &sregs->psr); + break; + case TADDCC: + *rdd = rs1 + operand2; + add_cc(rs1, operand2, *rdd, &sregs->psr); + if ((rs1 | operand2) & 0x3) + sregs->psr |= PSR_V; + break; + case TADDCCTV: + *rdd = rs1 + operand2; + result = 0; + add_cc(rs1, operand2, *rdd, &result); + if ((rs1 | operand2) & 0x3) + result |= PSR_V; + if (result & PSR_V) { + sregs->trap = TRAP_TAG; + } else { + sregs->psr = (sregs->psr & PSR_CC) | result; + } + break; + case SLL: + *rdd = rs1 << (operand2 & 0x1f); + break; + case SRL: + *rdd = rs1 >> (operand2 & 0x1f); + break; + case SRA: + *rdd = ((int) rs1) >> (operand2 & 0x1f); + break; + case SAVE: + new_cwp = ((sregs->psr & PSR_CWP) - 1) & PSR_CWP; + if (sregs->wim & (1 << new_cwp)) { + sregs->trap = TRAP_WOFL; + break; + } + if (rd > 7) + rdd = &(sregs->r[((new_cwp << 4) + rd) & 0x7f]); + *rdd = rs1 + operand2; + sregs->psr = (sregs->psr & ~PSR_CWP) | new_cwp; + break; + case RESTORE: + +#ifdef IUREV0 + if ((iurev0) && ((sregs->jmpltime + 1) == sregs->ninst)) { + if (!(sregs->rett_err)) { + sregs->rett_err = 1; + if (sis_verbose) + printf("IU rev.0 bug mode entered\n"); + } + } +#endif + + new_cwp = ((sregs->psr & PSR_CWP) + 1) & PSR_CWP; + if (sregs->wim & (1 << new_cwp)) { + sregs->trap = TRAP_WUFL; + break; + } + if (rd > 7) + rdd = &(sregs->r[((new_cwp << 4) + rd) & 0x7f]); + *rdd = rs1 + operand2; + sregs->psr = (sregs->psr & ~PSR_CWP) | new_cwp; + break; + case RDPSR: + if (!(sregs->psr & PSR_S)) { + sregs->trap = TRAP_PRIVI; + break; + } + *rdd = sregs->psr; +#ifdef IUREV0 + + if (iurev0 & sregs->rett_err) { + operand2 = sregs->psr; + *rdd |= PSR_ET; + *rdd &= ~(PSR_S); + *rdd |= ((*rdd & PSR_PS) << 1); + if (sis_verbose) { + if (operand2 != *rdd) + printf("rdpsr failed: %08X -> %08X\n", operand2, *rdd); + } + } +#endif + break; + case RDY: + if (!(sregs->psr & PSR_S)) { + sregs->trap = TRAP_PRIVI; + break; + } + *rdd = sregs->y; + break; + case RDWIM: + if (!(sregs->psr & PSR_S)) { + sregs->trap = TRAP_PRIVI; + break; + } + *rdd = sregs->wim; + break; + case RDTBR: + if (!(sregs->psr & PSR_S)) { + sregs->trap = TRAP_PRIVI; + break; + } + *rdd = sregs->tbr; + break; + case WRPSR: + if ((sregs->psr & 0x1f) > 7) { + sregs->trap = TRAP_UNIMP; + break; + } + if (!(sregs->psr & PSR_S)) { + sregs->trap = TRAP_PRIVI; + break; + } + sregs->psr = (rs1 ^ operand2) & 0x00f03fff; + break; + case WRWIM: + if (!(sregs->psr & PSR_S)) { + sregs->trap = TRAP_PRIVI; + break; + } + sregs->wim = (rs1 ^ operand2) & 0x0ff; + break; + case WRTBR: + if (!(sregs->psr & PSR_S)) { + sregs->trap = TRAP_PRIVI; + break; + } + sregs->tbr = (sregs->tbr & 0x00000ff0) | + ((rs1 ^ operand2) & 0xfffff000); + break; + case WRY: + sregs->y = (rs1 ^ operand2); + break; + case JMPL: + +#ifdef IUREV0 + if (iurev0) + sregs->jmpltime = sregs->ninst; +#endif +#ifdef STAT + sregs->nbranch++; +#endif + sregs->icnt = T_JMPL; /* JMPL takes two cycles */ + if (rs1 & 0x3) { + sregs->trap = TRAP_UNALI; + break; + } + *rdd = sregs->pc; + npc = rs1 + operand2; + break; + case RETT: +#ifdef IUREV0 + if (iurev0 && sregs->rett_err) { + sregs->rett_err = 0; + if (sis_verbose) + printf("IU rev.0 bug mode reset\n"); + } +#endif + + address = rs1 + operand2; + new_cwp = ((sregs->psr & PSR_CWP) + 1) & PSR_CWP; + sregs->icnt = T_RETT; /* RETT takes two cycles */ + if (sregs->psr & PSR_ET) { + sregs->trap = TRAP_UNIMP; + break; + } + if (!(sregs->psr & PSR_S)) { + sregs->trap = TRAP_PRIVI; + break; + } + if (sregs->wim & (1 << new_cwp)) { + sregs->trap = TRAP_WUFL; + break; + } + if (address & 0x3) { + sregs->trap = TRAP_UNALI; + break; + } + sregs->psr = (sregs->psr & ~PSR_CWP) | new_cwp | PSR_ET; + sregs->psr = + (sregs->psr & ~PSR_S) | ((sregs->psr & PSR_PS) << 1); + npc = address; + break; + + default: + sregs->trap = TRAP_UNIMP; + break; + } + } + break; + case 3: /* Load/store instructions */ + + address = rs1 + operand2; + + /* Check for load/store to alternate address space */ + + if ((op3 >> 4) == 1) { + if (!(sregs->psr & PSR_S)) { + sregs->trap = TRAP_PRIVI; + break; + } else if (sregs->inst & INST_I) { + sregs->trap = TRAP_UNIMP; + break; + } else + asi = (sregs->inst >> 5) & 0x0ff; + } else { + if (sregs->psr & PSR_S) + asi = 11; + else + asi = 10; +#ifdef IUREV0 + if (iurev0 && sregs->rett_err) { + asi &= ~0x1; + asi |= ((sregs->psr & PSR_PS) >> 6); + } +#endif + } + + if (op3 & 4) { + sregs->icnt = T_ST; /* Set store instruction count */ +#ifdef STAT + sregs->nstore++; +#endif + } else { + sregs->icnt = T_LD; /* Set load instruction count */ +#ifdef STAT + sregs->nload++; +#endif + } + + /* Decode load/store instructions */ + + switch (op3) { + case LDDA: + case LDD: + 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 = memory_read(asi, address, &data, &ws); + sregs->hold += ws; + sregs->icnt = T_LDD; + if (mexc) { + sregs->trap = TRAP_DEXC; + } else { + rdd[0] = data; + address += 4; + mexc = memory_read(asi, address, &data, &ws); + sregs->hold += ws; +#ifdef STAT + sregs->nload++; /* Double load counts twice */ +#endif + if (mexc) { + sregs->trap = TRAP_DEXC; + } else { + rdd[1] = data; + } + } + break; + + case LDA: + case LD: + if (address & 0x3) { + sregs->trap = TRAP_UNALI; + break; + } + mexc = memory_read(asi, address, &data, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + } else { + *rdd = data; + } + break; + case LDSTUB: + case LDSTUBA: + mexc = memory_read(asi, address, &data, &ws); + sregs->hold += ws; + sregs->icnt = T_LDST; + if (mexc) { + sregs->trap = TRAP_DEXC; + break; + } + data = (data >> ((3 - (address & 0x3)) << 3)) & 0x0ff; + *rdd = data; + data = 0x0ff; + mexc = memory_write(asi, address, &data, 0, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + } +#ifdef STAT + sregs->nload++; +#endif + break; + case LDSBA: + case LDUBA: + case LDSB: + case LDUB: + mexc = memory_read(asi, address, &data, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + break; + } + data = (data >> ((3 - (address & 0x3)) << 3)) & 0x0ff; + if ((op3 == LDSB) && (data >> 7)) + data |= 0xffffff00; + *rdd = data; + break; + case LDSHA: + case LDUHA: + case LDSH: + case LDUH: + if (address & 0x1) { + sregs->trap = TRAP_UNALI; + break; + } + mexc = memory_read(asi, address, &data, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + break; + } + if (!(address & 0x2)) + data >>= 16; + data &= 0x0ffff; + if ((op3 == LDSH) && (data >> 15)) + data |= 0xffff0000; + *rdd = data; + break; + case LDF: + if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) { + sregs->trap = TRAP_FPDIS; + break; + } + if (address & 0x3) { + sregs->trap = TRAP_UNALI; + break; + } + if (ebase.simtime < sregs->ftime) { + if ((sregs->frd == rd) || (sregs->frs1 == rd) || + (sregs->frs2 == rd)) + sregs->fhold += (sregs->ftime - ebase.simtime); + } + mexc = memory_read(asi, address, &data, &ws); + sregs->hold += ws; + sregs->flrd = rd; + sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD + + sregs->hold + sregs->fhold; + if (mexc) { + sregs->trap = TRAP_DEXC; + } else { + sregs->fs[rd] = *((float32 *) & data); + } + break; + case LDDF: + if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) { + sregs->trap = TRAP_FPDIS; + break; + } + if (address & 0x7) { + sregs->trap = TRAP_UNALI; + break; + } + if (ebase.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); + } + mexc = memory_read(asi, address, &data, &ws); + sregs->hold += ws; + sregs->icnt = T_LDD; + if (mexc) { + sregs->trap = TRAP_DEXC; + } else { + rd &= 0x1E; + sregs->flrd = rd; + sregs->fs[rd] = *((float32 *) & data); + mexc = memory_read(asi, address + 4, &data, &ws); + sregs->hold += ws; +#ifdef STAT + sregs->nload++; /* Double load counts twice */ +#endif + if (mexc) { + sregs->trap = TRAP_DEXC; + } else { + sregs->fs[rd + 1] = *((float32 *) & data); + sregs->ltime = ebase.simtime + sregs->icnt + FLSTHOLD + + sregs->hold + sregs->fhold; + } + } + break; + case LDFSR: + if (ebase.simtime < sregs->ftime) { + sregs->fhold += (sregs->ftime - ebase.simtime); + } + if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) { + sregs->trap = TRAP_FPDIS; + break; + } + if (address & 0x3) { + sregs->trap = TRAP_UNALI; + break; + } + mexc = memory_read(asi, address, &data, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + } else { + sregs->fsr = + (sregs->fsr & 0x7FF000) | (data & ~0x7FF000); + set_fsr(sregs->fsr); + } + break; + case STFSR: + if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) { + sregs->trap = TRAP_FPDIS; + break; + } + if (address & 0x3) { + sregs->trap = TRAP_UNALI; + break; + } + if (ebase.simtime < sregs->ftime) { + sregs->fhold += (sregs->ftime - ebase.simtime); + } + mexc = memory_write(asi, address, &sregs->fsr, 2, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + } + break; + + case ST: + case STA: + if (address & 0x3) { + sregs->trap = TRAP_UNALI; + break; + } + mexc = memory_write(asi, address, rdd, 2, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + } + break; + case STB: + case STBA: + mexc = memory_write(asi, address, rdd, 0, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + } + break; + case STD: + case STDA: + 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 = memory_write(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 STDFQ: + if ((sregs->psr & 0x1f) > 7) { + sregs->trap = TRAP_UNIMP; + break; + } + if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) { + sregs->trap = TRAP_FPDIS; + break; + } + if (address & 0x7) { + sregs->trap = TRAP_UNALI; + break; + } + if (!(sregs->fsr & FSR_QNE)) { + sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_SEQ_ERR; + break; + } + rdd = &(sregs->fpq[0]); + mexc = memory_write(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; + } else { + sregs->fsr &= ~FSR_QNE; + sregs->fpstate = FP_EXE_MODE; + } + break; + case STHA: + case STH: + if (address & 0x1) { + sregs->trap = TRAP_UNALI; + break; + } + mexc = memory_write(asi, address, rdd, 1, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + } + break; + case STF: + if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) { + sregs->trap = TRAP_FPDIS; + break; + } + if (address & 0x3) { + sregs->trap = TRAP_UNALI; + break; + } + if (ebase.simtime < sregs->ftime) { + if (sregs->frd == rd) + sregs->fhold += (sregs->ftime - ebase.simtime); + } + mexc = memory_write(asi, address, &sregs->fsi[rd], 2, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + } + break; + case STDF: + if (!((sregs->psr & PSR_EF) && chk_fp(sregs))) { + sregs->trap = TRAP_FPDIS; + break; + } + if (address & 0x7) { + sregs->trap = TRAP_UNALI; + break; + } + rd &= 0x1E; + if (ebase.simtime < sregs->ftime) { + if ((sregs->frd == rd) || (sregs->frd + 1 == rd)) + sregs->fhold += (sregs->ftime - ebase.simtime); + } + mexc = memory_write(asi, address, &sregs->fsi[rd], 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; + case SWAP: + case SWAPA: + if (address & 0x3) { + sregs->trap = TRAP_UNALI; + break; + } + mexc = memory_read(asi, address, &data, &ws); + sregs->hold += ws; + if (mexc) { + sregs->trap = TRAP_DEXC; + break; + } + mexc = memory_write(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; + + + default: + sregs->trap = TRAP_UNIMP; + break; + } + +#ifdef LOAD_DEL + + if (!(op3 & 4)) { + sregs->ildtime = ebase.simtime + sregs->hold + sregs->icnt; + sregs->ildreg = rd; + if ((op3 | 0x10) == 0x13) + sregs->ildreg |= 1; /* Double load, odd register loaded + * last */ + } +#endif + break; + + default: + sregs->trap = TRAP_UNIMP; + break; + } + sregs->g[0] = 0; + if (!sregs->trap) { + sregs->pc = pc; + sregs->npc = npc; + } + return (0); +} + +#define T_FABSs 2 +#define T_FADDs 4 +#define T_FADDd 4 +#define T_FCMPs 4 +#define T_FCMPd 4 +#define T_FDIVs 20 +#define T_FDIVd 35 +#define T_FMOVs 2 +#define T_FMULs 5 +#define T_FMULd 9 +#define T_FNEGs 2 +#define T_FSQRTs 37 +#define T_FSQRTd 65 +#define T_FSUBs 4 +#define T_FSUBd 4 +#define T_FdTOi 7 +#define T_FdTOs 3 +#define T_FiTOs 6 +#define T_FiTOd 6 +#define T_FsTOi 6 +#define T_FsTOd 2 + +#define FABSs 0x09 +#define FADDs 0x41 +#define FADDd 0x42 +#define FCMPs 0x51 +#define FCMPd 0x52 +#define FCMPEs 0x55 +#define FCMPEd 0x56 +#define FDIVs 0x4D +#define FDIVd 0x4E +#define FMOVs 0x01 +#define FMULs 0x49 +#define FMULd 0x4A +#define FNEGs 0x05 +#define FSQRTs 0x29 +#define FSQRTd 0x2A +#define FSUBs 0x45 +#define FSUBd 0x46 +#define FdTOi 0xD2 +#define FdTOs 0xC6 +#define FiTOs 0xC4 +#define FiTOd 0xC8 +#define FsTOi 0xD1 +#define FsTOd 0xC9 + + +int +fpexec(op3, rd, rs1, rs2, sregs) + uint32 op3, rd, rs1, rs2; + struct pstate *sregs; +{ + uint32 opf, tem, accex; + float32 ftmps; + float64 ftmpd; + int32 fcc; + char *res; + uint32 ldadj; + + if (sregs->fpstate == FP_EXC_MODE) { + sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_SEQ_ERR; + sregs->fpstate == FP_EXC_PE; + return (0); + } + if (sregs->fpstate == FP_EXC_PE) { + sregs->fpstate = FP_EXC_MODE; + return (TRAP_FPEXC); + } + opf = (sregs->inst >> 5) & 0x1ff; + + /* + * Check if we already have an FPop in the pipe. If so, halt until it is + * finished by incrementing fhold with the remaining execution time + */ + + if (ebase.simtime < sregs->ftime) { + sregs->fhold = (sregs->ftime - ebase.simtime); + } else { + sregs->fhold = 0; + + /* Check load dependencies. */ + + if (ebase.simtime < sregs->ltime) { + + /* Don't check rs1 if single operand instructions */ + + if (((opf >> 6) == 0) || ((opf >> 6) == 3)) + rs1 = 32; + + /* Adjust for double floats */ + + ldadj = opf & 1; + if (!(((sregs->flrd - rs1) >> ldadj) && ((sregs->flrd - rs2) >> ldadj))) + sregs->fhold++; + } + } + + sregs->finst++; + + sregs->frs1 = rs1; /* Store src and dst for dependecy check */ + sregs->frs2 = rs2; + sregs->frd = rd; + + sregs->ftime = ebase.simtime + sregs->hold + sregs->fhold; + + /* SPARC is big-endian - swap double floats if host is little-endian */ + /* This is ugly - I know ... */ +#ifdef HOST_LITTLE_ENDIAN_FLOAT + rs1 &= 0x1f; + switch (opf) { + case FADDd: + case FDIVd: + case FMULd: + case FSQRTd: + case FSUBd: + case FCMPd: + case FCMPEd: + case FdTOi: + case FdTOs: + sregs->fdp[rs1 | 1] = sregs->fs[rs1 & ~1]; + sregs->fdp[rs1 & ~1] = sregs->fs[rs1 | 1]; + sregs->fdp[rs2 | 1] = sregs->fs[rs2 & ~1]; + sregs->fdp[rs2 & ~1] = sregs->fs[rs2 | 1]; + default: + } +#endif + + clear_accex(); + + switch (opf) { + case FABSs: + sregs->fs[rd] = fabs(sregs->fs[rs2]); + sregs->ftime += T_FABSs; + sregs->frs1 = 32; /* rs1 ignored */ + break; + case FADDs: + sregs->fs[rd] = sregs->fs[rs1] + sregs->fs[rs2]; + sregs->ftime += T_FADDs; + break; + case FADDd: + sregs->fd[rd >> 1] = sregs->fd[rs1 >> 1] + sregs->fd[rs2 >> 1]; + sregs->ftime += T_FADDd; + break; + case FCMPs: + case FCMPEs: + if (sregs->fs[rs1] == sregs->fs[rs2]) + fcc = 3; + else if (sregs->fs[rs1] < sregs->fs[rs2]) + fcc = 2; + else if (sregs->fs[rs1] > sregs->fs[rs2]) + fcc = 1; + else + fcc = 0; + sregs->fsr |= 0x0C00; + sregs->fsr &= ~(fcc << 10); + sregs->ftime += T_FCMPs; + sregs->frd = 32; /* rd ignored */ + if ((fcc == 0) && (opf == FCMPEs)) { + sregs->fpstate == FP_EXC_PE; + sregs->fsr = (sregs->fsr & ~0x1C000) | (1 << 14); + } + break; + case FCMPd: + case FCMPEd: + if (sregs->fd[rs1 >> 1] == sregs->fd[rs2 >> 1]) + fcc = 3; + else if (sregs->fd[rs1 >> 1] < sregs->fd[rs2 >> 1]) + fcc = 2; + else if (sregs->fd[rs1 >> 1] > sregs->fd[rs2 >> 1]) + fcc = 1; + else + fcc = 0; + sregs->fsr |= 0x0C00; + sregs->fsr &= ~(fcc << 10); + sregs->ftime += T_FCMPd; + sregs->frd = 32; /* rd ignored */ + if ((fcc == 0) && (opf == FCMPEd)) { + sregs->fpstate == FP_EXC_PE; + sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE; + } + break; + case FDIVs: + sregs->fs[rd] = sregs->fs[rs1] / sregs->fs[rs2]; + sregs->ftime += T_FDIVs; + break; + case FDIVd: + sregs->fd[rd >> 1] = sregs->fd[rs1 >> 1] / sregs->fd[rs2 >> 1]; + sregs->ftime += T_FDIVd; + break; + case FMOVs: + sregs->fs[rd] = sregs->fs[rs2]; + sregs->ftime += T_FMOVs; + sregs->frs1 = 32; /* rs1 ignored */ + break; + case FMULs: + sregs->fs[rd] = sregs->fs[rs1] * sregs->fs[rs2]; + sregs->ftime += T_FMULs; + break; + case FMULd: + sregs->fd[rd >> 1] = sregs->fd[rs1 >> 1] * sregs->fd[rs2 >> 1]; + sregs->ftime += T_FMULd; + break; + case FNEGs: + sregs->fs[rd] = -sregs->fs[rs2]; + sregs->ftime += T_FNEGs; + sregs->frs1 = 32; /* rs1 ignored */ + break; + case FSQRTs: + if (sregs->fs[rs2] < 0.0) { + sregs->fpstate == FP_EXC_PE; + sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE; + sregs->fsr = (sregs->fsr & 0x1f) | 0x10; + break; + } + sregs->fs[rd] = sqrt(sregs->fs[rs2]); + sregs->ftime += T_FSQRTs; + sregs->frs1 = 32; /* rs1 ignored */ + break; + case FSQRTd: + if (sregs->fd[rs2 >> 1] < 0.0) { + sregs->fpstate == FP_EXC_PE; + sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE; + sregs->fsr = (sregs->fsr & 0x1f) | 0x10; + break; + } + sregs->fd[rd >> 1] = sqrt(sregs->fd[rs2 >> 1]); + sregs->ftime += T_FSQRTd; + sregs->frs1 = 32; /* rs1 ignored */ + break; + case FSUBs: + sregs->fs[rd] = sregs->fs[rs1] - sregs->fs[rs2]; + sregs->ftime += T_FSUBs; + break; + case FSUBd: + sregs->fd[rd >> 1] = sregs->fd[rs1 >> 1] - sregs->fd[rs2 >> 1]; + sregs->ftime += T_FSUBd; + break; + case FdTOi: + sregs->fsi[rd] = (int) sregs->fd[rs2 >> 1]; + sregs->ftime += T_FdTOi; + sregs->frs1 = 32; /* rs1 ignored */ + break; + case FdTOs: + sregs->fs[rd] = (float32) sregs->fd[rs2 >> 1]; + sregs->ftime += T_FdTOs; + sregs->frs1 = 32; /* rs1 ignored */ + break; + case FiTOs: + sregs->fs[rd] = (float32) sregs->fsi[rs2]; + sregs->ftime += T_FiTOs; + sregs->frs1 = 32; /* rs1 ignored */ + break; + case FiTOd: + sregs->fd[rd >> 1] = (float64) sregs->fsi[rs2]; + sregs->ftime += T_FiTOd; + sregs->frs1 = 32; /* rs1 ignored */ + break; + case FsTOi: + sregs->fsi[rd] = (int) sregs->fs[rs2]; + sregs->ftime += T_FsTOi; + sregs->frs1 = 32; /* rs1 ignored */ + break; + case FsTOd: + sregs->fd[rd >> 1] = sregs->fs[rs2]; + sregs->ftime += T_FsTOd; + sregs->frs1 = 32; /* rs1 ignored */ + break; + + default: + sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_UNIMP; + sregs->fpstate == FP_EXC_PE; + } + + accex = get_accex(); + +#ifdef HOST_LITTLE_ENDIAN_FLOAT + switch (opf) { + case FADDd: + case FDIVd: + case FMULd: + case FSQRTd: + case FSUBd: + case FiTOd: + case FsTOd: + sregs->fs[rd & ~1] = sregs->fdp[rd | 1]; + sregs->fs[rd | 1] = sregs->fdp[rd & ~1]; + default: + } +#endif + if (sregs->fpstate == FP_EXC_PE) { + sregs->fpq[0] = sregs->pc; + sregs->fpq[1] = sregs->inst; + sregs->fsr |= FSR_QNE; + } else { + tem = (sregs->fsr >> 23) & 0x1f; + if (tem & accex) { + sregs->fpstate = FP_EXC_PE; + sregs->fsr = (sregs->fsr & ~FSR_TT) | FP_IEEE; + sregs->fsr = ((sregs->fsr & ~0x1f) | accex); + } else { + sregs->fsr = ((((sregs->fsr >> 5) | accex) << 5) | accex); + } + if (sregs->fpstate == FP_EXC_PE) { + sregs->fpq[0] = sregs->pc; + sregs->fpq[1] = sregs->inst; + sregs->fsr |= FSR_QNE; + } + } + clear_accex(); + + return (0); + + +} + +int +execute_trap(sregs) + struct pstate *sregs; +{ + int32 cwp; + + if (sregs->trap == 256) { + sregs->pc = 0; + sregs->npc = 4; + sregs->trap = 0; + } else { + + if ((sregs->psr & PSR_ET) == 0) + return (ERROR); + + 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; + sregs->r[(cwp + 18) & 0x7f] = sregs->npc; + sregs->psr |= PSR_S; + sregs->pc = sregs->tbr; + sregs->npc = sregs->tbr + 4; + + /* Increase simulator time */ + sregs->icnt = TRAP_C; + + } + + + return (0); + +} + +extern struct irqcell irqarr[16]; + +void +check_interrupts(sregs) + struct pstate *sregs; +{ + if ((ext_irl) && (sregs->psr & PSR_ET) && + ((ext_irl == 15) || (ext_irl > ((sregs->psr & PSR_PIL) >> 8)))) { + if (sregs->trap == 0) { + sregs->trap = 16 + ext_irl; + irqarr[ext_irl & 0x0f].callback(irqarr[ext_irl & 0x0f].arg); + clear_int(ext_irl); + } + } +} + +init_regs(sregs) + struct pstate *sregs; +{ + int32 i; + + sregs->pc = 0; + sregs->npc = 4; + sregs->trap = 0; + sregs->psr &= 0x00f03fdf; + sregs->psr |= 0x080; /* 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; + irqpend = 0; + sregs->g[0] = 0; +#ifdef HOST_LITTLE_ENDIAN_FLOAT + sregs->fdp = (float32 *) sregs->fd; + sregs->fsi = (int32 *) sregs->fs; +#else + sregs->fs = (float32 *) sregs->fd; + sregs->fsi = (int32 *) sregs->fd; +#endif + sregs->fsr = 0; + sregs->fpu_pres = !nfp; + set_fsr(sregs->fsr); + sregs->bphit = 0; + sregs->ildreg = 0; + sregs->ildtime = 0; + + sregs->rett_err = 0; + sregs->jmpltime = 0; +} + +chk_fp(sregs) + struct pstate *sregs; +{ + return (sregs->fpu_pres); +} diff --git a/sim/erc32/float.c b/sim/erc32/float.c new file mode 100644 index 00000000000..30ffffa3b08 --- /dev/null +++ b/sim/erc32/float.c @@ -0,0 +1,169 @@ +/* + * This file is part of SIS. + * + * SIS, SPARC instruction simulator. 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 2 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, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. + * + * + * This file implements the interface between the host and the simulated + * FPU. IEEE trap handling is done as follows: + * 1. In the host, all IEEE traps are masked + * 2. After each simulated FPU instruction, check if any exception occured + * by reading the exception bits from the host FPU status register + * (get_accex()). + * 3. Propagate any exceptions to the simulated FSR. + * 4. Clear host exception bits + * + * + * This can also be done using ieee_flags() library routine on sun. + */ + +#include "sis.h" + +/* This host dependent routine should return the accrued exceptions */ +int +get_accex() +{ +#ifdef sparc + return ((_get_fsr_raw() >> 5) & 0x1F); +#elif i386 + uint32 accx; + + accx = _get_sw() & 0x3f; + accx = ((accx & 1) << 4) | ((accx & 2) >> 1) | ((accx & 4) >> 1) | + (accx & 8) | ((accx & 16) >> 2) | ((accx & 32) >> 5); + return(accx); +#else + return(0); +#warning no fpu trap support for this target +#endif + +} + +/* How to clear the accrued exceptions */ +int +clear_accex() +{ +#ifdef sparc + set_fsr((_get_fsr_raw() & ~0x3e0)); +#elif i386 + asm(" +.text + fnclex + + "); +#else +#warning no fpu trap support for this target +#endif +} + +/* How to map SPARC FSR onto the host */ +int +set_fsr(fsr) +uint32 fsr; +{ +#ifdef sparc + _set_fsr_raw(fsr & ~0x0f800000); +#elif i386 + uint32 rawfsr; + + fsr >>= 30; + switch (fsr) { + case 0: + case 2: break; + case 1: fsr = 3; + case 3: fsr = 1; + } + rawfsr = _get_cw(); + rawfsr |= (fsr << 10) | 0x3ff; + __setfpucw(rawfsr); +#else +#warning no fpu trap support for this target +#endif +} + + +/* Host dependent support functions */ + +#ifdef sparc + + asm(" + +.text + .align 4 + .global __set_fsr_raw,_set_fsr_raw +__set_fsr_raw: +_set_fsr_raw: + save %sp,-104,%sp + st %i0,[%fp+68] + ld [%fp+68], %fsr + mov 0,%i0 + ret + restore + + .align 4 + .global __get_fsr_raw + .global _get_fsr_raw +__get_fsr_raw: +_get_fsr_raw: + save %sp,-104,%sp + st %fsr,[%fp+68] + ld [%fp+68], %i0 + ret + restore + + "); + +#elif i386 + /* both these align statements were 16, not 8 */ + + asm(" + +.text + .align 8 +.globl _get_sw,__get_sw +__get_sw: +_get_sw: + pushl %ebp + movl %esp,%ebp + movl $0,%eax + fnstsw %ax + movl %ebp,%esp + popl %ebp + ret + + .align 8 +.globl _get_cw,__get_cw +__get_cw: +_get_cw: + pushl %ebp + movl %esp,%ebp + subw $2,%esp + fnstcw -2(%ebp) + movw -2(%ebp),%eax + movl %ebp,%esp + popl %ebp + ret + + + "); + + +#else +#warning no fpu trap support for this target +#endif + diff --git a/sim/erc32/func.c b/sim/erc32/func.c new file mode 100644 index 00000000000..2cd9bf2feb0 --- /dev/null +++ b/sim/erc32/func.c @@ -0,0 +1,968 @@ +/* + * func.c, misc simulator functions. This file is part of SIS. + * + * SIS, SPARC instruction simulator V1.8 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 2 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, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "sis.h" +#include "end.h" +#include + + +#define VAL(x) strtol(x,(char *)NULL,0) + +extern char *readline(char *prompt); /* GNU readline function */ + +struct disassemble_info dinfo; +struct pstate sregs; +extern struct estate ebase; +int ctrl_c = 0; +int sis_verbose = 0; +char *sis_version = "2.1"; +int nfp = 0; +char uart_dev1[128] = "/dev/ptypc"; +char uart_dev2[128] = "/dev/ptypd"; + +#ifdef IUREV0 +int iurev0 = 0; +#endif +#ifdef MECREV0 +int mecrev0 = 0; +#endif + +int +batch(sregs, fname) + struct pstate *sregs; + char *fname; +{ + FILE *fp; + char lbuf[1024]; + + if ((fp = fopen(fname, "r")) == NULL) { + fprintf(stderr, "couldn't open batch file %s\n", fname); + return (0); + } + while (!feof(fp)) { + lbuf[0] = 0; + fgets(lbuf, 1023, fp); + if ((strlen(lbuf) > 0) && (lbuf[strlen(lbuf) - 1] == '\n')) + lbuf[strlen(lbuf) - 1] = 0; + printf("sis> %s\n", lbuf); + exec_cmd(sregs, lbuf); + } + fclose(fp); + return (1); +} + +set_regi(sregs, reg, rval) + struct pstate *sregs; + int32 reg; + uint32 rval; +{ + uint32 cwp; + int32 err = 0; + + cwp = ((sregs->psr & 0x7) << 4); + if ((reg > 0) && (reg < 8)) { + sregs->g[reg] = rval; + } else if ((reg >= 8) && (reg < 32)) { + sregs->r[(cwp + reg) & 0x7f] = rval; + } else if ((reg >= 32) && (reg < 64)) { + sregs->fsi[reg - 32] = rval; + } else { + switch (reg) { + case 64: + sregs->y = rval; + break; + case 65: + sregs->psr = rval; + break; + case 66: + sregs->wim = rval; + break; + case 67: + sregs->tbr = rval; + break; + case 68: + sregs->pc = rval; + break; + case 69: + sregs->npc = rval; + break; + case 70: + sregs->fsr = rval; + set_fsr(rval); + break; + defualt:break; + } + } +} + +void +get_regi(struct pstate * sregs, int32 reg, char *buf) +{ + uint32 cwp; + uint32 rval = 0; + + cwp = ((sregs->psr & 0x7) << 4); + if ((reg >= 0) && (reg < 8)) { + rval = sregs->g[reg]; + } else if ((reg >= 8) && (reg < 32)) { + rval = sregs->r[(cwp + reg) & 0x7f]; + } else if ((reg >= 32) && (reg < 64)) { + rval = sregs->fsi[reg - 32]; + } else { + switch (reg) { + case 64: + rval = sregs->y; + break; + case 65: + rval = sregs->psr; + break; + case 66: + rval = sregs->wim; + break; + case 67: + rval = sregs->tbr; + break; + case 68: + rval = sregs->pc; + break; + case 69: + rval = sregs->npc; + break; + case 70: + rval = sregs->fsr; + break; + defualt:break; + } + } + buf[0] = (rval >> 24) & 0x0ff; + buf[1] = (rval >> 16) & 0x0ff; + buf[2] = (rval >> 8) & 0x0ff; + buf[3] = rval & 0x0ff; +} + + +set_rega(sregs, reg, rval) + struct pstate *sregs; + char *reg; + uint32 rval; +{ + uint32 cwp; + int32 err = 0; + + cwp = ((sregs->psr & 0x7) << 4); + if (strcmp(reg, "psr") == 0) + sregs->psr = (rval = (rval & 0x00f03fff)); + else if (strcmp(reg, "tbr") == 0) + sregs->tbr = (rval = (rval & 0xfffffff0)); + else if (strcmp(reg, "wim") == 0) + sregs->wim = (rval = (rval & 0x0ff)); + else if (strcmp(reg, "y") == 0) + sregs->y = rval; + else if (strcmp(reg, "pc") == 0) + sregs->pc = rval; + else if (strcmp(reg, "npc") == 0) + sregs->npc = rval; + else if (strcmp(reg, "fsr") == 0) { + sregs->fsr = rval; + set_fsr(rval); + } else if (strcmp(reg, "g0") == 0) + err = 2; + else if (strcmp(reg, "g1") == 0) + sregs->g[1] = rval; + else if (strcmp(reg, "g2") == 0) + sregs->g[2] = rval; + else if (strcmp(reg, "g3") == 0) + sregs->g[3] = rval; + else if (strcmp(reg, "g4") == 0) + sregs->g[4] = rval; + else if (strcmp(reg, "g5") == 0) + sregs->g[5] = rval; + else if (strcmp(reg, "g6") == 0) + sregs->g[6] = rval; + else if (strcmp(reg, "g7") == 0) + sregs->g[7] = rval; + else if (strcmp(reg, "o0") == 0) + sregs->r[(cwp + 8) & 0x7f] = rval; + else if (strcmp(reg, "o1") == 0) + sregs->r[(cwp + 9) & 0x7f] = rval; + else if (strcmp(reg, "o2") == 0) + sregs->r[(cwp + 10) & 0x7f] = rval; + else if (strcmp(reg, "o3") == 0) + sregs->r[(cwp + 11) & 0x7f] = rval; + else if (strcmp(reg, "o4") == 0) + sregs->r[(cwp + 12) & 0x7f] = rval; + else if (strcmp(reg, "o5") == 0) + sregs->r[(cwp + 13) & 0x7f] = rval; + else if (strcmp(reg, "o6") == 0) + sregs->r[(cwp + 14) & 0x7f] = rval; + else if (strcmp(reg, "o7") == 0) + sregs->r[(cwp + 15) & 0x7f] = rval; + else if (strcmp(reg, "l0") == 0) + sregs->r[(cwp + 16) & 0x7f] = rval; + else if (strcmp(reg, "l1") == 0) + sregs->r[(cwp + 17) & 0x7f] = rval; + else if (strcmp(reg, "l2") == 0) + sregs->r[(cwp + 18) & 0x7f] = rval; + else if (strcmp(reg, "l3") == 0) + sregs->r[(cwp + 19) & 0x7f] = rval; + else if (strcmp(reg, "l4") == 0) + sregs->r[(cwp + 20) & 0x7f] = rval; + else if (strcmp(reg, "l5") == 0) + sregs->r[(cwp + 21) & 0x7f] = rval; + else if (strcmp(reg, "l6") == 0) + sregs->r[(cwp + 22) & 0x7f] = rval; + else if (strcmp(reg, "l7") == 0) + sregs->r[(cwp + 23) & 0x7f] = rval; + else if (strcmp(reg, "i0") == 0) + sregs->r[(cwp + 24) & 0x7f] = rval; + else if (strcmp(reg, "i1") == 0) + sregs->r[(cwp + 25) & 0x7f] = rval; + else if (strcmp(reg, "i2") == 0) + sregs->r[(cwp + 26) & 0x7f] = rval; + else if (strcmp(reg, "i3") == 0) + sregs->r[(cwp + 27) & 0x7f] = rval; + else if (strcmp(reg, "i4") == 0) + sregs->r[(cwp + 28) & 0x7f] = rval; + else if (strcmp(reg, "i5") == 0) + sregs->r[(cwp + 29) & 0x7f] = rval; + else if (strcmp(reg, "i6") == 0) + sregs->r[(cwp + 30) & 0x7f] = rval; + else if (strcmp(reg, "i7") == 0) + sregs->r[(cwp + 31) & 0x7f] = rval; + else + err = 1; + switch (err) { + case 0: + printf("%s = %d (0x%08x)\n", reg, rval, rval); + break; + case 1: + printf("no such regiser: %s\n", reg); + break; + case 2: + printf("cannot set g0\n"); + break; + default: + break; + } + +} + +disp_reg(sregs, reg) + struct pstate *sregs; + char *reg; +{ + if (strncmp(reg, "w",1) == 0) + disp_regs(sregs, VAL(®[1])); +} + +exec_cmd(sregs, cmd) + char *cmd; + struct pstate *sregs; +{ + char *cmd1, *cmd2; + int32 ws, stat; + int32 len, i, clen, j; + static daddr = 0; + char *cmdsave; + + stat = OK; + cmdsave = strdup(cmd); + if ((cmd1 = strtok(cmd, " \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]); + } + } else if (strncmp(cmd1, "+bp", clen) == 0) { + if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) { + sregs->bpts[sregs->bptnum] = VAL(cmd1) & ~0x3; + printf("added breakpoint %d at 0x%08x\n", + sregs->bptnum + 1, sregs->bpts[sregs->bptnum]); + sregs->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)) { + 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]; + } + sregs->bptnum -= 1; + } + } + } else if (strncmp(cmd1, "batch", clen) == 0) { + if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) { + printf("no file specified\n"); + } else { + batch(sregs, cmd1); + } + } else if (strncmp(cmd1, "cont", clen) == 0) { + if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) { + stat = run_sim(sregs, 1, 0, 0); + } else { + stat = run_sim(sregs, 0, VAL(cmd1), 0); + } + daddr = sregs->pc; + sim_stop(); + } else if (strncmp(cmd1, "dis", clen) == 0) { + if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) { + daddr = VAL(cmd1); + } + if ((cmd2 = strtok(NULL, " \t\n\r")) != NULL) { + len = VAL(cmd2); + } else + len = 16; + printf("\n"); + dis_mem(daddr, len, &dinfo); + printf("\n"); + daddr += len * 4; + } else if (strncmp(cmd1, "echo", clen) == 0) { + if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) { + printf("%s\n", (&cmdsave[clen+1])); + } + } else if (strncmp(cmd1, "float", clen) == 0) { + stat = disp_fpu(sregs); + } else if (strncmp(cmd1, "go", clen) == 0) { + if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) { + printf("wrong syntax: go
[inst_count]\n"); + } else { + len = VAL(cmd1); + sregs->pc = len & ~3; + sregs->npc = sregs->pc + 4; + if ((cmd2 = strtok(NULL, " \t\n\r")) != NULL) { + stat = run_sim(sregs, 0, VAL(cmd2), 0); + } else { + stat = run_sim(sregs, 1, 0, 0); + } + } + daddr = sregs->pc; + sim_stop(); + } else if (strncmp(cmd1, "help", clen) == 0) { + 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; + + } else { + j = sregs->histind; + for (i = 0; i < sregs->histlen; i++) { + if (j >= sregs->histlen) + j = 0; + printf(" %8d ", sregs->histbuf[j].time); + dis_mem(sregs->histbuf[j].addr, 1, &dinfo); + j++; + } + } + + } else if (strncmp(cmd1, "load", clen) == 0) { + if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) { + bfd_load(cmd1); + } else { + printf("load: no file specified\n"); + } + } else if (strncmp(cmd1, "mem", clen) == 0) { + if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) + daddr = VAL(cmd1); + if ((cmd2 = strtok(NULL, " \t\n\r")) != NULL) + len = VAL(cmd2); + else + len = 64; + disp_mem(daddr, len); + daddr += len; + } else if (strncmp(cmd1, "perf", clen) == 0) { + cmd1 = strtok(NULL, " \t\n\r"); + if ((cmd1 != NULL) && + (strncmp(cmd1, "reset", strlen(cmd1)) == 0)) { + reset_stat(sregs); + } else + show_stat(sregs); + } else if (strncmp(cmd1, "quit", clen) == 0) { + exit(0); + } else if (strncmp(cmd1, "reg", clen) == 0) { + cmd1 = strtok(NULL, " \t\n\r"); + cmd2 = strtok(NULL, " \t\n\r"); + if (cmd2 != NULL) + set_rega(sregs, cmd1, VAL(cmd2)); + else if (cmd1 != NULL) + disp_reg(sregs, cmd1); + else { + disp_regs(sregs,sregs->psr); + disp_ctrl(sregs); + } + } else if (strncmp(cmd1, "reset", clen) == 0) { + ebase.simtime = 0; + reset_all(); + reset_stat(sregs); + } else if (strncmp(cmd1, "run", clen) == 0) { + ebase.simtime = 0; + reset_all(); + reset_stat(sregs); + if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) { + stat = run_sim(sregs, 1, 0, 0); + } else { + stat = run_sim(sregs, 0, VAL(cmd1), 0); + } + daddr = sregs->pc; + sim_stop(); + } else if (strncmp(cmd1, "shell", clen) == 0) { + if ((cmd1 = strtok(NULL, " \t\n\r")) != NULL) { + system(&cmdsave[clen]); + } + } else if (strncmp(cmd1, "step", clen) == 0) { + stat = run_sim(sregs, 0, 1, 1); + daddr = sregs->pc; + sim_stop(); + } else if (strncmp(cmd1, "tra", clen) == 0) { + if ((cmd1 = strtok(NULL, " \t\n\r")) == NULL) { + stat = run_sim(sregs, 1, 0, 1); + } else { + stat = run_sim(sregs, 0, VAL(cmd1), 1); + } + printf("\n"); + daddr = sregs->pc; + sim_stop(); + } else + printf("syntax error\n"); + } + if (cmdsave != NULL) + free(cmdsave); + return (stat); +} + + +reset_stat(sregs) + struct pstate *sregs; +{ + sregs->tottime = 0; + sregs->pwdtime = 0; + sregs->ninst = 0; + sregs->fholdt = 0; + sregs->holdt = 0; + sregs->icntt = 0; + sregs->finst = 0; + sregs->nstore = 0; + sregs->nload = 0; + sregs->nbranch = 0; + sregs->simstart = ebase.simtime; + +} + +show_stat(sregs) + struct pstate *sregs; +{ + int32 simperf = 0; + uint32 iinst; + uint32 stime; + + stime = ebase.simtime - sregs->simstart; /* Total simulated time */ +#ifdef STAT + + iinst = sregs->ninst - sregs->finst - sregs->nload - sregs->nstore - + sregs->nbranch; +#endif + + printf("\n Cycles : %9d\n\r", ebase.simtime - sregs->simstart); + printf(" Instructions : %9d\n", sregs->ninst); + +#ifdef STAT + printf(" integer : %9.2f %%\n", 100.0 * (float) iinst / (float) sregs->ninst); + printf(" load : %9.2f %%\n", + 100.0 * (float) sregs->nload / (float) sregs->ninst); + printf(" store : %9.2f %%\n", + 100.0 * (float) sregs->nstore / (float) sregs->ninst); + printf(" branch : %9.2f %%\n", + 100.0 * (float) sregs->nbranch / (float) sregs->ninst); + printf(" float : %9.2f %%\n", + 100.0 * (float) sregs->finst / (float) sregs->ninst); + printf(" Integer CPI : %9.2f\n", + ((float) (stime - sregs->pwdtime - sregs->fholdt - sregs->finst)) + / + (float) (sregs->ninst - sregs->finst)); + printf(" Float CPI : %9.2f\n", + ((float) sregs->fholdt / (float) 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 : %5.2f ms\n", (float) (ebase.simtime - sregs->simstart) / 1000.0 / sregs->freq); + printf(" Processor utilisation : %5.2f %%\n", 100.0 * (1.0 - ((float) sregs->pwdtime / (float) stime))); + printf(" Real-time / simulator-time : %5.2f \n", + ((float) sregs->tottime) / ((float) (stime) / (sregs->freq * 1.0E6))); + printf(" Used time (sys + user) : %3d s\n\n", sregs->tottime); +} + + + +init_bpt(sregs) + struct pstate *sregs; +{ + sregs->bptnum = 0; + sregs->histlen = 0; + sregs->histind = 0; + sregs->histbuf = NULL; + +} + +void +int_handler(sig) + int32 sig; +{ + if (sig != 2) + printf("\n\n Signal handler error (%d)\n\n", sig); + ctrl_c = 1; +} + +init_signals() +{ + typedef void (*PFI) (); + static PFI int_tab[2]; + + int_tab[0] = signal(SIGTERM, int_handler); + int_tab[1] = signal(SIGINT, int_handler); +} + + +extern struct disassemble_info dinfo; + +struct estate ebase; +struct evcell evbuf[EVENT_MAX]; +struct irqcell irqarr[16]; +int32 irqpend, ext_irl = 0; + +disp_fpu(sregs) + struct pstate *sregs; +{ + + int i, j; + float t; + + printf("\n fsr: %08X\n\n", sregs->fsr); + +#ifdef HOST_LITTLE_ENDIAN_FLOAT + for (i = 0; i < 32; i++) { + sregs->fdp[i ^ 1] = sregs->fs[i]; + } +#endif + + for (i = 0; i < 32; i++) { + t = sregs->fs[i]; + printf(" f%02d %08x %14e ", i, sregs->fsi[i], sregs->fs[i]); + if (!(i & 1)) + printf("%14e\n", sregs->fd[i >> 1]); + else + printf("\n"); + } + printf("\n"); + return (OK); +} + +disp_regs(sregs,cwp) + struct pstate *sregs; + int cwp; +{ + + int i; + + cwp = ((cwp & 0x7) << 4); + printf("\n\t INS LOCALS OUTS GLOBALS\n"); + for (i = 0; i < 8; i++) { + printf(" %d: %08X %08X %08X %08X\n", i, + sregs->r[(cwp + i + 24) & 0x7f], + sregs->r[(cwp + i + 16) & 0x7f], sregs->r[(cwp + i + 8) & 0x7f], + sregs->g[i]); + } +} + +disp_ctrl(sregs) + struct pstate *sregs; +{ + + uint32 i; + + printf("\n psr: %08X wim: %08X tbr: %08X y: %08X\n", + sregs->psr, sregs->wim, sregs->tbr, sregs->y); + sis_memory_read(sregs->pc, &i, 4); + printf("\n pc: %08X = %08X ", sregs->pc, i); + print_insn_sparc(sregs->pc, &dinfo); + sis_memory_read(sregs->npc, &i, 4); + printf("\n npc: %08X = %08X ", sregs->npc, i); + print_insn_sparc(sregs->npc, &dinfo); + if (sregs->err_mode) + printf("\n IU in error mode"); + printf("\n\n"); +} + +disp_mem(addr, len) + uint32 addr; + uint32 len; +{ + + int32 i, data, ws; + int32 mem[4], j; + char *p; + + for (i = addr & ~3; i < ((addr + len) & ~3); i += 16) { + printf("\n %8X ", i); + for (j = 0; j < 4; j++) { + sis_memory_read((i + (j * 4)), &data, 4); + printf("%08x ", data); + mem[j] = data; + } + printf(" "); + p = (char *) mem; + for (j = 0; j < 16; j++) { + if (isprint(p[j])) + putchar(p[j]); + else + putchar('.'); + } + } + printf("\n\n"); +} +dis_mem(addr, len, info) + uint32 addr; + uint32 len; + struct disassemble_info *info; +{ + int32 i, data, ws; + + for (i = addr & -3; i < ((addr & -3) + (len << 2)); i += 4) { + sis_memory_read(i, &data, 4); + printf(" %08x %08x ", i, data); + print_insn_sparc(i, info); + printf("\n"); + } + return (OK); +} + +int +buffer_read_memory(addr, buffer, size, info) + bfd_vma addr; + bfd_byte *buffer; + int32 size; + struct disassemble_info *info; +{ + if (size == sis_memory_read(addr, buffer, size)) + return (0); + else + return (1); +} + +void +perror_memory(status, addr, info) + int32 status; + bfd_vma addr; + struct disassemble_info *info; +{ + + printf("Could not read address 0x%08x\n", addr); +} + +void +generic_print_address(addr, info) + bfd_vma addr; + struct disassemble_info *info; +{ + + printf("0x%x", addr); +} + +/* Add event to event queue */ + +event(cfunc, arg, delta) + void (*cfunc) (); + int32 arg; + uint32 delta; +{ + struct evcell *ev1, *evins; + + if (ebase.freeq == NULL) { + printf("Error, too many events in event queue\n"); + return (0); + } + ev1 = &ebase.eq; + delta += ebase.simtime; + while ((ev1->nxt != NULL) && (ev1->nxt->time <= delta)) { + ev1 = ev1->nxt; + } + if (ev1->nxt == NULL) { + ev1->nxt = ebase.freeq; + ebase.freeq = ebase.freeq->nxt; + ev1->nxt->nxt = NULL; + } else { + evins = ebase.freeq; + ebase.freeq = ebase.freeq->nxt; + evins->nxt = ev1->nxt; + ev1->nxt = evins; + } + ev1->nxt->time = delta; + ev1->nxt->cfunc = cfunc; + ev1->nxt->arg = arg; +} + +stop_event() +{ +} + +init_event() +{ + int32 i; + + ebase.eq.nxt = NULL; + ebase.freeq = evbuf; + for (i = 0; i < EVENT_MAX; i++) { + evbuf[i].nxt = &evbuf[i + 1]; + } + evbuf[EVENT_MAX - 1].nxt = NULL; +} + +set_int(level, callback, arg) + int32 level; + void (*callback) (); + int32 arg; +{ + irqarr[level & 0x0f].callback = callback; + irqarr[level & 0x0f].arg = arg; + irqpend |= (1 << level); + if (level > ext_irl) + ext_irl = level; + +} + +clear_int(level) + int32 level; +{ + int32 tmpirq = irqpend; + + irqpend &= ~(1 << level); + ext_irl = 0; + if (irqpend) { + tmpirq >>= 1; + while (tmpirq) { + ext_irl++; + tmpirq >>= 1; + } + } +} + +/* Advance simulator time */ + +advance_time(sregs) + struct pstate *sregs; +{ + + struct evcell *evrem; + void (*cfunc) (); + uint32 arg, endtime, ws; + + ws = sregs->icnt + sregs->hold + sregs->fhold; + +#ifdef STAT + sregs->fholdt += sregs->fhold; + sregs->holdt += sregs->hold; + sregs->icntt += sregs->icnt; +#endif + + endtime = ebase.simtime += ws; + while ((ebase.eq.nxt != NULL) && (ebase.eq.nxt->time <= (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; + evrem->nxt = ebase.freeq; + ebase.freeq = evrem; + cfunc(arg); + } + ebase.simtime = endtime; + +} + +/* Advance time until an external interrupt is seen */ + +int +wait_for_irq() +{ + struct evcell *evrem; + void (*cfunc) (); + int32 arg, 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); +} + +int +check_bpt(sregs) + struct pstate *sregs; +{ + int32 i; + + if ((sregs->bphit) || (sregs->annul)) + return (0); + for (i = 0; i < sregs->bptnum; i++) { + if (sregs->pc == sregs->bpts[i]) + return (BPT_HIT); + } + return (0); +} + +reset_all() +{ + init_event(); /* Clear event queue */ + init_regs(&sregs); + reset(); +} + +sys_reset() +{ + reset_all(); + sregs.trap = 256; /* Force fake reset trap */ +} + +#include "ansidecl.h" + +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +#include "libiberty.h" +#include "bfd.h" + +#define min(A, B) (((A) < (B)) ? (A) : (B)) +#define LOAD_ADDRESS 0 + +int +bfd_load(fname) + char *fname; +{ + int cc, c; + unsigned char buf[10]; + asection *section; + bfd *pbfd; + unsigned long entry; + + pbfd = bfd_openr(fname, 0); + + if (pbfd == NULL) { + printf("open of %s failed\n", fname); + return (0); + } + if (!bfd_check_format(pbfd, bfd_object)) { + printf("file %s doesn't seem to be an object file\n", fname); + return (0); + } + printf("loading %s:", fname); + for (section = pbfd->sections; section; section = section->next) { + if (bfd_get_section_flags(pbfd, section) & SEC_ALLOC) { + bfd_vma section_address; + unsigned long section_size; + const char *section_name; + + section_name = bfd_get_section_name(pbfd, section); + + section_address = bfd_get_section_vma(pbfd, section); + /* + * Adjust sections from a.out files, since they don't carry their + * addresses with. + */ + if (bfd_get_flavour(pbfd) == bfd_target_aout_flavour) + section_address += bfd_get_start_address (pbfd); + section_size = bfd_section_size(pbfd, section); + + printf("\nsection %s at 0x%08lx (%ld bytes)", + section_name, section_address, section_size); + + /* Text, data or lit */ + if (bfd_get_section_flags(pbfd, section) & SEC_LOAD) { + file_ptr fptr; + + fptr = 0; + + while (section_size > 0) { + char buffer[1024]; + int count; + + count = min(section_size, 1024); + + bfd_get_section_contents(pbfd, section, buffer, fptr, count); + + sis_memory_write(section_address, buffer, count); + + section_address += count; + fptr += count; + section_size -= count; + } + } else /* BSS */ + printf("(not loaded)"); + } + } + printf("\n"); + + /* + * entry = bfd_get_start_address (pbfd); + * + * printf ("[Starting %s at 0x%lx]\n", fname, entry); + */ + + return (1); +} + +void +sim_set_callbacks (ptr) +struct host_callback_struct *ptr; +{ + +} + diff --git a/sim/erc32/help.c b/sim/erc32/help.c new file mode 100644 index 00000000000..8f57d8e61cc --- /dev/null +++ b/sim/erc32/help.c @@ -0,0 +1,30 @@ +usage() +{ + + printf("usage: sis [-uart1 uart_device1] [-uart2 uart_device2]\n"); + printf("[-nfp] [-freq frequency] [-c batch_file] [files]\n"); +} + +gen_help() +{ + + printf("\n batch execute a batch file of SIS commands\n"); + printf(" +bp add a breakpoint at \n"); + printf(" -bp delete breakpoint \n"); + printf(" bp print all breakpoints\n"); + printf(" cont [icnt] continue execution for [icnt] instructions\n"); + printf(" dis [addr] [count] disassemble [count] instructions at address [addr]\n"); + printf(" echo print to the simulator window\n"); + printf(" float print the FPU registers\n"); + printf(" go [icnt] start execution at for [icnt] instructions\n"); + printf(" hist [trace_length] enable/show trace history\n"); + printf(" load load a file into simulator memory\n"); + printf(" mem [addr] [count] display memory at [addr] for [count] bytes\n"); + printf(" quit exit the simulator\n"); + printf(" perf [reset] show/reset performance statistics\n"); + printf(" reg [w<0-7>] show integer registers (or windows, eg 're w2')\n"); + printf(" run [inst_count] reset and start execution for [icnt] instruction\n"); + printf(" step single step\n"); + printf(" tra [inst_count] trace [inst_count] instructions\n"); + printf("\n type Ctrl-C to interrupt execution\n\n"); +} diff --git a/sim/erc32/interf.c b/sim/erc32/interf.c new file mode 100644 index 00000000000..e81fbf3a7a5 --- /dev/null +++ b/sim/erc32/interf.c @@ -0,0 +1,372 @@ +/* + * This file is part of SIS. + * + * SIS, SPARC instruction simulator V1.6 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 2 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, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "sis.h" +#include "bfd.h" +#include + +#ifndef fprintf +extern fprintf(); +#endif + +#define VAL(x) strtol(x,(char *)NULL,0) + +extern char **buildargv(char *input); + +extern struct disassemble_info dinfo; +extern struct pstate sregs; +extern struct estate ebase; + +extern int ctrl_c; +extern int nfp; +extern int sis_verbose; +extern char *sis_version; +extern struct estate ebase; +extern struct evcell evbuf[]; +extern struct irqcell irqarr[]; +extern int irqpend, ext_irl; +extern char uart_dev1[], uart_dev2[]; + +int sis_gdb_break = 1; + +#ifdef IUREV0 +extern int iurev0; +#endif + +#ifdef MECREV0 +extern int mecrev0; +#endif + +run_sim(sregs, go, icount, dis) + struct pstate *sregs; + int go; + unsigned int icount; + int dis; +{ + int mexc, ws; + + if (sis_verbose) + printf_filtered("resuming at %x\n", sregs->pc); + sregs->starttime = time(NULL); + while ((!sregs->err_mode & (go || (icount > 0))) && + ((sregs->bptnum == 0) || !(sregs->bphit = check_bpt(sregs)))) { + + sregs->fhold = 0; + sregs->hold = 0; + sregs->icnt = 0; + + check_interrupts(sregs); + if (sregs->trap) { + sregs->err_mode = execute_trap(sregs); + } else { + if (sregs->psr & 0x080) + sregs->asi = 8; + else + sregs->asi = 9; +#ifdef IUREV0 + if (iurev0 && sregs->rett_err) { + sregs->asi &= ~0x1; + sregs->asi |= ((sregs->psr & 0x040) >> 6); + } +#endif + + mexc = memory_read(sregs->asi, sregs->pc, &sregs->inst, &sregs->hold); + if (sregs->annul) { + sregs->annul = 0; + sregs->icnt = 1; + sregs->pc = sregs->npc; + sregs->npc = sregs->npc + 4; + } else { + if (mexc) { + sregs->trap = I_ACC_EXC; + } else { + 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(" %8d ", ebase.simtime); + dis_mem(sregs->pc, 1, &dinfo); + } + if ((sis_gdb_break) && (sregs->inst == 0x91d02001)) { + if (sis_verbose) + printf_filtered("SW BP hit at %x\n", sregs->pc); + return (BPT_HIT); + } else + dispatch_instruction(sregs); + } + icount--; + } + if (sregs->trap) { + sregs->err_mode = execute_trap(sregs); + } + } + advance_time(sregs); + if (ctrl_c) { + go = icount = 0; + } + } + sregs->tottime += time(NULL) - sregs->starttime; + if (sregs->err_mode) + error_mode(sregs->pc); + if (sregs->err_mode) + return (ERROR); + if (sregs->bphit) { + if (sis_verbose) + printf_filtered("HW BP hit at %x\n", sregs->pc); + return (BPT_HIT); + } + if (ctrl_c) { + ctrl_c = 0; + return (CTRL_C); + } + return (TIME_OUT); +} + + +void +sim_open(char *args) +{ + + int argc = 0; + char **argv; + int cont = 1; + int stat = 0; + int grdl = 0; + int freq = 15; + + printf_filtered("\n SIS - SPARC instruction simulator %s\n", sis_version); + printf_filtered(" Bug-reports to Jiri Gaisler ESA/ESTEC (jgais@wd.estec.esa.nl)\n"); + argv = buildargv(args); + if (argv != NULL) + while (argv[argc]) + argc++; + while (stat < argc) { + if (argv[stat][0] == '-') { + if (strcmp(argv[stat], "-v") == 0) { + sis_verbose = 1; + } +#ifdef IUREV0 + if (strcmp(argv[stat], "-iurev0") == 0) { + iurev0 = 1; + printf_filtered(" simulating IU rev.0 jmpl/restore bug\n"); + } +#endif +#ifdef MECREV0 + if (strcmp(argv[stat], "-mecrev0") == 0) { + mecrev0 = 1; + printf_filtered(" simulating MEC rev.0 timer and uart interrupt bug\n"); + } +#endif + if (strcmp(argv[stat], "-nfp") == 0) { + printf_filtered("no FPU\n"); + nfp = 1; + } + if (strcmp(argv[stat], "-uart1") == 0) { + if ((stat + 1) < argc) + strcpy(uart_dev1, argv[++stat]); + } + if (strcmp(argv[stat], "-uart2") == 0) { + if ((stat + 1) < argc) + strcpy(uart_dev2, argv[++stat]); + } + if (strcmp(argv[stat], "-nogdb") == 0) { + printf_filtered("disabling GDB trap handling for breakpoints\n"); + sis_gdb_break = 0; + } + if (strcmp(argv[stat], "-freq") == 0) + if ((stat + 1) < argc) { + freq = VAL(argv[++stat]); + printf_filtered(" ERC32 freq %d Mhz\n", freq); + } + } else + bfd_load(argv[stat]); + stat++; + } + freeargv(argv); + sregs.freq = freq; + + INIT_DISASSEMBLE_INFO(dinfo, stdout, fprintf); + init_signals(); + reset_all(); + ebase.simtime = 0; + init_sim(); + init_bpt(&sregs); + reset_stat(&sregs); +} + +void +sim_close(int quitting) +{ + + exit_sim(); + +}; + +int +sim_load(char *prog, int from_tty) +{ + bfd_load(*prog); + return (0); +} + +void +sim_create_inferior(int start_address, char **argv, char **env) +{ + ebase.simtime = 0; + reset_all(); + reset_stat(&sregs); + sregs.pc = start_address & ~3; + sregs.npc = sregs.pc + 4; + +} + +void +sim_store_register(regno, value) + int regno; + unsigned char *value; +{ + /* FIXME: Review the computation of regval. */ + int regval = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3]; + set_regi(&sregs, regno, regval); +} + + +void +sim_fetch_register(regno, buf) + int regno; + unsigned char *buf; +{ + get_regi(&sregs, regno, buf); +} + +int +sim_write(mem, buf, length) + int mem; + unsigned char *buf; + int length; +{ + return (sis_memory_write(mem, buf, length)); +} + +int +sim_read(int mem, unsigned char *buf, int length) +{ + return (sis_memory_read(mem, buf, length)); +} + +void +sim_info(int verbose) +{ + show_stat(&sregs); + + +} + +int simstat = OK; + +enum sim_stop { + sim_exited, sim_stopped, sim_signalled +}; + +void +sim_stop_reason(enum sim_stop * reason, int *sigrc) +{ + + switch (simstat) { + case CTRL_C: + *reason = sim_stopped; + *sigrc = SIGINT; + break; + case OK: + case TIME_OUT: + case BPT_HIT: + *reason = sim_stopped; + *sigrc = SIGTRAP; + break; + case ERROR: + *sigrc = 0; + *reason = sim_exited; + } + ctrl_c = 0; + simstat = OK; +} + + +void +sim_resume(int step, int siggnal) +{ + simstat = run_sim(&sregs, 1, 0, 0); +} + +void +sim_kill(void) +{ +}; + + + +void +sim_do_command(cmd) + char *cmd; +{ + exec_cmd(&sregs, cmd); +} + + + +int +sim_insert_breakpoint(int addr) +{ + if (sregs.bptnum < BPT_MAX) { + sregs.bpts[sregs.bptnum] = addr & ~0x3; + sregs.bptnum++; + if (sis_verbose) + printf_filtered("inserted HW BP at %x\n", addr); + return 0; + } else + return 1; +} + +int +sim_remove_breakpoint(int addr) +{ + int i = 0; + + while ((i < sregs.bptnum) && (sregs.bpts[i] != addr)) + i++; + if (addr == sregs.bpts[i]) { + for (; i < sregs.bptnum - 1; i++) + sregs.bpts[i] = sregs.bpts[i + 1]; + sregs.bptnum -= 1; + if (sis_verbose) + printf_filtered("removed HW BP at %x\n", addr); + return 0; + } + return 1; +} diff --git a/sim/erc32/run.c b/sim/erc32/run.c new file mode 100644 index 00000000000..a571c4ad535 --- /dev/null +++ b/sim/erc32/run.c @@ -0,0 +1,92 @@ +/* + * run front end support for ERC32SIM Copyright (C) 1987, 1992 Free Software + * Foundation, Inc. + * + * This file is part of ERC32SIM + * + * ERC32SIM 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 2, or (at your option) any later version. + * + * ERC32SIM 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 + * ERC32SIM; see the file COPYING. If not, write to the Free Software + * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "bfd.h" + +main(ac, av) + int ac; + char **av; +{ + bfd *abfd; + bfd_vma start_address; + asection *s; + int i; + int verbose = 0; + int trace = 0; + char *name = ""; + for (i = 1; i < ac; i++) { + if (strcmp(av[i], "-v") == 0) { + verbose = 1; + } else if (strcmp(av[i], "-t") == 0) { + trace = 1; + } else { + name = av[i]; + } + } + if (verbose) { + printf("run %s\n", name); + } + sim_open(0); + abfd = bfd_openr(name, "a.out-sunos-big"); + + if (abfd) { + + if (bfd_check_format(abfd, bfd_object)) { + for (s = abfd->sections; s; s = s->next) { + char *buffer = malloc(bfd_section_size(abfd, s)); + bfd_get_section_contents(abfd, s, buffer, 0, bfd_section_size(abfd, s)); + sim_write(s->vma, buffer, bfd_section_size(abfd, s)); + } + + start_address = bfd_get_start_address(abfd); + sim_create_inferior(start_address, NULL, NULL); + if (trace) { + int done = 0; + while (!done) { + /* + * done = sim_trace(); + */ + } + } else { + sim_resume(0, 0); + } + if (verbose) { + sim_info(0); + } + return 0; + } + } + return 1; +} + +void +printf_filtered(va_alist) +va_dcl +{ + char *msg; + va_list args; + + va_start(args); + msg = va_arg(args, char *); + vfprintf(stdout, msg, args); + va_end(args); +} diff --git a/sim/erc32/startsim b/sim/erc32/startsim new file mode 100644 index 00000000000..1b9b41cb707 --- /dev/null +++ b/sim/erc32/startsim @@ -0,0 +1,4 @@ +# +xterm -e sis $* & +xterm -e tip /dev/ttypc & + -- 2.30.2