├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.am ├── Makefile.common.in ├── NEWS ├── README ├── TODO ├── TODO.variables ├── autogen.sh ├── config ├── Makefile.common.alpha ├── Makefile.common.alpha.orig ├── Makefile.common.i386-msdos-go32 ├── Makefile.common.i386-next-mach-o.dynamic ├── Makefile.common.i386-next-mach-o.static ├── Makefile.common.i386-pc-mingw32 ├── Makefile.common.i486-cygwin32 ├── Makefile.common.i486-cygwin32.debug ├── Makefile.common.i486-linux-a.out ├── Makefile.common.i486-linux-a.out-debug ├── Makefile.common.i486-linux-elf ├── Makefile.common.i486-linux-elf-nonnative ├── Makefile.common.i486-linux-elf.debug ├── Makefile.common.i486-linux-glibc ├── Makefile.common.i486-linux-glibc-ccr8 ├── Makefile.common.i486-linux-glibc-debug ├── Makefile.common.i486-linux-glibc-nonnative ├── Makefile.common.i486-linux-glibc-slowccr ├── Makefile.common.i486-linux-slam ├── Makefile.common.i486-new-cygwin32 ├── Makefile.common.i486-new-cygwin32.debug ├── Makefile.common.i486-next-ns3 ├── Makefile.common.i586-cygwin32 ├── Makefile.common.i586-cygwin32.debug ├── Makefile.common.i860 ├── Makefile.common.m68k-next-ns3 ├── Makefile.common.powerpc-linux-glibc └── Makefile.common.powerpc-linux-glibc-debug ├── configure.ac ├── include ├── .gitignore ├── safe_alloca.h ├── syn68k_private.h.in └── syn68k_public.h ├── profile ├── .gitignore ├── Makefile.am ├── amode.c ├── frequency.c ├── include │ ├── amode.h │ ├── bucket.h │ ├── frequency.h │ └── readprofile.h ├── main.c ├── makebucket.c └── readprofile.c ├── runtime ├── .gitignore ├── 68k.defines.scm ├── 68k.scm ├── Makefile.am ├── TODO ├── alloc.c ├── backpatch.c ├── block.c ├── blockinfo.c ├── callback.c ├── checksum.c ├── deathqueue.c ├── destroyblock.c ├── diagnostics.c ├── dosinterrupts.c ├── fold.pl ├── hash.c ├── i486-cleanup.pl ├── i486-optimize.pl ├── include │ ├── alloc.h │ ├── backpatch.h │ ├── block.h │ ├── blockinfo.h │ ├── callback.h │ ├── ccfuncs.h │ ├── checksum.h │ ├── deathqueue.h │ ├── destroyblock.h │ ├── diagnostics.h │ ├── hash.h │ ├── interrupt.h │ ├── mapping.h │ ├── native.h │ ├── profile.h │ ├── rangetree.h │ ├── recompile.h │ ├── translate.h │ └── trap.h ├── init.c ├── interrupt.c ├── native.c ├── native │ ├── i386 │ │ ├── .gitignore │ │ ├── Makefile.am │ │ ├── analyze.c │ │ ├── host-native.c │ │ ├── host-native.h │ │ ├── i386-aux.c │ │ ├── i386-aux.h │ │ ├── main.c │ │ ├── process.c │ │ ├── process.h │ │ ├── template.c │ │ ├── template.h │ │ ├── xlate-aux.c │ │ ├── xlate-aux.h │ │ ├── xlate.c │ │ ├── xlate.h │ │ ├── xlatemain.c │ │ └── xlatetable.c │ └── null │ │ ├── Makefile │ │ ├── host-native.h │ │ ├── host-xlate.h │ │ └── subdir-stmp ├── opcode_dummy.c ├── profile.c ├── rangetree.c ├── recompile.c ├── reg ├── sched.pl ├── syn68k_header.c ├── translate.c ├── trap.c └── x86_recog.pl ├── syngen ├── .gitignore ├── CAVEATS ├── INSTALL ├── Makefile.am ├── SYNOP_LAYOUT ├── TODO ├── bitstring.c ├── boolean.c ├── byteorder.c ├── defopcode.c ├── error.c ├── generatecode.c ├── hash.c ├── include │ ├── bitstring.h │ ├── boolean.h │ ├── byteorder.h │ ├── common.h │ ├── defopcode.h │ ├── error.h │ ├── generatecode.h │ ├── hash.h │ ├── list.h │ ├── macro.h │ ├── parse.h │ ├── reduce.h │ ├── token.h │ ├── tokenlist.h │ └── uniquestring.h ├── list.c ├── macro.c ├── main.c ├── parse.c ├── reduce.c ├── test.scm ├── token.c └── uniquestring.c └── test ├── .gdbinit ├── .gitignore ├── Makefile.am ├── TODO ├── callemulator.s ├── crc.c ├── driver.c ├── freq ├── include ├── callemulator.h ├── crc.h ├── driver.h ├── run68k.h ├── setup.h ├── testbattery.h ├── testqsort.h ├── testrt.h └── testtrap.h ├── main.c ├── maketestbattery.pl ├── output ├── 10000 ├── 10000-noncc ├── 10000-noncc-notnative ├── 10000-notnative ├── 68k.noncc.1000 ├── 68k.out.1000 ├── README ├── dump-68k-100-cc └── dump-68k-100-noncc ├── run68k.s ├── setup.c ├── testall.sh ├── testqsort.c ├── testrt.c ├── tests.c └── testtrap.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.[ao] 2 | config.mak 3 | autom4te.cache 4 | config.log 5 | config.status 6 | configure 7 | INSTALL 8 | Makefile 9 | Makefile.in 10 | aclocal.m4 11 | compile 12 | config.guess 13 | config.sub 14 | depcomp 15 | install-sh 16 | missing 17 | config.h 18 | config.h.in 19 | stamp-h1 20 | libtool 21 | ltmain.sh 22 | m4 23 | syn68k-*.tar.gz 24 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | $Id: AUTHORS 61 2004-12-21 23:44:50Z ctm $ 2 | 3 | Matthew J. Hostetter 4 | minor contributions by Clifford T. Matthews 5 | 6 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | $Id: COPYING 52 2004-12-16 02:08:47Z ctm $ 2 | 3 | Copyright 1994-2004 Abacus Research & Development, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | $Id: ChangeLog 74 2004-12-30 03:38:55Z ctm $ 2 | 3 | 2004-12-28 Clifford T. Matthews 4 | 5 | * Still in the process of switching to GNU build system. 6 | 7 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # $Id: Makefile.am 61 2004-12-21 23:44:50Z ctm $ 2 | ACLOCAL_AMFLAGS = -I m4 3 | SUBDIRS = syngen runtime test profile 4 | 5 | DIST_SOURCES = include/safe_alloca.h include/syn68k_public.h 6 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | $Id: NEWS 74 2004-12-30 03:38:55Z ctm $ 2 | 3 | Syn68k now uses automake for all the Makefiles, but we do enough 4 | things on our own that we're not getting proper dependency tracking 5 | and most likely make clean doesn't work as well as it could. 6 | 7 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | Mac OS X 10.6 (Snow Leopard) note: by default gcc now creates 64-bit 3 | binaries, which means the version of Syn68k that will be built won't work 4 | with Executor. The "-m32" command line option does the right thing, so it 5 | should be possible to get Syn68k (and Executor) to work on Snow Leopard 6 | again, but I don't know that I'll have much time for it. 7 | ======================================================================== 8 | 9 | 10 | Syn68k is a "synthetic CPU" that executes Motorola 68LC040 11 | instructions, either via interpretation or via compilation into Intel 12 | (32-bit) x86 instructions. It was originally written to allow 13 | Executor (a Macintosh emulator) to run on platforms that didn't 14 | contain a 680x0 CPU. Executor first ran on the Sun-3, and then on 15 | NeXT computers. 16 | 17 | Syn68k has not been actively worked on since about 1995. When it was 18 | originally written, there were a bunch of alterable variables in 19 | various Makefiles that allowed us to build Syn68k for many different 20 | architectures with a few different features. 21 | 22 | In late 2003 we did a partial conversion from our build system to the 23 | GNU build system. The result was a Syn68k that could be built with 24 | the then current version of gcc but basically only for the i386 25 | architecture using the native code back-end. That's basically the 26 | state Syn68k was in when I put the code on GitHub in September 2008. 27 | 28 | In June 2009, I've been able to scrape together a little free time and 29 | make it so Syn68k builds on a few more platforms than it did when I 30 | first put it on GitHub. There's still a lot of cruft that can be 31 | removed, but at least there are enough variants that can be built to 32 | show that both big-endian (e.g., PowerPC) and little-endian 33 | (e.g. i386, x86_64), 32-bit and 64-bit, native (i386-only) and 34 | non-native versions work. 35 | 36 | To compile syn68k, try 37 | 38 | ./autogen.sh 39 | ./configure 40 | make 41 | 42 | To test syn68k, run test/syngentest and compare the output to 43 | test/output/10000. It should be the same, assuming the same block of 44 | memory can be obtained for the test. If you want to be more thorough, 45 | you can use other command line options and compare the results to 46 | other files, as described in test/output/README. 47 | 48 | If you plan on building Executor, you'll need to put Syn68k where it 49 | can be found during Executor's build. The easiest way is with 50 | 51 | make install 52 | 53 | To compile a 32-bit syn68k on an x86_64 system, make sure you have all 54 | the 32-bit libraries you need: 55 | 56 | On Fedora 10 I needed to install glibc-devel.i386 and libgcc.i386 57 | On Fedora 11 I needed glibc-devel.i586 and libgcc.i586 58 | On Fedora 12 I needed the .i686 versions of those packages 59 | 60 | Once you have those install, try this: 61 | 62 | ./autogen.sh 63 | CC='gcc -m32' ./configure --build=i686-pc-linux-gnu --host=i686-pc-linux-gnu 64 | make 65 | make install 66 | 67 | It's possible to compile a 64-bit version of Syn68k on an x86_64, but 68 | such a version won't work with Executor yet (and will not use native 69 | x86 instructions). 70 | 71 | My email address is still , although ARDI itself is 72 | defunct. I get a ridiculous amount of spam and will quite possibly 73 | not see email addressed to me. I'm ctm on GitHub (http://github.com) 74 | and typically check my email there once a day. 75 | 76 | --Cliff Matthews 77 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | See if we can find an address to map that is available to all our 2 | currently tested targets (i386-native, i386-notnative, x86_64, 3 | ppc) 4 | 5 | Make so we can build the various debug versions, non-native, etc. 6 | 7 | figure out *exactly* which options should be available 8 | via configure 9 | 10 | Not sure what we should do with x86_64 machines; need to know more 11 | about what the popular distributions do 12 | 13 | Figure out exactly which variables Makefile.common.in sets, then 14 | get rid of Makefile.common.in 15 | 16 | see TODO.variables 17 | 18 | figure out what to do concerning bswap 19 | 20 | Look into what else from syn68k we can delete 21 | 22 | Makefile.common.in 23 | 24 | config 25 | 26 | Make sure make clean really does a make clean 27 | 28 | Make sure we get proper dependencies (if possible) 29 | 30 | write-up what is needed to do testing on a real m68k 31 | 32 | need a .spec file so we can build syn68k and syn68k-devel 33 | RPMS 34 | 35 | May be able to avoid dce problems if we use && for labels (that 36 | may also get rid of our need for the cleanup code, too) 37 | -------------------------------------------------------------------------------- /TODO.variables: -------------------------------------------------------------------------------- 1 | $Id: TODO.variables 55 2004-12-16 22:00:22Z ctm $ 2 | 3 | 4 | 5 | These are some rough notes associated with Makefile.common. These notes should 6 | go away after syn68k is fully transitioned to using the GNU build system 7 | 8 | NOTE: Need to know the difference between the cross-compiler and the 9 | local compiler 10 | 11 | AR 12 | AS 13 | RANLIB 14 | 15 | CC should probably be CC_FOR_BUILD 16 | CFLAGS should probably be CFLAGS_FOR_BUILD 17 | 18 | CLEANUP i486-cleanup.pl, if we're x86 and we don't have no-native set 19 | OPTIMIZE i486-optimize.pl, if we're x86 and we don't have no-native set 20 | 21 | HOSTCPU UNUSED 22 | 23 | INCLUDE_DIR 24 | LDFLAGS 25 | LIBDIR 26 | LIBS 27 | 28 | LIB_CC should probably be CC 29 | LIB_CFLAGS should probably be LIB_CFLAGS 30 | 31 | NO_NATIVE 32 | OFILE_DIR 33 | 34 | SYN68K_CFLAGS 35 | SYN68K_TARGET 36 | 37 | host-native 38 | var_host 39 | var_host_os 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # $Id: autogen.sh 65 2004-12-24 19:51:17Z ctm $ 4 | 5 | set -o errexit -o nounset -o noclobber 6 | 7 | libtoolize 8 | aclocal 9 | autoheader 10 | automake --add-missing 11 | autoconf 12 | -------------------------------------------------------------------------------- /config/Makefile.common.alpha: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = gcc 5 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | # NOTE: QUADALIGN DOESN'T WORK RIGHT NOW 8 | # LIB_CFLAGS = -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) -DQUADALIGN 9 | 10 | OFILE_DIR = obj/alpha-redhat-linux 11 | LIBDIR = $(topdir)/lib/alpha-redhat-linux 12 | LIBS = 13 | HOSTCPU = alpha-redhat-linux 14 | 15 | RANLIB = /usr/bin/ranlib 16 | 17 | # OPTIMIZE = ./i486-optimize.pl 18 | # CLEANUP = ./i486-cleanup.pl 19 | # LDFLAGS = -Lhost-native 20 | # LDFLAGS = -taso 21 | SYN68K_CFLAGS = $(LIB_CFLAGS) -O2 -fomit-frame-pointer 22 | # SYN68K_CFLAGS = -g -Wall -DQUADALIGN 23 | 24 | NO_NATIVE = TRUE 25 | -------------------------------------------------------------------------------- /config/Makefile.common.alpha.orig: -------------------------------------------------------------------------------- 1 | CC = cc 2 | OFILE_DIR = obj/alpha 3 | LIBDIR = ../lib/alpha 4 | LIBS = 5 | HOSTCPU = alpha 6 | RANLIB = /bin/ranlib 7 | LDFLAGS = -taso 8 | -------------------------------------------------------------------------------- /config/Makefile.common.i386-msdos-go32: -------------------------------------------------------------------------------- 1 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 2 | 3 | LIB_CC = i386-msdos-go32-gcc -m486 4 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 5 | 6 | OFILE_DIR = obj/i386-msdos-go32 7 | LIBDIR = $(topdir)/lib/i386-msdos-go32 8 | LIBS = 9 | HOSTCPU = i386-msdos-go32 10 | 11 | AR = ar 12 | AS = i386-msdos-go32-gcc -x assembler 13 | RANLIB = ranlib 14 | 15 | LDFLAGS = -Ttext 0 -Tdata 200000 16 | CLEANUP = ./i486-cleanup.pl 17 | OPTIMIZE = ./i486-optimize.pl 18 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer 19 | -------------------------------------------------------------------------------- /config/Makefile.common.i386-next-mach-o.dynamic: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = gcc 5 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | OFILE_DIR = obj/i386-next-mach-o 8 | LIBDIR = $(topdir)/lib/i386-next-mach-o 9 | LIBS = 10 | HOSTCPU = i386-next-mach-o 11 | 12 | RANLIB = /bin/ranlib 13 | 14 | OPTIMIZE = ./i486-optimize.pl 15 | CLEANUP = ./i486-cleanup.pl 16 | LDFLAGS = 17 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer 18 | -------------------------------------------------------------------------------- /config/Makefile.common.i386-next-mach-o.static: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -static -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = gcc 5 | LIB_CFLAGS = -static -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | OFILE_DIR = obj/i386-next-mach-o 8 | LIBDIR = $(topdir)/lib/i386-next-mach-o 9 | LIBS = 10 | HOSTCPU = i386-next-mach-o 11 | 12 | RANLIB = /bin/ranlib 13 | 14 | OPTIMIZE = ./i486-optimize.pl 15 | CLEANUP = ./i486-cleanup.pl 16 | LDFLAGS = 17 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer 18 | -------------------------------------------------------------------------------- /config/Makefile.common.i386-pc-mingw32: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = i386-pc-mingw32-gcc 5 | LIB_CFLAGS = -O6 -finline-functions -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | OFILE_DIR = obj/i386-pc-mingw32 8 | LIBDIR = $(topdir)/lib/i386-pc-mingw32 9 | LIBS = 10 | HOSTCPU = i386-pc-mingw32 11 | 12 | AR = ar 13 | AS = i386-pc-mingw32-gcc -x assembler 14 | RANLIB = i386-pc-mingw32-ranlib 15 | 16 | CLEANUP = ./i486-cleanup.pl 17 | OPTIMIZE = ./i486-optimize.pl 18 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer 19 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-cygwin32: -------------------------------------------------------------------------------- 1 | CC = gcc -m486 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = i486-pc-cygwin32-gcc -m486 5 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) -Dfree=free_hack 6 | 7 | OFILE_DIR = obj/i486-pc-cygwin32 8 | LIBDIR = $(topdir)/lib/i486-pc-cygwin32 9 | LIBS = 10 | HOSTCPU = i486-pc-cygwin32 11 | 12 | AR = ar 13 | AS = i486-pc-cygwin32-gcc -x assembler 14 | RANLIB = i486-pc-cygwin32-ranlib 15 | 16 | CLEANUP = ./i486-cleanup.pl 17 | OPTIMIZE = ./i486-optimize.pl 18 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer -Dfree=free_hack 19 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-cygwin32.debug: -------------------------------------------------------------------------------- 1 | # NOTE: we define __CHECKER__ so that we get a frame pointer and other 2 | # good stuff. We're not actually using checker. D'oh. 3 | CC = gcc -m486 4 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 5 | 6 | LIB_CC = i486-pc-cygwin32-gcc -m486 7 | LIB_CFLAGS = -g -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ -Dfree=free_hack 8 | 9 | OFILE_DIR = obj/i486-pc-cygwin32-debug 10 | LIBDIR = $(topdir)/lib/i486-pc-cygwin32-debug 11 | LIBS = 12 | HOSTCPU = i486-pc-cygwin32-debug 13 | 14 | AR = ar 15 | AS = i486-pc-cygwin32-gcc -x assembler 16 | RANLIB = i486-pc-cygwin32-ranlib 17 | 18 | CLEANUP = ./i486-cleanup.pl 19 | # OPTIMIZE = ./i486-optimize.pl 20 | SYN68K_CFLAGS = $(LIB_CFLAGS) -O 21 | LDFLAGS = -Lhost-native 22 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-a.out: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = gcc -b i486-linuxaout 5 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | OFILE_DIR = obj/i486-linux-a.out 8 | LIBDIR = $(topdir)/lib/i486-linux-a.out 9 | LIBS = 10 | HOSTCPU = i486-linux-a.out 11 | 12 | RANLIB = /usr/bin/ranlib 13 | 14 | OPTIMIZE = ./i486-optimize.pl 15 | CLEANUP = ./i486-cleanup.pl 16 | LDFLAGS = -Lhost-native 17 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer 18 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-a.out-debug: -------------------------------------------------------------------------------- 1 | # NOTE: we define __CHECKER__ so that we get a frame pointer and other 2 | # good stuff. We're not actually using checker. D'oh. 3 | CC = gcc 4 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 5 | 6 | LIB_CC = gcc -b i486-linuxaout 7 | LIB_CFLAGS = -g -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ 8 | 9 | SYN68K_CFLAGS = $(LIB_CFLAGS) -O 10 | 11 | OFILE_DIR = obj/i486-linux-debug 12 | LIBDIR = $(topdir)/lib/i486-linux-debug 13 | LIBS = 14 | HOSTCPU = i486-linux-debug 15 | 16 | AR = ar 17 | RANLIB = ranlib 18 | 19 | # don't optimize syn68k.s when compiling with checker 20 | # OPTIMIZE = ./i486-optimize.pl 21 | CLEANUP = ./i486-cleanup.pl 22 | 23 | LDFLAGS = -Lhost-native 24 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-elf: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = gcc 5 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | OFILE_DIR = obj/i486-linux-elf 8 | LIBDIR = $(topdir)/lib/i486-linux-elf 9 | LIBS = 10 | HOSTCPU = i486-linux-elf 11 | 12 | RANLIB = /usr/bin/ranlib 13 | 14 | OPTIMIZE = ./i486-optimize.pl 15 | CLEANUP = ./i486-cleanup.pl 16 | LDFLAGS = -Lhost-native 17 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer 18 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-elf-nonnative: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = gcc 5 | LIB_CFLAGS = -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ 6 | 7 | OFILE_DIR = obj/i486-linux-elf-nonnative 8 | LIBDIR = $(topdir)/lib/i486-linux-elf-nonnative 9 | LIBS = 10 | HOSTCPU = i486-linux-elf 11 | 12 | RANLIB = /usr/bin/ranlib 13 | 14 | # OPTIMIZE = ./i486-optimize.pl 15 | # CLEANUP = ./i486-cleanup.pl 16 | # LDFLAGS = -Lhost-native 17 | SYN68K_CFLAGS = -O 18 | 19 | NO_NATIVE = TRUE 20 | 21 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-elf.debug: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = gcc 5 | LIB_CFLAGS = -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ 6 | 7 | OFILE_DIR = obj/i486-linux-elf-debug 8 | LIBDIR = $(topdir)/lib/i486-linux-elf-debug 9 | LIBS = 10 | HOSTCPU = i486-linux-elf-debug 11 | 12 | RANLIB = /usr/bin/ranlib 13 | 14 | OPTIMIZE = ./i486-optimize.pl 15 | CLEANUP = ./i486-cleanup.pl 16 | LDFLAGS = -Lhost-native 17 | SYN68K_CFLAGS = $(LIB_CFLAGS) 18 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-glibc: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = gcc 5 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | OFILE_DIR = obj/i486-linux-glibc 8 | LIBDIR = $(topdir)/lib/i486-linux-glibc 9 | LIBS = 10 | HOSTCPU = i486-linux-glibc 11 | 12 | RANLIB = /usr/bin/ranlib 13 | 14 | OPTIMIZE = ./i486-optimize.pl 15 | CLEANUP = ./i486-cleanup.pl 16 | LDFLAGS = -Lhost-native 17 | 18 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer 19 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-glibc-ccr8: -------------------------------------------------------------------------------- 1 | # NOTE: we define __CHECKER__ so that we get a frame pointer and other 2 | # good stuff. We're not actually using checker. D'oh. 3 | CC = gcc 4 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 5 | 6 | LIB_CC = gcc 7 | LIB_CFLAGS = -g -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ -DNO_FAST_CC_FUNCS 8 | 9 | OFILE_DIR = obj/i486-linux-glibc-ccr8 10 | LIBDIR = $(topdir)/lib/i486-linux-glibc-ccr8 11 | LIBS = 12 | HOSTCPU = i486-linux-glibc-ccr8 13 | 14 | RANLIB = /usr/bin/ranlib 15 | 16 | # OPTIMIZE = ./i486-optimize.pl 17 | CLEANUP = ./i486-cleanup.pl 18 | LDFLAGS = -Lhost-native 19 | SYN68K_CFLAGS = $(LIB_CFLAGS) -O 20 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-glibc-debug: -------------------------------------------------------------------------------- 1 | # NOTE: we define __CHECKER__ so that we get a frame pointer and other 2 | # good stuff. We're not actually using checker. D'oh. 3 | CC = gcc 4 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 5 | 6 | LIB_CC = gcc 7 | LIB_CFLAGS = -g -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ 8 | 9 | OFILE_DIR = obj/i486-linux-glibc-debug 10 | LIBDIR = $(topdir)/lib/i486-linux-glibc-debug 11 | LIBS = 12 | HOSTCPU = i486-linux-glibc-debug 13 | 14 | RANLIB = /usr/bin/ranlib 15 | 16 | # OPTIMIZE = ./i486-optimize.pl 17 | CLEANUP = ./i486-cleanup.pl 18 | LDFLAGS = -Lhost-native 19 | SYN68K_CFLAGS = $(LIB_CFLAGS) 20 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-glibc-nonnative: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ -DNONNATIVE 3 | 4 | LIB_CC = gcc 5 | LIB_CFLAGS = -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ -DNONNATIVE 6 | 7 | OFILE_DIR = obj/i486-linux-glibc-nonnative 8 | LIBDIR = $(topdir)/lib/i486-linux-glibc-nonnative 9 | LIBS = 10 | HOSTCPU = i486-linux-glibc 11 | 12 | RANLIB = /usr/bin/ranlib 13 | 14 | # OPTIMIZE = ./i486-optimize.pl 15 | CLEANUP = ./i486-cleanup.pl 16 | # LDFLAGS = -Lhost-native 17 | SYN68K_CFLAGS = -DNONNATIVE -g -D__CHECKER__ 18 | 19 | NO_NATIVE = TRUE 20 | 21 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-glibc-slowccr: -------------------------------------------------------------------------------- 1 | # NOTE: we define __CHECKER__ so that we get a frame pointer and other 2 | # good stuff. We're not actually using checker. D'oh. 3 | CC = gcc 4 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 5 | 6 | LIB_CC = gcc 7 | LIB_CFLAGS = -g -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ -DNO_CCR_SPEEDUPS 8 | 9 | OFILE_DIR = obj/i486-linux-glibc-slowccr 10 | LIBDIR = $(topdir)/lib/i486-linux-glibc-slowccr 11 | LIBS = 12 | HOSTCPU = i486-linux-glibc-slowccr 13 | 14 | RANLIB = /usr/bin/ranlib 15 | 16 | # OPTIMIZE = ./i486-optimize.pl 17 | CLEANUP = ./i486-cleanup.pl 18 | LDFLAGS = -Lhost-native 19 | SYN68K_CFLAGS = $(LIB_CFLAGS) -O 20 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-linux-slam: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = checkergcc 5 | LIB_CFLAGS = -g -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | SYN68K_FLAGS = $(LIB_CFLAGS) 8 | 9 | OFILE_DIR = obj/i486-linux 10 | LIBDIR = $(topdir)/lib/i486-linux 11 | LIBS = 12 | HOSTCPU = i486-linux 13 | 14 | AR = /usr/local/lib/checker/ar 15 | RANLIB = /usr/local/lib/checker/ranlib 16 | 17 | # don't optimize syn68k.s when compiling with checker 18 | # OPTIMIZE = ./i486-optimize.pl 19 | CLEANUP = ./i486-cleanup.pl 20 | 21 | LDFLAGS = -Lhost-native 22 | SYN68K_CFLAGS = 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-new-cygwin32: -------------------------------------------------------------------------------- 1 | CC = gcc -m486 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = i486-pc-cygwin32-gcc -m486 -I/usr/local/i486-pc-cygwin32/include/mingw32 5 | LIB_CFLAGS = -O6 -finline-functions -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | OFILE_DIR = obj/i486-pc-new-cygwin32 8 | LIBDIR = $(topdir)/lib/i486-pc-new-cygwin32 9 | LIBS = 10 | HOSTCPU = i486-pc-new-cygwin32 11 | 12 | AR = ar 13 | AS = i486-pc-cygwin32-gcc -x assembler 14 | RANLIB = i486-pc-cygwin32-ranlib 15 | 16 | CLEANUP = ./i486-cleanup.pl 17 | OPTIMIZE = ./i486-optimize.pl 18 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer 19 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-new-cygwin32.debug: -------------------------------------------------------------------------------- 1 | # NOTE: we define __CHECKER__ so that we get a frame pointer and other 2 | # good stuff. We're not actually using checker. D'oh. 3 | CC = gcc -m486 4 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 5 | 6 | LIB_CC = i486-pc-cygwin32-gcc -m486 -I/usr/local/i486-pc-cygwin32/include/mingw32 7 | LIB_CFLAGS = -g -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ 8 | 9 | OFILE_DIR = obj/i486-pc-new-cygwin32-debug 10 | LIBDIR = $(topdir)/lib/i486-pc-new-cygwin32-debug 11 | LIBS = 12 | HOSTCPU = i486-pc-new-cygwin32-debug 13 | 14 | AR = ar 15 | AS = i486-pc-cygwin32-gcc -x assembler 16 | RANLIB = i486-pc-cygwin32-ranlib 17 | 18 | CLEANUP = ./i486-cleanup.pl 19 | # OPTIMIZE = ./i486-optimize.pl 20 | SYN68K_CFLAGS = $(LIB_CFLAGS) -O 21 | LDFLAGS = -Lhost-native 22 | -------------------------------------------------------------------------------- /config/Makefile.common.i486-next-ns3: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = gcc 5 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | OFILE_DIR = obj/i486-next-ns3 8 | LIBDIR = $(topdir)/lib/i486-next-ns3 9 | LIBS = 10 | HOSTCPU = i486-next-ns3 11 | 12 | RANLIB = /bin/ranlib 13 | 14 | OPTIMIZE = ./i486-optimize.pl 15 | CLEANUP = ./i486-cleanup.pl 16 | LDFLAGS = 17 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer 18 | -------------------------------------------------------------------------------- /config/Makefile.common.i586-cygwin32: -------------------------------------------------------------------------------- 1 | CC = gcc -m486 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = i586-cygwin32-gcc -m486 5 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | OFILE_DIR = obj/i586-cygwin32 8 | LIBDIR = $(topdir)/lib/i586-cygwin32 9 | LIBS = 10 | HOSTCPU = i586-cygwin32 11 | 12 | AR = ar 13 | AS = i586-cygwin32-gcc -x assembler 14 | RANLIB = i586-cygwin32-ranlib 15 | 16 | CLEANUP = ./i486-cleanup.pl 17 | OPTIMIZE = ./i486-optimize.pl 18 | SYN68K_CFLAGS = -O2 -fomit-frame-pointer 19 | -------------------------------------------------------------------------------- /config/Makefile.common.i586-cygwin32.debug: -------------------------------------------------------------------------------- 1 | CC = gcc -m486 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = i486-pc-cygwin32-gcc -m486 5 | LIB_CFLAGS = -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ 6 | 7 | OFILE_DIR = obj/i586-cygwin32-debug 8 | LIBDIR = $(topdir)/lib/i586-cygwin32-debug 9 | LIBS = 10 | HOSTCPU = i586-cygwin32-debug 11 | 12 | AR = ar 13 | AS = i486-pc-cygwin32-gcc -x assembler 14 | RANLIB = i486-pc-cygwin32-ranlib 15 | 16 | CLEANUP = ./i486-cleanup.pl 17 | OPTIMIZE = ./i486-optimize.pl 18 | SYN68K_CFLAGS = -O 19 | -------------------------------------------------------------------------------- /config/Makefile.common.i860: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | OFILE_DIR = obj/i860 3 | LIBDIR = ../lib/i860 4 | LIBS = -L/usr/ucblib -lucb 5 | HOSTCPU = i860 6 | -------------------------------------------------------------------------------- /config/Makefile.common.m68k-next-ns3: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 3 | 4 | LIB_CC = gcc 5 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 6 | 7 | OFILE_DIR = obj/m68k-next-ns3 8 | LIBDIR = $(topdir)/lib/m68k-next-ns3 9 | LIBS = 10 | 11 | RANLIB = /bin/ranlib -c 12 | 13 | HOSTCPU = m68k-next-ns3 14 | -------------------------------------------------------------------------------- /config/Makefile.common.powerpc-linux-glibc: -------------------------------------------------------------------------------- 1 | # NOTE: we define __CHECKER__ so that we get a frame pointer and other 2 | # good stuff. We're not actually using checker. D'oh. 3 | CC = gcc 4 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 5 | 6 | LIB_CC = gcc 7 | LIB_CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 8 | 9 | OFILE_DIR = obj/powerpc-linux-glibc 10 | LIBDIR = $(topdir)/lib/powerpc-linux-glibc 11 | LIBS = 12 | HOSTCPU = powerpc-linux-glibc 13 | 14 | RANLIB = /usr/bin/ranlib 15 | 16 | # OPTIMIZE = ./powerpc-optimize.pl 17 | # CLEANUP = ./powerpc-cleanup.pl 18 | # LDFLAGS = -Lhost-native 19 | SYN68K_CFLAGS = $(LIB_CFLAGS) -O2 -fomit-frame-pointer 20 | 21 | NO_NATIVE = TRUE 22 | -------------------------------------------------------------------------------- /config/Makefile.common.powerpc-linux-glibc-debug: -------------------------------------------------------------------------------- 1 | # NOTE: we define __CHECKER__ so that we get a frame pointer and other 2 | # good stuff. We're not actually using checker. D'oh. 3 | CC = gcc 4 | CFLAGS = -O2 -g -Wall -I$(topdir)/include $(LOCAL_CFLAGS) 5 | 6 | LIB_CC = gcc 7 | LIB_CFLAGS = -g -I$(topdir)/include $(LOCAL_CFLAGS) -D__CHECKER__ 8 | 9 | OFILE_DIR = obj/powerpc-linux-glibc-debug 10 | LIBDIR = $(topdir)/lib/powerpc-linux-glibc-debug 11 | LIBS = 12 | HOSTCPU = powerpc-linux-elf-debug 13 | 14 | RANLIB = /usr/bin/ranlib 15 | 16 | # OPTIMIZE = ./powerpc-optimize.pl 17 | # CLEANUP = ./powerpc-cleanup.pl 18 | # LDFLAGS = -Lhost-native 19 | SYN68K_CFLAGS = $(LIB_CFLAGS) -O 20 | 21 | NO_NATIVE = TRUE 22 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(syn68k, 1.0, ctm@ardi.com) 2 | LT_INIT 3 | AM_INIT_AUTOMAKE 4 | 5 | AC_CONFIG_MACRO_DIR([m4]) 6 | AC_CONFIG_SRCDIR([syngen/main.c]) 7 | AC_CONFIG_HEADERS([include/config.h]) 8 | 9 | # Checks for programs. 10 | AC_PROG_LIBTOOL 11 | AC_PROG_CC 12 | AM_PROG_CC_C_O 13 | AM_PROG_AS 14 | 15 | AC_CHECK_PROG([PERL], [perl], [perl]) 16 | AC_ARG_VAR([PERL], [perl for preening assembly]) 17 | 18 | AC_CANONICAL_BUILD 19 | AC_CANONICAL_HOST 20 | 21 | AC_MSG_CHECKING([(non-cross) C compiler for building tools]) 22 | if test "$cross_compiling" = "yes"; then 23 | CC_FOR_BUILD="${CC_FOR_BUILD-gcc}" 24 | else 25 | CC_FOR_BUILD="${CC_FOR_BUILD-$CC}" 26 | fi 27 | AC_MSG_RESULT([$CC_FOR_BUILD]) 28 | AC_ARG_VAR(CC_FOR_BUILD,[C compiler for building tools]) 29 | 30 | CFLAGS_FOR_BUILD="${CFLAGS_FOR_BUILD-}" 31 | AC_ARG_VAR(CFLAGS_FOR_BUILD,[C flags for building tools]) 32 | 33 | if test "$host_alias" = ""; then 34 | host=i486-linux-glibc 35 | fi 36 | 37 | case $host_cpu in 38 | i?86) 39 | host_cpu_class=i386;; 40 | *) 41 | host_cpu_class=$host_cpu;; 42 | esac 43 | 44 | AC_SUBST(host_cpu_class) 45 | 46 | # See lengthy explanation in runtime/Makefile.am for dce_fixup explanation 47 | 48 | if test x$host_cpu = xx86_64; then 49 | dce_fixup=-fno-dce 50 | fi 51 | 52 | AC_SUBST(dce_fixup) 53 | 54 | AC_MSG_CHECKING([Syn68k C flags (TODO: FIXME)]) 55 | SYN68K_CFLAGS="${SYN68K_CFLAGS--O2 -fomit-frame-pointer}" 56 | AC_MSG_RESULT([$SYN68K_CFLAGS]) 57 | AC_ARG_VAR(SYN68K_CFLAGS,[Syn68k C flags (TODO: FIXME)]) 58 | 59 | AC_ARG_ENABLE([native], 60 | AC_HELP_STRING([--enable-native], 61 | [recompile into x86 code (default enabled for x86)]), 62 | [], [if test x$host_cpu_class = xi386; then 63 | enable_native=yes 64 | else 65 | enable_native=no 66 | fi]) 67 | 68 | AC_MSG_CHECKING([native support]) 69 | if test x$enable_native = xyes; then 70 | if test x$host_cpu_class != xi386; then 71 | AC_MSG_ERROR([Can't build native on non-x86]) 72 | fi 73 | HOST_NATIVE="native/i386" 74 | NONNATIVE="" 75 | else 76 | HOST_NATIVE="native/null" 77 | NONNATIVE="#define NONNATIVE" 78 | fi 79 | AC_MSG_RESULT([$enable_native]) 80 | 81 | AC_SUBST(NONNATIVE) 82 | AC_SUBST(HOST_NATIVE) 83 | 84 | AC_ARG_ENABLE([assembly-cleanup], 85 | AC_HELP_STRING([--enable-assembly-cleanup], 86 | [remove unneeded assembler instructions (default enabled for x86)]), 87 | [], [if test x$host_cpu_class = xi386; then 88 | enable_assembly_cleanup=yes 89 | else 90 | enable_assembly_cleanup=no 91 | fi]) 92 | 93 | AC_MSG_CHECKING([assembler cleanup]) 94 | if test x$enable_assembly_cleanup = xyes; then 95 | assembly_cleanup_script=./i486-cleanup.pl 96 | else 97 | assembly_cleanup_script= 98 | fi 99 | AC_MSG_RESULT([$enable_assembly_cleanup]) 100 | AC_SUBST(assembly_cleanup_script) 101 | 102 | 103 | # TODO: finish this 104 | AC_ARG_ENABLE([assembly-optimization], 105 | AC_HELP_STRING([--enable-assembly-optimization], 106 | [reorder assembly instructions (x86 only; default is no]), 107 | [], [enable_assembly_optimization=no]) 108 | 109 | AC_MSG_CHECKING([assembly optimization]) 110 | if test x$enable_assembly_optimization = xyes; then 111 | assembly_optimization_script=./i486-optimize.pl 112 | else 113 | assembly_optimization_script= 114 | fi 115 | AC_MSG_RESULT($enable_assembly_optimization) 116 | AC_SUBST(assembly_optimization_script) 117 | 118 | AC_ARG_ENABLE([debug], 119 | AC_HELP_STRING([--enable-debug], 120 | [use debug -g (default is yes)]), 121 | [var_debug=$enable_debug] ,[var_debug=yes] ) 122 | if test "$var_debug" = "no" ; then 123 | DEBUGFLAG="" 124 | else 125 | DEBUGFLAG="-g" 126 | fi 127 | AC_SUBST(DEBUGFLAG) 128 | 129 | AC_ARG_WITH(ccrversion, 130 | [ --with-ccrversion= 131 | Specify ccr version], 132 | [ccrversion=$withval], 133 | [ccrversion]="") 134 | 135 | case "$ccrversion" in 136 | ccr8) 137 | CCRFLAG=ccr8 ;; 138 | *) 139 | CCRFLAG="" ;; 140 | esac 141 | 142 | # Checks for header files. 143 | AC_HEADER_STDC 144 | AC_CHECK_HEADERS([stddef.h stdlib.h string.h sys/param.h unistd.h stdint.h]) 145 | 146 | # Checks for typedefs, structures, and compiler characteristics. 147 | AC_C_CONST 148 | AC_C_INLINE 149 | AC_TYPE_SIZE_T 150 | AC_C_VOLATILE 151 | 152 | AC_LTDL_SYMBOL_USCORE 153 | if test x"$lt_cv_sys_symbol_underscore" = xyes ; then 154 | AC_DEFINE(HAVE_SYMBOL_UNDERSCORE, 1, 155 | [Define if C symbols have leading underscores]) 156 | fi 157 | 158 | # Checks for library functions. 159 | AC_FUNC_ALLOCA 160 | AC_FUNC_ERROR_AT_LINE 161 | AC_FUNC_MEMCMP 162 | AC_FUNC_MMAP 163 | AC_FUNC_MALLOC 164 | AC_FUNC_REALLOC 165 | AC_FUNC_VPRINTF 166 | AC_CHECK_FUNCS([getpagesize memmove memset strchr strdup strerror strstr]) 167 | 168 | AC_CHECK_SIZEOF([char *]) 169 | 170 | AC_TYPE_INT8_T 171 | AC_TYPE_UINT8_T 172 | 173 | AC_TYPE_INT16_T 174 | AC_TYPE_UINT16_T 175 | 176 | AC_TYPE_INT32_T 177 | AC_TYPE_UINT32_T 178 | 179 | AC_TYPE_INT64_T 180 | AC_TYPE_UINT64_T 181 | 182 | # The following is taken from wine-0.9.25's configure.ac 183 | 184 | AC_SUBST(EXECSTACK,"") 185 | saved_LDFLAGS="$LDFLAGS" 186 | LDFLAGS="$LDFLAGS -z execstack" 187 | AC_CACHE_CHECK([for -z execstack], ac_cv_z_execstack, 188 | AC_TRY_LINK([],[int main(void) {return 0;}], 189 | ac_cv_z_execstack=yes,ac_cv_z_execstack=no)) 190 | if test x$ac_cv_z_execstack = xyes; then 191 | EXECSTACK="-z execstack" 192 | fi 193 | LDFLAGS="$saved_LDFLAGS" 194 | 195 | AM_CONDITIONAL([M68K_HOSTCPU], [test "$host_alias" = "m68k-next-ns3"]) 196 | 197 | AC_CONFIG_FILES([Makefile 198 | syngen/Makefile 199 | test/Makefile 200 | profile/Makefile 201 | runtime/Makefile 202 | runtime/native/i386/Makefile 203 | include/syn68k_private.h]) 204 | 205 | AC_OUTPUT 206 | -------------------------------------------------------------------------------- /include/.gitignore: -------------------------------------------------------------------------------- 1 | stamp-h1 2 | syn68k_private.h 3 | -------------------------------------------------------------------------------- /include/safe_alloca.h: -------------------------------------------------------------------------------- 1 | #if !defined(__safe_alloca__) 2 | #define __safe_alloca__ 3 | 4 | #include 5 | 6 | #if !defined(NDEBUG) 7 | 8 | #define FIREWALL_START 0x940504FE 9 | #define FIREWALL_STOP_0 0xEE 10 | #define FIREWALL_STOP_1 0x41 11 | #define FIREWALL_STOP_2 0x51 12 | #define FIREWALL_STOP_3 0x59 13 | 14 | /* 15 | * I don't like this implementation, but it works. 16 | */ 17 | 18 | #define SAFE_DECL() \ 19 | unsigned long ___newsize; \ 20 | unsigned char *___tempptr 21 | 22 | #define SAFE_alloca(size) \ 23 | ( \ 24 | ___newsize = (size) + 3 * sizeof(long), \ 25 | ___tempptr = alloca(___newsize), \ 26 | ((long *)___tempptr)[0] = ___newsize, \ 27 | ((long *)___tempptr)[1] = FIREWALL_START, \ 28 | ___tempptr[___newsize-4] = FIREWALL_STOP_0, \ 29 | ___tempptr[___newsize-3] = FIREWALL_STOP_1, \ 30 | ___tempptr[___newsize-2] = FIREWALL_STOP_2, \ 31 | ___tempptr[___newsize-1] = FIREWALL_STOP_3, \ 32 | (void *) (___tempptr + 2 * sizeof(long)) \ 33 | ) 34 | 35 | #define ASSERT_SAFE(var) \ 36 | do { \ 37 | ___tempptr = (unsigned char *) (var); \ 38 | ___tempptr -= 2 * sizeof(long); \ 39 | assert(((long *)___tempptr)[1] == FIREWALL_START); \ 40 | ___newsize = ((long *)___tempptr)[0]; \ 41 | assert(___tempptr[___newsize-4] == FIREWALL_STOP_0); \ 42 | assert(___tempptr[___newsize-3] == FIREWALL_STOP_1); \ 43 | assert(___tempptr[___newsize-2] == FIREWALL_STOP_2); \ 44 | assert(___tempptr[___newsize-1] == FIREWALL_STOP_3); \ 45 | } while (0) 46 | 47 | #else /* defined(NDEBUG) */ 48 | 49 | #define SAFE_DECL() unsigned long ___newsize 50 | #define SAFE_alloca(size) alloca(size) 51 | #define ASSERT_SAFE(var) do {} while (0) 52 | 53 | #endif /* defined(NDEBUG) */ 54 | 55 | #endif /* !defined(__safe_alloca__) */ 56 | -------------------------------------------------------------------------------- /profile/.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | bucket.c 3 | makebucket 4 | profile 5 | -------------------------------------------------------------------------------- /profile/Makefile.am: -------------------------------------------------------------------------------- 1 | CC=@CC_FOR_BUILD@ 2 | noinst_PROGRAMS = makebucket profile 3 | EXEEXT = 4 | 5 | BUILT_SOURCES = bucket.c 6 | 7 | profile_SOURCES = main.c readprofile.c amode.c frequency.c \ 8 | include/amode.h include/bucket.h \ 9 | include/frequency.h include/readprofile.h 10 | 11 | nodist_profile_SOURCES = bucket.c 12 | 13 | makebucket_SOURCES = makebucket.c amode.c \ 14 | include/amode.h include/bucket.h 15 | 16 | 17 | AM_CFLAGS = -g -Wall -I$(srcdir)/include -I$(srcdir)/../include 18 | 19 | all: 20 | echo "Doing nothing, we don't use this any more" 21 | 22 | bucket.c: makebucket ../runtime/profileinfo.gz 23 | ./makebucket ../runtime/profileinfo.gz > bucket.c 24 | 25 | clean-local: 26 | -rm -f bucket.c 27 | -------------------------------------------------------------------------------- /profile/amode.c: -------------------------------------------------------------------------------- 1 | #include "amode.h" 2 | #include 3 | 4 | const char * 5 | amode_to_string (int amode) 6 | { 7 | static const char *amode_string[64] = { 8 | #if 0 9 | "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", 10 | "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", 11 | "a0@", "a1@", "a2@", "a3@", "a4@", "a5@", "a6@", "a7@", 12 | "a0@+", "a1@+", "a2@+", "a3@+", "a4@+", "a5@+", "a6@+", "a7@+", 13 | "a0@-", "a1@-", "a2@-", "a3@-", "a4@-", "a5@-", "a6@-", "a7@-", 14 | "a0@(d16)", "a1@(d16)", "a2@(d16)", "a3@(d16)", 15 | "a4@(d16)", "a5@(d16)", "a6@(d16)", "a7@(d16)", 16 | "[mode 6/a0]", "[mode 6/a1]", "[mode 6/a2]", "[mode 6/a3]", 17 | "[mode 6/a4]", "[mode 6/a5]", "[mode 6/a6]", "[mode 6/a7]", 18 | "abs.w", "abs.l", "pc@(d16)", "[amode 7/3]", 19 | "#", "[undefined]", "[undefined]", "[undefined]", 20 | #else /* We want more general categories. */ 21 | "dn", "dn", "dn", "dn", "dn", "dn", "dn", "dn", 22 | "an", "an", "an", "an", "an", "an", "an", "an", 23 | "an@", "an@", "an@", "an@", "an@", "an@", "an@", "an@", 24 | "an@+", "an@+", "an@+", "an@+", "an@+", "an@+", "an@+", "an@+", 25 | "an@-", "an@-", "an@-", "an@-", "an@-", "an@-", "an@-", "an@-", 26 | "an@(d16)", "an@(d16)", "an@(d16)", "an@(d16)", 27 | "an@(d16)", "an@(d16)", "an@(d16)", "an@(d16)", 28 | "[mode 6/an]", "[mode 6/an]", "[mode 6/an]", "[mode 6/an]", 29 | "[mode 6/an]", "[mode 6/an]", "[mode 6/an]", "[mode 6/an]", 30 | "abs.w", "abs.l", "pc@(d16)", "[amode 7/3]", 31 | "#", "[undefined]", "[undefined]", "[undefined]", 32 | #endif 33 | }; 34 | 35 | assert (amode >= 0 && amode < 64); 36 | return amode_string[amode]; 37 | } 38 | -------------------------------------------------------------------------------- /profile/frequency.c: -------------------------------------------------------------------------------- 1 | #include "bucket.h" 2 | #include "frequency.h" 3 | #include "readprofile.h" 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | static void 10 | fill_buckets () 11 | { 12 | int i; 13 | for (i = 65535; i >= 0; i--) 14 | bucket[bucket_map[i]].count += instruction_count[i]; 15 | } 16 | 17 | 18 | /* qsort helper function. Place larger counts first. */ 19 | static int 20 | compare_buckets (const void *b1, const void *b2) 21 | { 22 | int diff = ((const Bucket *)b2)->count - ((const Bucket *)b1)->count; 23 | if (diff != 0) 24 | return diff; 25 | 26 | /* Sort alphabetically if the counts are the same. */ 27 | return strcmp (((const Bucket *)b1)->name, ((const Bucket *)b2)->name); 28 | } 29 | 30 | 31 | void 32 | generate_frequency_report () 33 | { 34 | int i; 35 | 36 | fill_buckets (); 37 | qsort (bucket, num_buckets, sizeof bucket[0], compare_buckets); 38 | 39 | puts ("count\topcode\n" 40 | "-------\t-----------"); 41 | for (i = 0; i < num_buckets && bucket[i].count != 0; i++) 42 | printf ("%lu\t%s\n", bucket[i].count, bucket[i].name); 43 | } 44 | -------------------------------------------------------------------------------- /profile/include/amode.h: -------------------------------------------------------------------------------- 1 | #ifndef _amode_h_ 2 | #define _amode_h_ 3 | 4 | extern const char *amode_to_string (int amode); 5 | 6 | #endif /* Not _amode_h_ */ 7 | -------------------------------------------------------------------------------- /profile/include/bucket.h: -------------------------------------------------------------------------------- 1 | #ifndef _bucket_h_ 2 | #define _bucket_h_ 3 | 4 | #define NO_AMODE (-1) 5 | 6 | typedef struct { 7 | const char *name; /* Descriptive name for instruction. */ 8 | unsigned short litmask, litbits; /* Mask/values for fixed bits in 68k op. */ 9 | unsigned long count; /* Frequency of execution. */ 10 | } Bucket; 11 | 12 | extern Bucket bucket[]; 13 | extern const unsigned short bucket_map[65536]; 14 | extern const int num_buckets; 15 | 16 | #endif /* Not _bucket_h_ */ 17 | -------------------------------------------------------------------------------- /profile/include/frequency.h: -------------------------------------------------------------------------------- 1 | #ifndef _frequency_h_ 2 | #define _frequency_h_ 3 | 4 | extern void generate_frequency_report (void); 5 | 6 | #endif /* Not _frequency_h_ */ 7 | -------------------------------------------------------------------------------- /profile/include/readprofile.h: -------------------------------------------------------------------------------- 1 | #ifndef read_profile_h 2 | #define read_profile_h 3 | 4 | typedef enum { BO_BIG_ENDIAN, BO_LITTLE_ENDIAN } ByteOrder; 5 | extern unsigned long instruction_count[65536]; 6 | 7 | extern void read_profile (const char *filename); 8 | 9 | #endif /* Not read_profile_h */ 10 | -------------------------------------------------------------------------------- /profile/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "readprofile.h" 4 | #include "frequency.h" 5 | 6 | int 7 | main (int argc, char *argv[]) 8 | { 9 | /* Check arguments. */ 10 | if (argc != 2) 11 | { 12 | fprintf (stderr, "Usage: %s \n", argv[0]); 13 | exit (1); 14 | } 15 | 16 | /* Read in the profile file. */ 17 | read_profile (argv[1]); 18 | 19 | /* Process it. */ 20 | generate_frequency_report (); 21 | 22 | return EXIT_SUCCESS; 23 | } 24 | -------------------------------------------------------------------------------- /profile/makebucket.c: -------------------------------------------------------------------------------- 1 | #include "bucket.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "amode.h" 8 | 9 | #if 0 10 | #define IS_MOVE(n, x) (((n) & 0xC000) == 0 && (((n) & 0x3000) != 0) \ 11 | && !strncmp ((x), "move", 4)) 12 | #endif 13 | 14 | 15 | int 16 | main (int argc, char *argv[]) 17 | { 18 | int num_buckets; 19 | static unsigned short bucket_map[65536]; 20 | static Bucket bucket[65536]; 21 | static struct { 22 | unsigned char has_amode, has_reversed_amode; 23 | const char *name; 24 | } amode_info[65536]; 25 | int num_amode_infos = 0; 26 | int pass; 27 | int i; 28 | 29 | if (argc != 2) 30 | { 31 | fprintf (stderr, "Usage: %s ", argv[0]); 32 | exit (-1); 33 | } 34 | 35 | num_buckets = 1; 36 | bucket[0].name = "unmapped_spew"; 37 | 38 | for (pass = 2; pass >= 0; pass--) 39 | { 40 | FILE *fp; 41 | char cmd[1024]; 42 | 43 | sprintf (cmd, "zcat %s", argv[1]); 44 | fp = popen (cmd, "r"); 45 | assert (fp != NULL); 46 | 47 | while (!feof (fp)) 48 | { 49 | int opcode, has_amode, has_reversed_amode, litmask, litbits; 50 | char name[1024]; /* Fixed length arrays usually bad, but not here. */ 51 | 52 | if (fscanf (fp, " %d %d %d %d %d %s", &opcode, &has_amode, 53 | &has_reversed_amode, &litmask, &litbits, name) != 6) 54 | break; 55 | 56 | /* Make sure we have the right # of amodes for this pass. */ 57 | if (has_amode + has_reversed_amode != pass) 58 | continue; 59 | 60 | /* See if anything else with the same root name exists, and if it 61 | * does, assume we have at least as many addressing modes as that 62 | * guy. Why? Well, the syngen process loses info about the 63 | * existence of amodes/reverse amodes in favor of rewriting the 64 | * 68k.scm code you give it to special case amodes like registers. 65 | * This hack will try to determine if there were originally amodes 66 | * in this opcode. 67 | */ 68 | for (i = num_amode_infos - 1; i >= 0; i--) 69 | if (!strcmp (amode_info[i].name, name)) 70 | { 71 | has_amode |= amode_info[i].has_amode; 72 | has_reversed_amode |= amode_info[i].has_reversed_amode; 73 | break; 74 | } 75 | 76 | /* If we didn't find a match, add a new entry to the table and 77 | * remember what amodes it has. 78 | */ 79 | if (i < 0) 80 | { 81 | amode_info[num_amode_infos].has_amode = has_amode; 82 | amode_info[num_amode_infos].has_reversed_amode 83 | = has_reversed_amode; 84 | amode_info[num_amode_infos].name 85 | = strcpy (malloc (strlen (name) + 1), name); 86 | num_amode_infos++; 87 | } 88 | 89 | /* Generate the canonical name. */ 90 | if (has_amode) 91 | sprintf (name + strlen (name), " %s", 92 | amode_to_string (opcode & 0x3F)); 93 | if (has_reversed_amode) 94 | sprintf (name + strlen (name), ", %s", 95 | amode_to_string (((opcode >> 9) & 7) 96 | | ((opcode >> 3) & 0x38))); 97 | 98 | /* Look for a bucket with the same canonical name. 99 | * Isn't O(n^2) great? 100 | */ 101 | for (i = num_buckets - 1; i >= 0; i--) 102 | if (!strcmp (bucket[i].name, name) 103 | && bucket[i].litmask == litmask 104 | && bucket[i].litbits == litbits) 105 | { 106 | bucket_map[opcode] = i; 107 | break; 108 | } 109 | 110 | /* Did we fail to find a matching bucket? If so, make a new one. */ 111 | if (i < 0) 112 | { 113 | Bucket *b = &bucket[num_buckets++]; 114 | b->name = strcpy (malloc (strlen (name) + 1), name); 115 | b->litbits = litbits; 116 | b->litmask = litmask; 117 | b->count = 0; 118 | bucket_map[opcode] = b - bucket; 119 | } 120 | } 121 | pclose (fp); 122 | } 123 | 124 | printf ("#include \"bucket.h\"\n" 125 | "\n" 126 | "Bucket bucket[%d] = {\n", 127 | num_buckets); 128 | for (i = 0; i < num_buckets; i++) 129 | printf (" { \"%s\", 0 },\n", bucket[i].name); 130 | puts ("};\n" 131 | "\n" 132 | "const unsigned short bucket_map[65536] = {"); 133 | 134 | for (i = 0; i < 65536; i++) 135 | { 136 | if (i % 8 == 0) 137 | fputs ("\n ", stdout); 138 | printf (" 0x%04X,", (unsigned) bucket_map[i]); 139 | } 140 | 141 | printf ("\n" 142 | "};\n" 143 | "const int num_buckets = %d;\n", 144 | num_buckets); 145 | 146 | return EXIT_SUCCESS; 147 | } 148 | -------------------------------------------------------------------------------- /profile/readprofile.c: -------------------------------------------------------------------------------- 1 | #include "readprofile.h" 2 | #include "syn68k_public.h" 3 | #include 4 | #include 5 | 6 | unsigned long instruction_count[65536]; 7 | 8 | void 9 | read_profile (const char *filename) 10 | { 11 | FILE *fp; 12 | 13 | fp = fopen (filename, "rb"); 14 | if (fp == NULL) 15 | { 16 | perror ("Unable to open file"); 17 | exit (-1); 18 | } 19 | 20 | /* Read in the data. */ 21 | if (fread (instruction_count, sizeof (unsigned long), 65536, fp) != 65536) 22 | { 23 | fprintf (stderr, "Premature end of file!\n"); 24 | exit (-3); 25 | } 26 | 27 | /* Byte swap if necessary. */ 28 | #ifdef LITTLEENDIAN 29 | { 30 | unsigned long *p = instruction_count; 31 | int i; 32 | 33 | for (i = 65535; i >= 0; p++, i--) 34 | *p = SWAPUL (*p); 35 | } 36 | #endif 37 | 38 | fclose (fp); 39 | } 40 | -------------------------------------------------------------------------------- /runtime/.gitignore: -------------------------------------------------------------------------------- 1 | mapindex.c 2 | mapinfo.c 3 | profileinfo.gz 4 | syn68k.c 5 | .deps 6 | -------------------------------------------------------------------------------- /runtime/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = native/i386 2 | 3 | lib_LIBRARIES = libsyn68k.a 4 | include_HEADERS = ../include/syn68k_public.h 5 | 6 | host_native=@HOST_NATIVE@ 7 | 8 | SYN68K_CFLAGS=@SYN68K_CFLAGS@ 9 | CLEANUP=@assembly_cleanup_script@ 10 | OPTIMIZE=@assembly_optimization_script@ 11 | 12 | # The way we use labels in our assembler is out of spec. The gcc info 13 | # pages say that you're not allowed to jump between labels of asm. 14 | # Historically, however, we chose not to put everything into a single 15 | # function and then jump about within spec. IIRC, that was either due 16 | # to the compilation time and memory consumption to be excessive 17 | # and/or due to us running into compiler bugs. This was all back 18 | # around 1995 though and we have more memory and better compilers. As 19 | # such, it may make sense to re-evaluate the decision to split all the 20 | # opcodes into separate functions. However, until we do that, we need 21 | # to deal with the fact that some dead-code-elimination (DCE) 22 | # optimizations will cause our trickery to fail. As such, we include 23 | # "-fno-dce" in the architectures where we know we're going to have trouble. 24 | 25 | dce_fixup=@dce_fixup@ 26 | 27 | AM_CFLAGS = -DRUNTIME 28 | 29 | DIST_SOURCES = 68k.defines.scm 68k.scm alloc.c backpatch.c block.c \ 30 | blockinfo.c callback.c checksum.c deathqueue.c destroyblock.c \ 31 | diagnostics.c dosinterrupts.c fold.pl hash.c i486-cleanup.pl \ 32 | i486-optimize.pl init.c interrupt.c native.c opcode_dummy.c \ 33 | profile.c rangetree.c recompile.c reg sched.pl syn68k_header.c \ 34 | translate.c trap.c x86_recog.pl \ 35 | \ 36 | include/alloc.h \ 37 | include/backpatch.h include/block.h include/blockinfo.h \ 38 | include/callback.h include/ccfuncs.h include/checksum.h \ 39 | include/deathqueue.h include/destroyblock.h \ 40 | include/diagnostics.h include/hash.h include/interrupt.h \ 41 | include/mapping.h include/native.h include/profile.h \ 42 | include/rangetree.h include/recompile.h include/translate.h \ 43 | include/trap.h \ 44 | \ 45 | native/i386/analyze.c native/i386/host-native.c \ 46 | native/i386/host-native.h native/i386/i386-aux.c \ 47 | native/i386/i386-aux.h native/i386/main.c \ 48 | native/i386/process.c native/i386/process.h \ 49 | native/i386/template.c native/i386/template.h \ 50 | native/i386/xlate-aux.c native/i386/xlate-aux.h \ 51 | native/i386/xlate.c native/i386/xlate.h \ 52 | native/i386/xlatemain.c native/i386/xlatetable.c \ 53 | \ 54 | native/null/Makefile native/null/host-native.h \ 55 | native/null/host-xlate.h 56 | 57 | LOCAL_INCLUDES = 58 | 59 | LOCAL_INCLUDES += -I$(srcdir)/include \ 60 | -I$(srcdir)/../include -I$(srcdir) -I../include 61 | 62 | LOCAL_CFLAGS = -DRUNTIME -Iinclude 63 | 64 | all: libsyn68k.a 65 | 66 | .c.o: 67 | $(CC) $(AM_CFLAGS) -c $(LOCAL_INCLUDES) $< -o $@ 68 | 69 | OBJS = block.o diagnostics.o hash.o rangetree.o translate.o alloc.o \ 70 | blockinfo.o trap.o destroyblock.o callback.o init.o interrupt.o \ 71 | profile.o dosinterrupts.o deathqueue.o checksum.o native.o \ 72 | backpatch.o recompile.o \ 73 | mapindex.o mapinfo.o syn68k.o opcode_dummy.o 74 | 75 | mapinfo.o: $(host_native)/host-xlate.h 76 | 77 | $(host_native)/host-xlate.h: 78 | $(MAKE) -C $(host_native) host-xlate.h 79 | 80 | .PHONY: $(host_native)/subdir-stmp 81 | 82 | $(host_native)/subdir-stmp: 83 | $(MAKE) -C $(host_native) subdir-stmp 84 | 85 | libsyn68k.a: $(OBJS) $(host_native)/subdir-stmp 86 | $(RM) libsyn68k.a 87 | $(AR) cq $@ $(OBJS) \ 88 | $(addprefix $(host_native)/, \ 89 | $(shell cat $(host_native)/subdir-stmp)) 90 | $(RANLIB) $@ 91 | 92 | # Syn68k uses inline assembly that confuses various gcc stack optimizations. 93 | # Under gcc 2.x -fno-defer-pop is sufficient to get gcc to do the right thing 94 | # with our code. Under gcc 3.x we need to also add -maccumulate-outgoing-args. 95 | # Since we don't know what gcc we have until we try to execute CC, we 96 | # do a test right here to figure out if the c-compiler understands 97 | # -maccumulate-outgoing-args. If it does, we use it. 98 | # 99 | # A better solution would be to put something into our asm to form a 100 | # barrier that gcc won't try to do stack optimizations across. I haven't yet 101 | # scoured the gcc 3 documentation or source code to see if there's something 102 | # obvious that can be used. 103 | 104 | syn68k.o: syn68k.c 105 | outgoing=;\ 106 | $(CC) -maccumulate-outgoing-args -c -x c /dev/null 2> /dev/null \ 107 | && outgoing=-maccumulate-outgoing-args; \ 108 | $(CC) -S $(SYN68K_CFLAGS) $(dce_fixup) -Wall -static -fno-defer-pop -Wno-unused\ 109 | $(LOCAL_INCLUDES) $$outgoing syn68k.c -o ./syn68k.s 110 | if [ x"$(CLEANUP)" != x ] ; then \ 111 | $(PERL) $(srcdir)/$(CLEANUP) < syn68k.s > syn68k.s.new && \ 112 | mv syn68k.s.new syn68k.s ; fi 113 | if [ x"$(OPTIMIZE)" != x ] ; then \ 114 | $(PERL) $(srcdir)/$(OPTIMIZE) < syn68k.s > syn68k.s.new && \ 115 | mv syn68k.s.new syn68k.s ; fi 116 | $(CC) -xassembler-with-cpp -c ./syn68k.s -o syn68k.o 117 | $(RM) ./syn68k.s 118 | 119 | syn68k.c mapindex.c mapinfo.c profileinfo.gz: ../syngen/syngen syn68k_header.c 68k.scm 68k.defines.scm\ 120 | ../include/syn68k_private.h \ 121 | ../runtime/include/hash.h \ 122 | ../runtime/include/interrupt.h \ 123 | ../runtime/include/trap.h 124 | if [ "$(srcdir)" != "." ]; then \ 125 | cp -p $(srcdir)/68k.scm $(srcdir)/syn68k_header.c $(srcdir)/68k.defines.scm . ; \ 126 | fi 127 | ../syngen/syngen -v 68k.scm 128 | gzip -1f profileinfo 129 | 130 | clean-local: 131 | -rm -rf mapinfo.c syn68k.c mapindex.c \ 132 | profileinfo.gz bucket.c native/i386/asmdata.h \ 133 | native/i386/i386-isa.h native/i386/subdir-stmp \ 134 | native/i386/host-xlate.c native/i386/src-stmp \ 135 | native/i386/i386_stubs native/i386/template \ 136 | native/i386/host-xlate.h native/i386/xlate 137 | if [ "$(srcdir)" != "." ]; then \ 138 | rm -f 68k.scm syn68k_header.c 68k.defines.scm; \ 139 | fi 140 | -------------------------------------------------------------------------------- /runtime/TODO: -------------------------------------------------------------------------------- 1 | 2) Make generate_amode_fetch() in translate.c have the parameter m68k_operand 2 | be a syn68k_addr_t instead of a uint16 *, and then ditch all of the 3 | US_TO_SYN68K's that become superfluous. 4 | 5 | 6 | PERFORMANCE TWEAKS: 7 | -------------------------------------------------------------------------------- /runtime/alloc.c: -------------------------------------------------------------------------------- 1 | #include "alloc.h" 2 | #include "destroyblock.h" 3 | #include 4 | #include 5 | 6 | void * 7 | xmalloc (size_t size) 8 | { 9 | void *p; 10 | 11 | while ((p = malloc (size)) == NULL) 12 | { 13 | if (!destroy_any_block ()) 14 | { 15 | fprintf (stderr, "Out of memory. Tried to alloc 0x%lX bytes.\n", 16 | (unsigned long) size); 17 | exit (-1); 18 | } 19 | } 20 | 21 | return p; 22 | } 23 | 24 | 25 | void * 26 | xrealloc (void *old, size_t new_size) 27 | { 28 | void *p; 29 | 30 | while ((p = realloc (old, new_size)) == NULL && new_size) 31 | { 32 | if (!destroy_any_block ()) 33 | { 34 | fprintf (stderr, "Out of memory. Tried to realloc 0x%lX bytes.\n", 35 | (unsigned long) new_size); 36 | exit (-1); 37 | } 38 | } 39 | 40 | return p; 41 | } 42 | 43 | 44 | void * 45 | xcalloc (size_t num_elems, size_t byte_size) 46 | { 47 | void *p; 48 | 49 | while ((p = calloc (num_elems, byte_size)) == NULL) 50 | { 51 | if (!destroy_any_block ()) 52 | { 53 | fprintf (stderr, "Out of memory. Tried to calloc 0x%lX bytes.\n", 54 | (unsigned long) (num_elems * byte_size)); 55 | exit (-1); 56 | } 57 | } 58 | 59 | return p; 60 | } 61 | -------------------------------------------------------------------------------- /runtime/backpatch.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include "syn68k_private.h" 4 | #include "backpatch.h" 5 | #include "alloc.h" 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | void 12 | backpatch_apply_and_free (Block *b, backpatch_t *p) 13 | { 14 | ptr_sized_uint value; 15 | uint32 first_byte; 16 | int length; 17 | BOOL found_p; 18 | backpatch_t **bp; 19 | char *base; 20 | 21 | /* Find the backpatch in the block's list and remove it. */ 22 | for (bp = &b->backpatch, found_p = FALSE; *bp != NULL; bp = &(*bp)->next) 23 | if (*bp == p) 24 | { 25 | *bp = p->next; 26 | found_p = TRUE; 27 | break; 28 | } 29 | 30 | #ifdef DEBUG 31 | /* Make sure we actually found it in the list. */ 32 | if (!found_p) 33 | abort (); 34 | #endif 35 | 36 | if (p->target == NULL) 37 | base = (char *)0; 38 | else 39 | base = (char *)p->target->compiled_code; 40 | 41 | /* First, compute the value to write out to memory. */ 42 | first_byte = p->offset_location / 8; 43 | length = p->num_bits; 44 | if (p->relative_p) 45 | { 46 | value = ((base + p->const_offset) 47 | - ((char *)b->compiled_code + first_byte)); 48 | } 49 | else 50 | { 51 | value = ((ptr_sized_uint)(base + p->const_offset)); 52 | } 53 | #ifndef QUADALIGN 54 | if ((p->offset_location & 7) == 0) 55 | { 56 | if (length == 32) 57 | *(uint32 *)((char *)b->compiled_code + first_byte) = value; 58 | else if (length == 16) 59 | *(uint16 *)((char *)b->compiled_code + first_byte) = value; 60 | else if (length == 8) 61 | *(uint8 *)((char *)b->compiled_code + first_byte) = value; 62 | #if SIZEOF_CHAR_P == 8 63 | else if (length == 64) 64 | *(uint64 *)((char *)b->compiled_code + first_byte) = value; 65 | #endif 66 | else 67 | abort (); 68 | } 69 | else 70 | { 71 | abort (); 72 | } 73 | #else /* QUADALIGN */ 74 | /* The whole guy had better fit in one long! */ 75 | if ((p->offset_location & ~31) 76 | == ((p->offset_location + length - 1) & ~31)) 77 | { 78 | uint32 *ptr = (uint32 *)((char *)b->compiled_code + first_byte); 79 | if (length == 32) 80 | *ptr = value; 81 | else 82 | { 83 | int offset = p->offset_location & 31; 84 | #error "Write this case" 85 | #ifdef LITTLEENDIAN 86 | *ptr = (*ptr & ) | ; 87 | #else /* !LITTLEENDIAN */ 88 | *ptr = (*ptr & ) | ; 89 | #endif /* !LITTLEENDIAN */ 90 | } 91 | } 92 | else 93 | abort (); 94 | #endif /* QUADALIGN */ 95 | 96 | free (p); 97 | } 98 | 99 | 100 | void 101 | backpatch_add (Block *b, int offset_location, int num_bits, BOOL relative_p, 102 | int const_offset, Block *target) 103 | { 104 | backpatch_t *p; 105 | 106 | #ifdef DEBUG 107 | if (num_bits == 0) 108 | abort (); 109 | #endif 110 | 111 | p = (backpatch_t *) xmalloc (sizeof *p); 112 | p->next = b->backpatch; 113 | p->offset_location = offset_location; 114 | p->num_bits = num_bits; 115 | p->relative_p = relative_p; 116 | p->const_offset = const_offset; 117 | p->target = target; 118 | 119 | /* Prepend this guy to the block's list. */ 120 | b->backpatch = p; 121 | } 122 | -------------------------------------------------------------------------------- /runtime/callback.c: -------------------------------------------------------------------------------- 1 | #include "callback.h" 2 | #include "rangetree.h" 3 | #include "block.h" 4 | #include "alloc.h" 5 | #include "hash.h" 6 | #include "destroyblock.h" 7 | #include "deathqueue.h" 8 | #include "checksum.h" 9 | #include "translate.h" 10 | #include 11 | #include 12 | #include 13 | 14 | typedef struct { 15 | callback_handler_t func; 16 | void *arg; 17 | } CallBackInfo; 18 | 19 | CallBackInfo *callback; 20 | int num_callback_slots; 21 | int lowest_free_callback_slot; 22 | 23 | /* We just use this array to reserve some dereferenceable address 24 | * space to hold the callbacks, because we need memory locations we 25 | * know can never contain 68k code. We don't actually store anything 26 | * there. 27 | */ 28 | uint16 callback_dummy_address_space[MAX_CALLBACKS + CALLBACK_SLOP]; 29 | 30 | void 31 | callback_init (void) 32 | { 33 | callback = NULL; 34 | num_callback_slots = 0; 35 | lowest_free_callback_slot = 0; 36 | } 37 | 38 | 39 | /* Installs a given callback function at a given 68k address. If the 68k 40 | * ever executes code at that address, the callback function will be called 41 | * and provided with the 68k address of the callback and an arbitrary 42 | * 32 bit argument. If some block is already present at the specified 43 | * address, does nothing and returns 0. Otherwise, returns 1. 44 | */ 45 | int 46 | callback_compile (Block *parent, syn68k_addr_t m68k_address, Block **new) 47 | { 48 | Block *b; 49 | uint16 *code; 50 | uint32 ix = (m68k_address - CALLBACK_STUB_BASE) / sizeof (uint16); 51 | const CallBackInfo *callback_info = &callback[ix]; 52 | 53 | /* Make sure a callback is actually installed. */ 54 | if (ix >= num_callback_slots || callback_info->func == NULL) 55 | { 56 | *new = NULL; 57 | return 0; 58 | } 59 | 60 | b = *new = make_artificial_block (parent, m68k_address, 61 | OPCODE_WORDS + PTR_WORDS + PTR_WORDS + 2, 62 | &code); 63 | 64 | /* Create the synthetic code for the callback. */ 65 | #ifdef USE_DIRECT_DISPATCH 66 | *(const void **)code = direct_dispatch_table[0xB3]; /* callback opcode. */ 67 | #else 68 | *(void **)code = (void *)0xB3; /* Magical callback synthetic opcode. */ 69 | #endif 70 | *((callback_handler_t *) (code + OPCODE_WORDS)) = callback_info->func; 71 | *(void **)(code + OPCODE_WORDS + PTR_WORDS) = callback_info->arg; 72 | *(syn68k_addr_t *)(code + OPCODE_WORDS + PTR_WORDS + PTR_WORDS) 73 | = m68k_address; 74 | 75 | /* Insert block into the universe of blocks. */ 76 | hash_insert (b); 77 | range_tree_insert (b); 78 | 79 | /* Add this block to the end of the death queue. */ 80 | death_queue_enqueue (b); 81 | 82 | b->immortal = FALSE; 83 | 84 | return ALL_CCS; 85 | } 86 | 87 | 88 | /* Installs a callback stub in the 68k space and returns the 68k address 89 | * it chose for this stub. Any 68k code that hits this stub will call 90 | * the specified callback function. func must never be NULL. 91 | */ 92 | syn68k_addr_t 93 | callback_install (callback_handler_t func, void *arbitrary_argument) 94 | { 95 | uint32 slot; 96 | int old_sigmask; 97 | 98 | BLOCK_INTERRUPTS (old_sigmask); 99 | slot = lowest_free_callback_slot; 100 | 101 | if (lowest_free_callback_slot >= num_callback_slots) 102 | { 103 | if (num_callback_slots >= MAX_CALLBACKS) 104 | { 105 | fprintf (stderr, "Internal error: syn68k out of callback slots!\n"); 106 | abort (); 107 | } 108 | 109 | ++num_callback_slots; 110 | callback = (CallBackInfo *) xrealloc (callback, (num_callback_slots 111 | * sizeof callback[0])); 112 | } 113 | 114 | /* Remember the callback they are specifying. */ 115 | callback[slot].func = func; 116 | callback[slot].arg = arbitrary_argument; 117 | 118 | /* Move lowest free callback slot to next lowest slot. */ 119 | for (lowest_free_callback_slot++; ; lowest_free_callback_slot++) 120 | if (lowest_free_callback_slot >= num_callback_slots 121 | || callback[lowest_free_callback_slot].func == NULL) 122 | break; 123 | 124 | /* Reenable interrupts. */ 125 | RESTORE_INTERRUPTS (old_sigmask); 126 | 127 | return CALLBACK_STUB_BASE + (slot * sizeof (uint16)); 128 | } 129 | 130 | 131 | void * 132 | callback_argument (syn68k_addr_t callback_address) 133 | { 134 | uint32 ix = (callback_address - CALLBACK_STUB_BASE) / sizeof (uint16); 135 | 136 | if (ix >= num_callback_slots) 137 | return NULL; 138 | return callback[ix].arg; 139 | } 140 | 141 | 142 | callback_handler_t 143 | callback_function (syn68k_addr_t callback_address) 144 | { 145 | uint32 ix = (callback_address - CALLBACK_STUB_BASE) / sizeof (uint16); 146 | 147 | if (ix >= num_callback_slots) 148 | return NULL; 149 | return callback[ix].func; 150 | } 151 | 152 | 153 | void 154 | callback_remove (syn68k_addr_t m68k_address) 155 | { 156 | uint32 ix; 157 | Block *b; 158 | int old_sigmask; 159 | 160 | BLOCK_INTERRUPTS (old_sigmask); 161 | 162 | /* Fetch the block at that address. */ 163 | b = hash_lookup (m68k_address); 164 | if (b != NULL) 165 | destroy_block (b); 166 | 167 | ix = (m68k_address - CALLBACK_STUB_BASE) / sizeof (uint16); 168 | if (ix < num_callback_slots) 169 | { 170 | if (ix == num_callback_slots - 1) 171 | { 172 | --num_callback_slots; 173 | callback = (CallBackInfo *) xrealloc (callback, 174 | (num_callback_slots 175 | * sizeof callback[0])); 176 | } 177 | else 178 | { 179 | callback[ix].func = NULL; 180 | if (ix < lowest_free_callback_slot) 181 | lowest_free_callback_slot = ix; 182 | } 183 | } 184 | 185 | RESTORE_INTERRUPTS (old_sigmask); 186 | } 187 | -------------------------------------------------------------------------------- /runtime/checksum.c: -------------------------------------------------------------------------------- 1 | #define INLINE_CHECKSUM 2 | #include "checksum.h" 3 | 4 | 5 | #ifdef CHECKSUM_BLOCKS 6 | uint32 7 | compute_block_checksum (const Block *b) 8 | { 9 | return inline_compute_block_checksum (b); 10 | } 11 | #endif /* CHECKSUM_BLOCKS */ 12 | -------------------------------------------------------------------------------- /runtime/deathqueue.c: -------------------------------------------------------------------------------- 1 | #include "deathqueue.h" 2 | 3 | 4 | Block *death_queue_head = NULL, *death_queue_tail = NULL; 5 | 6 | 7 | /* Appends a block to the end of the doubly-linked death queue. */ 8 | void 9 | death_queue_enqueue (Block *b) 10 | { 11 | b->death_queue_prev = death_queue_tail; 12 | b->death_queue_next = NULL; 13 | 14 | if (death_queue_tail == NULL) 15 | death_queue_head = b; 16 | else 17 | death_queue_tail->death_queue_next = b; 18 | 19 | death_queue_tail = b; 20 | } 21 | 22 | 23 | /* Removes a block from the end of the doubly-linked death queue. */ 24 | void 25 | death_queue_dequeue (Block *b) 26 | { 27 | Block *p, *n; 28 | 29 | p = b->death_queue_prev; 30 | n = b->death_queue_next; 31 | 32 | if (p == NULL) 33 | { 34 | if (death_queue_head == b) /* Verify this just to be safe. */ 35 | death_queue_head = n; 36 | } 37 | else 38 | p->death_queue_next = n; 39 | 40 | if (n == NULL) 41 | { 42 | if (death_queue_tail == b) /* Verify this just to be safe. */ 43 | death_queue_tail = p; 44 | } 45 | else 46 | n->death_queue_prev = p; 47 | 48 | b->death_queue_prev = b->death_queue_next = NULL; 49 | } 50 | -------------------------------------------------------------------------------- /runtime/diagnostics.c: -------------------------------------------------------------------------------- 1 | #include "diagnostics.h" 2 | #include "deathqueue.h" 3 | 4 | void 5 | print_cc_bits (FILE *stream, int bits) 6 | { 7 | int i; 8 | 9 | for (i = 4; i >= 0; i--) 10 | if (bits & (1 << i)) 11 | putc ("ZXVNC"[i], stream); 12 | else putc ('-', stream); 13 | } 14 | 15 | 16 | void 17 | hexdump (const uint16 *addr, int num_words) 18 | { 19 | while (num_words--) 20 | printf ("\t0x%04X\n", (unsigned) *addr++); 21 | } 22 | 23 | 24 | void 25 | dump_cpu_state (void) 26 | { 27 | int i; 28 | 29 | for (i = 0; i < 16; i++) 30 | { 31 | 32 | #if !defined(__alpha) 33 | printf ("%c%d = 0x%08lX ", "da"[i >> 3], i % 8, cpu_state.regs[i].ul.n); 34 | #else 35 | printf ("%c%d = 0x%08X ", "da"[i >> 3], i % 8, cpu_state.regs[i].ul.n); 36 | #endif 37 | 38 | if ((i & 3) == 3) 39 | fputs ("\n\t", stdout); 40 | } 41 | printf ("c:%d n:%d v:%d x:%d z:%d\n", 42 | !!cpu_state.ccc, !!cpu_state.ccn, !!cpu_state.ccv, !!cpu_state.ccx, 43 | !cpu_state.ccnz); 44 | putchar ('\n'); 45 | } 46 | 47 | 48 | /* Given a PC (either synthetic or native), tries to find the m68k 49 | * block corresponding to that PC and prints it out. For debugging. 50 | */ 51 | void 52 | m68kaddr (const uint16 *pc) 53 | { 54 | const Block *b, *best_block; 55 | unsigned long best_error; 56 | 57 | best_error = 0xFFFFFFFF; 58 | best_block = NULL; 59 | for (b = death_queue_head; b != NULL; b = b->death_queue_next) 60 | { 61 | if (b->compiled_code <= pc) 62 | { 63 | unsigned long error = pc - b->compiled_code; 64 | if (error < best_error) 65 | { 66 | best_error = error; 67 | best_block = b; 68 | } 69 | } 70 | } 71 | 72 | if (best_block == NULL) 73 | { 74 | puts ("No matching m68k block found."); 75 | } 76 | else 77 | { 78 | printf ("Best guess m68k block start address 0x%lx, offset %lu bytes, " 79 | "block (Block *)%p\n", 80 | (unsigned long) best_block->m68k_start_address, 81 | best_error, (void *) best_block); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /runtime/dosinterrupts.c: -------------------------------------------------------------------------------- 1 | #ifdef MSDOS 2 | 3 | #include "syn68k_private.h" 4 | 5 | #ifndef SYNCHRONOUS_INTERRUPTS 6 | 7 | int 8 | dos_block_interrupts () 9 | { 10 | unsigned long iflag; 11 | asm ("pushfl\n\t" /* We save the old eflags, which has interrupt mask bit. */ 12 | "popl %0\n\t" 13 | "shrl $9,%0\n\t" 14 | "andl $1,%0\n\t" 15 | "jz 1f\n\t" /* Avoid CLI overhead under DPMI. */ 16 | "cli\n" 17 | "1:" 18 | : "=r" (iflag) 19 | : : "cc"); 20 | return iflag; 21 | } 22 | 23 | 24 | void 25 | dos_restore_interrupts (int onoff) 26 | { 27 | unsigned long current_iflag; 28 | 29 | asm ("pushfl\n\t" /* We save the old eflags, which has interrupt mask bit. */ 30 | "popl %0\n\t" 31 | "shrl $9,%0\n\t" 32 | "andl $1,%0" 33 | : "=r" (current_iflag) 34 | : : "cc"); 35 | 36 | if (onoff != current_iflag) 37 | { 38 | /* Only execute these when necessary, to avoid DPMI overhead. */ 39 | if (onoff) 40 | asm ("sti"); 41 | else 42 | asm ("cli"); 43 | } 44 | } 45 | 46 | #endif /* !SYNCHRONOUS_INTERRUPTS */ 47 | 48 | #endif /* MSDOS */ 49 | -------------------------------------------------------------------------------- /runtime/fold.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | $* = 1; # Enable multi-line patterns 3 | 4 | print STDERR "Parsing file..."; 5 | 6 | 7 | # Read the entire file into core, splitting it up into pseudo-basic blocks 8 | while (<>){ 9 | next if /^\s*$/; # Skip blank lines 10 | 11 | if (/\s*\.align/ || !$started) 12 | { 13 | if ($current_block) 14 | { 15 | push (@blocks, $current_block); 16 | push (@block_names, $current_block_name); 17 | } 18 | 19 | $current_block = $_; 20 | $current_block_name = ""; 21 | $started = 1; 22 | } 23 | elsif ($current_block && !$current_block_name && /^\w.*:$/) 24 | { 25 | $current_block .= "xx#BLOCK_NAME_HERE\n"; 26 | $current_block_name = $_; 27 | chop $current_block_name; 28 | $current_block_name =~ s/://g; 29 | } 30 | elsif ($current_block) 31 | { 32 | # Note: we don't add the name of the block to the block itself. 33 | $current_block .= $_; 34 | } 35 | } 36 | 37 | # Clean up any stuff left around at end of file 38 | if ($current_block) 39 | { 40 | push (@blocks, $current_block); 41 | push (@block_names, $current_block_name); 42 | } 43 | 44 | 45 | print STDERR "done.\n"; 46 | 47 | 48 | sub eliminate_duplicates 49 | { 50 | local (%blocks_found, $old, $new, $old_name, $new_name, $b, $bname, $n, 51 | $x, $clobbered_blocks, $clobbered_lines, @clobbered_old, 52 | @clobbered_new, @clobbered_old_s68k, @clobbered_new_s68k, 53 | @clobbered_old_non_s68k, @clobbered_new_non_s68k); 54 | 55 | print STDERR "Pass $pass:\t"; 56 | 57 | # Loop over all the blocks, looking for duplicates. 58 | $new = 0; 59 | $clobbered_blocks = 0; 60 | $clobbered_lines = 0; 61 | foreach $old (0 .. $#blocks) 62 | { 63 | $b = $blocks[$old]; 64 | $bname = $block_names[$old]; 65 | 66 | # If this block is redundant, add it to the clobbered list. 67 | if ($bname && $blocks_found{$b}) 68 | { 69 | # Create regexps for the old/new to replace 70 | $old_name = $bname; $old_name =~ s/(\W)/\\$1/g; 71 | $new_name = $blocks_found{$b}; $new_name =~ s/(\W)/\\$1/g; 72 | push (@clobbered_old, $old_name); 73 | push (@clobbered_new, $new_name); 74 | $clobbered_blocks++; 75 | $clobbered_lines += split (' ', $b); 76 | } 77 | else # Save this block 78 | { 79 | $blocks[$new] = $b; 80 | $block_names[$new] = $bname; 81 | $blocks_found{$b} = $bname; 82 | $new++; 83 | } 84 | } 85 | 86 | # Print out a status report. 87 | print STDERR "eliminating $clobbered_blocks/", $#blocks + 1, " blocks ", 88 | "($clobbered_lines lines)..."; 89 | 90 | # If we found something to clobber, clean everything up. 91 | if ($clobbered_blocks) 92 | { 93 | # Truncate the blocks array to the new number of blocks. 94 | $#blocks = $new - 1; 95 | $#block_names = $new - 1; 96 | 97 | # Divide up the replace strings into two classes, for speed. 98 | foreach $n (0 .. $#clobbered_old) 99 | { 100 | if (@clobbered_old[$n] =~ /_S68K_/) 101 | { 102 | push (@clobbered_old_s68k, @clobbered_old[$n]); 103 | push (@clobbered_new_s68k, @clobbered_new[$n]); 104 | } 105 | else 106 | { 107 | push (@clobbered_old_non_s68k, @clobbered_old[$n]); 108 | push (@clobbered_new_non_s68k, @clobbered_new[$n]); 109 | } 110 | } 111 | 112 | foreach $n (0 .. $#blocks) 113 | { 114 | # Dump out this block if it's unique or special. 115 | if (!$block_names[$n] 116 | || $blocks_found{@blocks[$n]} eq $block_names[$n]) 117 | { 118 | $b = $blocks[$n]; 119 | $b =~ s/xx#BLOCK_NAME_HERE/$block_names[$n]:/g; 120 | 121 | # Replace any _S68K_ labels (if there are any here). 122 | if ($b =~ /_S68K_/) 123 | { 124 | foreach $x (0 .. $#clobbered_old_s68k) 125 | { 126 | $old_name = $clobbered_old_s68k[x]; 127 | $new_name = $clobbered_new_s68k[x]; 128 | if ($b =~ /$old_name/) 129 | { 130 | $b =~ s/$old_name,/$new_name,/g; 131 | $b =~ s/$old_name$/$new_name$/g; 132 | 133 | # If we didn't eliminate the old label, fail! 134 | die "I'm afraid to replace \"$old_name\" in this ", 135 | "block:\n", $b if ($b =~ /$old_name/); 136 | } 137 | } 138 | } 139 | 140 | # Replace any non-_S68K_ labels. 141 | foreach $x (0 .. $#clobbered_old_non_s68k) 142 | { 143 | $old_name = $clobbered_old_non_s68k[x]; 144 | $new_name = $clobbered_new_non_s68k[x]; 145 | if ($b =~ /$old_name/) 146 | { 147 | $b =~ s/$old_name,/$new_name,/g; 148 | $b =~ s/$old_name$/$new_name$/g; 149 | 150 | # If we didn't eliminate the old label, fail! 151 | die "I'm afraid to replace \"$old_name\" in this ", 152 | "block:\n", $b if ($b =~ /$old_name/); 153 | } 154 | } 155 | $blocks[$n] = $b; 156 | } 157 | } 158 | } 159 | 160 | print STDERR "done.\n"; 161 | return $clobbered_blocks; 162 | } 163 | 164 | 165 | # Keep eliminating duplicates until nothing changes. 166 | $pass = 1; 167 | while (&eliminate_duplicates ()) 168 | { 169 | $pass++; 170 | } 171 | 172 | 173 | # Print out all of the blocks. 174 | foreach $n (0 .. $#blocks) 175 | { 176 | print $blocks[$n]; 177 | } 178 | -------------------------------------------------------------------------------- /runtime/hash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * hash.c - Routines for manipulating a hash table that maps 68k addresses 3 | * to the basic block that begins at that address. This exists 4 | * in addition to the range tree because runtime lookups are much 5 | * faster. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "hash.h" 13 | #include "alloc.h" 14 | #include "translate.h" 15 | 16 | 17 | /* Fixed size hash table, indexed by BLOCK_HASH (block->m68k_start_address). */ 18 | Block *block_hash_table[NUM_HASH_BUCKETS]; 19 | 20 | 21 | /* Initializes the hash table. Call this before calling any other hash 22 | * functions, and call it exactly once. 23 | */ 24 | void 25 | hash_init () 26 | { 27 | memset (block_hash_table, 0, sizeof block_hash_table); 28 | } 29 | 30 | 31 | /* Removes all blocks from the hash table and deallocates all space used by 32 | * the hash table. 33 | */ 34 | void 35 | hash_destroy () 36 | { 37 | Block *b, *next; 38 | int i; 39 | 40 | /* Remove all Blocks from the hash table. */ 41 | for (i = 0; i < NUM_HASH_BUCKETS; i++) 42 | for (b = block_hash_table[i]; b != NULL; b = next) 43 | { 44 | next = b->next_in_hash_bucket; 45 | b->next_in_hash_bucket = NULL; 46 | } 47 | 48 | memset (block_hash_table, 0, sizeof block_hash_table); 49 | } 50 | 51 | 52 | /* Finds the block associated with a given 68k address and returns a pointer 53 | * to that block. Returns NULL iff no block starting at that address exists. 54 | * Note that it is possible the address specified may fall inside a block of 55 | * compiled code but not at the beginning; this routine will not detect that 56 | * situation. If you want to know what block contains a given address when 57 | * that address may not refer to the first byte of a block, call the slower 58 | * range_tree_lookup (addr) function found in rangetree.c 59 | */ 60 | Block * 61 | hash_lookup (syn68k_addr_t addr) 62 | { 63 | Block *bucket = block_hash_table[BLOCK_HASH (addr)]; 64 | 65 | for (; bucket != NULL; bucket = bucket->next_in_hash_bucket) 66 | if (bucket->m68k_start_address == addr) 67 | return bucket; 68 | 69 | return NULL; 70 | } 71 | 72 | 73 | /* Similar to hash_lookup(), but this returns a pointer to the compiled 74 | * code associated with a given 68k address instead of to the block associated 75 | * with that code. If no compiled code exists for that block, code is 76 | * compiled for that block and a pointer to the new code is returned. This 77 | * function is guaranteed to return a non-NULL pointer to valid code. 78 | */ 79 | const uint16 * 80 | hash_lookup_code_and_create_if_needed (syn68k_addr_t addr) 81 | { 82 | Block *b, *bucket, **bucket_ptr; 83 | int old_sigmask; 84 | 85 | bucket_ptr = &block_hash_table[BLOCK_HASH (addr)]; 86 | bucket = *bucket_ptr; 87 | 88 | /* If there's anything in this bucket, check for a match. */ 89 | if (bucket != NULL) 90 | { 91 | Block *prev, *next; 92 | 93 | /* See if we get a match in the first element. */ 94 | if (bucket->m68k_start_address == addr) 95 | return bucket->compiled_code; 96 | 97 | /* See if we get a match in a later element. If we do, move it 98 | * to the head of the list, since it is likely to be referenced 99 | * again. 100 | */ 101 | for (prev = bucket; (next = prev->next_in_hash_bucket) != NULL; 102 | prev = next) 103 | { 104 | if (next->m68k_start_address == addr) 105 | { 106 | BLOCK_INTERRUPTS (old_sigmask); 107 | prev->next_in_hash_bucket = next->next_in_hash_bucket; 108 | next->next_in_hash_bucket = bucket; 109 | *bucket_ptr = next; 110 | RESTORE_INTERRUPTS (old_sigmask); 111 | return next->compiled_code; 112 | } 113 | } 114 | } 115 | 116 | BLOCK_INTERRUPTS (old_sigmask); 117 | generate_block (NULL, addr, &b, FALSE); 118 | RESTORE_INTERRUPTS (old_sigmask); 119 | 120 | /* Call the user-defined function to let them know we're done. */ 121 | if (call_while_busy_func != NULL) 122 | call_while_busy_func (0); 123 | 124 | return b->compiled_code; 125 | } 126 | 127 | 128 | /* Inserts a given block into the hash table based on it's m68k_start_address. 129 | * Inserting a block twice is illegal but is not checked for. 130 | */ 131 | void 132 | hash_insert (Block *b) 133 | { 134 | uint32 addr = b->m68k_start_address; 135 | Block **bucket = &block_hash_table[BLOCK_HASH (addr)]; 136 | 137 | /* Prepend this block to the beginning of the list. */ 138 | b->next_in_hash_bucket = *bucket; 139 | *bucket = b; 140 | } 141 | 142 | 143 | /* Removes a given block from the hash table. If it's not in the hash 144 | * table, no action is taken. 145 | */ 146 | void 147 | hash_remove (Block *b) 148 | { 149 | Block **bucket = &block_hash_table[BLOCK_HASH (b->m68k_start_address)]; 150 | 151 | for (; *bucket != NULL; bucket = &(*bucket)->next_in_hash_bucket) 152 | if (*bucket == b) 153 | { 154 | *bucket = b->next_in_hash_bucket; 155 | break; 156 | } 157 | } 158 | 159 | 160 | 161 | #ifdef DEBUG 162 | /* Runs through and checks the hash table for consistency. Returns YES 163 | * if everything is OK, NO if something is bad (in which case it prints 164 | * out appropriate errors to stderr.) 165 | */ 166 | BOOL 167 | hash_verify () 168 | { 169 | BOOL ok = YES; 170 | int i; 171 | Block *b, *b2; 172 | 173 | for (i = 0; i < NUM_HASH_BUCKETS; i++) 174 | for (b = block_hash_table[i]; b != NULL; b = b->next_in_hash_bucket) 175 | { 176 | if (!block_verify (b)) 177 | ok = NO; 178 | if (BLOCK_HASH (b->m68k_start_address) != i) 179 | { 180 | fprintf (stderr, "Internal inconsistency: Block 0x%lX seems to " 181 | "have ended up in hash bucket %d instead of hash " 182 | "bucket %d where it belongs.\n", 183 | b->m68k_start_address, i, 184 | BLOCK_HASH (b->m68k_start_address)); 185 | ok = NO; 186 | } 187 | 188 | for (b2 = b->next_in_hash_bucket; b2; b2 = b2->next_in_hash_bucket) 189 | if (b->m68k_start_address == b2->m68k_start_address) 190 | { 191 | fprintf (stderr, "Internal inconsistency: More than one block " 192 | "in the hash table has the same m68k_start_address " 193 | "(0x%lX).\n", b->m68k_start_address); 194 | ok = NO; 195 | break; 196 | } 197 | } 198 | 199 | return ok; 200 | } 201 | #endif 202 | 203 | 204 | #ifdef DEBUG 205 | void 206 | hash_stats () 207 | { 208 | int i, max = 0, sum = 0; 209 | 210 | for (i = 0; i < NUM_HASH_BUCKETS; i++) 211 | { 212 | int n; 213 | Block *b; 214 | 215 | for (n = 0, b = block_hash_table[i]; b != NULL; n++, 216 | b = b->next_in_hash_bucket); 217 | if (n > max) 218 | max = n; 219 | sum += n; 220 | } 221 | 222 | printf ("Hash stats: %d entries, %.2f average per bucket, %d in deepest " 223 | "bucket.\n", 224 | sum, (double) sum / NUM_HASH_BUCKETS, max); 225 | } 226 | 227 | #endif 228 | -------------------------------------------------------------------------------- /runtime/i486-cleanup.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -ni 2 | 3 | # This perl script strips out the extra cruft created as a side effect of 4 | # splitting syn68k.c into many functions. This will make the resulting 5 | # syn68k.o file smaller and also force the real branch targets to be 6 | # aligned optimally. 7 | 8 | # Delete the header for each function 9 | if (/^\.globl _?s68k_handle_opcode_0x/ .. /^[#\/]APP$|^_?S68K_HANDLE_0x....:$/) 10 | { 11 | print if (/^[#\/]APP/ || /^L/ || /^_?S68K_HANDLE_0x....:$/); 12 | } 13 | 14 | # Delete the trailer for each function 15 | elsif (/_S68K_DONE_WITH/ .. /^\s*ret$|^\s*jmp\s+_s68k_handle_opcode_dummy$/) 16 | { 17 | print if (!/\s*movl %ebp,%esp$/ 18 | && !/\s*leal\s*(-?\d+)?\(%ebp\),%esp$/ 19 | && !/\s*movl\s*(-?\d+)?\(%ebp\),%edi$/ 20 | && !/\s*popl/ 21 | && !/\s*ret$/ 22 | && !/^_S68K_DONE_WITH/ 23 | && !/s68k_handle_opcode/ 24 | && !/^\s*jmp\s+_s68k_handle_opcode_dummy$/); 25 | } 26 | elsif (/^\s*lods/) 27 | { 28 | die "lods not allowed; we're punting cld's these days."; 29 | } 30 | # elsif (/^\s*call/ && !/s68k_handle_opcode/) 31 | # { # no longer necessary since we punted lodsl 32 | # print "$_\tcld\n"; 33 | # } 34 | elsif (!/s68k_handle_opcode/) 35 | { 36 | print; 37 | } 38 | -------------------------------------------------------------------------------- /runtime/i486-optimize.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -ni 2 | 3 | chop; 4 | next if (/^[\#\/](NO_)?APP/ || /^\s*$/); 5 | $cur = $_; 6 | $first_changed = 0; 7 | 8 | 9 | # First we handle mapping cases like: 10 | # _S68K_HANDLE_0x00B5: 11 | # movw _cpu_state+4,%ax 12 | # movw (%esi),%bx 13 | # 14 | # to: 15 | # 16 | # _S68K_HANDLE_0x00B5: 17 | # movl _cpu_state+4,%eax 18 | # movl (%esi),%ebx 19 | # 20 | # Because we know cpu_state and %esi-relative pointers will be long-aligned, 21 | # and long ops are faster and more pairable than word ops. 22 | 23 | if ($prev_first_changed 24 | && ((($mem, $reg) = /^\s*movw (_cpu_state\+?\d*),%(ax|bx|cx|dx|di)$/) 25 | || (($mem, $reg) = /^\s*movw (\d*\(%esi\)),%(ax|bx|cx|dx|di)$/)) 26 | && ($prev !~ /$reg/)) { 27 | $cur = "\tmovl " . $mem . ",%e" . $reg; 28 | } 29 | if ($prev =~ /^_S68K_HANDLE_/) { 30 | if ((($mem, $reg) = /^\s*mov[wl] (_cpu_state\+?\d*),%e?(ax|bx|cx|dx|di)$/) 31 | || (($mem, $reg) = /^\s*mov[wl] (\d*\(%esi\)),%e?(ax|bx|cx|dx|di)$/)) { 32 | $cur = "\tmovl " . $mem . ",%e" . $reg; 33 | $first_changed = 1; 34 | } 35 | } 36 | 37 | # Next we'll handle brain damage like: 38 | # movl %eax,_cpu_state+80 39 | # movl _cpu_state+80,%eax 40 | # 41 | # by deleting the second line. Yes, this really happens. 42 | # We have to be conservative here so we don't botch cases like: 43 | # movb _cpu_state(%eax),%al 44 | # movb %al,_cpu_state(%eax) 45 | 46 | 47 | if (((($size1, $src1, $dst1) 48 | = ($prev =~ /^\s+mov([bwl])\s+(_cpu_state\+?\d*),\s*(%[a-z]+)$/)) 49 | || (($size1, $src1, $dst1) 50 | = ($prev =~ /^\s+mov([bwl])\s+(%[a-z]+),\s*(_cpu_state\+?\d*)$/)) 51 | || (($size1, $src1, $dst1) 52 | = ($prev =~ /^\s+mov([bwl])\s+(-?\d*\(%ebp\)),\s*(%[a-z]+)$/)) 53 | || (($size1, $src1, $dst1) 54 | = ($prev =~ /^\s+mov([bwl])\s+(%[a-z]+),\s*(-?\d*\(%ebp\))$/))) 55 | && (($size2, $src2, $dst2) 56 | = /^\s+mov([bwl])\s+([^,]+),\s*([^,]+)$/) 57 | && ($size1 eq $size2) 58 | && ($src1 eq $dst2) 59 | && ($src2 eq $dst1)) { 60 | # This second line is completely useless, so delete it. 61 | $cur = ""; 62 | } 63 | 64 | 65 | if (!($cur eq "")) { 66 | print $cur . "\n"; 67 | } 68 | $prev = $cur; 69 | $prev_first_changed = $first_changed; 70 | -------------------------------------------------------------------------------- /runtime/include/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _alloc_h_ 2 | #define _alloc_h_ 3 | 4 | #include /* typedef size_t */ 5 | 6 | extern void *xmalloc (size_t size); 7 | extern void *xrealloc (void *old, size_t new_size); 8 | extern void *xcalloc (size_t num_elems, size_t byte_size); 9 | 10 | #endif /* Not _alloc_h_ */ 11 | -------------------------------------------------------------------------------- /runtime/include/backpatch.h: -------------------------------------------------------------------------------- 1 | #ifndef _backpatch_h_ 2 | #define _backpatch_h_ 3 | 4 | typedef struct _backpatch_t 5 | { 6 | struct _backpatch_t *next; /* Next in linked list. */ 7 | int32 offset_location; /* Bit index from block to index start. */ 8 | int32 const_offset; /* Add this to src addr. */ 9 | int8 num_bits; /* Number of bits to be patched. */ 10 | int8 relative_p; /* Boolean: relative offset? */ 11 | struct _Block *target; /* Target block; we jmp to its code ptr. */ 12 | } backpatch_t; 13 | 14 | extern void backpatch_apply_and_free (struct _Block *b, backpatch_t *p); 15 | extern void backpatch_add (struct _Block *b, int offset_location, int num_bits, 16 | BOOL relative_p, int const_offset, 17 | struct _Block *target); 18 | 19 | #include "block.h" 20 | 21 | #endif /* !_backpatch_h_ */ 22 | -------------------------------------------------------------------------------- /runtime/include/block.h: -------------------------------------------------------------------------------- 1 | #ifndef _block_h_ 2 | #define _block_h_ 3 | 4 | #define BLOCK_MAGIC_VALUE 0xDEADBABEUL 5 | 6 | #include "syn68k_private.h" /* To typedef uint16 and uint32. */ 7 | #include "backpatch.h" 8 | 9 | struct _Block { 10 | struct _Block *next_in_hash_bucket; /* Next Block in this hash bucket. */ 11 | const uint16 *compiled_code; /* Memory containing compiled code. */ 12 | #ifdef GENERATE_NATIVE_CODE 13 | uint32 num_times_called; /* # of times nonnative code called. */ 14 | #endif 15 | struct _Block *death_queue_prev; /* Prev block to be nuked if mem needed. */ 16 | struct _Block *death_queue_next; /* Next block to be nuked if mem needed. */ 17 | struct _Block *range_tree_left; /* Left child in range tree. */ 18 | struct _Block *range_tree_right; /* Right " " " " (see rangetree.c) */ 19 | struct _Block *range_tree_parent; /* Parent in r-tree (see rangetree.c) */ 20 | struct _Block **parent; /* Array of ptrs to parent blocks. */ 21 | struct _Block *child[2]; /* Array of ptrs to child blocks. */ 22 | syn68k_addr_t m68k_start_address; /* Starting address of 68k code. */ 23 | #ifdef CHECKSUM_BLOCKS 24 | uint32 checksum; /* Checksum of m68k code for this block. */ 25 | #endif 26 | uint32 m68k_code_length; /* Length of 68k code, in _bytes_. */ 27 | uint32 range_tree_color :1; /* Either RED or BLACK. */ 28 | uint32 cc_clobbered :5; /* CC bits modified before use. */ 29 | uint32 cc_may_not_set :5; /* CC bits that may be changed. */ 30 | uint32 cc_needed :5; /* CC bits whose values we need. */ 31 | uint32 num_children :2; /* # of blocks that this feeds to. */ 32 | uint32 immortal :1; /* Can't be freed to save space. */ 33 | uint32 recursive_mark :1; /* 1 means hit during this recursion. */ 34 | #ifdef GENERATE_NATIVE_CODE 35 | uint32 recompile_me :1; /* Recompile me as native (temp. flag). */ 36 | #endif /* GENERATE_NATIVE_CODE */ 37 | uint16 malloc_code_offset:3; /* Pass compiled_code - this to free(). */ 38 | uint16 num_parents :13; /* # of blocks that feed into this one. */ 39 | backpatch_t *backpatch; /* Linked list of backpatches to apply. */ 40 | #ifdef DEBUG /* to ptr to the specified child block. */ 41 | uint32 magic; 42 | #endif 43 | }; 44 | 45 | typedef struct _Block Block; 46 | 47 | 48 | /* Function prototypes. */ 49 | extern Block *block_new (void); 50 | extern void block_free (Block *b); 51 | extern void block_add_parent (Block *b, Block *parent); 52 | extern void block_remove_parent (Block *b, Block *parent, BOOL reclaim_memory); 53 | extern void block_add_child (Block *b, Block *child); 54 | extern void block_remove_child (Block *b, Block *child); 55 | extern void block_do_for_each_parent (Block *b, void (*f)(Block *, void *), 56 | void *aux); 57 | #ifdef DEBUG 58 | extern BOOL block_verify (Block *b); 59 | extern void dump_block (const Block *b); 60 | #endif 61 | 62 | #endif /* Not _block_h_ */ 63 | -------------------------------------------------------------------------------- /runtime/include/blockinfo.h: -------------------------------------------------------------------------------- 1 | #ifndef _blockinfo_h_ 2 | #define _blockinfo_h_ 3 | 4 | #include "block.h" 5 | 6 | typedef struct { 7 | uint32 child[2]; /* m68k addresses of m68k code following this blk. */ 8 | int16 num_child_blocks; /* # of child addrs we can know at translate time. */ 9 | uint16 num_68k_instrs; 10 | int8 *next_instr_offset; /* word offset to next instr; 0 iff last instr. */ 11 | } TempBlockInfo; 12 | 13 | extern void compute_block_info (Block *b, const uint16 *code, 14 | TempBlockInfo *temp); 15 | extern int amode_size (int amode, const uint16 *code, int ref_size); 16 | extern int instruction_size (const uint16 *code, const OpcodeMappingInfo *map); 17 | 18 | #endif /* Not _blockinfo_h_ */ 19 | -------------------------------------------------------------------------------- /runtime/include/callback.h: -------------------------------------------------------------------------------- 1 | #ifndef _callback_h_ 2 | #define _callback_h_ 3 | 4 | #include "syn68k_private.h" 5 | #include "block.h" 6 | 7 | #define MAX_CALLBACKS 4352 /* Arbitrary...4096 plus some slop. */ 8 | 9 | #define CALLBACK_STUB_BASE (MAGIC_ADDRESS_BASE + 128) 10 | #define CALLBACK_STUB_LENGTH (MAX_CALLBACKS * sizeof (uint16)) 11 | 12 | #define IS_CALLBACK(n) (((syn68k_addr_t) (n)) - CALLBACK_STUB_BASE \ 13 | < CALLBACK_STUB_LENGTH) 14 | 15 | extern void callback_init (void); 16 | extern syn68k_addr_t callback_install (callback_handler_t func, 17 | void *arbitrary_argument); 18 | extern void callback_remove (syn68k_addr_t m68k_address); 19 | extern int callback_compile (Block *parent, uint32 m68k_address, Block **new); 20 | extern void *callback_argument (syn68k_addr_t callback_address); 21 | extern callback_handler_t callback_function (syn68k_addr_t callback_address); 22 | 23 | #endif /* Not callback_h_ */ 24 | -------------------------------------------------------------------------------- /runtime/include/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef _checksum_h_ 2 | #define _checksum_h_ 3 | 4 | #include "syn68k_private.h" 5 | 6 | #ifdef CHECKSUM_BLOCKS 7 | 8 | #include "block.h" 9 | 10 | extern uint32 compute_block_checksum (const Block *b); 11 | 12 | #ifdef INLINE_CHECKSUM 13 | #include "callback.h" 14 | 15 | static __inline__ uint32 16 | inline_compute_block_checksum (const Block *b) 17 | { 18 | const uint16 *code; 19 | uint32 sum; 20 | long n; 21 | syn68k_addr_t start; 22 | 23 | /* Don't actually checksum the bytes at a callback! */ 24 | start = b->m68k_start_address; 25 | if (IS_CALLBACK (start)) 26 | return (start 27 | + (unsigned long) callback_argument (start) 28 | + (unsigned long) callback_function (start)); 29 | else if (start >= MAGIC_ADDRESS_BASE 30 | && start < CALLBACK_STUB_BASE) 31 | return 0; 32 | 33 | code = SYN68K_TO_US (start); 34 | for (sum = 0, n = b->m68k_code_length / sizeof (uint16); --n >= 0; ) 35 | { 36 | /* Bizarre but fast checksum. A good checksum like CRC is 37 | * probably too slow. 38 | */ 39 | #if defined (__GNUC__) && defined(i386) 40 | uint32 tmp1, tmp2; 41 | 42 | /* This is taking lots of CPU time for HyperCard, and gcc was generating 43 | * lousy code, so I've hand-coded and hand-scheduled this for the 44 | * Pentium. This should do the same thing as the C code below. 45 | */ 46 | asm ("movl %0,%2\n\t" 47 | "movl %0,%1\n\t" 48 | "sall $5,%2\n\t" 49 | "shrl $14,%1\n\t" 50 | "addl %0,%2\n\t" 51 | "xorl %2,%1\n\t" 52 | "xorw (%4,%5,2),%w0\n\t" 53 | "xorl %1,%0" 54 | : "=r" (sum), "=&r" (tmp1), "=&r" (tmp2) 55 | : "0" (sum), "r" (code), "r" (n) 56 | : "cc"); 57 | #else /* !__GNUC__ || !i386 */ 58 | sum = (sum >> 14) ^ (sum * 33) ^ code[n]; 59 | #endif /* !__GNUC__ || !i386 */ 60 | } 61 | 62 | return sum; 63 | } 64 | #endif /* INLINE_CHECKSUM */ 65 | 66 | #endif /* CHECKSUM_BLOCKS */ 67 | 68 | #endif /* Not _checksum_h_ */ 69 | -------------------------------------------------------------------------------- /runtime/include/deathqueue.h: -------------------------------------------------------------------------------- 1 | #ifndef _deathqueue_h_ 2 | #define _deathqueue_h_ 3 | 4 | #include "block.h" 5 | 6 | extern Block *death_queue_head, *death_queue_tail; 7 | extern void death_queue_enqueue (Block *b); 8 | extern void death_queue_dequeue (Block *b); 9 | 10 | #endif /* Not _deathqueue_h_ */ 11 | -------------------------------------------------------------------------------- /runtime/include/destroyblock.h: -------------------------------------------------------------------------------- 1 | #ifndef _destroyblock_h_ 2 | #define _destroyblock_h_ 3 | 4 | #include "block.h" 5 | 6 | extern unsigned long destroy_block (Block *b); 7 | extern unsigned long destroy_blocks (syn68k_addr_t low_m68k_address, uint32 num_bytes); 8 | extern unsigned long destroy_any_block (void); 9 | 10 | #endif /* Not _destroyblock_h_ */ 11 | -------------------------------------------------------------------------------- /runtime/include/diagnostics.h: -------------------------------------------------------------------------------- 1 | #ifndef _diagnostics_h_ 2 | #define _diagnostics_h_ 3 | 4 | #include 5 | #include "syn68k_private.h" 6 | #include "block.h" 7 | 8 | extern void print_cc_bits (FILE *stream, int bits); 9 | extern void hexdump (const uint16 *addr, int num_words); 10 | extern void dump_cpu_state (void); 11 | extern Block *which_block (uint16 *code); 12 | 13 | #endif /* Not _diagnostics_h_ */ 14 | -------------------------------------------------------------------------------- /runtime/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef _hash_h_ 2 | #define _hash_h_ 3 | 4 | #include "block.h" 5 | 6 | #define LOG_NUM_BUCKETS 12 7 | #define NUM_HASH_BUCKETS (1UL << LOG_NUM_BUCKETS) 8 | 9 | /* This hash function assumes the low bit conveys no information (== 0). */ 10 | #define BLOCK_HASH(x) ((unsigned)((((x) ^ ((x) >> LOG_NUM_BUCKETS)) >> 1) \ 11 | % NUM_HASH_BUCKETS)) 12 | 13 | extern Block *block_hash_table[NUM_HASH_BUCKETS]; 14 | 15 | extern void hash_init (void); 16 | extern void hash_destroy (void); 17 | extern Block *hash_lookup (uint32 addr); 18 | /* defined in `syn68k_public.h' 19 | extern const uint16 *hash_lookup_code_and_create_if_needed (uint32 addr); */ 20 | extern const uint16 *hash_lookup_code_and_create_if_needed (uint32 addr); 21 | extern void hash_insert (Block *b); 22 | extern void hash_remove (Block *b); 23 | #ifdef DEBUG 24 | extern BOOL hash_verify (void); 25 | extern void hash_stats (void); 26 | #endif 27 | 28 | #endif /* Not _hash_h_ */ 29 | -------------------------------------------------------------------------------- /runtime/include/interrupt.h: -------------------------------------------------------------------------------- 1 | #ifndef _interrupt_h_ 2 | #define _interrupt_h_ 3 | 4 | #include "syn68k_private.h" 5 | 6 | /* Everything that would normally be here is in syn68k_public.h */ 7 | 8 | #endif /* Not _interrupt_h_ */ 9 | -------------------------------------------------------------------------------- /runtime/include/mapping.h: -------------------------------------------------------------------------------- 1 | #ifndef _mapping_h_ 2 | #define _mapping_h_ 3 | 4 | #include "syn68k_private.h" 5 | 6 | extern const uint16 opcode_map_index[]; 7 | extern const OpcodeMappingInfo opcode_map_info[]; 8 | 9 | #endif /* Not _mapping_h_ */ 10 | -------------------------------------------------------------------------------- /runtime/include/profile.h: -------------------------------------------------------------------------------- 1 | #ifndef _profile_h_ 2 | #define _profile_h_ 3 | 4 | #ifdef PROFILE 5 | 6 | #include "block.h" 7 | 8 | extern void profile_block (Block *b); 9 | extern void dump_profile (const char *file); 10 | 11 | #endif 12 | 13 | #endif /* Not _profile_h_ */ 14 | -------------------------------------------------------------------------------- /runtime/include/rangetree.h: -------------------------------------------------------------------------------- 1 | #ifndef _rangetree_h 2 | #define _rangetree_h 3 | 4 | #include "syn68k_private.h" 5 | #include "block.h" 6 | 7 | extern void range_tree_init (void); 8 | extern void range_tree_destroy (void); 9 | extern void range_tree_insert (Block *b); 10 | extern void range_tree_remove (Block *b); 11 | extern Block *range_tree_lookup (syn68k_addr_t h); 12 | extern Block *range_tree_find_first_at_or_after (syn68k_addr_t addr); 13 | extern Block *range_tree_first_to_intersect (syn68k_addr_t low, 14 | syn68k_addr_t high); 15 | #ifdef DEBUG 16 | extern BOOL range_tree_verify (void); 17 | extern void range_tree_dump (void); 18 | #endif 19 | 20 | #endif /* Not _rangetree_h_ */ 21 | -------------------------------------------------------------------------------- /runtime/include/recompile.h: -------------------------------------------------------------------------------- 1 | #ifndef _recompile_h_ 2 | #define _recompile_h_ 3 | 4 | #ifdef GENERATE_NATIVE_CODE 5 | 6 | #include "block.h" 7 | #include "deathqueue.h" 8 | 9 | extern void recompile_block_as_native (Block *b); 10 | extern double native_fraction (void); 11 | 12 | /* This is the number of times a nonnative block must be called before 13 | * we scrap it and recompile it as native. 14 | */ 15 | #define RECOMPILE_CUTOFF 50 16 | 17 | /* This is how many times a descendent of a nonnative block about to be 18 | * recompiled must have been called before we decide to smash it as 19 | * well. Smashing nearby blocks avoids extra recompiles. 20 | */ 21 | #define RECOMPILE_CHILD_CUTOFF 35 22 | 23 | 24 | #endif /* GENERATE_NATIVE_CODE */ 25 | 26 | #endif /* !_recompile_h_ */ 27 | -------------------------------------------------------------------------------- /runtime/include/translate.h: -------------------------------------------------------------------------------- 1 | #ifndef _translate_h 2 | #define _translate_h_ 3 | 4 | #include "block.h" 5 | 6 | extern void (*call_while_busy_func)(int); 7 | 8 | typedef struct { 9 | BOOL valid; 10 | BOOL reversed; 11 | const uint16 *m68koperand; 12 | int amode; 13 | int size; 14 | } AmodeFetchInfo; 15 | 16 | extern int generate_block (Block *parent, uint32 m68k_address, Block **new 17 | /* #ifdef GENERATE_NATIVE_CODE */ 18 | , BOOL try_native_p 19 | /* #endif */ /* GENERATE_NATIVE_CODE */ 20 | ); 21 | extern Block *make_artificial_block (Block *parent, syn68k_addr_t m68k_address, 22 | int extra_words, uint16 **extra_start); 23 | 24 | #ifdef GENERATE_NATIVE_CODE 25 | extern int native_code_p; 26 | #endif /* GENERATE_NATIVE_CODE */ 27 | 28 | extern int emulation_depth; 29 | 30 | #endif /* Not _translate_h_ */ 31 | -------------------------------------------------------------------------------- /runtime/include/trap.h: -------------------------------------------------------------------------------- 1 | #ifndef _trap_h_ 2 | #define _trap_h_ 3 | 4 | #include "syn68k_private.h" 5 | 6 | extern syn68k_addr_t trap_direct (uint32 trap_number, 7 | syn68k_addr_t exception_pc, 8 | syn68k_addr_t exception_address); 9 | extern uint32 trap_forwarded (syn68k_addr_t m68k_address, void *arg); 10 | extern void trap_init (void); 11 | extern void trap_install_handler (unsigned trap_number, 12 | callback_handler_t func, 13 | void *arbitrary_argument); 14 | extern void trap_remove_handler (unsigned trap_number); 15 | 16 | extern uint32 *trap_vector_array; 17 | 18 | #define SR_SUPERVISOR_BIT 0x2000 19 | #define SR_MASTER_BIT 0x1000 20 | 21 | #define USE_USP(sr) (!((sr) & SR_SUPERVISOR_BIT)) 22 | #define USE_MSP(sr) (((sr) & (SR_SUPERVISOR_BIT | SR_MASTER_BIT)) \ 23 | == (SR_SUPERVISOR_BIT | SR_MASTER_BIT)) 24 | #define USE_ISP(sr) (((sr) & (SR_SUPERVISOR_BIT | SR_MASTER_BIT)) \ 25 | == SR_SUPERVISOR_BIT) 26 | 27 | #define FETCH_USP() (USE_USP (cpu_state.sr) ? EM_A7 : cpu_state.usp) 28 | #define FETCH_MSP() (USE_MSP (cpu_state.sr) ? EM_A7 : cpu_state.msp) 29 | #define FETCH_ISP() (USE_ISP (cpu_state.sr) ? EM_A7 : cpu_state.isp) 30 | 31 | #define SET_USP(n) \ 32 | (USE_USP (cpu_state.sr) ? (EM_A7 = (n)) : (cpu_state.usp = (n))) 33 | #define SET_MSP(n) \ 34 | (USE_MSP (cpu_state.sr) ? (EM_A7 = (n)) : (cpu_state.msp = (n))) 35 | #define SET_ISP(n) \ 36 | (USE_ISP (cpu_state.sr) ? (EM_A7 = (n)) : (cpu_state.isp = (n))) 37 | 38 | #define SWITCH_A7(old_sr, new_sr) \ 39 | do \ 40 | { \ 41 | if (((old_sr) ^ (new_sr)) & (SR_SUPERVISOR_BIT | SR_MASTER_BIT)) \ 42 | { \ 43 | /* Save away the old a7. */ \ 44 | if (USE_USP (old_sr)) \ 45 | cpu_state.usp = EM_A7; \ 46 | else if (USE_MSP (old_sr)) \ 47 | cpu_state.msp = EM_A7; \ 48 | else \ 49 | cpu_state.isp = EM_A7; \ 50 | \ 51 | /* Load up the new value. */ \ 52 | if (USE_USP (new_sr)) \ 53 | EM_A7 = cpu_state.usp; \ 54 | else if (USE_MSP (new_sr)) \ 55 | EM_A7 = cpu_state.msp; \ 56 | else \ 57 | EM_A7 = cpu_state.isp; \ 58 | } \ 59 | } while (0) 60 | 61 | #endif /* Not _trap_h_ */ 62 | -------------------------------------------------------------------------------- /runtime/init.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #include "syn68k_private.h" 4 | #include "hash.h" 5 | #include "rangetree.h" 6 | #include "callback.h" 7 | #include "trap.h" 8 | #include "alloc.h" 9 | #include "mapping.h" 10 | #include "translate.h" 11 | #include "native.h" 12 | #include "checksum.h" 13 | #include "deathqueue.h" 14 | #include "interrupt.h" 15 | #ifdef USE_BIOS_TIMER 16 | #include "go32.h" 17 | #include "dpmi.h" 18 | #endif /* USE_BIOS_TIMER */ 19 | #include 20 | #include 21 | 22 | 23 | /* Global CPU state struct. */ 24 | CPUState cpu_state; 25 | 26 | #if SIZEOF_CHAR_P == 4 27 | uint32 ROMlib_offset; 28 | #else 29 | uint64 ROMlib_offset; 30 | #endif 31 | 32 | /* This function initializes syn68k. Call it exactly once, before any 33 | * other syn68k calls. DOS_INT_FLAG_ADDR is the conventional memory 34 | * offset of the 32 bit synchronous interrupt flag. Just pass in zero 35 | * for the non-MSDOS and non-SYNCHRONOUS_INTERRUPTS cases. 36 | */ 37 | void 38 | initialize_68k_emulator (void (*while_busy)(int), int native_p, 39 | uint32 trap_vector_storage[64], 40 | uint32 dos_int_flag_addr) 41 | { 42 | static uint16 rte = 43 | #ifdef LITTLEENDIAN 44 | 0x734E; 45 | #else 46 | 0x4E73; 47 | #endif 48 | Block *b; 49 | uint16 *code; 50 | 51 | #ifdef __CHECKER__ 52 | /* Checker can't work with native code. */ 53 | native_p = FALSE; 54 | #endif 55 | 56 | /* Zero out CPU state (not necessary since statics are 0'd) */ 57 | memset (&cpu_state, 0, sizeof cpu_state); 58 | memset (&cpu_state.jsr_stack, -1, sizeof cpu_state.jsr_stack); 59 | 60 | /* Record the function to periodically call while we are busy doing stuff. */ 61 | call_while_busy_func = while_busy; 62 | 63 | #ifdef GENERATE_NATIVE_CODE 64 | native_code_p = native_p; 65 | #endif 66 | trap_vector_array = trap_vector_storage; 67 | 68 | /* Set up the status register & interrupt stack pointer. */ 69 | cpu_state.sr = 0x2000; /* supervisor/interrupt mode (this appears 70 | * to be what programs really expect, e.g. 71 | * PGA Tour Golf does movew #8192,sr). 72 | */ 73 | cpu_state.usp = 0xDEADF00D; /* Never use this stack pointer! */ 74 | cpu_state.msp = 0xDEAD0666; /* Never use this stack pointer! */ 75 | 76 | #ifdef USE_BIOS_TIMER 77 | dos_memory_selector = _go32_conventional_mem_selector (); 78 | assert (dos_int_flag_addr != 0); 79 | dos_interrupt_flag_addr = dos_int_flag_addr; 80 | #endif /* USE_BIOS_TIMER */ 81 | 82 | #ifdef SYNCHRONOUS_INTERRUPTS 83 | SET_INTERRUPT_STATUS (INTERRUPT_STATUS_UNCHANGED); 84 | #endif 85 | 86 | /* Call various initialization routines. */ 87 | hash_init (); 88 | range_tree_init (); 89 | callback_init (); 90 | trap_init (); 91 | 92 | #ifdef GENERATE_NATIVE_CODE 93 | native_code_init (); 94 | #endif /* GENERATE_NATIVE_CODE */ 95 | 96 | /* Create the magical block that exits the emulator if you ever 97 | * jump to it. Don't add it to the death queue, since we never want 98 | * this block to go away. 99 | */ 100 | b = make_artificial_block (NULL, MAGIC_EXIT_EMULATOR_ADDRESS, 101 | OPCODE_WORDS, &code); 102 | 103 | #ifdef USE_DIRECT_DISPATCH 104 | *(const void **)code = direct_dispatch_table[0]; 105 | #else 106 | *(const void **)code = (const void *)0; /* Exit emulator opc. */ 107 | #endif 108 | 109 | hash_insert (b); 110 | range_tree_insert (b); 111 | 112 | /* Create the magical block that contains an RTE. */ 113 | b = NULL; 114 | #if SIZEOF_CHAR_P != 8 115 | generate_block (NULL, US_TO_SYN68K (&rte), &b, TRUE); 116 | #else 117 | { 118 | typeof (ROMlib_offset) save_offset; 119 | 120 | save_offset = ROMlib_offset; 121 | ROMlib_offset = &rte; /* so the RTE will be reachable with 32 bit addr */ 122 | generate_block (NULL, US_TO_SYN68K (&rte), &b, TRUE); 123 | ROMlib_offset = save_offset; 124 | } 125 | #endif 126 | assert (b != NULL); 127 | hash_remove (b); 128 | range_tree_remove (b); 129 | death_queue_dequeue (b); 130 | b->m68k_start_address = MAGIC_RTE_ADDRESS; 131 | b->m68k_code_length = 1; 132 | b->checksum = compute_block_checksum (b); 133 | b->immortal = TRUE; 134 | hash_insert (b); 135 | range_tree_insert (b); 136 | } 137 | -------------------------------------------------------------------------------- /runtime/interrupt.c: -------------------------------------------------------------------------------- 1 | #include "interrupt.h" 2 | 3 | #ifdef SYNCHRONOUS_INTERRUPTS 4 | 5 | #include "trap.h" 6 | 7 | #ifdef USE_BIOS_TIMER 8 | uint16 dos_memory_selector; 9 | uint32 dos_interrupt_flag_addr; 10 | #endif 11 | 12 | 13 | void 14 | interrupt_generate (unsigned priority) 15 | { 16 | /* Calling this with a weird priority will just note that an interrupt 17 | * should be checked for. 18 | */ 19 | if (priority >= 1 && priority <= 7) 20 | cpu_state.interrupt_pending[priority] = TRUE; 21 | 22 | SET_INTERRUPT_STATUS (INTERRUPT_STATUS_CHANGED); 23 | } 24 | 25 | 26 | /* This function turns on the global "check for an interrupt" bit if 27 | * any interrupts are currently pending. 28 | */ 29 | void 30 | interrupt_note_if_present () 31 | { 32 | int i; 33 | 34 | for (i = 1; i <= 7; i++) 35 | if (cpu_state.interrupt_pending[i]) 36 | { 37 | SET_INTERRUPT_STATUS (INTERRUPT_STATUS_CHANGED); 38 | break; 39 | } 40 | } 41 | 42 | 43 | /* This function looks to see if any interrupts of high enough 44 | * priority are pending, and if they are it processes the highest 45 | * priority interrupt. It adjusts the machine state appropriately for 46 | * the interrupt and returns the 68k PC at which execution should 47 | * resume. The INTERRUPT_PC parameter specifies the address 48 | * of the 68k instruction about to be executed when the interrupt 49 | * was detected. 50 | */ 51 | syn68k_addr_t 52 | interrupt_process_any_pending (syn68k_addr_t interrupt_pc) 53 | { 54 | int priority; 55 | syn68k_addr_t continuation_pc; 56 | int cpu_priority; 57 | 58 | /* First note that the interrupt has been processed. The RTE 59 | * will end up causing another check when it reloads the SR, so 60 | * we shouldn't miss any interrupts. 61 | */ 62 | SET_INTERRUPT_STATUS (INTERRUPT_STATUS_UNCHANGED); 63 | 64 | /* Determine if any interrupt with high enough priority is pending. */ 65 | cpu_priority = (cpu_state.sr >> 8) & 7; 66 | if (cpu_state.interrupt_pending[7]) 67 | priority = 7; /* Priority 7 interrupt cannot be masked. */ 68 | else 69 | { 70 | for (priority = 6; priority > cpu_priority; priority--) 71 | if (cpu_state.interrupt_pending[priority]) 72 | break; 73 | if (priority <= cpu_priority) 74 | priority = -1; 75 | } 76 | 77 | #ifdef USE_BIOS_TIMER 78 | /* The BIOS has no way of specifying the interrupt priority when 79 | * an interrupt comes in. Therefore if we don't see any other 80 | * explicitly specified interrupts, we'll assume it must have been 81 | * a timer interrupt and act accordingly. 82 | */ 83 | if (priority == -1 && cpu_priority < M68K_TIMER_PRIORITY) 84 | priority = M68K_TIMER_PRIORITY; 85 | #endif 86 | 87 | /* Did we find an interrupt of high enough priority? */ 88 | if (priority != -1) 89 | { 90 | /* Process the interrupt. */ 91 | cpu_state.interrupt_pending[priority] = 0; 92 | continuation_pc = trap_direct (24 + priority, interrupt_pc, 0); 93 | } 94 | else 95 | { 96 | /* Nothing interesting after all, so just return unchanged. */ 97 | continuation_pc = interrupt_pc; 98 | } 99 | 100 | return continuation_pc; 101 | } 102 | 103 | #endif /* SYNCHRONOUS_INTERRUPTS */ 104 | -------------------------------------------------------------------------------- /runtime/native/i386/.gitignore: -------------------------------------------------------------------------------- 1 | asmdata.h 2 | host-xlate.c 3 | host-xlate.h 4 | i386_stubs 5 | obj-stmp 6 | src-stmp 7 | subdir-stmp 8 | template 9 | xlate 10 | i386-isa.h 11 | -------------------------------------------------------------------------------- /runtime/native/i386/Makefile.am: -------------------------------------------------------------------------------- 1 | # Although this is nominally processed by automake, it's really a bunch 2 | # of stuff we do by hand that we never converted to the proper automake 3 | # method 4 | 5 | CC_FOR_BUILD=@CC_FOR_BUILD@ 6 | CFLAGS_FOR_BUILD=@CFLAGS_FOR_BUILD@ 7 | 8 | LOCAL_INCLUDES = 9 | 10 | CLEANFILES = obj-stmp *.o 11 | 12 | runtimedir = $(top_srcdir)/runtime 13 | 14 | LOCAL_INCLUDES += -I$(srcdir)/include \ 15 | -I$(runtimedir)/include \ 16 | -I$(runtimedir)/../include -I$(srcdir) -I. -I../../../include 17 | 18 | # these objects must be compiled with LIB_CC 19 | MISC_OBJS = host-native.o host-xlate.o i386-aux.o xlate-aux.o 20 | 21 | # these objects must be compiled with CC 22 | TEMPLATE_OBJS = main.o template.o process.o 23 | ANALYZE_OBJS = analyze.o template.o 24 | XLATE_OBJS = xlatemain.o xlatetable.o xlate.o 25 | 26 | i386-isa.h: src-stmp 27 | 28 | host-native.o: host-native.c i386-isa.h 29 | $(CC) $(CFLAGS) -c $(LOCAL_INCLUDES) -o $(@F) $< 30 | host-xlate.o: host-xlate.c 31 | $(CC) $(CFLAGS) -c $(LOCAL_INCLUDES) -o $(@F) $< 32 | i386-aux.o: i386-aux.c 33 | $(CC) $(CFLAGS) -c $(LOCAL_INCLUDES) -o $(@F) $< 34 | xlate-aux.o: xlate-aux.c 35 | $(CC) $(CFLAGS) -c $(LOCAL_INCLUDES) -o $(@F) $< 36 | 37 | xlatemain.o: xlatemain.c 38 | $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $(LOCAL_INCLUDES) -o $(@F) $< 39 | xlatetable.o: xlatetable.c 40 | $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $(LOCAL_INCLUDES) -o $(@F) $< 41 | xlate.o: xlate.c 42 | $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $(LOCAL_INCLUDES) -o $(@F) $< 43 | 44 | .c.o: 45 | $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $(LOCAL_INCLUDES) -o $(@F) $< 46 | 47 | subdir-stmp: $(MISC_OBJS) src-stmp obj-stmp 48 | echo $(MISC_OBJS) \ 49 | `ls _*.o` > subdir-stmp 50 | 51 | obj-stmp: 52 | k=1; \ 53 | for i in i386_stubs/*; do \ 54 | $(CC) $(CFLAGS) $(LOCAL_INCLUDES) $$i -c -o _i386_$$k.o;\ 55 | k=`expr $$k + 1`; \ 56 | echo done processing $$i into _i386_$$k.o; \ 57 | done 58 | touch obj-stmp 59 | 60 | src-stmp: template 61 | mkdir -p i386_stubs 62 | ./template "$(MAKE)" 63 | $(RM) analyze 64 | touch src-stmp 65 | 66 | template: $(TEMPLATE_OBJS) analyze.c 67 | $(CC_FOR_BUILD) $(TEMPLATE_OBJS) -o template 68 | 69 | host-xlate.c host-xlate.h: xlate 70 | ./xlate 71 | 72 | xlate: $(XLATE_OBJS) 73 | $(CC_FOR_BUILD) $(XLATE_OBJS) -o xlate 74 | 75 | analyze: $(ANALYZE_OBJS) 76 | $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(ANALYZE_OBJS) -o analyze 77 | 78 | analyze.o: asmdata.h template.h 79 | 80 | 81 | # Invoked only from ./template 82 | nextobj: 83 | #doesn't do anything 84 | -------------------------------------------------------------------------------- /runtime/native/i386/host-native.h: -------------------------------------------------------------------------------- 1 | #ifndef _HOST_NATIVE_H_ 2 | #define _HOST_NATIVE_H_ 3 | 4 | #define REG_EAX 0 5 | #define REG_ECX 1 6 | #define REG_EDX 2 7 | #define REG_EBX 3 8 | #define REG_ESP 4 9 | #define REG_EBP 5 10 | #define REG_ESI 6 11 | #define REG_EDI 7 12 | 13 | #define REG_AX 0 14 | #define REG_CX 1 15 | #define REG_DX 2 16 | #define REG_BX 3 17 | #define REG_SP 4 18 | #define REG_BP 5 19 | #define REG_SI 6 20 | #define REG_DI 7 21 | 22 | #define REG_AL 0 23 | #define REG_CL 1 24 | #define REG_DL 2 25 | #define REG_BL 3 26 | #define REG_AH 4 27 | #define REG_CH 5 28 | #define REG_DH 6 29 | #define REG_BH 7 30 | 31 | /* Don't allow %ebp or %esp. These registers are strange because in 32 | * some situations they are used as "escape" registers on the i386. 33 | * We could work around this by only allowing them when they are legal, 34 | * but legend has it that we can't use either under DPMI because of 35 | * a strange stack segment value. 36 | */ 37 | #define ALLOCATABLE_REG_MASK ((host_reg_mask_t) ( (1 << REG_EAX) \ 38 | | (1 << REG_EBX) \ 39 | | (1 << REG_ECX) \ 40 | | (1 << REG_EDX) \ 41 | | (1 << REG_ESI) \ 42 | | (1 << REG_EDI))) 43 | 44 | 45 | /* Any of the 6 regs we free up to use. */ 46 | #define REGSET_ALL ALLOCATABLE_REG_MASK 47 | 48 | /* Only those regs which are byte-addressable: %eax, %ebx, %ecx, %edx. */ 49 | #define REGSET_BYTE ((host_reg_mask_t) ( (1 << REG_EAX) \ 50 | | (1 << REG_EBX) \ 51 | | (1 << REG_ECX) \ 52 | | (1 << REG_EDX))) 53 | #define REGSET_EMPTY 0 54 | 55 | #define NUM_HOST_REGS 8 56 | 57 | typedef uint8 host_code_t; 58 | 59 | extern uint8 have_i486_p; 60 | 61 | #define NATIVE_TO_SYNTH_STUB_BYTES 10 62 | #define NATIVE_TO_SYNTH_STUB_WORDS \ 63 | (((NATIVE_TO_SYNTH_STUB_BYTES + 1) / 2 + 1) & ~1)/* Must be even # of words. */ 64 | 65 | #ifdef SYNCHRONOUS_INTERRUPTS 66 | # ifdef USE_BIOS_TIMER 67 | # define CHECK_INTERRUPT_STUB_BYTES 18 68 | # else /* !USE_BIOS_TIMER */ 69 | # if defined (__CHECKER__) 70 | # define CHECK_INTERRUPT_STUB_BYTES 18 71 | # else /* !__CHECKER__ */ 72 | # define CHECK_INTERRUPT_STUB_BYTES 14 73 | # endif /* !__CHECKER__ */ 74 | # endif /* !USE_BIOS_TIMER */ 75 | #else 76 | # define CHECK_INTERRUPT_STUB_BYTES 0 77 | #endif /* !SYNCHRONOUS_INTERRUPTS */ 78 | 79 | #define HOST_SWAP16(r) \ 80 | i386_rorw_imm_reg (c, codep, cc_spill_if_changed, M68K_CC_NONE, NO_REG, 8, (r)) 81 | #define HOST_SWAP32(r) \ 82 | host_swap32 (c, codep, cc_spill_if_changed, M68K_CC_NONE, NO_REG, (r)) 83 | 84 | #endif /* !_HOST_NATIVE_H_ */ 85 | -------------------------------------------------------------------------------- /runtime/native/i386/main.c: -------------------------------------------------------------------------------- 1 | #include "template.h" 2 | #include "process.h" 3 | #include 4 | 5 | 6 | int 7 | main (int argc, char *argv[]) 8 | { 9 | #ifdef GENERATE_NATIVE_CODE 10 | FILE *fp, *header_fp; 11 | int i, success, swapop_p; 12 | 13 | success = SUCCESS; /* default */ 14 | 15 | if (argc != 2) 16 | { 17 | fprintf (stderr, "Usage: %s \n", argv[0]); 18 | exit (EXIT_FAILURE); 19 | } 20 | 21 | header_fp = fopen ("i386-isa.h", "w"); 22 | if (header_fp == NULL) 23 | { 24 | fprintf (stderr, "Unable to open \"i386-isa.h\" for writing.\n"); 25 | exit (-1); 26 | } 27 | fputs ("/* This file is machine-generated; DO NOT EDIT! */\n" 28 | "\n" 29 | "#ifndef _I386_ISA_H_\n" 30 | "#define _I386_ISA_H_\n" 31 | "\n" 32 | "#ifdef GENERATE_NATIVE_CODE\n" 33 | "\n", 34 | header_fp); 35 | 36 | swapop_p = FALSE; 37 | for (i = 0; success == SUCCESS && template[i].macro_name != NULL; 38 | i += swapop_p, swapop_p = !swapop_p) 39 | { 40 | char cmd[1024], c_file[1024], o_file[1024]; 41 | 42 | /* Only bother swapping those that have exactly two operands. */ 43 | /* Swapop hack is no longer useful. */ 44 | if (swapop_p /* && count_operands (template[i].code) != 2 */) 45 | continue; 46 | 47 | if (!swapop_p) 48 | { 49 | printf ("Processing %s...", template[i].macro_name); 50 | fflush (stdout); 51 | } 52 | 53 | sprintf (c_file, "i386_stubs/_%s.c", template[i].macro_name); 54 | sprintf (o_file, "_i386_%d.o", i * 2 + swapop_p);/* Short for archive. */ 55 | fp = fopen (c_file, "w"); 56 | if (fp == NULL) 57 | { 58 | fprintf (stderr, "Unable to open file \"%s\" for writing.\n", 59 | c_file); 60 | exit (EXIT_FAILURE); 61 | } 62 | if (process_template (fp, header_fp, &template[i], argv[1], swapop_p) 63 | == FAILURE) 64 | success = FAILURE; 65 | if (!swapop_p) 66 | puts ("done."); 67 | if (template[i + 1].macro_name != NULL) 68 | putc ('\n', fp); /* Add an extra blank line. */ 69 | fclose (fp); 70 | 71 | sprintf (cmd, "%s -s nextobj NEW_C_FILE=%s NEW_O_FILE=%s > /dev/null", 72 | argv[1], c_file, o_file); 73 | if (system (cmd)) 74 | { 75 | fprintf (stderr, "Unable to make \"%s\".\n", c_file); 76 | success = FAILURE; 77 | } 78 | } 79 | 80 | fputs ("#endif /* GENERATE_NATIVE_CODE */\n" 81 | "\n" 82 | "#endif /* !_I386_ISA_H_ */\n", header_fp); 83 | fclose (header_fp); 84 | 85 | return (success == SUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE; 86 | #else /* !GENERATE_NATIVE_CODE */ 87 | return EXIT_SUCCESS; 88 | #endif /* !GENERATE_NATIVE_CODE */ 89 | } 90 | -------------------------------------------------------------------------------- /runtime/native/i386/process.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROCESS_H_INCLUDED_ 2 | #define _PROCESS_H_INCLUDED_ 3 | 4 | #include 5 | 6 | extern int process_template (FILE *fp, FILE *header_fp, const template_t *t, 7 | const char *make, int swapop_p); 8 | extern int count_operands (const char *s); 9 | 10 | #endif /* !_PROCESS_H_INCLUDED_ */ 11 | -------------------------------------------------------------------------------- /runtime/native/i386/template.h: -------------------------------------------------------------------------------- 1 | #ifndef _TEMPLATE_H_INCLUDED_ 2 | #define _TEMPLATE_H_INCLUDED_ 3 | 4 | #include "syn68k_private.h" 5 | 6 | #define FAILURE 1 7 | #define SUCCESS 0 8 | 9 | typedef enum 10 | { 11 | REGISTER, CONSTANT 12 | } i386_op_type_t; 13 | 14 | typedef enum 15 | { 16 | IN, OUT, INOUT 17 | } io_t; 18 | 19 | /* BROKEN_SIZE_32 is a variant of SIZE_32 that is only used with addresses 20 | that cause trouble on Mac OS X's ld. The problem ld doesn't recognize 21 | 0x80000000 (-2147483648) as a legitimate 32-bit relative offset. See 22 | the extended comment in process.c for more info */ 23 | 24 | typedef enum { SIZE_8, SIZE_16, SIZE_32 } byte_size_t; 25 | 26 | typedef struct 27 | { 28 | byte_size_t size; 29 | i386_op_type_t type; 30 | io_t inout; 31 | } operand_t; 32 | 33 | #define MAX_OPERANDS 6 34 | 35 | typedef BOOL boolean_t; 36 | 37 | typedef uint8 cc_mask_t; 38 | 39 | typedef struct 40 | { 41 | const char *macro_name; 42 | const char *i386_cc_in, *i386_cc_out; 43 | const char *i386_in, *i386_out; /* All non-cc inputs and outputs. */ 44 | const char *pipe; 45 | const char *code; 46 | const char *operand_name[MAX_OPERANDS]; 47 | operand_t operand[MAX_OPERANDS]; 48 | } template_t; 49 | 50 | extern const template_t template[]; 51 | 52 | #ifndef MIN 53 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 54 | #endif 55 | 56 | #endif /* !_TEMPLATE_H_INCLUDED_ */ 57 | -------------------------------------------------------------------------------- /runtime/native/i386/xlate-aux.h: -------------------------------------------------------------------------------- 1 | #ifndef _xlate_aux_h_ 2 | #define _xlate_aux_h_ 3 | 4 | #ifdef GENERATE_NATIVE_CODE 5 | 6 | extern const guest_code_descriptor_t xlate_cmpmb_postinc_postinc_1_0; 7 | extern const guest_code_descriptor_t xlate_cmpmw_postinc_postinc_1_0; 8 | extern const guest_code_descriptor_t xlate_cmpml_postinc_postinc_1_0; 9 | 10 | extern const guest_code_descriptor_t xlate_bclr_imm_reg_1_0; 11 | extern const guest_code_descriptor_t xlate_bset_imm_reg_1_0; 12 | extern const guest_code_descriptor_t xlate_bchg_imm_reg_1_0; 13 | extern const guest_code_descriptor_t xlate_btst_imm_reg_1_0; 14 | 15 | extern const guest_code_descriptor_t xlate_bcc; 16 | extern const guest_code_descriptor_t xlate_bcs; 17 | extern const guest_code_descriptor_t xlate_beq; 18 | extern const guest_code_descriptor_t xlate_bge; 19 | extern const guest_code_descriptor_t xlate_bgt; 20 | extern const guest_code_descriptor_t xlate_bhi; 21 | extern const guest_code_descriptor_t xlate_ble; 22 | extern const guest_code_descriptor_t xlate_bls; 23 | extern const guest_code_descriptor_t xlate_blt; 24 | extern const guest_code_descriptor_t xlate_bmi; 25 | extern const guest_code_descriptor_t xlate_bne; 26 | extern const guest_code_descriptor_t xlate_bpl; 27 | extern const guest_code_descriptor_t xlate_bvc; 28 | extern const guest_code_descriptor_t xlate_bvs; 29 | 30 | extern const guest_code_descriptor_t xlate_st_reg_0; 31 | extern const guest_code_descriptor_t xlate_sf_reg_0; 32 | extern const guest_code_descriptor_t xlate_scc_reg_0; 33 | extern const guest_code_descriptor_t xlate_scs_reg_0; 34 | extern const guest_code_descriptor_t xlate_seq_reg_0; 35 | extern const guest_code_descriptor_t xlate_sge_reg_0; 36 | extern const guest_code_descriptor_t xlate_sgt_reg_0; 37 | extern const guest_code_descriptor_t xlate_shi_reg_0; 38 | extern const guest_code_descriptor_t xlate_sle_reg_0; 39 | extern const guest_code_descriptor_t xlate_sls_reg_0; 40 | extern const guest_code_descriptor_t xlate_slt_reg_0; 41 | extern const guest_code_descriptor_t xlate_smi_reg_0; 42 | extern const guest_code_descriptor_t xlate_sne_reg_0; 43 | extern const guest_code_descriptor_t xlate_spl_reg_0; 44 | extern const guest_code_descriptor_t xlate_svc_reg_0; 45 | extern const guest_code_descriptor_t xlate_svs_reg_0; 46 | 47 | extern const guest_code_descriptor_t xlate_jmp; 48 | 49 | extern const guest_code_descriptor_t xlate_dbra; 50 | 51 | extern const guest_code_descriptor_t xlate_swap; 52 | 53 | extern const guest_code_descriptor_t xlate_extbw; 54 | extern const guest_code_descriptor_t xlate_extbl; 55 | extern const guest_code_descriptor_t xlate_extwl; 56 | 57 | extern const guest_code_descriptor_t xlate_unlk; 58 | extern const guest_code_descriptor_t xlate_link; 59 | 60 | extern const guest_code_descriptor_t xlate_moveml_reg_predec_0_1; 61 | extern const guest_code_descriptor_t xlate_moveml_postinc_reg_0_1; 62 | 63 | extern const guest_code_descriptor_t xlate_pea_indoff; 64 | 65 | extern const guest_code_descriptor_t xlate_leal_indoff_areg_2_1_0; 66 | 67 | extern const guest_code_descriptor_t xlate_rts; 68 | 69 | extern const guest_code_descriptor_t xlate_mulsw_imm_reg_1_0; 70 | extern const guest_code_descriptor_t xlate_mulsw_abs_reg_1_0; 71 | extern const guest_code_descriptor_t xlate_mulsw_reg_reg_1_0; 72 | extern const guest_code_descriptor_t xlate_mulsw_ind_reg_1_0; 73 | extern const guest_code_descriptor_t xlate_mulsw_indoff_reg_2_1_0; 74 | extern const guest_code_descriptor_t xlate_mulsw_postinc_reg_1_0; 75 | extern const guest_code_descriptor_t xlate_mulsw_predec_reg_1_0; 76 | 77 | extern const guest_code_descriptor_t xlate_muluw_imm_reg_1_0; 78 | extern const guest_code_descriptor_t xlate_muluw_abs_reg_1_0; 79 | extern const guest_code_descriptor_t xlate_muluw_reg_reg_1_0; 80 | extern const guest_code_descriptor_t xlate_muluw_ind_reg_1_0; 81 | extern const guest_code_descriptor_t xlate_muluw_indoff_reg_2_1_0; 82 | extern const guest_code_descriptor_t xlate_muluw_postinc_reg_1_0; 83 | extern const guest_code_descriptor_t xlate_muluw_predec_reg_1_0; 84 | 85 | extern const guest_code_descriptor_t xlate_jsr_abs_0; 86 | extern const guest_code_descriptor_t xlate_jsr_pcd16_0; 87 | extern const guest_code_descriptor_t xlate_jsr_d16_0_1; 88 | extern const guest_code_descriptor_t xlate_bsr; 89 | 90 | extern const guest_code_descriptor_t xlate_moveb_imm_indix_1_0; 91 | extern const guest_code_descriptor_t xlate_movew_imm_indix_1_0; 92 | extern const guest_code_descriptor_t xlate_movel_imm_indix_1_0; 93 | 94 | extern const guest_code_descriptor_t xlate_moveb_zero_indix_0; 95 | extern const guest_code_descriptor_t xlate_movew_zero_indix_0; 96 | extern const guest_code_descriptor_t xlate_movel_zero_indix_0; 97 | 98 | extern const guest_code_descriptor_t xlate_cmpb_zero_indix_0; 99 | extern const guest_code_descriptor_t xlate_cmpw_zero_indix_0; 100 | extern const guest_code_descriptor_t xlate_cmpl_zero_indix_0; 101 | 102 | extern const guest_code_descriptor_t xlate_moveb_reg_indix_1_0; 103 | extern const guest_code_descriptor_t xlate_movew_reg_indix_1_0; 104 | extern const guest_code_descriptor_t xlate_movel_reg_indix_1_0; 105 | 106 | extern const guest_code_descriptor_t xlate_moveb_indix_reg_1_0; 107 | extern const guest_code_descriptor_t xlate_movew_indix_reg_1_0; 108 | extern const guest_code_descriptor_t xlate_movel_indix_reg_1_0; 109 | extern const guest_code_descriptor_t xlate_movel_indix_areg_1_0; 110 | 111 | extern const guest_code_descriptor_t xlate_cmpb_indix_reg_1_0; 112 | extern const guest_code_descriptor_t xlate_cmpw_indix_reg_1_0; 113 | extern const guest_code_descriptor_t xlate_cmpl_indix_reg_1_0; 114 | 115 | extern const guest_code_descriptor_t xlate_leal_indix_areg_1_0; 116 | 117 | extern const guest_code_descriptor_t xlate_addb_imm_indix_0_1; 118 | extern const guest_code_descriptor_t xlate_addw_imm_indix_0_1; 119 | extern const guest_code_descriptor_t xlate_addl_imm_indix_0_1; 120 | 121 | extern const guest_code_descriptor_t xlate_subb_imm_indix_0_1; 122 | extern const guest_code_descriptor_t xlate_subw_imm_indix_0_1; 123 | extern const guest_code_descriptor_t xlate_subl_imm_indix_0_1; 124 | 125 | extern const guest_code_descriptor_t xlate_divsw_imm_reg_1_0; 126 | extern const guest_code_descriptor_t xlate_divsw_reg_reg_1_0; 127 | extern const guest_code_descriptor_t xlate_divsw_ind_reg_1_0; 128 | extern const guest_code_descriptor_t xlate_divsw_predec_reg_1_0; 129 | extern const guest_code_descriptor_t xlate_divsw_postinc_reg_1_0; 130 | extern const guest_code_descriptor_t xlate_divsw_indoff_reg_2_1_0; 131 | 132 | extern const guest_code_descriptor_t xlate_addxb_reg_reg_1_0; 133 | extern const guest_code_descriptor_t xlate_addxw_reg_reg_1_0; 134 | extern const guest_code_descriptor_t xlate_addxl_reg_reg_1_0; 135 | 136 | #endif /* GENERATE_NATIVE_CODE */ 137 | 138 | #endif /* !_xlate_aux_h_ */ 139 | -------------------------------------------------------------------------------- /runtime/native/i386/xlate.h: -------------------------------------------------------------------------------- 1 | #ifndef _xlate_h_ 2 | #define _xlate_h_ 3 | 4 | #include "syn68k_private.h" 5 | #include "native.h" 6 | 7 | 8 | typedef enum { NA=0, B=1, W=2, L=4, BW=3, BL=5, WL=6, BWL=7 } size_mask_t; 9 | 10 | typedef enum 11 | { 12 | AMODE_NONE, 13 | AMODE_IMM, 14 | AMODE_REG, 15 | AMODE_AREG, 16 | AMODE_IND, 17 | AMODE_POSTINC, 18 | AMODE_PREDEC, 19 | AMODE_INDOFF, 20 | AMODE_ABS, 21 | AMODE_INDIX, 22 | } amode_t; 23 | 24 | #define MEMORY_AMODE_P(a) ((a) >= AMODE_IND && (a) <= AMODE_INDIX) 25 | #define REGISTER_AMODE_P(a) ((a) == AMODE_REG || (a) == AMODE_AREG) 26 | 27 | typedef enum 28 | { 29 | OP_UNARY, /* e.g. negw a0@ */ 30 | OP_BINARY, /* e.g. addl d0,a5 */ 31 | OP_MOVE /* e.g. movel a0@(124),d0 */ 32 | } op_type_t; 33 | 34 | typedef struct 35 | { 36 | amode_t amode; /* Addressing mode for how to grab this value. */ 37 | int operand_num[2]; /* Which ops specify this value (may not use all). */ 38 | } value_t; 39 | 40 | #define MAX_XLATE_VALUES 2 41 | 42 | typedef struct 43 | { 44 | const char *name; 45 | op_type_t type; 46 | size_mask_t sizes; 47 | int cc_to_compute; 48 | const char *i386_op; 49 | value_t value[MAX_XLATE_VALUES]; /* For binops & moves, 2nd is the dest. */ 50 | } xlate_descriptor_t; 51 | 52 | #ifndef NELEM 53 | #define NELEM(a) ((sizeof (a)) / sizeof ((a)[0])) 54 | #endif 55 | 56 | extern guest_code_descriptor_t 57 | *process_xlate_descriptor (const xlate_descriptor_t *x); 58 | 59 | extern const xlate_descriptor_t xlate_table[]; 60 | 61 | #endif /* !_xlate_h_ */ 62 | -------------------------------------------------------------------------------- /runtime/native/i386/xlatemain.c: -------------------------------------------------------------------------------- 1 | #include "xlate.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | static void output_desc_list (FILE *table_fp, FILE *header_fp, 9 | guest_code_descriptor_t *g); 10 | static BOOL gcd_equal_p (const guest_code_descriptor_t *g1, 11 | const guest_code_descriptor_t *g2); 12 | 13 | 14 | int 15 | main (void) 16 | { 17 | const xlate_descriptor_t *x; 18 | FILE *table_fp, *header_fp; 19 | 20 | table_fp = fopen ("host-xlate.c", "w"); 21 | assert (table_fp); 22 | header_fp = fopen ("host-xlate.h", "w"); 23 | assert (header_fp); 24 | 25 | fputs ("/* This file is machine-generated; DO NOT EDIT! */\n" 26 | "\n" 27 | "#ifndef _host_xlate_h_\n" 28 | "#define _host_xlate_h_\n" 29 | "\n", 30 | header_fp); 31 | 32 | fputs ("/* This file is machine-generated; DO NOT EDIT! */\n" 33 | "\n" 34 | "#ifndef RUNTIME\n" 35 | "#define RUNTIME /* So stuff gets typedefed properly. */\n" 36 | "#endif\n" 37 | "#include \"syn68k_private.h\"\n" 38 | "#include \"native.h\"\n" 39 | "#include \"host-xlate.h\"\n" 40 | "#include \"i386-isa.h\"\n" 41 | "#include \"i386-aux.h\"\n" 42 | "\n" 43 | "\n", 44 | table_fp); 45 | 46 | for (x = xlate_table; x->name != NULL; x++) 47 | output_desc_list (table_fp, header_fp, process_xlate_descriptor (x)); 48 | 49 | fputs ("\n" 50 | "#endif /* _host_xlate_h */\n", 51 | header_fp); 52 | 53 | fclose (table_fp); 54 | fclose (header_fp); 55 | 56 | return EXIT_SUCCESS; 57 | } 58 | 59 | 60 | static void 61 | output_desc (FILE *table_fp, FILE *header_fp, guest_code_descriptor_t *g) 62 | { 63 | int i; 64 | guest_code_descriptor_t *next; 65 | 66 | if (g->static_p) 67 | fputs ("static ", table_fp); 68 | else 69 | fprintf (header_fp, "extern const guest_code_descriptor_t %s;\n", g->name); 70 | fprintf (table_fp, "const guest_code_descriptor_t %s =\n" 71 | "{\n", g->name); 72 | 73 | fputs (" {\n", table_fp); 74 | for (i = 0; g->reg_op_info[i].legitimate_p; i++) 75 | { 76 | const reg_operand_info_t *r = &g->reg_op_info[i]; 77 | fprintf (table_fp, " { TRUE, %s, %d, 0x%X, %d, %d, 0x%X },\n", 78 | r->add8_p ? "TRUE" : "FALSE", r->operand_num, 79 | (unsigned) r->acceptable_mapping, r->request_type, 80 | r->output_state, (unsigned) r->regset); 81 | } 82 | fputs (" { FALSE },\n" 83 | " },\n", 84 | table_fp); 85 | 86 | fprintf (table_fp, " 0x%X, 0x%X, 0x%X,\n" 87 | " {\n", 88 | (unsigned) g->cc_in, (unsigned) g->cc_out, 89 | (unsigned) g->scratch_reg); 90 | 91 | 92 | for (i = 0; i < MAX_COMPILE_FUNCS && g->compile_func[i].func; i++) 93 | { 94 | fprintf (table_fp, " { %s, { { %d, %d, %d, %d } } },\n", 95 | g->compile_func[i].func, 96 | g->compile_func[i].order.operand_num[0], 97 | g->compile_func[i].order.operand_num[1], 98 | g->compile_func[i].order.operand_num[2], 99 | g->compile_func[i].order.operand_num[3]); 100 | } 101 | 102 | next = g->next; 103 | if (next && !g->next->static_p) 104 | next = NULL; 105 | fprintf (table_fp, 106 | " },\n" 107 | " %s%s\n" 108 | "};\n" 109 | "\n", next ? "&" : "", next ? next->name : "NULL"); 110 | } 111 | 112 | 113 | /* Prints out the list in reverse order. */ 114 | static void 115 | output_desc_list (FILE *table_fp, FILE *header_fp, 116 | guest_code_descriptor_t *g) 117 | { 118 | if (g == NULL) 119 | return; 120 | 121 | /* Filter out two adjacent desc's that are equal except for the 122 | * cc bits they claim to compute. If we hit this situation, we might 123 | * as well only bother with the guy who claims to compute the most 124 | * cc bits. 125 | */ 126 | if (!g->static_p && g->next != NULL && g->next->static_p 127 | && (g->cc_out & g->next->cc_out) == g->cc_out) 128 | { 129 | int equal_p; 130 | unsigned save_cc_out; 131 | 132 | /* See if the two are essentially identical. */ 133 | save_cc_out = g->cc_out; 134 | g->cc_out = g->next->cc_out; 135 | equal_p = gcd_equal_p (g, g->next); 136 | g->cc_out = save_cc_out; 137 | 138 | if (equal_p) 139 | { 140 | g->next->name = g->name; 141 | g->next->static_p = FALSE; 142 | output_desc_list (table_fp, header_fp, g->next); 143 | return; 144 | } 145 | } 146 | 147 | output_desc_list (table_fp, header_fp, g->next); 148 | output_desc (table_fp, header_fp, g); 149 | } 150 | 151 | 152 | static BOOL 153 | gcd_equal_p (const guest_code_descriptor_t *g1, 154 | const guest_code_descriptor_t *g2) 155 | { 156 | int i; 157 | 158 | if (g1->cc_in != g2->cc_in 159 | || g1->cc_out != g2->cc_out 160 | || g1->scratch_reg != g2->scratch_reg) 161 | return FALSE; 162 | 163 | if (memcmp (g1->reg_op_info, g2->reg_op_info, sizeof g1->reg_op_info)) 164 | return FALSE; 165 | 166 | for (i = 0; i < MAX_COMPILE_FUNCS; i++) 167 | { 168 | int g1n, g2n; 169 | 170 | g1n = (g1->compile_func[i].func == NULL); 171 | g2n = (g2->compile_func[i].func == NULL); 172 | if (g1n || g2n) 173 | { 174 | if (g1n ^ g2n) 175 | return FALSE; 176 | break; 177 | } 178 | 179 | if (strcmp (g1->compile_func[i].func, g2->compile_func[i].func)) 180 | return FALSE; 181 | if (memcmp (&g1->compile_func[i].order, &g2->compile_func[i].order, 182 | sizeof g1->compile_func[i].order)) 183 | return FALSE; 184 | } 185 | 186 | return TRUE; 187 | } 188 | -------------------------------------------------------------------------------- /runtime/native/null/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | clean: 4 | 5 | obj/i486-linux-glibc-nonnative/subdir-stmp: 6 | -------------------------------------------------------------------------------- /runtime/native/null/host-native.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctm/syn68k/88219957db18260090bfc82363210ea8f15d8c1b/runtime/native/null/host-native.h -------------------------------------------------------------------------------- /runtime/native/null/host-xlate.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctm/syn68k/88219957db18260090bfc82363210ea8f15d8c1b/runtime/native/null/host-xlate.h -------------------------------------------------------------------------------- /runtime/native/null/subdir-stmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctm/syn68k/88219957db18260090bfc82363210ea8f15d8c1b/runtime/native/null/subdir-stmp -------------------------------------------------------------------------------- /runtime/opcode_dummy.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | * s68k_handle_opcode_dummy is used to detect portions of assembly in 5 | * syn68k.s that are unreachable and should be removed via 6 | * i486-cleanup.pl. The call to s68k_handle_opcode_dummy should never 7 | * be made. It won't be reachable even if i486-cleanup.pl isn't run, 8 | * but it will be assembled and linked in, so that's why we actually 9 | * supply s68k_handle_opcode_dummy but expect it to never be called. 10 | */ 11 | 12 | void s68k_handle_opcode_dummy (void) 13 | { 14 | fprintf (stderr, "This function should never be called\n"); 15 | abort (); 16 | } 17 | -------------------------------------------------------------------------------- /runtime/profile.c: -------------------------------------------------------------------------------- 1 | #ifdef PROFILE 2 | 3 | #include "profile.h" 4 | #include "mapping.h" 5 | #include "blockinfo.h" 6 | #include 7 | 8 | static uint32 instruction_frequency[65536]; 9 | 10 | /* Global variable to tweak with gdb to turn profiling on and off. */ 11 | int should_profile = 1; 12 | 13 | void 14 | profile_block (Block *b) 15 | { 16 | syn68k_addr_t addr = b->m68k_start_address; 17 | 18 | if ((addr < MAGIC_ADDRESS_BASE || addr > 0x00FFFFFF) 19 | && should_profile) 20 | { 21 | while (addr < b->m68k_start_address + b->m68k_code_length) 22 | { 23 | uint16 m68kop = READUW (addr); 24 | ++instruction_frequency[m68kop]; 25 | addr += 2 * (instruction_size 26 | (SYN68K_TO_US (addr), 27 | &opcode_map_info[opcode_map_index[m68kop]])); 28 | } 29 | } 30 | } 31 | 32 | 33 | void 34 | dump_profile (const char *file) 35 | { 36 | FILE *fp; 37 | #ifdef LITTLEENDIAN 38 | int i; 39 | uint32 *p; 40 | #endif 41 | 42 | /* Choose default filename. */ 43 | if (file == NULL) 44 | file = "/tmp/instrfreq"; 45 | 46 | fp = fopen (file, "wb"); 47 | if (fp == NULL) 48 | { 49 | fprintf (stderr, "Unable to write to %s", file); 50 | perror (""); 51 | return; 52 | } 53 | 54 | /* Assure that we always write out the profiling info in big endian order. */ 55 | #ifdef LITTLEENDIAN 56 | for (i = 65535, p = instruction_frequency; i >= 0; p++, i--) 57 | *p = SWAPUL (*p); 58 | #endif 59 | 60 | fwrite (instruction_frequency, sizeof instruction_frequency[0], 61 | sizeof instruction_frequency / sizeof instruction_frequency[0], 62 | fp); 63 | 64 | /* Undo byte swaps and put it back into native order. */ 65 | #ifdef LITTLEENDIAN 66 | for (i = 65535, p = instruction_frequency; i >= 0; p++, i--) 67 | *p = SWAPUL (*p); 68 | #endif 69 | 70 | fclose (fp); 71 | } 72 | 73 | #endif /* PROFILE */ 74 | -------------------------------------------------------------------------------- /runtime/recompile.c: -------------------------------------------------------------------------------- 1 | #include "syn68k_private.h" 2 | 3 | #ifdef GENERATE_NATIVE_CODE 4 | 5 | #include "recompile.h" 6 | #include "translate.h" 7 | #include "destroyblock.h" 8 | #include "hash.h" 9 | #include "alloc.h" 10 | #include "native.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | static void find_blocks_to_recompile (Block *b, syn68k_addr_t **bad_blocks, 18 | unsigned long *num_bad_blocks, 19 | unsigned long *max_bad_blocks); 20 | 21 | 22 | static int 23 | compare_m68k_addrs (const void *p1, const void *p2) 24 | { 25 | return *(syn68k_addr_t *)p1 - *(syn68k_addr_t *)p2; 26 | } 27 | 28 | void 29 | recompile_block_as_native (Block *b) 30 | { 31 | syn68k_addr_t *bad_blocks, orig_address; 32 | long n; 33 | unsigned long num_bad_blocks, max_bad_blocks; 34 | int old_sigmask; 35 | 36 | BLOCK_INTERRUPTS (old_sigmask); 37 | 38 | orig_address = b->m68k_start_address; 39 | 40 | #if 0 41 | fprintf (stderr, 42 | "recompiling block %p at address 0x%X. Block ptr in code is %p.\n", 43 | (void *)b, (unsigned)b->m68k_start_address, 44 | *(void **)(b->compiled_code + PTR_WORDS)); 45 | #endif 46 | 47 | /* Allocate some space for the blocks to recompile. */ 48 | max_bad_blocks = 256; 49 | num_bad_blocks = 0; 50 | bad_blocks = (syn68k_addr_t *)xmalloc (max_bad_blocks 51 | * sizeof bad_blocks[0]); 52 | 53 | /* Find a bunch of blocks to smash. */ 54 | find_blocks_to_recompile (b, &bad_blocks, &num_bad_blocks, &max_bad_blocks); 55 | 56 | assert (num_bad_blocks != 0); 57 | 58 | /* Sort the blocks by address. Hopefully this will require fewer 59 | * passes when recompiling below. 60 | */ 61 | qsort (bad_blocks, num_bad_blocks, sizeof bad_blocks[0], compare_m68k_addrs); 62 | 63 | #if 0 64 | for (n = 0; n < num_bad_blocks; n++) 65 | fprintf (stderr, "\t0x%X\n", 66 | (unsigned)(hash_lookup (bad_blocks[n])->m68k_start_address)); 67 | #endif 68 | 69 | /* Destroy them all. */ 70 | for (n = num_bad_blocks - 1; n >= 0; n--) 71 | { 72 | /* We need to do a hash check since this block may have been 73 | * recursively destroyed on some previous call to destroy_block(). 74 | * That's why we don't just keep an array of Block *'s. 75 | */ 76 | Block *b = hash_lookup (bad_blocks[n]); 77 | if (b != NULL) 78 | destroy_block (b); 79 | } 80 | 81 | /* Recompile them all with native code enabled. */ 82 | for (n = 0; n < num_bad_blocks; n++) 83 | { 84 | Block *junk; 85 | generate_block (NULL, bad_blocks[n], &junk, TRUE); 86 | } 87 | 88 | free (bad_blocks); 89 | 90 | /* Smash the jsr stack to be safe. */ 91 | memset (&cpu_state.jsr_stack, -1, sizeof cpu_state.jsr_stack); 92 | 93 | assert ((b = hash_lookup (orig_address)) && NATIVE_CODE_TRIED (b)); 94 | 95 | RESTORE_INTERRUPTS (old_sigmask); 96 | 97 | #if 0 98 | fprintf (stderr, 99 | " done compiling. New block == %p, new block pointer == %p\n", 100 | (void *)b, *(void **)(b->compiled_code + PTR_WORDS)); 101 | #endif 102 | } 103 | 104 | 105 | static void 106 | find_parents (Block *b, syn68k_addr_t **bad_blocks, 107 | unsigned long *num_bad_blocks, 108 | unsigned long *max_bad_blocks) 109 | { 110 | while (b != NULL && !b->recompile_me) 111 | { 112 | int i; 113 | 114 | b->recompile_me = TRUE; 115 | 116 | if (*num_bad_blocks >= *max_bad_blocks) 117 | { 118 | *max_bad_blocks *= 2; 119 | *bad_blocks = (syn68k_addr_t *) 120 | xrealloc (*bad_blocks, (*max_bad_blocks 121 | * sizeof (*bad_blocks)[0])); 122 | } 123 | 124 | /* Append this block to the list of blocks to smash. */ 125 | (*bad_blocks)[(*num_bad_blocks)++] = b->m68k_start_address; 126 | b->recompile_me = TRUE; 127 | 128 | for (i = b->num_parents - 1; i > 0; i--) 129 | { 130 | Block *p = b->parent[i]; 131 | if (!p->recompile_me) /* Check now for speed. */ 132 | find_parents (p, bad_blocks, num_bad_blocks, max_bad_blocks); 133 | } 134 | 135 | /* Iterate on the last one, for speed. */ 136 | if (b->num_parents) 137 | b = b->parent[0]; 138 | } 139 | } 140 | 141 | 142 | static void 143 | find_blocks_to_recompile (Block *b, syn68k_addr_t **bad_blocks, 144 | unsigned long *num_bad_blocks, 145 | unsigned long *max_bad_blocks) 146 | { 147 | while (b != NULL 148 | && !b->recompile_me 149 | && b->num_times_called >= RECOMPILE_CHILD_CUTOFF 150 | && !NATIVE_CODE_TRIED (b)) 151 | { 152 | find_parents (b, bad_blocks, num_bad_blocks, max_bad_blocks); 153 | 154 | if (b->child[1] != NULL) 155 | find_blocks_to_recompile (b->child[1], bad_blocks, num_bad_blocks, 156 | max_bad_blocks); 157 | 158 | /* Iterate, for speed. */ 159 | b = b->child[0]; 160 | } 161 | } 162 | 163 | 164 | /* Just to give us interesting statistics on what fraction was actually 165 | * recompiled as native. 166 | */ 167 | double 168 | native_fraction () 169 | { 170 | Block *b; 171 | unsigned long native, nonnative; 172 | double ratio; 173 | 174 | native = nonnative = 0; 175 | for (b = death_queue_head; b != NULL; b = b->death_queue_next) 176 | { 177 | if (NATIVE_CODE_TRIED (b)) 178 | ++native; 179 | else 180 | ++nonnative; 181 | } 182 | 183 | if (native + nonnative == 0) 184 | ratio = 0.0; 185 | else 186 | ratio = (double)native / (native + nonnative); 187 | 188 | printf ("%lu/%lu native (%.2f%%)\n", native, native + nonnative, 189 | ratio * 100.0); 190 | 191 | return ratio; 192 | } 193 | 194 | 195 | #endif /* GENERATE_NATIVE_CODE */ 196 | -------------------------------------------------------------------------------- /runtime/reg: -------------------------------------------------------------------------------- 1 | eax l reg_a_hh reg_a_hl reg_a_lh reg_a_ll 2 | eax w reg_a_lh reg_a_ll 3 | eax b reg_a_ll 4 | ax l reg_a_hh reg_a_hl reg_a_lh reg_a_ll 5 | ax w reg_a_lh reg_a_ll 6 | ax b reg_a_ll 7 | ah l reg_a_hh reg_a_hl reg_a_lh reg_a_ll 8 | ah w reg_a_lh reg_a_ll 9 | ah b reg_a_lh 10 | al l reg_a_hh reg_a_hl reg_a_lh reg_a_ll 11 | al w reg_a_lh reg_a_ll 12 | al b reg_a_ll 13 | ebx l reg_b_hh reg_b_hl reg_b_lh reg_b_ll 14 | ebx w reg_b_lh reg_b_ll 15 | ebx b reg_b_ll 16 | bx l reg_b_hh reg_b_hl reg_b_lh reg_b_ll 17 | bx w reg_b_lh reg_b_ll 18 | bx b reg_b_ll 19 | bh l reg_b_hh reg_b_hl reg_b_lh reg_b_ll 20 | bh w reg_b_lh reg_b_ll 21 | bh b reg_b_lh 22 | bl l reg_b_hh reg_b_hl reg_b_lh reg_b_ll 23 | bl w reg_b_lh reg_b_ll 24 | bl b reg_b_ll 25 | ecx l reg_c_hh reg_c_hl reg_c_lh reg_c_ll 26 | ecx w reg_c_lh reg_c_ll 27 | ecx b reg_c_ll 28 | cx l reg_c_hh reg_c_hl reg_c_lh reg_c_ll 29 | cx w reg_c_lh reg_c_ll 30 | cx b reg_c_ll 31 | ch l reg_c_hh reg_c_hl reg_c_lh reg_c_ll 32 | ch w reg_c_lh reg_c_ll 33 | ch b reg_c_lh 34 | cl l reg_c_hh reg_c_hl reg_c_lh reg_c_ll 35 | cl w reg_c_lh reg_c_ll 36 | cl b reg_c_ll 37 | edx l reg_d_hh reg_d_hl reg_d_lh reg_d_ll 38 | edx w reg_d_lh reg_d_ll 39 | edx b reg_d_ll 40 | dx l reg_d_hh reg_d_hl reg_d_lh reg_d_ll 41 | dx w reg_d_lh reg_d_ll 42 | dx b reg_d_ll 43 | dh l reg_d_hh reg_d_hl reg_d_lh reg_d_ll 44 | dh w reg_d_lh reg_d_ll 45 | dh b reg_d_lh 46 | dl l reg_d_hh reg_d_hl reg_d_lh reg_d_ll 47 | dl w reg_d_lh reg_d_ll 48 | dl b reg_d_ll 49 | esi l reg_si_hh reg_si_hl reg_si_lh reg_si_ll 50 | esi w reg_si_lh reg_si_ll 51 | si l reg_si_hh reg_si_hl reg_si_lh reg_si_ll 52 | si w reg_si_lh reg_si_ll 53 | edi l reg_di_hh reg_di_hl reg_di_lh reg_di_ll 54 | edi w reg_di_lh reg_di_ll 55 | di l reg_di_hh reg_di_hl reg_di_lh reg_di_ll 56 | di w reg_di_lh reg_di_ll 57 | ebp l reg_bp_hh reg_bp_hl reg_bp_lh reg_bp_ll 58 | ebp w reg_bp_lh reg_bp_ll 59 | bp l reg_bp_hh reg_bp_hl reg_bp_lh reg_bp_ll 60 | bp w reg_bp_lh reg_bp_ll 61 | esp l reg_sp_hh reg_sp_hl reg_sp_lh reg_sp_ll 62 | esp w reg_sp_lh reg_sp_ll 63 | sp l reg_sp_hh reg_sp_hl reg_sp_lh reg_sp_ll 64 | sp w reg_sp_lh reg_sp_ll 65 | -------------------------------------------------------------------------------- /runtime/trap.c: -------------------------------------------------------------------------------- 1 | #include "trap.h" 2 | #include "callback.h" 3 | #include 4 | #include 5 | 6 | /* Pointer to the array of trap vectors. */ 7 | uint32 *trap_vector_array; 8 | 9 | void 10 | trap_init () 11 | { 12 | volatile TrapHandlerInfo *thi; 13 | int i; 14 | 15 | cpu_state.vbr = US_TO_SYN68K (trap_vector_array); 16 | for (i = 63, thi = &cpu_state.trap_handler_info[63]; i >= 0; thi--, i--) 17 | { 18 | thi->callback_address = callback_install (trap_forwarded, (void *) thi); 19 | WRITE_LONG (&trap_vector_array[i], thi->callback_address); 20 | thi->func = NULL; 21 | thi->arg = NULL; 22 | } 23 | } 24 | 25 | 26 | void 27 | trap_install_handler (unsigned trap_number, callback_handler_t func, 28 | void *arbitrary_argument) 29 | { 30 | cpu_state.trap_handler_info[trap_number].func = func; 31 | cpu_state.trap_handler_info[trap_number].arg = arbitrary_argument; 32 | } 33 | 34 | 35 | void 36 | trap_remove_handler (unsigned trap_number) 37 | { 38 | cpu_state.trap_handler_info[trap_number].func = NULL; 39 | } 40 | 41 | 42 | uint32 43 | trap_forwarded (uint32 m68k_address, void *arg) 44 | { 45 | const TrapHandlerInfo *thi = (TrapHandlerInfo *) arg; 46 | 47 | if (thi->func == NULL) /* If no handler installed, just rte. */ 48 | { 49 | static const char *trap_description[] = { 50 | /* I've only put the really interesting ones in. */ 51 | NULL, NULL, NULL, NULL, 52 | "Illegal instruction", 53 | "Integer divide by zero", 54 | "CHK/CHK2", 55 | "FTRAPcc, TRAPcc, TRAPV", 56 | "Privilege violation", 57 | "Trace", 58 | "A-line", 59 | "F-line", 60 | NULL, 61 | NULL, 62 | "Format error" 63 | }; 64 | int which_trap = thi - cpu_state.trap_handler_info; 65 | 66 | fprintf (stderr, "Unhandled trap %d!", which_trap); 67 | if (which_trap >= 0 68 | && which_trap < sizeof trap_description / sizeof trap_description[0] 69 | && trap_description[which_trap] != NULL) 70 | fprintf (stderr, " (%s)", trap_description[which_trap]); 71 | putc ('\n', stderr); 72 | 73 | return MAGIC_RTE_ADDRESS; 74 | } 75 | return thi->func (READUL (EM_A7 + 2), thi->arg); 76 | } 77 | 78 | 79 | uint32 80 | trap_direct (uint32 trap_number, uint32 exception_pc, 81 | uint32 exception_address) 82 | { 83 | const volatile TrapHandlerInfo *thi; 84 | uint16 *p, old_sr; 85 | uint32 trap_addr; 86 | uint32 retval; 87 | 88 | /* Fetch trap address from vector table. */ 89 | trap_addr = READUL (cpu_state.vbr + (trap_number << 2)); 90 | 91 | switch (trap_number) { 92 | case 4: /* Illegal instruction. */ 93 | case 8: /* Privilege violation. */ 94 | case 10: /* A-line. */ 95 | case 11: /* F-line. */ 96 | case 14: /* Format error. */ 97 | case 15: /* Uninitialized interrupt. */ 98 | case 24: /* Spurious interrupt. */ 99 | case 25: /* Level 1 interrupt autovector. */ 100 | case 26: /* Level 2 interrupt autovector. */ 101 | case 27: /* Level 3 interrupt autovector. */ 102 | case 28: /* Level 4 interrupt autovector. */ 103 | case 29: /* Level 5 interrupt autovector. */ 104 | case 30: /* Level 6 interrupt autovector. */ 105 | case 31: /* Level 7 interrupt autovector. */ 106 | case 32: /* TRAP #0 vector. */ 107 | case 33: /* TRAP #1 vector. */ 108 | case 34: /* TRAP #2 vector. */ 109 | case 35: /* TRAP #3 vector. */ 110 | case 36: /* TRAP #4 vector. */ 111 | case 37: /* TRAP #5 vector. */ 112 | case 38: /* TRAP #6 vector. */ 113 | case 39: /* TRAP #7 vector. */ 114 | case 40: /* TRAP #8 vector. */ 115 | case 41: /* TRAP #9 vector. */ 116 | case 42: /* TRAP #10 vector. */ 117 | case 43: /* TRAP #11 vector. */ 118 | case 44: /* TRAP #12 vector. */ 119 | case 45: /* TRAP #13 vector. */ 120 | case 46: /* TRAP #14 vector. */ 121 | case 47: /* TRAP #15 vector. */ 122 | /* Save away the old SR. */ 123 | old_sr = COMPUTE_SR_FROM_CPU_STATE (); 124 | 125 | /* Clear TR0 and TR1. */ 126 | cpu_state.sr &= 0x3FFF; 127 | 128 | /* If this is an actual interrupt, adjust the SR appropriately. */ 129 | if (trap_number >= 15 && trap_number <= 31) 130 | { 131 | /* Bump up interrupt mask priority. */ 132 | if (trap_number >= 24 && trap_number <= 31) 133 | cpu_state.sr = ((cpu_state.sr & ~(7 << 8)) 134 | | ((trap_number - 24) << 8)); 135 | 136 | /* Switch into interrupt mode. */ 137 | cpu_state.sr &= ~SR_MASTER_BIT; 138 | } 139 | 140 | cpu_state.sr |= SR_SUPERVISOR_BIT; 141 | 142 | /* Switch stacks appropriately. */ 143 | SWITCH_A7 (old_sr, cpu_state.sr); 144 | 145 | /* Push the exception frame. */ 146 | EM_A7 -= 8; 147 | p = SYN68K_TO_US (CLEAN (EM_A7)); 148 | WRITE_WORD (p, old_sr); 149 | WRITE_LONG (p + 1, exception_pc); 150 | WRITE_WORD (p + 3, 0x0000 | (trap_number << 2)); 151 | break; 152 | 153 | case 3: /* Address error. */ 154 | case 6: /* CHK/CHK2 instruction. */ 155 | case 7: /* FTRAPcc, TRAPcc, TRAPV instructions. */ 156 | case 9: /* Trace. */ 157 | case 5: /* Integer divide by zero. */ 158 | /* Save away the old SR. */ 159 | old_sr = COMPUTE_SR_FROM_CPU_STATE (); 160 | 161 | /* Clear TR0 and TR1. */ 162 | cpu_state.sr &= 0x3FFF; 163 | 164 | /* Switch into supervisor mode. */ 165 | cpu_state.sr |= SR_SUPERVISOR_BIT; 166 | 167 | /* Switch stacks. */ 168 | SWITCH_A7 (old_sr, cpu_state.sr); 169 | 170 | EM_A7 -= 12; 171 | p = SYN68K_TO_US (CLEAN (EM_A7)); 172 | WRITE_WORD (p, old_sr); 173 | WRITE_LONG (p + 1, exception_pc); 174 | WRITE_WORD (p + 3, 0x2000 | (trap_number << 2)); 175 | WRITE_LONG (p + 4, exception_address); 176 | break; 177 | 178 | /* I don't know how to handle these or they can't happen. */ 179 | case 0: /* Reset initial interrupt stack pointer. */ 180 | case 1: /* Reset initial program counter. */ 181 | case 2: /* Access fault */ 182 | case 13: /* ? */ 183 | case 48: /* FP Branch or Set on Unordered Condition. */ 184 | case 49: /* FP Inexact result. */ 185 | case 50: /* FP Divide by zero. */ 186 | case 51: /* FP Underflow. */ 187 | case 52: /* FP Operand error. */ 188 | case 53: /* FP Overflow. */ 189 | case 54: /* FP Signaling NAN. */ 190 | case 55: /* FP Unimplemented Data Type. */ 191 | default: 192 | abort (); 193 | } 194 | 195 | /* See if they haven't set up their own vector. If they haven't, 196 | * and we are interested in the trap, dispatch it directly to the handling 197 | * function. 198 | */ 199 | thi = &cpu_state.trap_handler_info[trap_number]; 200 | 201 | if (trap_addr == thi->callback_address && thi->func != NULL) 202 | retval = thi->func (exception_pc, thi->arg); 203 | else /* Otherwise, trap back to m68k space. */ 204 | retval = trap_addr; 205 | 206 | #ifdef USE_BIOS_TIMER 207 | /* Just to be safe, guarantee that %fs points to conventional memory. */ 208 | asm volatile ("movw %0,%%fs" 209 | : : "g" (dos_memory_selector)); 210 | #endif /* USE_BIOS_TIMER */ 211 | 212 | return retval; 213 | } 214 | -------------------------------------------------------------------------------- /syngen/.gitignore: -------------------------------------------------------------------------------- 1 | syngen 2 | .deps 3 | -------------------------------------------------------------------------------- /syngen/CAVEATS: -------------------------------------------------------------------------------- 1 | 1) CC bits may not be valid during an interrupt 2 | 2) We don't support supervisor mode properly 3 | a) We have only one SP (no MSP, ISP, USP) 4 | b) You cannot leave supervisor mode 5 | 3) The interrupt stack space is in a static array which may not look 6 | like a valid address from the Mac's point of view. 7 | 4) Interrupt/trap handlers we write are responsible for performing their 8 | own RTE. 9 | 5) Flushing the cache during an interrupt can have bad effects; the compiled 10 | code being interpreted would get destroyed, and on return back to the 11 | compiled code bad things would happen. 12 | 6) Expanding multiple CC variants of the same opcode won't work properly. 13 | It will only expand the piecewise intersections of the specified addressing 14 | modes. Instead, it should go through and do all the intersections, and then 15 | run through each variant's expansion pattern with "----------------" as the 16 | expansion pattern for all other variants. 17 | -------------------------------------------------------------------------------- /syngen/INSTALL: -------------------------------------------------------------------------------- 1 | TODO 2 | -------------------------------------------------------------------------------- /syngen/Makefile.am: -------------------------------------------------------------------------------- 1 | CC=@CC_FOR_BUILD@ 2 | noinst_PROGRAMS = syngen 3 | 4 | syngen_CPPFLAGS = -DSYNGEN 5 | 6 | syngen_SOURCES = main.c token.c hash.c parse.c list.c reduce.c macro.c \ 7 | boolean.c error.c defopcode.c bitstring.c generatecode.c \ 8 | uniquestring.c byteorder.c \ 9 | \ 10 | include/boolean.h include/error.h include/reduce.h include/parse.h \ 11 | include/bitstring.h include/uniquestring.h include/hash.h \ 12 | include/byteorder.h include/tokenlist.h include/common.h \ 13 | include/macro.h include/generatecode.h include/list.h include/token.h \ 14 | include/defopcode.h 15 | 16 | INCLUDES = -I$(srcdir)/include -I$(srcdir)/../include -I../include 17 | 18 | EXEEXT = 19 | -------------------------------------------------------------------------------- /syngen/SYNOP_LAYOUT: -------------------------------------------------------------------------------- 1 | Synthetic opcodes are composed of a 16 bit opcode followed by 2 | operands. All operands will be aligned appropriately. Operands taking 16 or 3 | fewer bits in the 68k instruction stream will NEVER be extended to 32 bits 4 | in the synthetic stream. 5 | 6 | If this instruction ends a block and has one or more known destination 7 | blocks, the synthetic opcode is immediately followed by pointers to 8 | the synthetic code in those blocks. 9 | 10 | Next come any 32 bit operands not mentioned in the 68k description 11 | file (eg, return addresses for jsrs). 12 | 13 | Next come all 32 bit operands explicitly mentioned in the 68k 14 | description file, in "field number" order (eg, $2.u precedes $4.s, etc.) 15 | 16 | Finally we have all 16 bit operands, also in "field number" order. 17 | -------------------------------------------------------------------------------- /syngen/TODO: -------------------------------------------------------------------------------- 1 | 6) Fold amodes 6 and 7 together, ignoring the reg field of the amode. 2 | Some amode 7 (abs short, abs long, imm) should not be folded if the 3 | amode as a whole is being expanded. 4 | 7) Grab unexpanded regs at the beginning of the case? Saves code iff 5 | the reg is referred to more than once. Watch out for lvalues and 6 | aliases... 7 | 14) Table builder should be more aggressive about using OpcodeMappingInfo 8 | sequences from similar instructions 9 | 20) Look into changing beq et al: 10 | (if (not ccnz) 11 | (assign code (deref "uint16 **" code 1)) 12 | (assign code (deref "uint16 **" code 0))))) 13 | To: 14 | (assign code (deref "uint16 **" code (not ccnz))) 15 | 22) Handle assigns to dollar registers not in the first instruction word 16 | (happens now for bitfields, cas2...) 17 | 23) Don't generate switch to correct for postinc/predec when that amode isn't 18 | possible. 19 | 25) Right now VBR points to a static array in trap.c; make it point 20 | to real m68k memory. 21 | 27) Rewrite movemw/moveml #ifdef'd for the case where our regs are in an 22 | array. It should be possible to write it as a nice tight loop. 23 | 33) Expanding two different cc variants of the same instruction won't work. 24 | Instead, it will only expand bit patterns in the intersection of the two 25 | bits_to_expand's as it marches along the list, or something like that. 26 | 36) Add a new operand type for 3 bit numbers where 0 is really 8. These 27 | are common in instructions that specify small constants, and this should 28 | let us cut down the number of synthetic opcodes we need, thus 29 | reducing the size of 68k.scm and syn68k.c. 30 | 37) Rewrite parts of byteorder.c to better handle assigning expressions of 31 | unknown size to memory. As it is, it doesn't know what size of byte 32 | swapping macro to use when, for example, doing: 33 | (assign $1.muw (| (<> ccc 0) (<> ccx 0))) 34 | The current heuristic is to swap based on the size of the smaller of the 35 | LHS and RHS. This doesn't work in the above example. For now, I've 36 | worked around this in 68k.scm by inserting native order temp variables of 37 | the appropriate size, like: 38 | (assign tmp1.uw (| (<> ccc 0) (<> ccx 0))) 39 | (assign $1.muw tmp1.uw) 40 | Here it is straightforward for byteorder.c to figure out what size 41 | the data to be swapped (tmp1.uw) is. I think this only comes up 42 | in the ccr/sr instructions. 43 | 38) Test move16 44 | 39) gcc isn't clever about: 45 | (d0.ub.n = (*(uint8 *) CLEAN ((a0.ul.n - 1) )) ) ; 46 | a0.ul.n -= 1; 47 | It computes a0.ul.n - 1 twice! It would be nice to replace this 48 | with: 49 | (d0.ub.n = (*(uint8 *) CLEAN ((--a0.ul.n)))); 50 | but it's tricky to do this because, if the dereference of the 51 | predecremented a0 is used more than once, we want to avoid decrementing 52 | it more than once. 53 | 40) Separate arrays for the two fields of amode_cleanup_info might be 54 | faster on the 486; if we are clever, we can possibly get the compiler to 55 | use the "xlatb" instruction, although perhaps this isn't a win. 56 | -------------------------------------------------------------------------------- /syngen/bitstring.c: -------------------------------------------------------------------------------- 1 | #include "bitstring.h" 2 | #include "error.h" 3 | #include 4 | 5 | 6 | /* This takes a 16 bit number and a bitset (described by a lisp-style 7 | * expression) and returns TRUE iff the number is a member of that set. 8 | * A bitset would be described by an expression like: 9 | * 10 | * (union "00001111xx0011xx" "mmmm00111011xxx1" 11 | * (intersect "1001xxxx0011nnn1" (not "0110001111000101"))) 12 | * 13 | * The number will be in the set if the usual union, intersect and not 14 | * properties are met. A number matches a simple string if each literal 15 | * '0' and '1' in the string matches a 0 or 1 bit in the number, respectively. 16 | * All non-'0' and non-'1' characters in the string are assumed to be 17 | * wildcards; anything in the corresponding bit position in the number will 18 | * be considered a match. 19 | */ 20 | 21 | BOOL 22 | is_member_of_set (unsigned short n, List *set) 23 | { 24 | List *tmp; 25 | char buf[512]; 26 | 27 | /* If we are looking for a match against a quoted string, efficiently 28 | * determine if all of the literal bits match. This could be vastly 29 | * faster if the quoted string were replaced with a mask of bits that must 30 | * be valid and a set of values for those bits, but speed just doesn't 31 | * matter here, and it's handy to deal with the original string (which 32 | * can contain other information via the specific choice of non-'0' 33 | * and non-'1' characters). 34 | */ 35 | if (set->token.type == TOK_QUOTED_STRING) 36 | { 37 | const char *s = set->token.u.string; 38 | int mask; 39 | 40 | 41 | for (mask = 1 << 15; mask != 0; s++, mask >>= 1) 42 | if ((*s == '0' && (n & mask)) || (*s == '1' && !(n & mask))) 43 | { 44 | return FALSE; 45 | } 46 | 47 | return TRUE; 48 | } 49 | 50 | if (set->token.type != TOK_LIST) 51 | { 52 | /* This error will get printed a zillion times, but who cares. */ 53 | parse_error (set, "Malformed bit set; expecting quoted string of bits, " 54 | "union, intersect, or not, found %s\n", 55 | unparse_token (&set->token, buf)); 56 | return FALSE; 57 | } 58 | 59 | /* Not a member of the empty list. */ 60 | if (set->car == NULL) 61 | return FALSE; 62 | 63 | /* See what type of operation we are performing, and do the appropriate 64 | * thing. 65 | */ 66 | switch (set->car->token.type) { 67 | case TOK_UNION: 68 | if (list_length (set->car) < 2) 69 | parse_error (set->car, "Missing arguments to union.\n"); 70 | for (tmp = CDAR (set); tmp != NULL; tmp = tmp->cdr) 71 | if (is_member_of_set (n, tmp)) 72 | return TRUE; 73 | return FALSE; 74 | case TOK_INTERSECT: 75 | if (list_length (set->car) < 2) 76 | parse_error (set->car, "Missing arguments to intersect.\n"); 77 | for (tmp = CDAR (set); tmp != NULL; tmp = tmp->cdr) 78 | if (!is_member_of_set (n, tmp)) 79 | return FALSE; 80 | return TRUE; 81 | case TOK_NOT: 82 | if (list_length (set->car) != 2) 83 | { 84 | parse_error (set->car, "Must have exactly one argument to not.\n"); 85 | return FALSE; 86 | } 87 | return !is_member_of_set (n, CDAR (set)); 88 | default: 89 | /* This error will get printed a zillion times, but who cares. */ 90 | parse_error (set, "Malformed bit set; expecting quoted string of bits, " 91 | "union, intersect, or not.\n"); 92 | return FALSE; 93 | } 94 | } 95 | 96 | 97 | BOOL 98 | empty_set (List *set, int literal_bits_mask, int literal_bits) 99 | { 100 | int i; 101 | 102 | for (i = 0; i < 65536; i++) 103 | if ((i & literal_bits_mask) == literal_bits && is_member_of_set (i, set)) 104 | return FALSE; 105 | return TRUE; 106 | } 107 | 108 | 109 | /* Given a bit pattern like "0010ddd0000ddd001xxx001ppp" and a field number, 110 | * returns by reference the low index and length of the nth field, where 111 | * the first field (in this case the first string of 3 d's) is # 1. Returns 112 | * TRUE if such a field exists, else FALSE. 113 | */ 114 | BOOL 115 | pattern_range (const char *pattern, int which, PatternRange *range) 116 | { 117 | const char *p = pattern, *p2; 118 | 119 | do 120 | { 121 | if (*p == '\0') 122 | return FALSE; 123 | 124 | /* Skip to first sequence. */ 125 | for (; *p != '\0' && (*p == '0' || *p == '1'); p++) 126 | ; 127 | 128 | /* Remember where the pattern started. */ 129 | range->index = p - pattern; 130 | p2 = p; 131 | 132 | /* Find the end of the sequence. */ 133 | for (; *p != '\0' && *p == *p2; p++) 134 | ; 135 | 136 | /* Remember the length of the pattern. */ 137 | range->length = p - p2; 138 | } 139 | while (--which > 0); 140 | 141 | return TRUE; 142 | } 143 | 144 | 145 | int 146 | field_with_index (const char *opcode_bits, int index) 147 | { 148 | PatternRange range; 149 | int i; 150 | 151 | for (i = 1; pattern_range (opcode_bits, i, &range); i++) 152 | { 153 | if (range.index == index) 154 | return i; 155 | } 156 | return 0; 157 | } 158 | 159 | 160 | BOOL 161 | field_expanded (int field_number, const char *opcode_bits, 162 | const char *bits_to_expand) 163 | { 164 | PatternRange range; 165 | int i; 166 | 167 | /* If there is no such field, return FALSE. */ 168 | if (!pattern_range (opcode_bits, field_number, &range)) 169 | return FALSE; 170 | 171 | /* If the field falls outside the first 16 bits, it can't be expanded. */ 172 | if (range.index >= 16) 173 | return FALSE; 174 | 175 | for (i = range.index; i < range.index + range.length; i++) 176 | if (bits_to_expand[i] == '-' && opcode_bits[i] != '0' 177 | && opcode_bits[i] != '1') 178 | return FALSE; 179 | 180 | return TRUE; 181 | } 182 | 183 | 184 | int 185 | num_fields (const char *opcode_bits) 186 | { 187 | PatternRange range; 188 | int i; 189 | 190 | for (i = 1; pattern_range (opcode_bits, i, &range); i++) 191 | ; 192 | return i - 1; 193 | } 194 | 195 | 196 | void 197 | make_unique_field_of_width (const char *opcode_bits, char *where, int width) 198 | { 199 | int i, x; 200 | for (x = 'A'; strchr (opcode_bits, x) != NULL; x++) 201 | ; 202 | for (i = 0; i < width; i++) 203 | *where++ = x; 204 | *where = '\0'; 205 | } 206 | 207 | 208 | /* Handy utility function. */ 209 | void 210 | print_16_bits (FILE *stream, unsigned short n) 211 | { 212 | int shift; 213 | for (shift = 15; shift >= 0; shift--) 214 | putc ('0' + ((n >> shift) & 1), stream); 215 | } 216 | -------------------------------------------------------------------------------- /syngen/error.c: -------------------------------------------------------------------------------- 1 | /* 2 | * error.c 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "token.h" 9 | #include "common.h" 10 | #include "list.h" 11 | 12 | 13 | /* Prints out an error message and returns. */ 14 | 15 | void 16 | error (const char *fmt, ...) 17 | { 18 | va_list ap; 19 | 20 | va_start (ap, fmt); 21 | vfprintf (stderr, fmt, ap); 22 | } 23 | 24 | 25 | /* Prints out an error message and aborts. */ 26 | 27 | void 28 | fatal_error (const char *fmt, ...) 29 | { 30 | va_list ap; 31 | 32 | va_start (ap, fmt); 33 | vfprintf (stderr, fmt, ap); 34 | fputs ("*** Exit\n", stderr); 35 | abort (); 36 | } 37 | 38 | 39 | /* Prints out an error message for a given List and returns. */ 40 | 41 | void 42 | parse_error (const List *ls, const char *fmt, ...) 43 | { 44 | va_list ap; 45 | 46 | va_start (ap, fmt); 47 | fprintf (stderr, "%s, line %lu:\t", ls->token.filename, ls->token.lineno); 48 | vfprintf (stderr, fmt, ap); 49 | } 50 | 51 | 52 | /* Prints out an error message for a given List and aborts. */ 53 | 54 | void 55 | fatal_parse_error (const List *ls, const char *fmt, ...) 56 | { 57 | va_list ap; 58 | 59 | va_start (ap, fmt); 60 | fprintf (stderr, "%s, line %lu:\t", ls->token.filename, ls->token.lineno); 61 | vfprintf (stderr, fmt, ap); 62 | fputs ("*** Exit\n", stderr); 63 | exit (-1); 64 | } 65 | 66 | 67 | /* Prints out an error message for the current file and returns. */ 68 | 69 | void 70 | input_error (const char *fmt, ...) 71 | { 72 | va_list ap; 73 | const InputFile *current = get_input_file (0); 74 | const InputFile *tmp = get_input_file (1); 75 | int lev = 2; 76 | 77 | if (tmp != NULL) 78 | { 79 | error ("In file included from %s:%d", tmp->filename, tmp->lineno); 80 | for (tmp = get_input_file (2); tmp != NULL; tmp = get_input_file (++lev)) 81 | error (", from %s:%d", tmp->filename, tmp->lineno); 82 | error (":\n"); 83 | } 84 | if (current != NULL) 85 | error ("%s: %d: ", current->filename, current->lineno); 86 | 87 | va_start (ap, fmt); 88 | vfprintf (stderr, fmt, ap); 89 | } 90 | 91 | 92 | /* Prints out an error message for the current file and aborts. */ 93 | 94 | void 95 | fatal_input_error (const char *fmt, ...) 96 | { 97 | va_list ap; 98 | const InputFile *current = get_input_file (0); 99 | const InputFile *tmp = get_input_file (1); 100 | int lev = 2; 101 | 102 | if (tmp != NULL) 103 | { 104 | error ("In file included from %s:%d", tmp->filename, tmp->lineno); 105 | for (tmp = get_input_file (2); tmp != NULL; tmp = get_input_file (++lev)) 106 | error (", from %s:%d", tmp->filename, tmp->lineno); 107 | error (":\n"); 108 | } 109 | if (current != NULL) 110 | error ("%s: %d: ", current->filename, current->lineno); 111 | 112 | va_start (ap, fmt); 113 | vfprintf (stderr, fmt, ap); 114 | fputs ("*** Exit\n", stderr); 115 | exit (-1); 116 | } 117 | -------------------------------------------------------------------------------- /syngen/hash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "hash.h" 5 | 6 | /* This file contains: 7 | * make_symbol_table() - returns a new, empty symbol table. 8 | * free_symbol_table() - deallocates all memory associated with an s.t. 9 | * insert_symbol() - inserts a key/value pair into a symbol table. 10 | * NOTE: key is NOT duplicated! 11 | * lookup_symbol() - returns the value associated with a key. 12 | * dump_symbol_table() - prints out a symbol table in human-readable form. 13 | */ 14 | 15 | 16 | static int hash_code (const char *string); 17 | 18 | 19 | /* Returns a new, empty symbol table needed for subsequent symbol table 20 | * manipulations. 21 | */ 22 | 23 | SymbolTable * 24 | make_symbol_table (void) 25 | { 26 | SymbolTable *s = malloc (sizeof (SymbolTable)); 27 | Bucket **b; 28 | int i; 29 | 30 | for (i = 0, b = &s->bucket[0]; i < HASH_BUCKETS; i++, b++) 31 | { 32 | *b = (Bucket *) malloc (sizeof (Bucket)); 33 | (*b)->num_symbols = 0; 34 | (*b)->max_symbols = INITIAL_SYMBOLS; 35 | } 36 | 37 | return s; 38 | } 39 | 40 | 41 | /* Deallocates all memory taken by a symbol table. */ 42 | 43 | void 44 | free_symbol_table (SymbolTable *s) 45 | { 46 | int i; 47 | 48 | for (i = 0; i < HASH_BUCKETS; i++) 49 | free (s->bucket[i]); 50 | free (s); 51 | } 52 | 53 | 54 | /* Inserts a symbol and an associated value into a symbol table. If successful, 55 | * returns HASH_NOERR. If that symbol is already defined, it returns 56 | * HASH_DUPLICATE. Note that the string NAME is not duplicated! Only the 57 | * pointer is copied, so be sure not to deallocate NAME, or the symbol table 58 | * will become corrupt. VAL is duplicated. 59 | */ 60 | 61 | HashErr 62 | insert_symbol (SymbolTable *s, const char *name, SymbolInfo val) 63 | { 64 | int i, bucket_num = hash_code (name); 65 | Symbol *sym; 66 | Bucket *b; 67 | char firstc = *name; 68 | 69 | b = s->bucket[bucket_num]; 70 | 71 | /* First, check for a duplicate. */ 72 | for (i = b->num_symbols, sym = &b->symbol[0]; i > 0; sym++, i--) 73 | if (firstc == sym->name[0] && !strcmp (name, sym->name)) 74 | return HASH_DUPLICATE; 75 | 76 | /* If there isn't room, double the size of the bucket. */ 77 | if (b->num_symbols >= b->max_symbols) 78 | { 79 | b->max_symbols *= 2; 80 | b = s->bucket[bucket_num] = 81 | (Bucket *) realloc (b, sizeof *b + ((b->max_symbols - INITIAL_SYMBOLS) 82 | * sizeof (Symbol))); 83 | } 84 | 85 | sym = &b->symbol[b->num_symbols++]; 86 | sym->name = name; 87 | sym->value = val; 88 | 89 | return HASH_NOERR; 90 | } 91 | 92 | 93 | /* Looks up a symbol in a symbol table. If successful, it places the 94 | * associated value in *val, the original key in *original_name_ptr, 95 | * and returns HASH_NOERR. If either val or original_name_ptr are NULL their 96 | * contents are not modified. If not successful, *val, *original_name_ptr are 97 | * unchanged and HASH_NOTFOUND is returned. 98 | */ 99 | 100 | HashErr 101 | lookup_symbol (const SymbolTable *s, const char *name, SymbolInfo *val, 102 | const char **original_name_ptr) 103 | { 104 | int i, bucket_num = hash_code (name); 105 | Bucket *b = s->bucket[bucket_num]; 106 | Symbol *sym; 107 | char firstc = *name; 108 | 109 | for (i = b->num_symbols, sym = &b->symbol[0]; i > 0; sym++, i--) 110 | if (firstc == sym->name[0] && !strcmp (name, sym->name)) 111 | { 112 | if (val != NULL) 113 | *val = sym->value; 114 | if (original_name_ptr != NULL) 115 | *original_name_ptr = sym->name; 116 | return HASH_NOERR; 117 | } 118 | 119 | return HASH_NOTFOUND; 120 | } 121 | 122 | 123 | /* Prints out a symbol table in human-readable format. */ 124 | 125 | void 126 | dump_symbol_table (const SymbolTable *s) 127 | { 128 | const Bucket *b; 129 | int i, j, collisions; 130 | 131 | for (i = collisions = 0; i < HASH_BUCKETS; i++) 132 | { 133 | b = s->bucket[i]; 134 | if (b->num_symbols > 0) 135 | { 136 | printf ("Bucket #%d:\n---------------\n", i); 137 | for (j = 0; j < b->num_symbols; j++) 138 | printf ("\t\"%s\"\t:\t%ld\n", b->symbol[j].name, 139 | b->symbol[j].value.n); 140 | collisions += b->num_symbols - 1; 141 | } 142 | } 143 | 144 | printf ("Total collisions: %d\n", collisions); 145 | } 146 | 147 | 148 | static int 149 | hash_code (const char *string) 150 | { 151 | unsigned long c, h = 0; 152 | 153 | while ((c = *string++)) 154 | { 155 | h += c; 156 | h = (h << 3) + (h >> 2) + c; 157 | } 158 | 159 | return (h % HASH_BUCKETS); 160 | } 161 | -------------------------------------------------------------------------------- /syngen/include/bitstring.h: -------------------------------------------------------------------------------- 1 | #ifndef _bitset_h_ 2 | #define _bitset_h_ 3 | 4 | #include "common.h" 5 | #include "list.h" 6 | 7 | typedef struct { 8 | int index, length; 9 | } PatternRange; 10 | 11 | extern BOOL is_member_of_set (unsigned short n, List *set); 12 | extern void print_16_bits (FILE *stream, unsigned short n); 13 | extern BOOL pattern_range (const char *pattern, int which, 14 | PatternRange *range); 15 | extern int num_fields (const char *opcode_bits); 16 | extern void make_unique_field_of_width (const char *opcode_bits, char *where, 17 | int width); 18 | extern int field_with_index (const char *opcode_bits, int index); 19 | extern BOOL field_expanded (int field_number, const char *opcode_bits, 20 | const char *bits_to_expand); 21 | extern BOOL empty_set (List *set, int literal_bits_mask, int literal_bits); 22 | 23 | #endif /* Not _bitset_h_ */ 24 | -------------------------------------------------------------------------------- /syngen/include/boolean.h: -------------------------------------------------------------------------------- 1 | #ifndef _boolean_h_ 2 | #define _boolean_h_ 3 | 4 | #include "list.h" 5 | 6 | typedef enum { 7 | E_FALSE, E_TRUE, E_UNKNOWN, E_AND, E_OR, E_XOR, E_NOT 8 | } BoolExprType; 9 | 10 | typedef struct BoolExprStruct { 11 | BoolExprType type; 12 | struct BoolExprStruct *subexpr; 13 | struct BoolExprStruct *next; 14 | } BoolExpr; 15 | 16 | extern BoolExpr *make_boolean_expr (const List *ls); 17 | extern BoolExprType eval_bool_expr (const BoolExpr *be); 18 | extern void print_boolean_expr (const BoolExpr *be); 19 | 20 | #endif /* not _boolean_h_ */ 21 | -------------------------------------------------------------------------------- /syngen/include/byteorder.h: -------------------------------------------------------------------------------- 1 | #ifndef _byteorder_h_ 2 | #define _byteorder_h_ 3 | 4 | #include "defopcode.h" 5 | #include "syn68k_private.h" 6 | 7 | typedef struct { 8 | const char *operand_decls; 9 | int num_bitfields; 10 | BitfieldInfo bitfield[8]; 11 | } OperandInfo; 12 | 13 | extern int compute_operand_info (OperandInfo *op, const ParsedOpcodeInfo *p, 14 | const CCVariant *v); 15 | 16 | #endif /* Not _byteorder_h_ */ 17 | -------------------------------------------------------------------------------- /syngen/include/common.h: -------------------------------------------------------------------------------- 1 | #ifndef _common_h_ 2 | #define _common_h_ 3 | 4 | #include 5 | #include "syn68k_private.h" /* To typedef BOOL. */ 6 | 7 | /* Useful macros. */ 8 | #define ABS(x) ((x)>=0?(x):-(x)) 9 | #define SGN(x) ((x)>0?1:((x<0)?-1:0)) /* or (((x) > 0) - ((x) < 0)) :-) */ 10 | #define MIN(a,b) (((a)<(b))?(a):(b)) 11 | #define MAX(a,b) (((a)>(b))?(a):(b)) 12 | 13 | /* Global variables. */ 14 | extern int optimization_level; 15 | extern BOOL preprocess_only; 16 | extern FILE *syn68k_c_stream, *mapinfo_c_stream, *mapindex_c_stream; 17 | extern FILE *profileinfo_stream; 18 | extern BOOL verbose; 19 | 20 | #endif /* not _common_h_ */ 21 | -------------------------------------------------------------------------------- /syngen/include/defopcode.h: -------------------------------------------------------------------------------- 1 | #ifndef _defopcode_h_ 2 | #define _defopcode_h_ 3 | 4 | #include "list.h" 5 | #include "hash.h" 6 | 7 | #define MAX_OPCODE_WORDS 16 8 | #define MAX_VARIANTS 64 9 | 10 | typedef struct _CCVariant { 11 | unsigned cc_may_set :5; 12 | unsigned cc_may_not_set :5; 13 | unsigned cc_needed :5; 14 | unsigned cc_to_known_value :5; 15 | unsigned cc_known_values :5; 16 | char *bits_to_expand; 17 | List *code; 18 | const char *native_code_info; 19 | struct _CCVariant *next; 20 | } CCVariant; 21 | 22 | typedef struct { 23 | const char *name; 24 | int cpu; 25 | List *amode; 26 | List *misc_flags; 27 | char opcode_bits[16 * MAX_OPCODE_WORDS + 1];/* Concat'd 16-bit patterns. */ 28 | CCVariant *cc_variant; /* Linked list of CC variants. */ 29 | BOOL ends_block; 30 | BOOL next_block_dynamic; 31 | BOOL dont_postincdec_unexpanded; 32 | int operand_words_to_skip; 33 | } ParsedOpcodeInfo; 34 | 35 | extern void generate_opcode (ParsedOpcodeInfo *info, SymbolTable *sym); 36 | extern void begin_generating_code (void); 37 | extern void done_generating_code (void); 38 | extern int synthetic_opcode_size (const OpcodeMappingInfo *map); 39 | 40 | #endif /* Not _defopcode_h_ */ 41 | -------------------------------------------------------------------------------- /syngen/include/error.h: -------------------------------------------------------------------------------- 1 | #ifndef _error_h_ 2 | #define _error_h_ 3 | 4 | #include "parse.h" 5 | 6 | extern void error (const char *fmt, ...); 7 | #if defined(__GNUC__) && !defined(__STRICT_ANSI__) 8 | extern volatile void fatal_error (const char *fmt, ...); 9 | extern volatile void fatal_parse_error (const List *ls, const char *fmt, ...); 10 | extern volatile void fatal_input_error (const char *fmt, ...); 11 | #else 12 | extern void fatal_error (const char *fmt, ...); 13 | extern void fatal_parse_error (const List *ls, const char *fmt, ...); 14 | extern void fatal_input_error (const char *fmt, ...); 15 | #endif 16 | extern void parse_error (const List *ls, const char *fmt, ...); 17 | extern void input_error (const char *fmt, ...); 18 | 19 | #endif /* Not _error_h_ */ 20 | -------------------------------------------------------------------------------- /syngen/include/generatecode.h: -------------------------------------------------------------------------------- 1 | #ifndef _generatecode_h_ 2 | #define _generatecode_h_ 3 | 4 | #include "syn68k_private.h" 5 | #include "defopcode.h" 6 | 7 | extern void generate_c_code (const ParsedOpcodeInfo *info, 8 | const CCVariant *var, 9 | int m68kop, int synop, SymbolTable *sym, 10 | const char *operand_decls, const char *postcode, 11 | const OpcodeMappingInfo *map); 12 | 13 | #endif /* Not _generatecode_h_ */ 14 | -------------------------------------------------------------------------------- /syngen/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef _hash_h_ 2 | #define _hash_h_ 3 | 4 | #define HASH_BUCKETS 253 5 | #define INITIAL_SYMBOLS 7 6 | 7 | typedef union { 8 | long n; 9 | void *p; 10 | } SymbolInfo; 11 | 12 | typedef struct { 13 | const char *name; 14 | SymbolInfo value; 15 | } Symbol; 16 | 17 | typedef struct { 18 | int num_symbols, max_symbols; 19 | Symbol symbol[INITIAL_SYMBOLS]; /* variable length array. */ 20 | } Bucket; 21 | 22 | typedef struct { 23 | Bucket *bucket[HASH_BUCKETS]; 24 | } SymbolTable; 25 | 26 | 27 | typedef enum { HASH_NOERR, HASH_DUPLICATE, HASH_NOTFOUND } HashErr; 28 | 29 | 30 | extern SymbolTable *make_symbol_table (void); 31 | extern void free_symbol_table (SymbolTable *s); 32 | extern HashErr insert_symbol (SymbolTable *s, const char *name, 33 | SymbolInfo val); 34 | extern HashErr lookup_symbol (const SymbolTable *s, const char *name, 35 | SymbolInfo *val, const char **original_name_ptr); 36 | extern void dump_symbol_table (const SymbolTable *s); 37 | 38 | #endif /* Not hash_h_ */ 39 | -------------------------------------------------------------------------------- /syngen/include/list.h: -------------------------------------------------------------------------------- 1 | #ifndef _list_h_ 2 | #define _list_h_ 3 | 4 | #include "token.h" 5 | 6 | typedef struct ListStruct { 7 | struct ListStruct *cdr, *car; 8 | Token token; /* car == NULL, token.type = TOK_LIST -> empty list. */ 9 | } List; 10 | 11 | #define CDR(c) ((c)->cdr) 12 | #define CAR(c) ((c)->car) 13 | #define CDDR(c) ((c)->cdr->cdr) 14 | #define CDAR(c) ((c)->car->cdr) 15 | #define CADR(c) ((c)->cdr->car) 16 | #define CAAR(c) ((c)->car->car) 17 | #define CDDDR(c) ((c)->cdr->cdr->cdr) 18 | #define CDDAR(c) ((c)->car->cdr->cdr) 19 | #define CDADR(c) ((c)->cdr->car->cdr) 20 | #define CDAAR(c) ((c)->car->car->cdr) 21 | #define CADDR(c) ((c)->cdr->cdr->car) 22 | #define CADAR(c) ((c)->car->cdr->car) 23 | #define CAADR(c) ((c)->cdr->car->car) 24 | #define CAAAR(c) ((c)->car->car->car) 25 | #define CDDDDR(c) ((c)->cdr->cdr->cdr->cdr) 26 | #define CADDAR(c) ((c)->car->cdr->cdr->car) 27 | #define CADDDR(c) ((c)->cdr->cdr->cdr->car) 28 | 29 | extern List *alloc_list (void); 30 | extern List *copy_list (const List *ls); 31 | extern void propagate_fileinfo (const Token *original, List *ls); 32 | extern BOOL lists_equal (const List *l1, const List *l2); 33 | extern int list_length (const List *ls); 34 | extern Token *has_token_of_type (List *list, TokenType type); 35 | extern void print_list (FILE *out, const List *ls); 36 | extern void replace_list (List *old, List *new); 37 | extern void replace_tokens_of_type (List *list, TokenType old, TokenType new); 38 | extern void replace_tokens_of_type_with_list (List *list, TokenType old, 39 | const List *new); 40 | extern int list_size (const List *ls); 41 | extern BOOL list_overlap (const List *l1, const List *l2); 42 | 43 | #endif /* Not _list_h_ */ 44 | -------------------------------------------------------------------------------- /syngen/include/macro.h: -------------------------------------------------------------------------------- 1 | #ifndef _macro_h_ 2 | #define _macro_h_ 3 | 4 | #include "list.h" 5 | #include "hash.h" 6 | 7 | #define MAX_MACRO_EXPANSIONS 64 8 | 9 | typedef struct MacroStruct { 10 | List *expr; 11 | struct MacroStruct *next; 12 | } Macro; 13 | 14 | extern BOOL macro_sub (List *ls, const SymbolTable *sym, BOOL flag_err); 15 | 16 | #endif /* Not _macro_h_ */ 17 | -------------------------------------------------------------------------------- /syngen/include/parse.h: -------------------------------------------------------------------------------- 1 | #ifndef _parse_h_ 2 | #define _parse_h_ 3 | 4 | #include "token.h" 5 | #include "list.h" 6 | #include "hash.h" 7 | 8 | extern int parse_all_expressions (SymbolTable *sym); 9 | extern List *string_to_list (const char *string, const char *include_dirs[]); 10 | 11 | #endif /* Not _parse_h_ */ 12 | -------------------------------------------------------------------------------- /syngen/include/reduce.h: -------------------------------------------------------------------------------- 1 | #ifndef _reduce_h_ 2 | #define _reduce_h_ 3 | 4 | #include "list.h" 5 | #include "hash.h" 6 | 7 | extern List *reduce_list (List *ls, const SymbolTable *sym, int macro_level); 8 | extern List *reduce (List *ls, const SymbolTable *sym, int macro_level); 9 | 10 | #endif /* Not _reduce_h_ */ 11 | -------------------------------------------------------------------------------- /syngen/include/token.h: -------------------------------------------------------------------------------- 1 | #ifndef _token_h_ 2 | #define _token_h_ 3 | 4 | #include 5 | 6 | #include "common.h" 7 | 8 | /* Current file stuff. */ 9 | #define MAX_INCLUDE_DEPTH 32 10 | #define MAX_FILENAME_LENGTH 248 11 | #define MAX_TOKEN_SIZE 1024 12 | 13 | typedef struct { 14 | FILE *fp; 15 | unsigned long lineno; 16 | char filename[MAX_FILENAME_LENGTH]; 17 | } InputFile; 18 | 19 | 20 | /* Token stuff. */ 21 | typedef enum { 22 | TOK_FALSE, TOK_TRUE, 23 | 24 | TOK_IF, TOK_SWITCH, TOK_DEFAULT, 25 | TOK_AND, TOK_OR, TOK_XOR, TOK_NOT, 26 | 27 | TOK_EQUAL, TOK_NOT_EQUAL, TOK_GREATER_THAN, TOK_LESS_THAN, 28 | TOK_GREATER_OR_EQUAL, TOK_LESS_OR_EQUAL, 29 | 30 | TOK_DOLLAR_DATA_REGISTER, 31 | TOK_DOLLAR_ADDRESS_REGISTER, 32 | TOK_DOLLAR_GENERAL_REGISTER, 33 | TOK_DOLLAR_AMODE, 34 | TOK_DOLLAR_REVERSED_AMODE, /* Used in move; reg/mode order reversed. */ 35 | TOK_DOLLAR_NUMBER, 36 | TOK_DOLLAR_AMODE_PTR, TOK_DOLLAR_REVERSED_AMODE_PTR, 37 | 38 | TOK_AMODE, TOK_REVERSED_AMODE, 39 | TOK_AMODE_PTR, TOK_REVERSED_AMODE_PTR, 40 | 41 | TOK_IDENTIFIER, 42 | TOK_QUOTED_STRING, 43 | TOK_NUMBER, 44 | 45 | TOK_LEFT_PAREN, TOK_RIGHT_PAREN, 46 | 47 | TOK_DATA_REGISTER, TOK_ADDRESS_REGISTER, TOK_TEMP_REGISTER, 48 | 49 | TOK_NOP, 50 | 51 | TOK_UNION, TOK_INTERSECT, 52 | 53 | TOK_CCC, TOK_CCN, TOK_CCV, TOK_CCX, TOK_CCNZ, 54 | 55 | TOK_SHIFT_LEFT, TOK_SHIFT_RIGHT, 56 | 57 | TOK_ASSIGN, 58 | 59 | TOK_PLUS, TOK_MINUS, TOK_MULTIPLY, TOK_DIVIDE, TOK_MOD, 60 | TOK_BITWISE_AND, TOK_BITWISE_OR, TOK_BITWISE_XOR, TOK_BITWISE_NOT, 61 | 62 | TOK_NUMARGS, 63 | TOK_NIL, 64 | 65 | TOK_FUNC_CALL, 66 | TOK_CAST, TOK_DEREF, 67 | TOK_CODE, 68 | 69 | TOK_SWAP, 70 | 71 | TOK_EXPLICIT_LIST, 72 | 73 | TOK_ENDS_BLOCK, TOK_DONT_POSTINCDEC_UNEXPANDED, 74 | TOK_NEXT_BLOCK_DYNAMIC, TOK_SKIP_TWO_OPERAND_WORDS, 75 | TOK_SKIP_FOUR_OPERAND_WORDS, TOK_SKIP_ONE_POINTER, TOK_SKIP_TWO_POINTERS, 76 | TOK_NATIVE_CODE, 77 | 78 | TOK_DEFINE, 79 | TOK_DEFOPCODE, 80 | TOK_ERROR, 81 | TOK_TAIL, 82 | TOK_INCLUDE, 83 | TOK_LIST, 84 | TOK_UNKNOWN, TOK_EMPTY 85 | } TokenType; 86 | 87 | 88 | #define IS_DOLLAR_TOKEN(t) \ 89 | ((t) == TOK_DOLLAR_DATA_REGISTER \ 90 | || (t) == TOK_DOLLAR_ADDRESS_REGISTER \ 91 | || (t) == TOK_DOLLAR_GENERAL_REGISTER \ 92 | || (t) == TOK_DOLLAR_AMODE \ 93 | || (t) == TOK_DOLLAR_REVERSED_AMODE \ 94 | || (t) == TOK_DOLLAR_NUMBER \ 95 | || (t) == TOK_DOLLAR_AMODE_PTR \ 96 | || (t) == TOK_DOLLAR_REVERSED_AMODE_PTR) 97 | 98 | #define IS_CCBIT_TOKEN(t) \ 99 | ((t) == TOK_CCC || (t) == TOK_CCN || (t) == TOK_CCV || (t) == TOK_CCX \ 100 | || (t) == TOK_CCNZ) 101 | 102 | 103 | typedef struct { 104 | TokenType type; 105 | union { 106 | const char *string; 107 | long n; 108 | struct { 109 | unsigned char sgnd; /* Signed or unsigned? */ 110 | unsigned char size; /* 1 == byte, 2 == short, 4 == long. */ 111 | unsigned char which; /* Which field or register. */ 112 | } reginfo, amodeinfo, dollarinfo; /* KEEP THESE THE SAME! */ 113 | /* Types changed blindly. */ 114 | struct { 115 | unsigned char sgnd; /* Signed or unsigned? */ 116 | unsigned char size; /* 0 == untyped, 1 == byte, 2 == short, 4 == long. */ 117 | } derefinfo, swapinfo; 118 | } u; 119 | const char *filename; 120 | unsigned long lineno; 121 | } Token; 122 | 123 | 124 | extern void init_tokenizer (void); 125 | extern const InputFile *get_input_file (int levels_back); 126 | extern void open_file (const char *file, const char *search_dirs[]); 127 | extern void open_stream (const char *name, FILE *fp); 128 | extern BOOL fetch_next_token (Token *t); 129 | extern BOOL tokens_equal (const Token *t1, const Token *t2); 130 | extern void dump_token (const Token *t); 131 | extern char *unparse_token (const Token *t, char *buf); 132 | extern FILE *current_stream (void); 133 | extern int skip_to_next_token (void); 134 | extern void close_file (void); 135 | 136 | #endif /* Not _token_h_ */ 137 | -------------------------------------------------------------------------------- /syngen/include/uniquestring.h: -------------------------------------------------------------------------------- 1 | #ifndef __UNIQUESTRING_H__ 2 | #define __UNIQUESTRING_H__ 3 | 4 | extern void init_unique_string (void); 5 | extern const char *unique_string (const char *s); 6 | 7 | #endif /* Not __UNIQUESTRING_H__ */ 8 | -------------------------------------------------------------------------------- /syngen/list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * list.c 3 | */ 4 | 5 | #include "token.h" 6 | #include "parse.h" 7 | #include 8 | 9 | 10 | /* Allocates and initializes a new list. */ 11 | 12 | List * 13 | alloc_list () 14 | { 15 | List *new; 16 | 17 | new = (List *) malloc (sizeof (List)); 18 | new->cdr = new->car = NULL; 19 | new->token.type = TOK_UNKNOWN; 20 | new->token.u.string = ""; 21 | new->token.lineno = -666; 22 | new->token.filename = ""; 23 | 24 | return new; 25 | } 26 | 27 | 28 | /* Creates an independent copy of ls and returns it. */ 29 | 30 | List * 31 | copy_list (const List *ls) 32 | { 33 | List *new; 34 | 35 | if (ls == NULL) 36 | return NULL; 37 | 38 | new = alloc_list (); 39 | *new = *ls; 40 | new->car = copy_list (ls->car); 41 | new->cdr = copy_list (ls->cdr); 42 | 43 | return new; 44 | } 45 | 46 | 47 | /* Copies the filename and line number from original to every element of ls. */ 48 | 49 | void 50 | propagate_fileinfo (const Token *original, List *ls) 51 | { 52 | while (ls != NULL) 53 | { 54 | ls->token.filename = original->filename; 55 | ls->token.lineno = original->lineno; 56 | if (ls->car != NULL) 57 | propagate_fileinfo (original, ls->car); 58 | ls = ls->cdr; 59 | } 60 | } 61 | 62 | 63 | void 64 | replace_list (List *old, List *new) 65 | { 66 | List *tmp; 67 | 68 | if (new == NULL) 69 | { 70 | old->token.type = TOK_EMPTY; 71 | return; 72 | } 73 | 74 | /* Find the end of the new list. */ 75 | for (tmp = new; tmp->cdr != NULL; tmp = tmp->cdr); 76 | 77 | /* Insert it into where the old list was. */ 78 | tmp->cdr = old->cdr; 79 | *old = *new; 80 | } 81 | 82 | 83 | /* Returns the length of a given list. */ 84 | 85 | int 86 | list_length (const List *ls) 87 | { 88 | int len; 89 | 90 | for (len = 0; ls != NULL; ls = ls->cdr) 91 | len++; 92 | return len; 93 | } 94 | 95 | 96 | 97 | static int 98 | list_size_aux (const List *ls, int level) 99 | { 100 | if (level > 1000) /* avoid infinite death */ 101 | abort (); 102 | if (ls == NULL) /* Recursion base case. */ 103 | return 0; 104 | return (1 + list_size_aux (ls->car, level + 1) 105 | + list_size_aux (ls->cdr, level + 1)); 106 | } 107 | 108 | 109 | /* Total number of cons cells in a list. */ 110 | int 111 | list_size (const List *ls) 112 | { 113 | return list_size_aux (ls, 0); 114 | } 115 | 116 | 117 | BOOL 118 | lists_equal (const List *l1, const List *l2) 119 | { 120 | if (l1 == l2) /* Handles NULL == NULL case. */ 121 | return TRUE; 122 | if (l1 == NULL || l2 == NULL) 123 | return FALSE; 124 | if (!tokens_equal (&l1->token, &l2->token)) 125 | return FALSE; 126 | return lists_equal (l1->car, l2->car) && lists_equal (l1->cdr, l2->cdr); 127 | } 128 | 129 | 130 | /* Returns NULL if no element anywhere in the list or sublist has a token 131 | * of the specified type, else returns a pointer to an Token of the specified 132 | * type. 133 | */ 134 | Token * 135 | has_token_of_type (List *list, TokenType type) 136 | { 137 | Token *t; 138 | 139 | if (list == NULL) 140 | return NULL; 141 | if (list->token.type == type) 142 | return &list->token; 143 | t = has_token_of_type (list->car, type); 144 | if (t != NULL) 145 | return t; 146 | t = has_token_of_type (list->cdr, type); 147 | if (t != NULL) 148 | return t; 149 | return NULL; 150 | } 151 | 152 | 153 | /* Goes through a list and all sublists and replaces all tokens of the 154 | * specified type with tokens of another type. Does NOT replace 155 | * the auxiliary token info. 156 | */ 157 | void 158 | replace_tokens_of_type (List *list, TokenType old, TokenType new) 159 | { 160 | if (list == NULL) 161 | return; 162 | if (list->token.type == old) 163 | list->token.type = new; 164 | replace_tokens_of_type (list->car, old, new); 165 | replace_tokens_of_type (list->cdr, old, new); 166 | } 167 | 168 | 169 | /* Goes through a list and all sublists and replaces all tokens of the 170 | * specified type with the specified token. 171 | */ 172 | void 173 | replace_tokens_of_type_with_list (List *list, TokenType old, const List *new) 174 | { 175 | if (list == NULL) 176 | return; 177 | 178 | if (list->token.type == old) 179 | { 180 | List *old_cdr = list->cdr; 181 | List *n = copy_list (new); 182 | *list = *n; 183 | list->cdr = old_cdr; 184 | } 185 | replace_tokens_of_type_with_list (list->car, old, new); 186 | replace_tokens_of_type_with_list (list->cdr, old, new); 187 | } 188 | 189 | 190 | /* Recursive helper function for print_list (). */ 191 | 192 | static void 193 | print_list_aux (const List *ls, int indent, FILE *out) 194 | { 195 | BOOL print_space = FALSE; 196 | int i; 197 | char buf[256]; 198 | const List *l2; 199 | 200 | for (; ls != NULL; ls = ls->cdr) 201 | { 202 | /* Print a space before each token but the first. */ 203 | if (print_space) putc (' ', out); 204 | else print_space = TRUE; 205 | 206 | /* Print lists recursively. */ 207 | if (ls->token.type == TOK_LIST) 208 | { 209 | /* If it has sublists, or it's a sequence, put it down on another 210 | * line and indent it. 211 | */ 212 | for (l2 = ls->car; l2 != NULL; l2 = l2->cdr) 213 | if (l2->token.type == TOK_LIST) 214 | break; 215 | if (l2 != NULL) 216 | { 217 | putc ('\n', out); 218 | for (i = 0; i < indent; i++) 219 | putc (' ', out); 220 | putc ('(', out); 221 | print_list_aux (ls->car, indent + 2, out); 222 | putc (')', out); 223 | } 224 | else /* No sublists? */ 225 | { 226 | putc ('(', out); 227 | print_list_aux (ls->car, indent, out); 228 | putc (')', out); 229 | } 230 | } 231 | else fputs (unparse_token (&ls->token, buf), out); 232 | } 233 | } 234 | 235 | 236 | /* Outputs a list in human-readable format. */ 237 | 238 | void 239 | print_list (FILE *out, const List *ls) 240 | { 241 | print_list_aux (ls, 0, out); 242 | } 243 | 244 | 245 | void 246 | dump_list (const List *ls) 247 | { 248 | print_list (stdout, ls); 249 | } 250 | 251 | 252 | BOOL 253 | list_overlap (const List *l1, const List *l2) 254 | { 255 | if (l1 == NULL || l2 == NULL) 256 | return FALSE; 257 | if (l1 == l2) 258 | return TRUE; 259 | return (list_overlap (l1, l2->car) 260 | || list_overlap (l1, l2->cdr) 261 | || list_overlap (l1->car, l2) 262 | || list_overlap (l1->cdr, l2)); 263 | } 264 | -------------------------------------------------------------------------------- /syngen/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.c 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "list.h" 9 | #include "token.h" 10 | #include "common.h" 11 | #include "parse.h" 12 | #include "error.h" 13 | #include "reduce.h" 14 | #include "defopcode.h" 15 | #include "uniquestring.h" 16 | 17 | static void usage (const char *progname); 18 | static void unrecognized (const char *progname, const char *badopt); 19 | 20 | /* Global variables to control compilation options. */ 21 | int optimization_level; 22 | BOOL preprocess_only; 23 | FILE *syn68k_c_stream, *mapinfo_c_stream, *mapindex_c_stream; 24 | FILE *profileinfo_stream; 25 | BOOL verbose; 26 | 27 | int 28 | main (int argc, char *argv[]) 29 | { 30 | SymbolTable *sym = make_symbol_table (); 31 | const char *include_dirs[32] = { ".", NULL }; 32 | static const char *current_dir[] = { ".", NULL }; 33 | int include_dir_index = 1; 34 | int i; 35 | 36 | init_tokenizer (); 37 | init_unique_string (); 38 | 39 | /* Set up global variables with default values. */ 40 | optimization_level = 0; 41 | preprocess_only = FALSE; 42 | verbose = FALSE; 43 | syn68k_c_stream = NULL; 44 | mapinfo_c_stream = NULL; 45 | mapindex_c_stream = NULL; 46 | profileinfo_stream = NULL; 47 | 48 | /* Parse command line arguments. */ 49 | for (i = 1; i < argc; i++) 50 | { 51 | if (argv[i][0] != '-') 52 | { 53 | open_file (argv[i], current_dir); 54 | 55 | /* Open output code streams. */ 56 | if (!preprocess_only) 57 | { 58 | syn68k_c_stream = fopen ("syn68k.c", "w"); 59 | mapinfo_c_stream = fopen ("mapinfo.c", "w"); 60 | mapindex_c_stream = fopen ("mapindex.c", "w"); 61 | profileinfo_stream = fopen ("profileinfo", "w"); 62 | } 63 | 64 | /* Initialize code generator and output header stuff. */ 65 | begin_generating_code (); 66 | 67 | /* Munch through everything and generate appropriate stuff. */ 68 | parse_all_expressions (sym); 69 | 70 | /* Do any necessary cleanup. */ 71 | done_generating_code (); 72 | 73 | /* Close up all streams. */ 74 | if (!preprocess_only) 75 | { 76 | fclose (syn68k_c_stream); syn68k_c_stream = NULL; 77 | fclose (mapinfo_c_stream); mapinfo_c_stream = NULL; 78 | fclose (mapindex_c_stream); mapindex_c_stream = NULL; 79 | fclose (profileinfo_stream); profileinfo_stream = NULL; 80 | } 81 | 82 | continue; 83 | } 84 | 85 | switch (argv[i][1]) { 86 | 87 | case 's': 88 | if (!strcmp (argv[i], "-stdin")) 89 | { 90 | open_stream ("", stdin); 91 | parse_all_expressions (sym); 92 | } 93 | else unrecognized (argv[0], argv[i]); 94 | break; 95 | 96 | case 'I': 97 | if (argv[i][2] == '\0') 98 | fatal_error ("Missing include directory for -I option.\n"); 99 | if (include_dir_index >= sizeof include_dirs / sizeof include_dirs[0]) 100 | fatal_error ("Too many -I directories specified.\n"); 101 | 102 | include_dirs[include_dir_index++] = argv[i] + 2; 103 | include_dirs[include_dir_index] = NULL; 104 | break; 105 | 106 | case 'E': 107 | if (argv[i][2] != '\0') 108 | unrecognized (argv[0], argv[i]); 109 | preprocess_only = TRUE; 110 | break; 111 | 112 | case 'O': 113 | if (argv[i][2] == '\0') 114 | optimization_level = 1; 115 | else optimization_level = atoi (argv[i] + 2); 116 | break; 117 | 118 | case 'v': 119 | if (argv[i][2] != '\0') 120 | unrecognized (argv[0], argv[i]); 121 | verbose = TRUE; 122 | break; 123 | 124 | default: 125 | unrecognized (argv[0], argv[i]); 126 | break; 127 | } 128 | } 129 | 130 | return 0; 131 | } 132 | 133 | 134 | static void 135 | unrecognized (const char *progname, const char *badopt) 136 | { 137 | error ("Unrecognized option \"%s\".\n", badopt); 138 | usage (progname); 139 | } 140 | 141 | 142 | /* Prints out usage and exits. */ 143 | static void 144 | usage (const char *progname) 145 | { 146 | fatal_error ("Usage: %s \n", progname); 147 | } 148 | -------------------------------------------------------------------------------- /syngen/test.scm: -------------------------------------------------------------------------------- 1 | (include "68k.defines.scm") 2 | 3 | (define (ADDB name bit_pattern expand amode src dst) 4 | (defopcode name 5 | (list 68000 amode () bit_pattern) 6 | (list "-----" "-----" expand 7 | (assign dst (+ dst src))) 8 | (list "CNVXZ" "-----" dont_expand 9 | (list 10 | (assign tmp2.ub dst) 11 | (assign ccv (& (~ (^ tmp2.ub src)) 0x80)) 12 | (ASSIGN_NNZ_BYTE (assign dst (assign tmp.uw (+ dst src)))) 13 | (assign ccx (assign ccc (>> tmp.uw 8))) 14 | (assign ccv (& ccv (^ tmp.ub tmp2.ub))))))) 15 | 16 | (define add_sub_expand (list "----xxx---00xxxx" ; [ad]n, [ad]n 17 | "----xxx---010xxx" ; an@, [ad]n 18 | "----xxx---101xxx")) ; an@(d16), [ad]n 19 | 20 | (ADDB addb_dest_reg (list "1101ddd000mmmmmm") add_sub_expand 21 | (intersect amode_all_combinations (not "xxxxxxxxxx001xxx")) ; no an 22 | $2.mub $1.dub) 23 | -------------------------------------------------------------------------------- /syngen/uniquestring.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | #include "uniquestring.h" 3 | #include "common.h" 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | static SymbolTable *sym = NULL; 10 | 11 | void 12 | init_unique_string () 13 | { 14 | if (sym == NULL) 15 | sym = make_symbol_table (); 16 | } 17 | 18 | 19 | const char * 20 | unique_string (const char *s) 21 | { 22 | SymbolInfo si; 23 | const char *p; 24 | 25 | if (lookup_symbol (sym, s, &si, &p) != HASH_NOERR) 26 | { 27 | char *newp; 28 | 29 | newp = malloc (strlen (s) + 1); 30 | assert(newp); 31 | strcpy (newp, s); 32 | insert_symbol (sym, newp, si); 33 | p = newp; 34 | } 35 | 36 | return p; 37 | } 38 | -------------------------------------------------------------------------------- /test/.gdbinit: -------------------------------------------------------------------------------- 1 | directory ../syngen 2 | directory ../runtime 3 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | syngentest 2 | testbattery.c 3 | .deps 4 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = syngentest 2 | 3 | syngentest_CPPFLAGS = -DMEMORY_OFFSET=8192 4 | 5 | syngentest_SOURCES = main.c driver.c tests.c setup.c \ 6 | testtrap.c crc.c testrt.c testqsort.c \ 7 | \ 8 | include/callemulator.h include/crc.h include/driver.h \ 9 | include/run68k.h include/setup.h include/testbattery.h \ 10 | include/testqsort.h include/testrt.h include/testtrap.h \ 11 | \ 12 | maketestbattery.pl testall.sh 13 | 14 | if M68K_HOSTCPU 15 | syngentest_SOURCES += callemulator.s run68k.s 16 | endif 17 | 18 | nodist_syngentest_SOURCES = testbattery.c 19 | 20 | testbattery.c: tests.c maketestbattery.pl 21 | rm -f testbattery.c 22 | $(srcdir)/maketestbattery.pl < $(srcdir)/tests.c > testbattery.c 23 | chmod a-w testbattery.c 24 | 25 | syngentest_LDADD = ../runtime/libsyn68k.a 26 | 27 | syngentest_LDFLAGS = @EXECSTACK@ 28 | 29 | INCLUDES = -I$(srcdir)/include -I$(srcdir)/../include -I../include 30 | 31 | CLEANFILES = testbattery.c 32 | 33 | -------------------------------------------------------------------------------- /test/TODO: -------------------------------------------------------------------------------- 1 | 1) Test funky addressing modes. 2 | 2) Test abs.w addressing mode. We don't test it now because we don't 3 | know that the pointer to the test data will fit in two bytes (in fact, 4 | it won't). 5 | 3) Check undefined behavior for mull when dh and di are the same register. 6 | 4) unlk a7 wedges the 68040, so we aren't testing it. When we run the test 7 | suite on a 68020, we may want to put it back in. 8 | 5) Test move16 9 | -------------------------------------------------------------------------------- /test/callemulator.s: -------------------------------------------------------------------------------- 1 | #NO_APP 2 | .text 3 | .align 1 4 | .globl _call_emulator 5 | _call_emulator: 6 | link a6,#0 7 | pea 100:w 8 | pea a6@(8) 9 | pea a6@(-2048) 10 | jbsr _memcpy 11 | lea a6@(-2048),a0 12 | movel #0x00FFF000,a0@ 13 | movel a0,_cpu_state+60 14 | movel a6,_cpu_state+56 15 | movel a6@(8),sp@- 16 | jbsr _hash_lookup_code_and_create_if_needed 17 | movel d0,sp@- 18 | jbsr _interpret_code 19 | movel _cpu_state,d0 20 | unlk a6 21 | rts 22 | -------------------------------------------------------------------------------- /test/crc.c: -------------------------------------------------------------------------------- 1 | #include "crc.h" 2 | 3 | /* 4 | * Algorithm from "Computer Networks" by Andrew S. Tanenbaum pp. 129-132. 5 | * 6 | * Code lifted from ROMlib's crc.c. by mjhostet (with permission), 3/28/93. 7 | * Lookup table added 3/29/93. 8 | */ 9 | 10 | #define GEN 0x88108000 11 | #define GEN1 (GEN >> 1) 12 | #define GEN2 (GEN >> 2) 13 | #define GEN3 (GEN >> 3) 14 | #define GEN4 (GEN >> 4) 15 | #define GEN5 (GEN >> 5) 16 | #define GEN6 (GEN >> 6) 17 | #define GEN7 (GEN >> 7) 18 | 19 | 20 | #if 0 21 | static unsigned long 22 | polydivide(unsigned long l) 23 | { 24 | if (l & 0x80000000) 25 | l ^= GEN; 26 | if (l & 0x40000000) 27 | l ^= GEN1; 28 | if (l & 0x20000000) 29 | l ^= GEN2; 30 | if (l & 0x10000000) 31 | l ^= GEN3; 32 | if (l & 0x08000000) 33 | l ^= GEN4; 34 | if (l & 0x04000000) 35 | l ^= GEN5; 36 | if (l & 0x02000000) 37 | l ^= GEN6; 38 | if (l & 0x01000000) 39 | l ^= GEN7; 40 | return l; 41 | } 42 | #else 43 | static unsigned long 44 | polydivide (unsigned long l) 45 | { 46 | static const unsigned long crc_table[] = { 47 | 0x00000000, 0x01102100, 0x02204200, 0x03306300, 0x04408400, 0x0550A500, 48 | 0x0660C600, 0x0770E700, 0x08810800, 0x09912900, 0x0AA14A00, 0x0BB16B00, 49 | 0x0CC18C00, 0x0DD1AD00, 0x0EE1CE00, 0x0FF1EF00, 0x10123100, 0x11021000, 50 | 0x12327300, 0x13225200, 0x1452B500, 0x15429400, 0x1672F700, 0x1762D600, 51 | 0x18933900, 0x19831800, 0x1AB37B00, 0x1BA35A00, 0x1CD3BD00, 0x1DC39C00, 52 | 0x1EF3FF00, 0x1FE3DE00, 0x20246200, 0x21344300, 0x22042000, 0x23140100, 53 | 0x2464E600, 0x2574C700, 0x2644A400, 0x27548500, 0x28A56A00, 0x29B54B00, 54 | 0x2A852800, 0x2B950900, 0x2CE5EE00, 0x2DF5CF00, 0x2EC5AC00, 0x2FD58D00, 55 | 0x30365300, 0x31267200, 0x32161100, 0x33063000, 0x3476D700, 0x3566F600, 56 | 0x36569500, 0x3746B400, 0x38B75B00, 0x39A77A00, 0x3A971900, 0x3B873800, 57 | 0x3CF7DF00, 0x3DE7FE00, 0x3ED79D00, 0x3FC7BC00, 0x4048C400, 0x4158E500, 58 | 0x42688600, 0x4378A700, 0x44084000, 0x45186100, 0x46280200, 0x47382300, 59 | 0x48C9CC00, 0x49D9ED00, 0x4AE98E00, 0x4BF9AF00, 0x4C894800, 0x4D996900, 60 | 0x4EA90A00, 0x4FB92B00, 0x505AF500, 0x514AD400, 0x527AB700, 0x536A9600, 61 | 0x541A7100, 0x550A5000, 0x563A3300, 0x572A1200, 0x58DBFD00, 0x59CBDC00, 62 | 0x5AFBBF00, 0x5BEB9E00, 0x5C9B7900, 0x5D8B5800, 0x5EBB3B00, 0x5FAB1A00, 63 | 0x606CA600, 0x617C8700, 0x624CE400, 0x635CC500, 0x642C2200, 0x653C0300, 64 | 0x660C6000, 0x671C4100, 0x68EDAE00, 0x69FD8F00, 0x6ACDEC00, 0x6BDDCD00, 65 | 0x6CAD2A00, 0x6DBD0B00, 0x6E8D6800, 0x6F9D4900, 0x707E9700, 0x716EB600, 66 | 0x725ED500, 0x734EF400, 0x743E1300, 0x752E3200, 0x761E5100, 0x770E7000, 67 | 0x78FF9F00, 0x79EFBE00, 0x7ADFDD00, 0x7BCFFC00, 0x7CBF1B00, 0x7DAF3A00, 68 | 0x7E9F5900, 0x7F8F7800, 0x80918800, 0x8181A900, 0x82B1CA00, 0x83A1EB00, 69 | 0x84D10C00, 0x85C12D00, 0x86F14E00, 0x87E16F00, 0x88108000, 0x8900A100, 70 | 0x8A30C200, 0x8B20E300, 0x8C500400, 0x8D402500, 0x8E704600, 0x8F606700, 71 | 0x9083B900, 0x91939800, 0x92A3FB00, 0x93B3DA00, 0x94C33D00, 0x95D31C00, 72 | 0x96E37F00, 0x97F35E00, 0x9802B100, 0x99129000, 0x9A22F300, 0x9B32D200, 73 | 0x9C423500, 0x9D521400, 0x9E627700, 0x9F725600, 0xA0B5EA00, 0xA1A5CB00, 74 | 0xA295A800, 0xA3858900, 0xA4F56E00, 0xA5E54F00, 0xA6D52C00, 0xA7C50D00, 75 | 0xA834E200, 0xA924C300, 0xAA14A000, 0xAB048100, 0xAC746600, 0xAD644700, 76 | 0xAE542400, 0xAF440500, 0xB0A7DB00, 0xB1B7FA00, 0xB2879900, 0xB397B800, 77 | 0xB4E75F00, 0xB5F77E00, 0xB6C71D00, 0xB7D73C00, 0xB826D300, 0xB936F200, 78 | 0xBA069100, 0xBB16B000, 0xBC665700, 0xBD767600, 0xBE461500, 0xBF563400, 79 | 0xC0D94C00, 0xC1C96D00, 0xC2F90E00, 0xC3E92F00, 0xC499C800, 0xC589E900, 80 | 0xC6B98A00, 0xC7A9AB00, 0xC8584400, 0xC9486500, 0xCA780600, 0xCB682700, 81 | 0xCC18C000, 0xCD08E100, 0xCE388200, 0xCF28A300, 0xD0CB7D00, 0xD1DB5C00, 82 | 0xD2EB3F00, 0xD3FB1E00, 0xD48BF900, 0xD59BD800, 0xD6ABBB00, 0xD7BB9A00, 83 | 0xD84A7500, 0xD95A5400, 0xDA6A3700, 0xDB7A1600, 0xDC0AF100, 0xDD1AD000, 84 | 0xDE2AB300, 0xDF3A9200, 0xE0FD2E00, 0xE1ED0F00, 0xE2DD6C00, 0xE3CD4D00, 85 | 0xE4BDAA00, 0xE5AD8B00, 0xE69DE800, 0xE78DC900, 0xE87C2600, 0xE96C0700, 86 | 0xEA5C6400, 0xEB4C4500, 0xEC3CA200, 0xED2C8300, 0xEE1CE000, 0xEF0CC100, 87 | 0xF0EF1F00, 0xF1FF3E00, 0xF2CF5D00, 0xF3DF7C00, 0xF4AF9B00, 0xF5BFBA00, 88 | 0xF68FD900, 0xF79FF800, 0xF86E1700, 0xF97E3600, 0xFA4E5500, 0xFB5E7400, 89 | 0xFC2E9300, 0xFD3EB200, 0xFE0ED100, 0xFF1EF000, 90 | }; 91 | 92 | return l ^ crc_table[l >> 24]; 93 | } 94 | 95 | #endif 96 | 97 | 98 | unsigned short 99 | compute_crc (unsigned char *data, long length, unsigned short seed) 100 | { 101 | unsigned long l; 102 | 103 | #if 0 104 | if (length == 0) 105 | l = 0; 106 | else if (length == 1) 107 | l = data[0]; 108 | else if (length == 2) 109 | l = (data[0] << 8) | data[1]; 110 | else 111 | l = (data[0] << 16) | (data[1] << 8) | data[2]; 112 | data += 3; 113 | length -= 2; 114 | #else 115 | /* This is spew, but it munges in the seed. */ 116 | if (length == 0) 117 | l = seed; 118 | else 119 | l = (seed << 8) | data[0]; 120 | data++; 121 | #endif 122 | 123 | while (--length > 0) 124 | { 125 | l = (l << 8) | *data++; 126 | l = polydivide(l); 127 | } 128 | l <<= 8; 129 | l = polydivide(l); 130 | l <<= 8; 131 | l = polydivide(l); 132 | 133 | return l >> 8; 134 | } 135 | -------------------------------------------------------------------------------- /test/freq: -------------------------------------------------------------------------------- 1 | 1925792.000000 instructions total. 2 | 0x14C0: 525216 27.27% 3 | 0x0056: 350144 18.18% 4 | 0x0000: 175072 9.09% 5 | 0x00B2: 175072 9.09% 6 | 0x059F: 175072 9.09% 7 | 0x05C2: 175072 9.09% 8 | 0x0A2A: 175072 9.09% 9 | 0x14FB: 175072 9.09% 10 | -------------------------------------------------------------------------------- /test/include/callemulator.h: -------------------------------------------------------------------------------- 1 | #ifndef _callemulator_h_ 2 | #define _callemulator_h_ 3 | 4 | extern int call_emulator (int (*func)(), ...); 5 | 6 | #endif /* Not _callemulator_h_ */ 7 | -------------------------------------------------------------------------------- /test/include/crc.h: -------------------------------------------------------------------------------- 1 | #ifndef _crc_h_ 2 | #define _crc_h_ 3 | 4 | extern unsigned short compute_crc (unsigned char *data, long length, 5 | unsigned short seed); 6 | 7 | #endif /* Not _crc_h_ */ 8 | -------------------------------------------------------------------------------- /test/include/driver.h: -------------------------------------------------------------------------------- 1 | #ifndef _driver_h_ 2 | #define _driver_h_ 3 | 4 | #include "syn68k_public.h" 5 | 6 | typedef enum { 7 | DM_USE_EMULATOR, 8 | DM_USE_68000, 9 | DM_COMPARE_AS_YOU_GO 10 | } DriverMode; 11 | 12 | extern uint32 times_called; 13 | extern uint16 ccr; 14 | extern int test_only_non_cc_variants; 15 | extern int generate_crc; 16 | 17 | extern void test_all_instructions (uint32 try_count); 18 | 19 | #define MAX_ERRORS 30 20 | 21 | #endif /* Not driver_h_ */ 22 | -------------------------------------------------------------------------------- /test/include/run68k.h: -------------------------------------------------------------------------------- 1 | #ifndef _run68k_h_ 2 | #define _run68k_h_ 3 | 4 | #include "syn68k_public.h" 5 | 6 | extern void run_code_on_68000 (uint16 *code, uint32 *return_address); 7 | 8 | #endif /* Not _run68k_h_ */ 9 | -------------------------------------------------------------------------------- /test/include/setup.h: -------------------------------------------------------------------------------- 1 | #ifndef _setup_h_ 2 | #define _setup_h_ 3 | 4 | #include "syn68k_public.h" 5 | 6 | #define MEM_SIZE 2048 7 | 8 | extern uint8 *mem; 9 | 10 | extern void randomize_mem (void); 11 | extern void randomize_regs (int low_reg, int high_reg, uint32 low_val, 12 | uint32 high_val, uint32 bits_to_mask); 13 | extern void fully_randomize_regs (void); 14 | extern int32 randint (int32 low, int32 high); 15 | extern int32 randnum (); 16 | 17 | #endif /* Not _setup_h_ */ 18 | -------------------------------------------------------------------------------- /test/include/testbattery.h: -------------------------------------------------------------------------------- 1 | #ifndef _testbattery_h_ 2 | #define _testbattery_h_ 3 | 4 | typedef struct { 5 | const char *name; 6 | void (*code_creator)(uint16 *); 7 | int cc_mask; 8 | int code_words; 9 | int might_change_memory; 10 | int max_times_to_call; /* 0 if no limit */ 11 | } TestInfo; 12 | 13 | #define C_BIT 0x01 14 | #define V_BIT 0x02 15 | #define Z_BIT 0x04 16 | #define N_BIT 0x08 17 | #define X_BIT 0x10 18 | #define ALL_CCS 0x1F 19 | #define NO_CCS 0x00 20 | 21 | #define MOVE16_CHANGE_MEMORY 2 /* nasty hack because move16 isn't guaranteed 22 | to move memory under NS 3.1 */ 23 | #define MIGHT_CHANGE_MEMORY 1 24 | #define WONT_CHANGE_MEMORY 0 25 | 26 | #define NO_LIMIT 0 27 | 28 | extern const TestInfo test_info[]; 29 | 30 | #endif /* Not _testbattery_h_ */ 31 | -------------------------------------------------------------------------------- /test/include/testqsort.h: -------------------------------------------------------------------------------- 1 | #ifndef _testqsort_h_ 2 | #define _testqsort_h_ 3 | 4 | extern void test_qsort (void); 5 | 6 | #endif /* _testqsort_h_ */ 7 | -------------------------------------------------------------------------------- /test/include/testrt.h: -------------------------------------------------------------------------------- 1 | #ifndef _testrt_h_ 2 | #define _testrt_h_ 3 | 4 | extern void test_rangetree (void); 5 | 6 | #endif /* Not _testrt_h_ */ 7 | -------------------------------------------------------------------------------- /test/include/testtrap.h: -------------------------------------------------------------------------------- 1 | #ifndef _testtrap_h_ 2 | #define _testtrap_h_ 3 | 4 | extern void test_traps (void); 5 | 6 | #endif /* Not _testtrap_h_ */ 7 | -------------------------------------------------------------------------------- /test/main.c: -------------------------------------------------------------------------------- 1 | #include "syn68k_public.h" 2 | #include "driver.h" 3 | #include "callemulator.h" 4 | #include "testtrap.h" 5 | #include "crc.h" 6 | #include "testrt.h" 7 | #include "testqsort.h" 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef EXIT_SUCCESS 13 | #define EXIT_SUCCESS 0 14 | #endif 15 | 16 | 17 | int 18 | main (int argc, char *argv[]) 19 | { 20 | static uint32 trap_vectors[64]; 21 | uint32 count = 10000; 22 | int i; 23 | int native_p; 24 | 25 | native_p = 1; 26 | 27 | #ifdef NeXT 28 | malloc_debug (31); /* Just to be safe. */ 29 | #endif 30 | 31 | ROMlib_offset = MEMORY_OFFSET; 32 | 33 | /* Set up default values for command line switches. */ 34 | test_only_non_cc_variants = 0; 35 | #ifdef mc68000 36 | generate_crc = 0; 37 | #else 38 | generate_crc = 1; 39 | #endif 40 | 41 | /* Grab command-line switches. */ 42 | for (i = 1; i < argc; i++) 43 | { 44 | #ifdef mc68000 45 | if (!strcmp (argv[i], "-crc")) 46 | generate_crc = 1; 47 | else 48 | #endif 49 | if (!strcmp (argv[i], "-noncc")) 50 | test_only_non_cc_variants = 1; 51 | else if (strcmp (argv[i], "-notnative") == 0) 52 | native_p = 0; 53 | else if (atoi (argv[i]) != 0) 54 | count = atoi (argv[i]); 55 | else 56 | { 57 | #ifdef mc68000 58 | fprintf (stderr, "Usage: %s [test count] [-crc] [-noncc] [-notnative]\n", 59 | argv[0]); 60 | #else 61 | fprintf (stderr, "Usage: %s [test count] [-noncc] [-notnative]\n", 62 | argv[0]); 63 | #endif 64 | exit (-1); 65 | } 66 | } 67 | 68 | /* Initialize stuff. */ 69 | initialize_68k_emulator (NULL, native_p, trap_vectors, 0); 70 | 71 | #if 0 72 | test_rangetree (); 73 | exit (0); 74 | #endif 75 | 76 | #if 0 77 | test_qsort (); 78 | dump_profile ("../profile/instrfreq"); 79 | exit (0); 80 | #endif 81 | 82 | #if 0 83 | test_traps (); 84 | #else 85 | /* Run through test suite. */ 86 | test_all_instructions (count); 87 | #endif 88 | 89 | return EXIT_SUCCESS; 90 | } 91 | 92 | #if 0 && defined(GO32) 93 | void __main(void) 94 | { 95 | } 96 | #endif 97 | -------------------------------------------------------------------------------- /test/maketestbattery.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | print ("#include \"syn68k_public.h\"\n", 4 | "#include \"testbattery.h\"\n", 5 | "\n"); 6 | 7 | while (<>) 8 | { 9 | if (/^TEST\s*\(([^,]*),\s*([^,]*),\s*([^,]*),\s*([^,]*),\s*([^\)]*)\s*\)/) 10 | { 11 | $decls .= "extern void $1 (uint16 *);\n"; 12 | $array .= " { \"$1\", $1, $2, $3, $4, $5 },\n"; 13 | } 14 | } 15 | 16 | print ($decls, "\n", 17 | "const TestInfo test_info[] = {\n", 18 | $array, 19 | " { 0, 0, 0, 0, 0, 0 }\n", 20 | "};\n"); 21 | -------------------------------------------------------------------------------- /test/output/README: -------------------------------------------------------------------------------- 1 | This is the output from running syngentest with various command line options 2 | on two different platforms. 3 | 4 | One platform was a hardware 68k (probably a 68040 running NEXTSTEP, 5 | but it's been so long that I don't remember), done sometime in the mid 6 | 1990s. IIRC, the command line options were 7 | 8 | ../syngentest 1000 > 68k.1000 9 | ../syngentest -noncc 1000 > 68k.noncc.1000 10 | ../syngentest 100 > dump-68k-100-cc 11 | ../syngentest -noncc 100 > dump-68k-100-noncc 12 | 13 | The other platform is an i686 Fedora 9 system and those command line switches 14 | were: 15 | 16 | ../syngentest > 10000 17 | ../syngentest -noncc > 10000-noncc 18 | ../syngentest -noncc -notnative > 10000-noncc-notnative 19 | ../syngentest -notnative > 10000-notnative 20 | 21 | Unfortunately, the memory location that we used to use to test on the 68k 22 | is unavailable on modern Linux systems, so we can't actually compare the 23 | old output from a real 680x0 to the new output, but the new output is 24 | presumably correct, since we did a lot of testing with a real 68k a long time 25 | ago and Executor runs with the libsyn68k used with this Fedora 9 syn68k. 26 | 27 | The output when you include "-noncc" *should* be different from when 28 | you don't include it (you can see the difference between 68k.1000 and 29 | 68k.noncc.1000. The output when you include "-notnative" "shouldn't" 30 | be different, but it is, and that may well be a bug in Syn68k, 31 | although it's a bug that has (IIRC) been there from day one. The 32 | problem is that we get a different set of condition codes for divs_reg 33 | in a particular case. 34 | -------------------------------------------------------------------------------- /test/run68k.s: -------------------------------------------------------------------------------- 1 | #NO_APP 2 | .lcomm _saved_regs,64 3 | .lcomm _jump_address,4 4 | .text 5 | .globl _run_code_on_68000 6 | _run_code_on_68000: 7 | link a6,#0 8 | moveml #0xFFFF,_saved_regs 9 | movel a6@(8),_jump_address 10 | movel a6@(12),a0 11 | movel #L0,a0@ 12 | moveml _cpu_state,#0xFFFF 13 | jmp @(_jump_address)@(0) 14 | L0: 15 | moveml #0xFFFF,_cpu_state 16 | moveml _saved_regs,#0xFFFF 17 | unlk a6 18 | rts 19 | -------------------------------------------------------------------------------- /test/setup.c: -------------------------------------------------------------------------------- 1 | #include "syn68k_public.h" 2 | #include "setup.h" 3 | #include "driver.h" 4 | #include 5 | #ifdef NeXT 6 | # include /* To prototype random(). */ 7 | #else 8 | extern int random (void); 9 | #endif 10 | 11 | uint8 *mem; 12 | 13 | static inline int32 14 | my_random () 15 | { 16 | static unsigned n = 9; 17 | n = (n * 1233143127) ^ (n >> 13); 18 | return n & 0x7FFFFFFF; 19 | } 20 | 21 | 22 | int32 23 | randint (int32 low, int32 high) 24 | { 25 | assert (high >= low); 26 | 27 | return low + (my_random () % (high - low + 1)); 28 | } 29 | 30 | 31 | /* Choose a random 32 bit value. Half the time, choose one 32 | * of the "important" values at random. The important values are more 33 | * likely to elicit rare cc behavior, so we artificially make them more 34 | * likely. This also increases the chances of two values being equal. 35 | */ 36 | int32 37 | randnum () 38 | { 39 | static const uint32 important_values[] = { 40 | 0x00000000, 0x00000001, 0x00000080, 0x000000FF, 41 | 0x00000100, 0x00007FFF, 0x00008000, 0x0000FFFF, 42 | 0x00010000, 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF, 43 | 0x00000101, 0x00010001, 0x10000001 44 | }; 45 | 46 | if (randint (0, 1)) /* 50-50 chance. */ 47 | { 48 | return important_values[randint (0, ((sizeof important_values 49 | / sizeof important_values[0]) 50 | - 1))]; 51 | } 52 | else 53 | { 54 | return my_random (); 55 | } 56 | } 57 | 58 | 59 | void 60 | randomize_mem () 61 | { 62 | int32 *m = (int32 *)mem; 63 | int i; 64 | 65 | for (i = MEM_SIZE / sizeof (int32); i > 0; i--) 66 | { 67 | int32 n = randint (-1, 6); 68 | if (n <= 0) 69 | *m++ = n; /* 0 or -1 some of the time, no need to byte swap. */ 70 | else 71 | *m++ = SWAPUL_IFLE (my_random ()); 72 | } 73 | } 74 | 75 | 76 | void 77 | randomize_regs (int low_reg, int high_reg, uint32 low_val, uint32 high_val, 78 | uint32 bits_to_mask) 79 | { 80 | int i; 81 | for (i = low_reg; i <= high_reg; i++) 82 | cpu_state.regs[i].sl.n = randint (low_val, high_val) & ~bits_to_mask; 83 | } 84 | 85 | 86 | void 87 | fully_randomize_regs () 88 | { 89 | M68kReg *r; 90 | int i; 91 | 92 | for (i = 15, r = cpu_state.regs; i >= 0; r++, i--) 93 | r->sl.n = randnum (); 94 | } 95 | -------------------------------------------------------------------------------- /test/testall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -o errexit -o nounset -o noclobber 4 | 5 | function die () 6 | { 7 | echo $* 1>&2 8 | exit 1 9 | } 10 | 11 | function main () 12 | { 13 | 14 | local test_count 15 | local crc 16 | local noncc 17 | local notnative 18 | 19 | for ((test_count=1; test_count<1000000000; test_count*=10)); do 20 | for crc in "" "-crc"; do 21 | for noncc in "" "-noncc"; do 22 | for notnative in "" "-notnative"; do 23 | #echo $crc $noncc $notnative > /tmp/pg.$$ 24 | ./tst-i486-linux-glibc.PROBABLY_GOOD $test_count $crc $noncc $notnative >| /tmp/pg.$$ 25 | ./tst-i486-linux-glibc $test_count $crc $noncc $notnative >| /tmp/br.$$ 26 | diff /tmp/pg.$$ /tmp/br.$$ || die $test_count $crc $noncc $notnative 27 | done 28 | done 29 | done 30 | done 31 | 32 | } 33 | 34 | main "$@" 35 | -------------------------------------------------------------------------------- /test/testqsort.c: -------------------------------------------------------------------------------- 1 | #include "testqsort.h" 2 | #include "callemulator.h" 3 | #include "syn68k_public.h" 4 | #include 5 | #include 6 | 7 | #define ARRAY_SIZE 103 8 | 9 | #if defined(mc68000) 10 | static int emulator_array[ARRAY_SIZE], real_array[ARRAY_SIZE]; 11 | 12 | /* qsort helper function. */ 13 | static int 14 | compare_ints (const void *n1, const void *n2) 15 | { 16 | return *(const int *)n1 - *(const int *)n2; 17 | } 18 | #endif 19 | 20 | #ifdef USE_STUB 21 | static void 22 | stub () 23 | { 24 | qsort (emulator_array, sizeof emulator_array / sizeof emulator_array[0], 25 | sizeof emulator_array[0], compare_ints); 26 | } 27 | #endif 28 | 29 | 30 | void 31 | test_qsort () 32 | { 33 | #ifndef mc68000 34 | fputs ("You can't test qsort on a non-68000.\n", stderr); 35 | #else 36 | int i; 37 | 38 | 39 | /* Randomize the array. */ 40 | for (i = 0; i < sizeof real_array / sizeof real_array[0]; i++) 41 | emulator_array[i] = real_array[i] = rand (); 42 | 43 | /* Sort it on the real CPU. */ 44 | qsort (real_array, sizeof real_array / sizeof real_array[0], 45 | sizeof real_array[0], compare_ints); 46 | 47 | #ifndef USE_STUB 48 | /* Sort it under the emulator. */ 49 | call_emulator ((int (*)())qsort, emulator_array, 50 | sizeof emulator_array / sizeof emulator_array[0], 51 | sizeof emulator_array[0], compare_ints); 52 | #else 53 | { 54 | char stack[8192]; 55 | EM_A7 = EM_A6 = &stack[6000]; 56 | CALL_EMULATOR ((syn68k_addr_t) stub); 57 | } 58 | #endif 59 | 60 | 61 | /* Compare the results. */ 62 | if (memcmp (real_array, emulator_array, sizeof real_array)) 63 | fprintf (stderr, "test_qsort failed; emulator gets different " 64 | "results than the real 680x0.\n"); 65 | else 66 | fprintf (stderr, "test_qsort succeeded.\n"); 67 | #endif /* mc68000 */ 68 | } 69 | -------------------------------------------------------------------------------- /test/testrt.c: -------------------------------------------------------------------------------- 1 | /* This file tests the range tree. It has to include private header files 2 | * belonging to the runtime system because there is no official outside 3 | * interface to blocks or to the range tree; don't do this at home. 4 | */ 5 | 6 | #define DEBUG 7 | #include "../runtime/include/block.h" 8 | #include "../runtime/include/rangetree.h" 9 | #include "../runtime/include/destroyblock.h" 10 | #include "../runtime/include/hash.h" 11 | #include "../runtime/include/deathqueue.h" 12 | #include "testrt.h" 13 | #include 14 | #include 15 | #include 16 | 17 | #define MAX_BLOCKS 4096 18 | 19 | #if defined (__MINGW32__) 20 | 21 | int 22 | random (void) 23 | { 24 | unsigned int i1, i2, i3; 25 | int retval; 26 | 27 | i1 = (rand () >> 5) & 0x7ff; 28 | i2 = (rand () >> 5) & 0x7ff; 29 | i3 = (rand () >> 5) & 0x7ff; 30 | retval = (i1 << 22) | (i2 << 11) | i3; 31 | return retval; 32 | } 33 | 34 | #endif 35 | 36 | void 37 | test_rangetree () 38 | { 39 | int i; 40 | 41 | for (i = 1; i <= 1000000; i++) 42 | { 43 | Block *b, *b2; 44 | 45 | if (i % 50 == 0) 46 | printf ("%d...", i), fflush (stdout); 47 | 48 | if (i % 5 == 0) 49 | { 50 | destroy_blocks (0, ~0); 51 | /* range_tree_verify (); */ 52 | } 53 | 54 | b = block_new (); 55 | 56 | b->m68k_code_length = 2; 57 | do 58 | { 59 | b->m68k_start_address = rand () & ~1; 60 | } 61 | while (range_tree_find_first_at_or_after (b->m68k_start_address) != NULL); 62 | 63 | /* Add this block to the end of the death queue. */ 64 | death_queue_enqueue (b); 65 | 66 | b->num_children = 0; 67 | 68 | range_tree_insert (b); 69 | hash_insert (b); 70 | 71 | if (random () & 1) 72 | { 73 | b2 = range_tree_find_first_at_or_after (random ()); 74 | if (b2 != NULL && !b2->immortal) 75 | { 76 | b->child[0] = b2; 77 | block_add_parent (b2, b); 78 | b->num_children = 1; 79 | 80 | if (random () & 1) 81 | { 82 | b2 = range_tree_find_first_at_or_after (random ()); 83 | if (b2 != NULL && b2 != b->child[0] && !b2->immortal) 84 | { 85 | b->child[1] = b2; 86 | block_add_parent (b2, b); 87 | b->num_children = 2; 88 | } 89 | } 90 | } 91 | } 92 | 93 | /* range_tree_verify (); */ 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /test/testtrap.c: -------------------------------------------------------------------------------- 1 | #include "testtrap.h" 2 | #include "syn68k_public.h" 3 | #include "callemulator.h" 4 | #include 5 | 6 | #ifdef mc68000 7 | static void test_aline_traps (void); 8 | #endif 9 | static void test_callbacks (void); 10 | 11 | void 12 | test_traps () 13 | { 14 | #ifdef mc68000 15 | test_aline_traps (); 16 | #endif 17 | test_callbacks (); 18 | } 19 | 20 | 21 | static uint32 22 | handle_callback (uint32 addr, void *arg) 23 | { 24 | printf ("Callback: addr == 0x%08lX, arg == %p\n", addr, arg); 25 | return MAGIC_EXIT_EMULATOR_ADDRESS; 26 | } 27 | 28 | 29 | static void 30 | test_callbacks () 31 | { 32 | uint32 callback_addr[10]; 33 | int i, j; 34 | 35 | for (i = 0; i < 10; i++) 36 | callback_addr[i] = callback_install (handle_callback, (void *) i); 37 | 38 | for (j = 0; j < 2; j++) 39 | for (i = 0; i < 10; i++) 40 | interpret_code (hash_lookup_code_and_create_if_needed 41 | (callback_addr[i])); 42 | } 43 | 44 | #ifdef mc68000 45 | static uint32 46 | catch_aline_trap (uint32 m68k_addr, void *unused) 47 | { 48 | printf ("Hit a-line trap 0x%04X\n", 49 | (unsigned)*(uint16 *)(SYN68K_TO_US (m68k_addr))); 50 | return m68k_addr + 2; 51 | } 52 | 53 | 54 | static int 55 | aline_trap_death () 56 | { 57 | int i, result = 91; 58 | asm (".word 0xA000"); 59 | for (i = 0; i < 5; i++) 60 | { 61 | asm (".word 0xA003"); 62 | result += i * 3; 63 | } 64 | asm (".word 0xA001"); 65 | return result; 66 | } 67 | 68 | 69 | static void 70 | test_aline_traps () 71 | { 72 | trap_install_handler (10, catch_aline_trap, NULL); 73 | call_emulator (aline_trap_death); 74 | } 75 | #endif 76 | --------------------------------------------------------------------------------