mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-10 22:10:21 +02:00
Remove `qt/'.
This commit is contained in:
parent
7f991c7d32
commit
62aea16669
71 changed files with 0 additions and 7471 deletions
15
qt/CHANGES
15
qt/CHANGES
|
@ -1,15 +0,0 @@
|
|||
QuickThreads 002: Changes since QuickThreads 001.
|
||||
|
||||
- Now can be used by C++ programs.
|
||||
- Now *really* works with stacks that grow up.
|
||||
- Supports AXP OSF 2.x cc's varargs.
|
||||
- Supports HP Precision (HP-PA) on workstations and Convex.
|
||||
- Supports assemblers for Intel iX86 ith only '//'-style comments.
|
||||
- Supports Silicon Graphics Irix 5.x with dynamic linking.
|
||||
- Supports System V and Solaris 2.x with no `_' on compiler-generated
|
||||
identifiers; *some* platforms only.
|
||||
|
||||
Note: not all "./config" arguments are compatible with QT 001.
|
||||
|
||||
|
||||
QuickThreads 001: Base version.
|
|
@ -1,283 +0,0 @@
|
|||
2003-04-13 Rob Browning <rlb@defaultvalue.org>
|
||||
|
||||
* md/axp.s '.file 2 "axp.s"' -> '.file 2 "axp.s".
|
||||
(qt_vstart): .end qt_vstart, not qt_start. Thanks to Falk
|
||||
Hueffner.
|
||||
|
||||
2002-08-24 Marius Vollmer <mvo@zagadka.ping.de>
|
||||
|
||||
* md/Makefile.am (EXTRA_DIST): Added arm.h and arm.s.
|
||||
|
||||
2002-07-17 Marius Vollmer <mvo@zagadka.ping.de>
|
||||
|
||||
* arm.s, arm.h: New.
|
||||
|
||||
2002-02-24 Rob Browning <rlb@defaultvalue.org>
|
||||
|
||||
* Makefile.am (libqthreads_la_LDFLAGS): use @LIBQTHREADS_INTERFACE@.
|
||||
|
||||
2001-11-21 Gary Houston <ghouston@arglist.com>
|
||||
|
||||
* Makefile.am (OMIT_DEPENDENCIES): removed, since it seems to be
|
||||
obsolete. autogen.sh says:
|
||||
invalid unused variable name: `OMIT_DEPENDENCIES'
|
||||
|
||||
2001-11-04 Stefan Jahn <stefan@lkcc.org>
|
||||
|
||||
* md/Makefile.am (EXTRA_DIST): Added `i386.asm'.
|
||||
|
||||
* md/i386.asm: New file. Contains the Intel syntax version for
|
||||
nasm/tasm/masm of the file `i386.s'.
|
||||
|
||||
* qt.h.in: Definition of QT_API, QT_IMPORT and QT_EXPORT.
|
||||
Prefixed each symbols which is meant to go into a DLL.
|
||||
|
||||
* Makefile.am (libqthreads_la_LDFLAGS): Put `-no-undefined'
|
||||
into LDFLAGS to support linkers which do not allow unresolved
|
||||
symbols inside shared libraries.
|
||||
(EXTRA_DIST): Add `libqthreads.def', which is an export file
|
||||
definition for M$-Windows. It defines exported symbols. This is
|
||||
necessary because the M$VC linker does not know how to export
|
||||
assembler symbols into a DLL.
|
||||
|
||||
2001-08-25 Marius Vollmer <mvo@zagadka.ping.de>
|
||||
|
||||
* Makefile.am, md/Makefile.am, time/Makefile.am:
|
||||
(AUTOMAKE_OPTIONS): Change "foreign" to "gnu".
|
||||
|
||||
2001-08-15 Rob Browning <rlb@defaultvalue.org>
|
||||
|
||||
* Makefile.am (libqthreads_la_LDFLAGS): use libtool interface version
|
||||
variables.
|
||||
|
||||
2000-06-12 Mikael Djurfeldt <mdj@thalamus.nada.kth.se>
|
||||
|
||||
* Makefile.am (OMIT_DEPENDENCIES): Defined to contain the list of
|
||||
machine specific headers. This is necessary, otherwise automake
|
||||
will include a dependency specific for the machine on which the
|
||||
distribution archive was built.
|
||||
|
||||
2000-04-21 Mikael Djurfeldt <mdj@thalamus.nada.kth.se>
|
||||
|
||||
* *.*: Change includes so that they always use the "prefixes"
|
||||
libguile/, qt/, guile-readline/, or libltdl/.
|
||||
|
||||
* Makefile.am (DEFS): Added. automake adds -I options to DEFS,
|
||||
and we don't want that.
|
||||
(INCLUDES): Removed all -I options except for the root source
|
||||
directory and the root build directory.
|
||||
|
||||
1999-10-05 Jim Blandy <jimb@savonarola.red-bean.com>
|
||||
|
||||
* Makefile.in, md/Makefile.in, time/Makefile.in: Deleted from CVS
|
||||
repository. Run the autogen.sh script to create generated files
|
||||
like this one.
|
||||
|
||||
1999-09-11 Jim Blandy <jimb@savonarola.red-bean.com>
|
||||
|
||||
* time/Makefile.in: Regenerated.
|
||||
* md/Makefile.in: Regenerated.
|
||||
* Makefile.in: Regenerated.
|
||||
|
||||
1999-04-17 Jim Blandy <jimb@savonarola.red-bean.com>
|
||||
|
||||
* Makefile.in, time/Makefile.in: Regenerated.
|
||||
|
||||
1998-10-16 Jim Blandy <jimb@zwingli.cygnus.com>
|
||||
|
||||
* md/i386.s: Remove nested comment starter, to quiet warnings.
|
||||
|
||||
* Makefile.am (.s.lo): Supply our own rule here, which passes
|
||||
qthread_asflags through. See today's change to ../qthreads.m4.
|
||||
* Makefile.in, qt/Makefile.in, time/Makefile.in: Regenerated.
|
||||
|
||||
1998-10-03 Jim Blandy <jimb@zwingli.cygnus.com>
|
||||
|
||||
* Makefile.in: Regenerated with a patched automake, to get
|
||||
dependency generation right when using EGCS.
|
||||
|
||||
1998-09-29 Jim Blandy <jimb@totoro.red-bean.com>
|
||||
|
||||
* stp.h (stp_create): Doc fix.
|
||||
|
||||
1998-07-30 Jim Blandy <jimb@zwingli.cygnus.com>
|
||||
|
||||
* qt.h.in (qt_null, qt_error): Add prototypes for these.
|
||||
|
||||
1998-07-29 Jim Blandy <jimb@zwingli.cygnus.com>
|
||||
|
||||
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated using
|
||||
the last public version of automake, not the hacked Cygnus
|
||||
version.
|
||||
|
||||
1998-07-28 Jim Blandy <jimb@zwingli.cygnus.com>
|
||||
|
||||
* time/Makefile.in, md/Makefile.in, Makefile.in: Regenerated,
|
||||
after removing Totoro kludge.
|
||||
|
||||
1998-07-26 Jim Blandy <jimb@zwingli.cygnus.com>
|
||||
|
||||
Use libtool, and the thread configuration mechanism.
|
||||
* Makefile.am (lib_LTLIBRARIES, EXTRA_LTLIBRARIES,
|
||||
libqthreads_la_SOURCES, libqthreads_la_LIBADD): These replace
|
||||
lib_LIBRARIES, EXTRA_LIBRARIES, libqthreads_a_SOURCES,
|
||||
libqthreads_a_LIBADD. Use the variables set by the new config
|
||||
system.
|
||||
(libqthreads_la_DEPENDENCIES): New var.
|
||||
(libqthreads_la_LDFLAGS): Add -rpath; automake claims it can't set
|
||||
it itself, but I don't completely understand why.
|
||||
(qtmds.o, qtmdc.o): Rules removed. Use implicit build rules.
|
||||
(qtmds.s, qtmdc.c, qtdmdb.s): Rules added, to make symlinks to the
|
||||
appropriate files in the source tree.
|
||||
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated.
|
||||
|
||||
1998-04-15 Mikael Djurfeldt <mdj@nada.kth.se>
|
||||
|
||||
* qt.h.in: Declare return type of qt_abort as void.
|
||||
|
||||
1997-12-02 Tim Pierce <twp@skepsis.com>
|
||||
|
||||
* md/axp.s (qt_vstart): Typo fixes, thanks to Alexander Jolk.
|
||||
|
||||
Sat Oct 25 02:54:11 1997 Jim Blandy <jimb@totoro.red-bean.com>
|
||||
|
||||
* Makefile.am: Call the library libqthreads.a, not libqt.a. The
|
||||
old name conflicts with the Qt user interface toolkit.
|
||||
* Makefile.in: Regenerated.
|
||||
|
||||
Mon Sep 29 23:54:28 1997 Jim Blandy <jimb@totoro.red-bean.com>
|
||||
|
||||
* time/Makefile.in: Regenerated with automake 1.2c.
|
||||
|
||||
* md/Makefile.in: Regenerated with automake 1.2c.
|
||||
|
||||
* Makefile.in: Regenerated with automake 1.2c.
|
||||
|
||||
Sat Sep 27 23:14:13 1997 Jim Blandy <jimb@totoro.red-bean.com>
|
||||
|
||||
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated with
|
||||
automake 1.2a.
|
||||
|
||||
Thu Aug 28 23:49:19 1997 Jim Blandy <jimb@totoro.red-bean.com>
|
||||
|
||||
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated.
|
||||
|
||||
Wed Aug 27 17:43:38 1997 Jim Blandy <jimb@totoro.red-bean.com>
|
||||
|
||||
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated, so
|
||||
it uses "tar", not "gtar".
|
||||
|
||||
* config: Use the QuickThreads assembler fragment with Irix
|
||||
dynamic linking support for Irix 6 as well as Irix 5. Thanks to
|
||||
Jesse Glick.
|
||||
|
||||
Wed Jul 23 20:32:42 1997 Mikael Djurfeldt <djurf@zafir.e.kth.se>
|
||||
|
||||
* md/axp.s, md/axp_b.s: Changed comments from C-style to # to
|
||||
please the alpha assembler.
|
||||
|
||||
Sun Jun 22 18:44:11 1997 Jim Blandy <jimb@floss.red-bean.com>
|
||||
|
||||
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated after
|
||||
timestamp change; see ../ChangeLog.
|
||||
|
||||
Wed Jun 11 00:33:10 1997 Jim Blandy <jimb@floss.red-bean.com>
|
||||
|
||||
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated after
|
||||
xtra_PLUGIN_guile_libs change in ../configure.in.
|
||||
|
||||
Tue May 13 16:40:06 1997 Jim Blandy <jimb@floss.cyclic.com>
|
||||
|
||||
* Makefile.in: Regenerated, using automake-1.1p.
|
||||
|
||||
Sun Apr 27 18:00:06 1997 Jim Blandy <jimb@floss.cyclic.com>
|
||||
|
||||
* aclocal.m4: Removed; unnecessary, given changes of Apr 24.
|
||||
|
||||
Thu Apr 24 01:37:49 1997 Jim Blandy <jimb@floss.cyclic.com>
|
||||
|
||||
Get 'make dist' to work again.
|
||||
* Makefile.am (EXTRA_DIST): Remove PLUGIN files.
|
||||
* Makefile.in: Regenerated, like the secret sachets of seven
|
||||
sultry sailors.
|
||||
|
||||
Changes for reduced Guile distribution: one configure script,
|
||||
no plugins.
|
||||
* configure.in, configure: Removed.
|
||||
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated.
|
||||
|
||||
Tue Apr 15 17:46:54 1997 Jim Blandy <jimb@floss.cyclic.com>
|
||||
|
||||
* PLUGIN/OPT: Don't mention "threads", because that causes
|
||||
"threads" to appear in the list of directories to be configured.
|
||||
Just say enough to get qt to appear in the list. I don't think qt
|
||||
needs to be built before or after anything else in particular...
|
||||
|
||||
Mon Feb 24 21:47:16 1997 Mikael Djurfeldt <mdj@mdj.nada.kth.se>
|
||||
|
||||
* configure.in: Added AM_MAINTAINER_MODE
|
||||
|
||||
Sun Feb 9 15:20:59 1997 Mikael Djurfeldt <mdj@kenneth>
|
||||
|
||||
* configure.in: Added changequote(,) before the host case (since
|
||||
we use [ and ] in a pattern).
|
||||
* configure: Regenerated.
|
||||
|
||||
Fri Feb 7 18:00:07 1997 Jim Blandy <jimb@floss.cyclic.com>
|
||||
|
||||
* configure.in: Recognize i686 as an okay processor too.
|
||||
* configure: Regenerated.
|
||||
|
||||
Mon Dec 9 17:55:59 1996 Jim Blandy <jimb@duality.gnu.ai.mit.edu>
|
||||
|
||||
We need to name the object files produced from the
|
||||
machine-dependent C and assembler files qtmds.o and qtmdc.o, but
|
||||
using -c and -o together on the cc command line isn't portable.
|
||||
* configure.in: Generate the names of the .o files here, and
|
||||
substitute them into Makefile.
|
||||
* Makefile.am (qtmds.o, qtmdc.o): Let CC name them what it wants,
|
||||
and then rename them when it's done.
|
||||
(configure, Makefile.in): Regenerated.
|
||||
|
||||
Sat Nov 30 23:59:06 1996 Tom Tromey <tromey@cygnus.com>
|
||||
|
||||
* PLUGIN/greet: Removed.
|
||||
* Makefile.am, md/Makefile.am, time/Makefile.am, aclocal.m4: New
|
||||
files.
|
||||
* configure.in: Updated for Automake.
|
||||
|
||||
Sun Nov 10 17:40:47 1996 Jim Blandy <jimb@floss.cyclic.com>
|
||||
|
||||
* configure.in, Makefile.in: The 'install' and 'uninstall'
|
||||
Makefile targets should be affected by whether or not we have a
|
||||
port to the current target architecture too, not just the 'all'
|
||||
target.
|
||||
|
||||
Wed Oct 9 19:40:13 1996 Jim Blandy <jimb@floss.cyclic.com>
|
||||
|
||||
* configure.in: If we don't have a port to the current machine,
|
||||
just arrange for 'make all' to do nothing. Don't abort
|
||||
configuration. We need a fully configured directory tree in order
|
||||
to make distributions and the like.
|
||||
|
||||
* Makefile.in (distfiles): Update for the new directory structure.
|
||||
(plugin_distfiles, md_distfiles, time_distfiles): New variables.
|
||||
(dist-dir): New target; use all the above to build a subtree of a
|
||||
distribution.
|
||||
(manifest): Target deleted.
|
||||
|
||||
Tue Oct 1 02:06:19 1996 Mikael Djurfeldt <mdj@woody.nada.kth.se>
|
||||
|
||||
* configure.in: Solaris 2 should use sparc.s.
|
||||
*Older* systems use _sparc.s
|
||||
|
||||
Fri Mar 29 11:50:20 1996 Anthony Green <green@snuffle.cygnus.com>
|
||||
|
||||
* configure: Rebuilt
|
||||
* Makefile.in, configure.in: Fixed installation.
|
||||
|
||||
Fri Mar 22 16:20:27 1996 Anthony Green (green@gerbil.cygnus.com)
|
||||
|
||||
* all files: installed qt-002 package. Autoconfiscated.
|
||||
|
||||
|
81
qt/INSTALL
81
qt/INSTALL
|
@ -1,81 +0,0 @@
|
|||
Installation of the `QuickThreads' threads-building toolkit.
|
||||
|
||||
* Notice
|
||||
|
||||
QuickThreads -- Threads-building toolkit.
|
||||
Copyright (c) 1993 by David Keppel
|
||||
|
||||
Permission to use, copy, modify and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice and this notice
|
||||
appear in all copies. This software is provided as a
|
||||
proof-of-concept and for demonstration purposes; there is no
|
||||
representation about the suitability of this software for any
|
||||
purpose.
|
||||
|
||||
|
||||
* Configuration
|
||||
|
||||
Configure with
|
||||
|
||||
./config *machtype*
|
||||
|
||||
where "*machtype*" is one of the supported target machines. As of
|
||||
October 1994, the supported machines (targets) are:
|
||||
|
||||
axp -- All Digital Equipment Corporation AXP (DEC Alpha)
|
||||
processors, compile with GNU CC
|
||||
axp-osf1 -- AXP running OSF 1.x
|
||||
axp-osf2 -- AXP running OSF 2.x
|
||||
hppa -- HP's PA-RISC 1.1 processor
|
||||
hppa-cnx-spp -- Convex SPP (PA-RISC 1.1 processor)
|
||||
iX86 -- 80386, 80486, and 80586-compatible processors
|
||||
See notes below for OS/2.
|
||||
iX86-ss -- 'iX86 for assemblers that use slash-slash ('//')
|
||||
comments.
|
||||
ksr1 -- All KSR processors
|
||||
m88k -- All members of the Motorola 88000 family
|
||||
mips -- MIPS R2000 and R3000 processors
|
||||
mips-irix5 -- Irix 5.xx (use `mips' for Irix 4.xx)
|
||||
sparc-os1 -- V8-compliant SPARC processors using compilers
|
||||
that prefix labels (e.g. "foo" appears as "_foo")
|
||||
Includes Solaris 1 (SunOS 4.X).
|
||||
sparc-os2 -- V8-compliant SPARC processors using compilers
|
||||
that do not prefix labels. Includes Solaris 2.
|
||||
vax -- All VAX processors
|
||||
|
||||
In addition, the target `clean' will deconfigure QuickThreads.
|
||||
|
||||
Note that a given machine target may not work on all instances of that
|
||||
machine because e.g., the assembler syntax varies from machine to
|
||||
machine.
|
||||
|
||||
Note also that additions to a processor family may require a new
|
||||
target. So, for example, the `vax' target might not work for all
|
||||
future VAX processors if, say, new VAX processors are introduced and
|
||||
they use separate floating-point registers.
|
||||
|
||||
For OS/2, change `ranlib' to `ar -s', `configure' to `configure.cmd'
|
||||
(or was that `config' to `config.cmd'?), and replace the soft links
|
||||
(`ln -s') with plain copies.
|
||||
|
||||
|
||||
* Build
|
||||
|
||||
To build the QuickThreads library, first configure (see above) then
|
||||
type `make libqt.a' in the top-level directory.
|
||||
|
||||
To build the demonstration threads package, SimpleThreads, type
|
||||
`make libstp.a' in the top-level directory.
|
||||
|
||||
To build an executable ``stress-test'' and measurement program, type
|
||||
`make run' in the top-level directory. Run `time/raw' to run the
|
||||
stress tests.
|
||||
|
||||
|
||||
* Installation
|
||||
|
||||
Build the QuickThreads library (see above) and then copy `libqt.a' to
|
||||
the installation library directory (e.g., /usr/local/lib) and `qt.h'
|
||||
and `qtmd.h' to the installation include directory (e.g.,
|
||||
/usr/local/include).
|
|
@ -1,54 +0,0 @@
|
|||
## Process this file with automake to produce Makefile.in.
|
||||
##
|
||||
## Copyright (C) 1998, 2000, 2006 Free Software Foundation, Inc.
|
||||
##
|
||||
## This file is part of GUILE.
|
||||
##
|
||||
## GUILE is free software; you can redistribute it and/or modify it
|
||||
## under the terms of the GNU Lesser General Public License as
|
||||
## published by the Free Software Foundation; either version 3, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## GUILE is distributed in the hope that it will be useful, but
|
||||
## WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU Lesser General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU Lesser General Public
|
||||
## License along with GUILE; see the file COPYING.LESSER. If not,
|
||||
## write to the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
## Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
AUTOMAKE_OPTIONS = gnu
|
||||
|
||||
## subdirs are for making distributions only.
|
||||
SUBDIRS = md time
|
||||
|
||||
lib_LTLIBRARIES = @QTHREAD_LTLIBS@
|
||||
EXTRA_LTLIBRARIES = libqthreads.la
|
||||
|
||||
## Prevent automake from adding extra -I options
|
||||
DEFS = @DEFS@
|
||||
INCLUDES = -I.. -I$(srcdir)/..
|
||||
|
||||
libqthreads_la_SOURCES = qt.c copyright.h
|
||||
libqthreads_la_LIBADD = qtmds.lo qtmdc.lo
|
||||
libqthreads_la_DEPENDENCIES = qtmds.lo qtmdc.lo
|
||||
libqthreads_la_LDFLAGS = -rpath $(libdir) -export-dynamic -no-undefined \
|
||||
-version-info @LIBQTHREADS_INTERFACE@
|
||||
|
||||
# Seems to be obsolete - autogen.sh is giving:
|
||||
# invalid unused variable name: `OMIT_DEPENDENCIES'
|
||||
#OMIT_DEPENDENCIES = axp.h hppa.h i386.h ksr.h m88k.h mips.h sparc.h vax.h
|
||||
|
||||
.s.lo:
|
||||
$(LIBTOOL) --mode=compile $(COMPILE) $(qthread_asflags) -c $<
|
||||
qtmds.s:
|
||||
${LN_S} ${srcdir}/${qtmds_s} qtmds.s
|
||||
qtmdc.c:
|
||||
${LN_S} ${srcdir}/${qtmdc_c} qtmdc.c
|
||||
qtdmdb.s:
|
||||
${LN_S} ${srcdir}/${qtdmdb_s} qtdmdb.s
|
||||
|
||||
EXTRA_DIST = CHANGES README.MISC README.PORT b.h meas.c stp.c stp.h \
|
||||
Makefile.base config libqthreads.def
|
112
qt/Makefile.base
112
qt/Makefile.base
|
@ -1,112 +0,0 @@
|
|||
.SUFFIXES: .c .o .s .E
|
||||
|
||||
#
|
||||
# Need to include from the current directory because "qt.h"
|
||||
# will include <qtmd.h>.
|
||||
#
|
||||
CFLAGS = -I. -g
|
||||
|
||||
#
|
||||
# Fix this to be something meaningful for your system.
|
||||
#
|
||||
DEST = /dev/null
|
||||
|
||||
DOC = users.tout
|
||||
|
||||
EXTHDRS = /usr/include/stdio.h
|
||||
|
||||
HDRS = qt.h \
|
||||
qtmd.h \
|
||||
stp.h
|
||||
|
||||
LDFLAGS = $(CFLAGS)
|
||||
|
||||
EXTLIBS =
|
||||
|
||||
LIBS = libstp.a libqt.a
|
||||
|
||||
LINKER = $(CC)
|
||||
|
||||
MAKEFILE = Makefile
|
||||
|
||||
M = Makefile configuration
|
||||
|
||||
OBJS = qtmdb.o \
|
||||
meas.o
|
||||
|
||||
QTOBJS = qt.o qtmds.o qtmdc.o
|
||||
|
||||
STPOBJS = stp.o
|
||||
|
||||
PR = -Pps
|
||||
|
||||
PRINT = pr
|
||||
|
||||
PROGRAM = run
|
||||
|
||||
SRCS = meas.c \
|
||||
qt.c \
|
||||
qtmdc.c \
|
||||
qtmds.s \
|
||||
qtmdb.s
|
||||
|
||||
TMP_INIT = tmp.init
|
||||
TMP_SWAP = tmp.swap
|
||||
|
||||
.DEFAULT:
|
||||
co -q $@
|
||||
|
||||
.c.E: force
|
||||
$(CC) $(CFLAGS) -E $*.c > $*.E
|
||||
|
||||
all: libqt.a libstp.a $(PROGRAM) $(M)
|
||||
|
||||
libqt.a: $(QTOBJS) $(M)
|
||||
ar crv libqt.a $(QTOBJS)
|
||||
ranlib libqt.a
|
||||
|
||||
libstp.a: $(STPOBJS) $(M)
|
||||
ar crv libstp.a $(STPOBJS)
|
||||
ranlib libstp.a
|
||||
|
||||
$(PROGRAM): $(OBJS) $(LIBS) $(M)
|
||||
@echo "Loading $(PROGRAM) ... "
|
||||
# ld -o $(PROGRAM) /lib/crt0.o $(OBJS) -lc
|
||||
$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) $(EXTLIBS) -o $(PROGRAM)
|
||||
@echo "done"
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(PROGRAM) $(TMP_INIT) $(TMP_SWAP) $(DOC)
|
||||
rm -f libqt.a libstp.a
|
||||
rm -f $(QTOBJS) $(STPOBJS)
|
||||
|
||||
depend:; @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)
|
||||
|
||||
doc: users.ms raw
|
||||
time/assim < raw | grep "^init" | sed 's/^init //' > $(TMP_INIT)
|
||||
time/assim < raw | grep "^swap" | sed 's/^swap //' > $(TMP_SWAP)
|
||||
soelim users.ms | tbl $(PR) | troff -t $(PR) -ms > $(DOC)
|
||||
|
||||
index:; @ctags -wx $(HDRS) $(SRCS)
|
||||
|
||||
print:; @$(PRINT) $(HDRS) $(SRCS)
|
||||
|
||||
program: $(PROGRAM)
|
||||
|
||||
tags: $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)
|
||||
|
||||
update: $(DEST)/$(PROGRAM)
|
||||
|
||||
$(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS)
|
||||
@make -f $(MAKEFILE) DEST=$(DEST) install
|
||||
|
||||
QT_H = qt.h $(QTMD_H)
|
||||
QTMD_H = qtmd.h
|
||||
|
||||
###
|
||||
qtmdb.o: $(M) qtmdb.s b.h
|
||||
meas.o: $(M) meas.c /usr/include/stdio.h $(QT_H) b.h stp.h
|
||||
qt.o: $(M) qt.c $(QT_H)
|
||||
stp.o: $(M) stp.c stp.h $(QT_H)
|
||||
qtmds.o: $(M) qtmds.s
|
||||
qtmdc.o: $(M) qtmdc.c $(QT_H)
|
89
qt/README
89
qt/README
|
@ -1,89 +0,0 @@
|
|||
This is a source code distribution for QuickThreads. QuickThreads is a
|
||||
toolkit for building threads packages; it is described in detail in the
|
||||
University of Washington CS&E Technical report #93-05-06, available via
|
||||
anonymous ftp from `ftp.cs.washington.edu' (128.95.1.4, as of Oct. '94)
|
||||
in `tr/1993/05/UW-CSE-93-05-06.PS.Z'.
|
||||
|
||||
This distribution shows basic ideas in QuickThreads and elaborates with
|
||||
example implementations for a gaggle of machines. As of October those
|
||||
machines included:
|
||||
|
||||
80386 faimly
|
||||
88000 faimily
|
||||
DEC AXP (Alpha) family
|
||||
HP-PA family
|
||||
KSR
|
||||
MIPS family
|
||||
SPARC V8 family
|
||||
VAX family
|
||||
|
||||
Configuration, build, and installation are described in INSTALL.
|
||||
|
||||
Be aware: that there is no varargs code for the KSR.
|
||||
|
||||
The HP-PA port was designed to work with both HP workstations
|
||||
and Convex SPP computers. It was generously provided by Uwe Reder
|
||||
<uereder@cip.informatik.uni-erlangen.de>. It is part of the ELiTE
|
||||
(Erlangen Lightweight Thread Environment) project directed by
|
||||
Frank Bellosa <bellosa@informatik.uni-erlangen.de> at the Operating
|
||||
Systems Department of the University of Erlangen (Germany).
|
||||
|
||||
Other contributors include: Weihaw Chuang, Richard O'Keefe,
|
||||
Laurent Perron, John Polstra, Shinji Suzuki, Assar Westerlund,
|
||||
thanks also to Peter Buhr and Dirk Grunwald.
|
||||
|
||||
|
||||
Here is a brief summary:
|
||||
|
||||
QuickThreads is a toolkit for building threads packages. It is my hope
|
||||
that you'll find it easier to use QuickThreads normally than to take it
|
||||
and modify the raw cswap code to fit your application. The idea behind
|
||||
QuickThreads is that it should make it easy for you to write & retarget
|
||||
threads packages. If you want the routine `t_create' to create threads
|
||||
and `t_block' to suspend threads, you write them using the QuickThreads
|
||||
`primitive' operations `QT_SP', `QT_INIT', and `QT_BLOCK', that perform
|
||||
machine-dependent initialization and blocking, plus code you supply for
|
||||
performing the portable operatons. For example, you might write:
|
||||
|
||||
t_create (func, arg)
|
||||
{
|
||||
stk = malloc (STKSIZE);
|
||||
stackbase = QT_SP (stk, STKSIZE);
|
||||
sp = QT_INIT (stakcbase, func, arg);
|
||||
qput (runq, sp);
|
||||
}
|
||||
|
||||
Threads block by doing something like:
|
||||
|
||||
t_block()
|
||||
{
|
||||
sp_next = qget (runq);
|
||||
QT_BLOCK (helper, runq, sp_next);
|
||||
// wake up again here
|
||||
}
|
||||
|
||||
// called by QT_BLOCK after the old thread has blocked,
|
||||
// puts the old thread on the queue `onq'.
|
||||
helper (sp_old, onq)
|
||||
{
|
||||
qput (onq, sp_old);
|
||||
}
|
||||
|
||||
(Of course) it's actually a bit more complex than that, but the general
|
||||
idea is that you write portable code to allocate stacks and enqueue and
|
||||
dequeue threads. Than, to get your threads package up and running on a
|
||||
different machine, you just reconfigure QuickThreads and recompile, and
|
||||
that's it.
|
||||
|
||||
The QuickThreads `distribution' includes a sample threads package (look
|
||||
at stp.{c,h}) that is written in terms of QuickThreads operations. The
|
||||
TR mentioned above explains the simple threads package in detail.
|
||||
|
||||
|
||||
|
||||
If you do use QuickThreads, I'd like to hear both about what worked for
|
||||
you and what didn't work, problems you had, insights gleaned, etc.
|
||||
|
||||
Let me know what you think.
|
||||
|
||||
David Keppel <pardo@cs.washington.edu>
|
|
@ -1,56 +0,0 @@
|
|||
Here's some machine-specific informatin for various systems:
|
||||
|
||||
m88k on g88.sim
|
||||
|
||||
.g88init:
|
||||
echo (gdb) target sim\n
|
||||
target sim
|
||||
echo (gdb) ecatch all\n
|
||||
ecatch all
|
||||
echo (gdb) break exit\n
|
||||
break exit
|
||||
% vi Makefile // set CC and AS
|
||||
% setenv MEERKAT /projects/cer/meerkat
|
||||
% set path=($MEERKAT/bin $path)
|
||||
% make run
|
||||
% g88.sim run
|
||||
(g88) run run N // where `N' is the test number
|
||||
|
||||
|
||||
m88k on meerkats, cross compile as above (make run)
|
||||
|
||||
Run w/ g88:
|
||||
%g88 run
|
||||
(g88) source /homes/rivers/robertb/.gdbinit
|
||||
(g88) me
|
||||
which does
|
||||
(g88) set $firstchars=6
|
||||
(g88) set $resetonattach=1
|
||||
(g88) attach /dev/pp0
|
||||
then download
|
||||
(g88) dl
|
||||
and run with
|
||||
(g88) continue
|
||||
|
||||
Really the way to run it is:
|
||||
(g88) source
|
||||
(g88) me
|
||||
(g88) win
|
||||
(g88) dead 1
|
||||
(g88) dead 2
|
||||
(g88) dead 3
|
||||
(g88) dl
|
||||
(g88) cont
|
||||
|
||||
To rerun
|
||||
(g88) init
|
||||
(g88) dl
|
||||
|
||||
To run simulated meerkat:
|
||||
(g88) att sim
|
||||
<<then use normal commands>>
|
||||
|
||||
On 4.5 g88:
|
||||
(g88) target sim memsize
|
||||
instead of attatch
|
||||
(g88) ecatch all # catch exception before becomes error
|
112
qt/README.PORT
112
qt/README.PORT
|
@ -1,112 +0,0 @@
|
|||
Date: Tue, 11 Jan 94 13:23:11 -0800
|
||||
From: "pardo@cs.washington.edu" <pardo@meitner.cs.washington.edu>
|
||||
|
||||
>[What's needed to get `qt' on an i860-based machine?]
|
||||
|
||||
Almost certainly "some assembly required" (pun accepted).
|
||||
|
||||
To write a cswap port, you need to understand the context switching
|
||||
model. Turn to figure 2 in the QT TR. Here's about what the assembly
|
||||
code looks like to implement that:
|
||||
|
||||
qt_cswap:
|
||||
adjust stack pointer
|
||||
save callee-save registers on to old's stack
|
||||
argument register <- old sp
|
||||
sp <- new sp
|
||||
(*helper)(args...)
|
||||
restore callee-save registers from new's stack
|
||||
unadjust stack pointer
|
||||
return
|
||||
|
||||
Once more in slow motion:
|
||||
|
||||
- `old' thread calls context switch routine (new, a0, a1, h)
|
||||
- cswap routine saves registers that have useful values
|
||||
- cswap routine switches to new stack
|
||||
- cswap routine calls helper function (*h)(old, a0, a1)
|
||||
- when helper returns, cswap routine restores registers
|
||||
that were saved the last time `new' was suspended
|
||||
- cswap routine returns to whatever `new' routine called the
|
||||
context switch routine
|
||||
|
||||
There's a few tricks here. First, how do you start a thread running
|
||||
for the very first time? Answer is: fake some stuff on the stack
|
||||
so it *looks* like it was called from the middle of some routine.
|
||||
When the new thread is restarted, it is treated like any other
|
||||
thread. It just so happens that it's never really run before, but
|
||||
you can't tell that because the saved state makes it look like like
|
||||
it's been run. The return pc is set to point at a little stub of
|
||||
assembly code that loads up registers with the right values and
|
||||
then calls `only'.
|
||||
|
||||
Second, I advise you to forget about varargs routines (at least
|
||||
until you get single-arg routines up and running).
|
||||
|
||||
Third, on most machines `qt_abort' is the same as `qt_cswap' except
|
||||
that it need not save any callee-save registers.
|
||||
|
||||
Fourth, `qt_cswap' needs to save and restore any floating-point
|
||||
registers that are callee-save (see your processor handbook). On
|
||||
some machines, *no* floating-point registers are callee-save, so
|
||||
`qt_cswap' is exactly the same as the integer-only cswap routine.
|
||||
|
||||
I suggest staring at the MIPS code for a few minutes. It's "mostly"
|
||||
generic RISC code, so it gets a lot of the flavor across without
|
||||
getting too bogged down in little nitty details.
|
||||
|
||||
|
||||
|
||||
Now for a bit more detail: The stack is laid out to hold callee-save
|
||||
registers. On many machines, I implemented fp cswap as save fp
|
||||
regs, call integer cswap, and when integer cswap returns (when the
|
||||
thread wakes up again), restore fp regs.
|
||||
|
||||
For thread startup, I figure out some callee-save registers that
|
||||
I use to hold parameters to the startup routine (`only'). When
|
||||
the thread is being started it doesn't have any saved registers
|
||||
that need to be restored, but I go ahead and let the integer context
|
||||
switch routine restore some registers then "return" to the stub
|
||||
code. The stub code then copies the "callee save" registers to
|
||||
argument registers and calls the startup routine. That keeps the
|
||||
stub code pretty darn simple.
|
||||
|
||||
For each machine I need to know the machine's procedure calling
|
||||
convention before I write a port. I figure out how many callee-save
|
||||
registers are there and allocate enough stack space for those
|
||||
registers. I also figure out how parameters are passed, since I
|
||||
will need to call the helper function. On most RISC machines, I
|
||||
just need to put the old sp in the 0'th arg register and then call
|
||||
indirect through the 3rd arg register; the 1st and 2nd arg registers
|
||||
are already set up correctly. Likewise, I don't touch the return
|
||||
value register between the helper's return and the context switch
|
||||
routine's return.
|
||||
|
||||
I have a bunch of macros set up to do the stack initialization.
|
||||
The easiest way to debug this stuff is to go ahead and write a C
|
||||
routine to do stack initialization. Once you're happy with it you
|
||||
can turn it in to a macro.
|
||||
|
||||
In general there's a lot of ugly macros, but most of them do simple
|
||||
things like return constants, etc. Any time you're looking at it
|
||||
and it looks confusing you just need to remember "this is actually
|
||||
simple code, the only tricky thing is calling the helper between
|
||||
the stack switch and the new thread's register restore."
|
||||
|
||||
|
||||
You will almost certainly need to write the assembly code fragment
|
||||
that starts a thread. You might be able to do a lot of the context
|
||||
switch code with `setjmp' and `longjmp', if they *happen* to have
|
||||
the "right" implementation. But getting all the details right (the
|
||||
helper can return a value to the new thread's cswap routine caller)
|
||||
is probaby trickier than writing code that does the minimum and
|
||||
thus doesn't have any extra instructions (or generality) to cause
|
||||
problems.
|
||||
|
||||
I don't know of any ports besides those included with the source
|
||||
code distribution. If you send me a port I will hapily add it to
|
||||
the distribution.
|
||||
|
||||
Let me know as you have questions and/or comments.
|
||||
|
||||
;-D on ( Now *that*'s a switch... ) Pardo
|
11
qt/b.h
11
qt/b.h
|
@ -1,11 +0,0 @@
|
|||
#ifndef B_H
|
||||
#define B_H "$Header: /home/ludo/src/guile.cvs/gitification/guile-cvs/guile/guile-core/qt/b.h,v 1.1 1996-10-01 03:27:25 mdj Exp $"
|
||||
|
||||
#include "copyright.h"
|
||||
|
||||
extern void b_call_reg (int n);
|
||||
extern void b_call_imm (int n);
|
||||
extern void b_add (int n);
|
||||
extern void b_load (int n);
|
||||
|
||||
#endif /* ndef B_H */
|
308
qt/config
308
qt/config
|
@ -1,308 +0,0 @@
|
|||
#! /bin/sh -x
|
||||
|
||||
rm -f Makefile Makefile.md README.md qtmd.h qtmdb.s qtmdc.c qtmds.s configuration
|
||||
|
||||
case $1 in
|
||||
axp*)
|
||||
: "DEC AXP"
|
||||
case $1 in
|
||||
axp-osf1*)
|
||||
: "Compile using /bin/cc under OSF 1.x."
|
||||
ln -s md/axp.1.Makefile Makefile.md
|
||||
;;
|
||||
axp-osf2*)
|
||||
: "Compile using /bin/cc under OSF 2.x."
|
||||
ln -s md/axp.1.Makefile Makefile.md
|
||||
;;
|
||||
*)
|
||||
: "Compile using GNU CC."
|
||||
ln -s md/axp.Makefile Makefile.md
|
||||
;;
|
||||
esac
|
||||
|
||||
ln -s md/axp.h qtmd.h
|
||||
ln -s md/axp.c qtmdc.c
|
||||
ln -s md/axp.s qtmds.s
|
||||
ln -s md/axp_b.s qtmdb.s
|
||||
ln -s md/axp.README README.md
|
||||
iter_init=1000000000
|
||||
iter_runone=10000000
|
||||
iter_blockint=10000000
|
||||
iter_blockfloat=10000000
|
||||
iter_vainit0=10000000
|
||||
iter_vainit2=10000000
|
||||
iter_vainit4=10000000
|
||||
iter_vainit8=10000000
|
||||
iter_vastart0=10000000
|
||||
iter_vastart2=10000000
|
||||
iter_vastart4=10000000
|
||||
iter_vastart8=10000000
|
||||
iter_bench_call_reg=10000000
|
||||
iter_bench_call_imm=10000000
|
||||
iter_bench_add=100000000
|
||||
iter_bench_load=100000000
|
||||
;;
|
||||
|
||||
hppa*)
|
||||
: "HP's PA-RISC 1.1 processors."
|
||||
|
||||
case $1 in
|
||||
hppa-cnx-spp*)
|
||||
: "Convex SPP (PA-RISC 1.1 processors)."
|
||||
ln -s md/hppa-cnx.Makefile Makefile.md
|
||||
;;
|
||||
*)
|
||||
ln -s md/hppa.Makefile Makefile.md
|
||||
;;
|
||||
esac
|
||||
|
||||
ln -s md/hppa.h qtmd.h
|
||||
ln -s md/null.c qtmdc.c
|
||||
ln -s md/hppa.s qtmds.s
|
||||
ln -s md/hppa_b.s qtmdb.s
|
||||
iter_init=10000000
|
||||
iter_runone=1000000
|
||||
iter_blockint=1000000
|
||||
iter_blockfloat=1000000
|
||||
iter_vainit0=1000000
|
||||
iter_vainit2=1000000
|
||||
iter_vainit4=1000000
|
||||
iter_vainit8=1000000
|
||||
iter_vastart0=1000000
|
||||
iter_vastart2=1000000
|
||||
iter_vastart4=1000000
|
||||
iter_vastart8=1000000
|
||||
iter_bench_call_reg=10000000
|
||||
iter_bench_call_imm=10000000
|
||||
iter_bench_add=100000000
|
||||
iter_bench_load=100000000
|
||||
;;
|
||||
|
||||
iX86*)
|
||||
case $1 in
|
||||
iX86-ss*)
|
||||
: "Assemlber comments '//'"
|
||||
sed 's/\/\*/\/\//' < md/i386.s > qtmds.s
|
||||
sed 's/\/\*/\/\//' < md/i386_b.s > qtmdb.s
|
||||
;;
|
||||
|
||||
*)
|
||||
ln -s md/i386.s qtmds.s
|
||||
ln -s md/i386_b.s qtmdb.s
|
||||
;;
|
||||
esac
|
||||
: "Intel 80386 and compatibles (not '286...)"
|
||||
ln -s md/default.Makefile Makefile.md
|
||||
ln -s md/i386.h qtmd.h
|
||||
ln -s md/null.c qtmdc.c
|
||||
ln -s md/i386.README README.md
|
||||
iter_init=10000000
|
||||
iter_runone=1000000
|
||||
iter_blockint=1000000
|
||||
iter_blockfloat=1000000
|
||||
iter_vainit0=1000000
|
||||
iter_vainit2=1000000
|
||||
iter_vainit4=1000000
|
||||
iter_vainit8=1000000
|
||||
iter_vastart0=1000000
|
||||
iter_vastart2=1000000
|
||||
iter_vastart4=1000000
|
||||
iter_vastart8=1000000
|
||||
iter_bench_call_reg=1000000
|
||||
iter_bench_call_imm=1000000
|
||||
iter_bench_add=100000000
|
||||
iter_bench_load=10000000
|
||||
;;
|
||||
|
||||
m68k)
|
||||
: "Motorola 68000 family -- incomplete!"
|
||||
ln -s md/default.Makefile Makefile.md
|
||||
ln -s md/m68k.h qtmd.h
|
||||
ln -s md/null.c qtmdc.c
|
||||
ln -s md/m68k.s qtmds.s
|
||||
ln -s md/m68k_b.s qtmdb.s
|
||||
ln -s md/null.README README.md
|
||||
;;
|
||||
|
||||
m88k)
|
||||
: "Motorola 88000 family"
|
||||
ln -s md/m88k.Makefile Makefile.md
|
||||
ln -s md/m88k.h qtmd.h
|
||||
ln -s md/m88k.c qtmdc.c
|
||||
ln -s md/m88k.s qtmds.s
|
||||
ln -s md/m88k_b.s qtmdb.s
|
||||
ln -s md/null.README README.md
|
||||
iter_init=1000000
|
||||
iter_runone=100000
|
||||
iter_blockint=100000
|
||||
iter_blockfloat=100000
|
||||
iter_vainit0=100000
|
||||
iter_vainit2=100000
|
||||
iter_vainit4=100000
|
||||
iter_vainit8=100000
|
||||
iter_vastart0=100000
|
||||
iter_vastart2=100000
|
||||
iter_vastart4=100000
|
||||
iter_vastart8=100000
|
||||
iter_bench_call_reg=100000000
|
||||
iter_bench_call_imm=100000000
|
||||
iter_bench_add=1000000000
|
||||
iter_bench_load=100000000
|
||||
;;
|
||||
|
||||
mips*)
|
||||
: "MIPS R2000 and R3000."
|
||||
|
||||
case $1 in
|
||||
mips-irix[56]*)
|
||||
: "Silicon Graphics Irix with dynamic linking"
|
||||
: "Use mips for irix4."
|
||||
ln -s md/mips-irix5.s qtmds.s
|
||||
;;
|
||||
*)
|
||||
ln -s md/mips.s qtmds.s
|
||||
;;
|
||||
esac
|
||||
|
||||
ln -s md/default.Makefile Makefile.md
|
||||
ln -s md/mips.h qtmd.h
|
||||
ln -s md/null.c qtmdc.c
|
||||
ln -s md/mips_b.s qtmdb.s
|
||||
ln -s md/null.README README.md
|
||||
iter_init=10000000
|
||||
iter_runone=10000000
|
||||
iter_blockint=10000000
|
||||
iter_blockfloat=10000000
|
||||
iter_vainit0=1000000
|
||||
iter_vainit2=1000000
|
||||
iter_vainit4=1000000
|
||||
iter_vainit8=1000000
|
||||
iter_vastart0=1000000
|
||||
iter_vastart2=1000000
|
||||
iter_vastart4=1000000
|
||||
iter_vastart8=1000000
|
||||
iter_bench_call_reg=100000000
|
||||
iter_bench_call_imm=100000000
|
||||
iter_bench_add=1000000000
|
||||
iter_bench_load=100000000
|
||||
;;
|
||||
|
||||
sparc*)
|
||||
: "SPARC processors"
|
||||
case $1 in
|
||||
sparc-os2*)
|
||||
sed 's/_qt_/qt_/' md/sparc.s > qtmds.s
|
||||
sed 's/_b_/b_/' md/sparc_b.s > qtmdb.s
|
||||
ln -s md/solaris.README README.md
|
||||
;;
|
||||
*)
|
||||
ln -s md/sparc.s qtmds.s
|
||||
ln -s md/sparc_b.s qtmdb.s
|
||||
ln -s md/null.README README.md
|
||||
;;
|
||||
esac
|
||||
|
||||
ln -s md/default.Makefile Makefile.md
|
||||
ln -s md/sparc.h qtmd.h
|
||||
ln -s md/null.c qtmdc.c
|
||||
iter_init=10000000
|
||||
iter_runone=1000000
|
||||
iter_blockint=1000000
|
||||
iter_blockfloat=1000000
|
||||
iter_vainit0=1000000
|
||||
iter_vainit2=1000000
|
||||
iter_vainit4=1000000
|
||||
iter_vainit8=1000000
|
||||
iter_vastart0=1000000
|
||||
iter_vastart2=1000000
|
||||
iter_vastart4=1000000
|
||||
iter_vastart8=1000000
|
||||
iter_bench_call_reg=10000000
|
||||
iter_bench_call_imm=10000000
|
||||
iter_bench_add=100000000
|
||||
iter_bench_load=100000000
|
||||
;;
|
||||
|
||||
vax*)
|
||||
: "DEC VAX processors."
|
||||
ln -s md/default.Makefile Makefile.md
|
||||
ln -s md/vax.h qtmd.h
|
||||
ln -s md/null.c qtmdc.c
|
||||
ln -s md/vax.s qtmds.s
|
||||
ln -s md/vax_b.s qtmdb.s
|
||||
ln -s md/null.README README.md
|
||||
iter_init=1000000
|
||||
iter_runone=100000
|
||||
iter_blockint=100000
|
||||
iter_blockfloat=100000
|
||||
iter_vainit0=100000
|
||||
iter_vainit2=100000
|
||||
iter_vainit4=100000
|
||||
iter_vainit8=100000
|
||||
iter_vastart0=100000
|
||||
iter_vastart2=100000
|
||||
iter_vastart4=100000
|
||||
iter_vastart8=100000
|
||||
iter_bench_call_reg=10000000
|
||||
iter_bench_call_imm=10000000
|
||||
iter_bench_add=10000000
|
||||
iter_bench_load=1000000
|
||||
;;
|
||||
|
||||
ksr1)
|
||||
: "Kendall Square Research model KSR-1."
|
||||
: "Varargs is not currently supported."
|
||||
ln -s md/ksr1.Makefile Makefile.md
|
||||
ln -s md/ksr1.h qtmd.h
|
||||
ln -s md/null.c qtmdc.c
|
||||
ln -s md/ksr1.s qtmds.s
|
||||
ln -s md/ksr1_b.s qtmdb.s
|
||||
ln -s md/null.README README.md
|
||||
iter_init=1000000
|
||||
iter_runone=100000
|
||||
iter_blockint=100000
|
||||
iter_blockfloat=100000
|
||||
iter_vainit0=100000
|
||||
iter_vainit2=100000
|
||||
iter_vainit4=100000
|
||||
iter_vainit8=100000
|
||||
iter_vastart0=100000
|
||||
iter_vastart2=100000
|
||||
iter_vastart4=100000
|
||||
iter_vastart8=100000
|
||||
iter_bench_call_reg=10000000
|
||||
iter_bench_call_imm=10000000
|
||||
iter_bench_add=10000000
|
||||
iter_bench_load=1000000
|
||||
;;
|
||||
|
||||
clean)
|
||||
: Deconfigure
|
||||
exit 0
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown configuration"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
cat Makefile.md Makefile.base > Makefile
|
||||
|
||||
echo set config_machine=$1 >> configuration
|
||||
echo set config_init=$iter_init >> configuration
|
||||
echo set config_runone=$iter_runone >> configuration
|
||||
echo set config_blockint=$iter_blockint >> configuration
|
||||
echo set config_blockfloat=$iter_blockfloat >> configuration
|
||||
echo set config_vainit0=$iter_vainit0 >> configuration
|
||||
echo set config_vainit2=$iter_vainit2 >> configuration
|
||||
echo set config_vainit4=$iter_vainit4 >> configuration
|
||||
echo set config_vainit8=$iter_vainit8 >> configuration
|
||||
echo set config_vastart0=$iter_vastart0 >> configuration
|
||||
echo set config_vastart2=$iter_vastart2 >> configuration
|
||||
echo set config_vastart4=$iter_vastart4 >> configuration
|
||||
echo set config_vastart8=$iter_vastart8 >> configuration
|
||||
echo set config_bcall_reg=$iter_bench_call_reg >> configuration
|
||||
echo set config_bcall_imm=$iter_bench_call_imm >> configuration
|
||||
echo set config_b_add=$iter_bench_add >> configuration
|
||||
echo set config_b_load=$iter_bench_load >> configuration
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
|
@ -1,10 +0,0 @@
|
|||
LIBRARY libqthreads
|
||||
DESCRIPTION "libqthreads: QuickThreads Library"
|
||||
EXPORTS
|
||||
qt_abort
|
||||
qt_block
|
||||
qt_blocki
|
||||
qt_error
|
||||
qt_null
|
||||
qt_vargs
|
||||
qt_vstart
|
|
@ -1,30 +0,0 @@
|
|||
## Process this file with automake to produce Makefile.in.
|
||||
##
|
||||
## Copyright (C) 1998, 2002, 2006 Free Software Foundation, Inc.
|
||||
##
|
||||
## This file is part of GUILE.
|
||||
##
|
||||
## GUILE is free software; you can redistribute it and/or modify it
|
||||
## under the terms of the GNU Lesser General Public License as
|
||||
## published by the Free Software Foundation; either version 3, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## GUILE is distributed in the hope that it will be useful, but
|
||||
## WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU Lesser General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU Lesser General Public
|
||||
## License along with GUILE; see the file COPYING.LESSER. If not,
|
||||
## write to the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
## Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
AUTOMAKE_OPTIONS = gnu
|
||||
|
||||
EXTRA_DIST = _sparc.s _sparc_b.s axp.1.Makefile axp.2.Makefile \
|
||||
axp.Makefile axp.README axp.c axp.h axp.s axp_b.s default.Makefile \
|
||||
hppa-cnx.Makefile hppa.Makefile hppa.h hppa.s hppa_b.s i386.README \
|
||||
i386.h i386.s i386_b.s ksr1.Makefile ksr1.h ksr1.s ksr1_b.s \
|
||||
m88k.Makefile m88k.c m88k.h m88k.s m88k_b.s mips-irix5.s mips.h mips.s \
|
||||
mips_b.s null.README null.c solaris.README sparc.h sparc.s sparc_b.s \
|
||||
vax.h vax.s vax_b.s i386.asm arm.h arm.s
|
142
qt/md/_sparc.s
142
qt/md/_sparc.s
|
@ -1,142 +0,0 @@
|
|||
/* sparc.s -- assembly support for the `qt' thread building kit. */
|
||||
|
||||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
/* #include <machine/trap.h> */
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.global _qt_blocki
|
||||
.global _qt_block
|
||||
.global _qt_abort
|
||||
.global _qt_start
|
||||
.global _qt_vstart
|
||||
|
||||
/* Register assignment:
|
||||
// %o0: incoming `helper' function to call after cswap
|
||||
// also used as outgoing sp of old thread (qt_t *)
|
||||
// %o1, %o2:
|
||||
// parameters to `helper' function called after cswap
|
||||
// %o3: sp of new thread
|
||||
// %o5: tmp used to save old thread sp, while using %o0
|
||||
// to call `helper' f() after cswap.
|
||||
//
|
||||
//
|
||||
// Aborting a thread is easy if there are no cached register window
|
||||
// frames: just switch to the new stack and away we go. If there are
|
||||
// cached register window frames they must all be written back to the
|
||||
// old stack before we move to the new stack. If we fail to do the
|
||||
// writeback then the old stack memory can be written with register
|
||||
// window contents e.g., after the stack memory has been freed and
|
||||
// reused.
|
||||
//
|
||||
// If you don't believe this, try setting the frame pointer to zero
|
||||
// once we're on the new stack. This will not affect correctnes
|
||||
// otherwise because the frame pointer will eventually get reloaded w/
|
||||
// the new thread's frame pointer. But it will be zero briefly before
|
||||
// the reload. You will eventually (100,000 cswaps later on a small
|
||||
// SPARC machine that I tried) get an illegal instruction trap from
|
||||
// the kernel trying to flush a cached window to location 0x0.
|
||||
//
|
||||
// Solution: flush windows before switching stacks, which invalidates
|
||||
// all the other register windows. We could do the trap
|
||||
// conditionally: if we're in the lowest frame of a thread, the fp is
|
||||
// zero already so we know there's nothing cached. But we expect most
|
||||
// aborts will be done from a first function that does a `save', so we
|
||||
// will rarely save anything and always pay the cost of testing to see
|
||||
// if we should flush.
|
||||
//
|
||||
// All floating-point registers are caller-save, so this routine
|
||||
// doesn't need to do anything to save and restore them.
|
||||
//
|
||||
// `qt_block' and `qt_blocki' return the same value as the value
|
||||
// returned by the helper function. We get this ``for free''
|
||||
// since we don't touch the return value register between the
|
||||
// return from the helper function and return from qt_block{,i}.
|
||||
*/
|
||||
|
||||
_qt_block:
|
||||
_qt_blocki:
|
||||
sub %sp, 8, %sp /* Allocate save area for return pc. */
|
||||
st %o7, [%sp+64] /* Save return pc. */
|
||||
_qt_abort:
|
||||
ta 0x03 /* Save locals and ins. */
|
||||
mov %sp, %o5 /* Remember old sp w/o chng ins/locals. */
|
||||
sub %o3, 64, %sp /* Allocate kwsa, switch stacks. */
|
||||
call %o0, 0 /* Call `helper' routine. */
|
||||
mov %o5, %o0 /* Pass old thread to qt_after_t() */
|
||||
/* .. along w/ args in %o1 & %o2. */
|
||||
|
||||
/* Restore callee-save regs. The kwsa
|
||||
// is on this stack, so offset all
|
||||
// loads by sizeof(kwsa), 64 bytes.
|
||||
*/
|
||||
ldd [%sp+ 0+64], %l0
|
||||
ldd [%sp+ 8+64], %l2
|
||||
ldd [%sp+16+64], %l4
|
||||
ldd [%sp+24+64], %l6
|
||||
ldd [%sp+32+64], %i0
|
||||
ldd [%sp+40+64], %i2
|
||||
ldd [%sp+48+64], %i4
|
||||
ldd [%sp+56+64], %i6
|
||||
ld [%sp+64+64], %o7 /* Restore return pc. */
|
||||
|
||||
retl /* Return to address in %o7. */
|
||||
add %sp, 72, %sp /* Deallocate kwsa, ret pc area. */
|
||||
|
||||
|
||||
/* The function calling conventions say there has to be a 1-word area
|
||||
// in the caller's stack to hold a pointer to space for aggregate
|
||||
// return values. It also says there should be a 6-word area to hold
|
||||
// %o0..%o5 if the callee wants to save them (why? I don't know...)
|
||||
// Round up to 8 words to maintain alignment.
|
||||
//
|
||||
// Parameter values were stored in callee-save regs and are moved to
|
||||
// the parameter registers.
|
||||
*/
|
||||
_qt_start:
|
||||
mov %i1, %o0 /* `pu': Set up args to `only'. */
|
||||
mov %i2, %o1 /* `pt'. */
|
||||
mov %i4, %o2 /* `userf'. */
|
||||
call %i5, 0 /* Call client function. */
|
||||
sub %sp, 32, %sp /* Allocate 6-word callee space. */
|
||||
|
||||
call _qt_error, 0 /* `only' erroniously returned. */
|
||||
nop
|
||||
|
||||
|
||||
/* Same comments as `_qt_start' about allocating rounded-up 7-word
|
||||
// save areas. */
|
||||
|
||||
_qt_vstart:
|
||||
sub %sp, 32, %sp /* Allocate 7-word callee space. */
|
||||
call %i5, 0 /* call `startup'. */
|
||||
mov %i2, %o0 /* .. with argument `pt'. */
|
||||
|
||||
add %sp, 32, %sp /* Use 7-word space in varargs. */
|
||||
ld [%sp+ 4+64], %o0 /* Load arg0 ... */
|
||||
ld [%sp+ 8+64], %o1
|
||||
ld [%sp+12+64], %o2
|
||||
ld [%sp+16+64], %o3
|
||||
ld [%sp+20+64], %o4
|
||||
call %i4, 0 /* Call `userf'. */
|
||||
ld [%sp+24+64], %o5
|
||||
|
||||
/* Use 6-word space in varargs. */
|
||||
mov %o0, %o1 /* Pass return value from userf */
|
||||
call %i3, 0 /* .. when call `cleanup. */
|
||||
mov %i2, %o0 /* .. along with argument `pt'. */
|
||||
|
||||
call _qt_error, 0 /* `cleanup' erroniously returned. */
|
||||
nop
|
106
qt/md/_sparc_b.s
106
qt/md/_sparc_b.s
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
.globl _b_call_reg
|
||||
.globl _b_call_imm
|
||||
.globl _b_add
|
||||
.globl _b_load
|
||||
|
||||
_b_null:
|
||||
retl
|
||||
nop
|
||||
|
||||
_b_call_reg:
|
||||
sethi %hi(_b_null),%o4
|
||||
or %o4,%lo(_b_null),%o4
|
||||
add %o7,%g0, %o3
|
||||
L0:
|
||||
call %o4
|
||||
nop
|
||||
call %o4
|
||||
nop
|
||||
call %o4
|
||||
nop
|
||||
call %o4
|
||||
nop
|
||||
call %o4
|
||||
nop
|
||||
|
||||
subcc %o0,1,%o0
|
||||
bg L0
|
||||
nop
|
||||
add %o3,%g0, %o7
|
||||
retl
|
||||
nop
|
||||
|
||||
_b_call_imm:
|
||||
sethi %hi(_b_null),%o4
|
||||
or %o4,%lo(_b_null),%o4
|
||||
add %o7,%g0, %o3
|
||||
L1:
|
||||
call _b_null
|
||||
call _b_null
|
||||
call _b_null
|
||||
call _b_null
|
||||
call _b_null
|
||||
|
||||
subcc %o0,1,%o0
|
||||
bg L0
|
||||
nop
|
||||
add %o3,%g0, %o7
|
||||
retl
|
||||
nop
|
||||
|
||||
|
||||
_b_add:
|
||||
add %o0,%g0,%o1
|
||||
add %o0,%g0,%o2
|
||||
add %o0,%g0,%o3
|
||||
add %o0,%g0,%o4
|
||||
L2:
|
||||
sub %o0,5,%o0
|
||||
sub %o1,5,%o1
|
||||
sub %o2,5,%o2
|
||||
sub %o3,5,%o3
|
||||
sub %o4,5,%o4
|
||||
|
||||
subcc %o0,5,%o0
|
||||
sub %o1,5,%o1
|
||||
sub %o2,5,%o2
|
||||
sub %o3,5,%o3
|
||||
sub %o4,5,%o4
|
||||
|
||||
bg L2
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
|
||||
|
||||
_b_load:
|
||||
ld [%sp+ 0], %g0
|
||||
L3:
|
||||
ld [%sp+ 4],%g0
|
||||
ld [%sp+ 8],%g0
|
||||
ld [%sp+12],%g0
|
||||
ld [%sp+16],%g0
|
||||
ld [%sp+20],%g0
|
||||
ld [%sp+24],%g0
|
||||
ld [%sp+28],%g0
|
||||
ld [%sp+32],%g0
|
||||
ld [%sp+36],%g0
|
||||
|
||||
subcc %o0,10,%o0
|
||||
bg L3
|
||||
ld [%sp+ 0],%g0
|
||||
retl
|
||||
nop
|
96
qt/md/arm.h
96
qt/md/arm.h
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
* Copyright (c) 2002 by Marius Vollmer
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#ifndef QT_ARM_H
|
||||
#define QT_ARM_H
|
||||
|
||||
typedef unsigned long qt_word_t;
|
||||
|
||||
#define QT_GROW_DOWN
|
||||
|
||||
/* Stack layout on the ARM:
|
||||
|
||||
Callee-save registers are: r4-r11 (f4-f7)
|
||||
Also save r14, link register, and restore as pc.
|
||||
|
||||
+---
|
||||
| lr/pc
|
||||
| r11
|
||||
| r10
|
||||
| r9
|
||||
| r8
|
||||
| r7
|
||||
| r6
|
||||
| r5
|
||||
| r4 <- sp of a suspended thread
|
||||
+---
|
||||
|
||||
Startup:
|
||||
|
||||
+---
|
||||
| only
|
||||
| user
|
||||
| argt
|
||||
| argu <- sp on entry to qt_start
|
||||
+---
|
||||
| pc == qt_start
|
||||
| r11
|
||||
| r10
|
||||
| r9
|
||||
| r8
|
||||
| r7
|
||||
| r6
|
||||
| r5
|
||||
| r4
|
||||
+---
|
||||
|
||||
*/
|
||||
|
||||
/* Stack must be word aligned. */
|
||||
#define QT_STKALIGN (4) /* Doubleword aligned. */
|
||||
|
||||
/* How much space is allocated to hold all the crud for
|
||||
initialization: r4-r11, r14, and the four args for qt_start. */
|
||||
|
||||
#define QT_STKBASE ((9+4)*4)
|
||||
|
||||
|
||||
/* Offsets of various registers, in words, relative to final value of SP. */
|
||||
#define QT_LR 8
|
||||
#define QT_11 7
|
||||
#define QT_10 6
|
||||
#define QT_9 5
|
||||
#define QT_8 4
|
||||
#define QT_7 3
|
||||
#define QT_6 2
|
||||
#define QT_5 1
|
||||
#define QT_4 0
|
||||
|
||||
|
||||
/* When a never-before-run thread is restored, the return pc points
|
||||
to a fragment of code that starts the thread running. For
|
||||
non-vargs functions, it just calls the client's `only' function.
|
||||
*/
|
||||
|
||||
extern void qt_start(void);
|
||||
#define QT_ARGS_MD(sp) (QT_SPUT (sp, QT_LR, qt_start))
|
||||
|
||||
|
||||
/* The *index* (positive offset) of where to put each value. */
|
||||
#define QT_ONLY_INDEX (12)
|
||||
#define QT_USER_INDEX (11)
|
||||
#define QT_ARGT_INDEX (10)
|
||||
#define QT_ARGU_INDEX (9)
|
||||
|
||||
#endif /* ndef QT_ARM_H */
|
34
qt/md/arm.s
34
qt/md/arm.s
|
@ -1,34 +0,0 @@
|
|||
.text
|
||||
.align 2
|
||||
.global qt_abort
|
||||
.global qt_block
|
||||
.global qt_blocki
|
||||
|
||||
# r0: helper
|
||||
# r1: arg1
|
||||
# r2: arg2
|
||||
# r3: new_sp
|
||||
qt_abort:
|
||||
qt_block:
|
||||
qt_blocki:
|
||||
stmfd sp!, {r4-r11,lr}
|
||||
mov ip, r0
|
||||
mov r0, sp
|
||||
mov sp, r3
|
||||
mov lr, pc
|
||||
mov pc, ip
|
||||
ldmfd sp!, {r4-r11,pc}
|
||||
|
||||
|
||||
.global qt_start
|
||||
.global qt_error
|
||||
.type qt_start,function
|
||||
qt_start:
|
||||
ldr r0, [sp]
|
||||
ldr r1, [sp, #4]
|
||||
ldr r2, [sp, #8]
|
||||
ldr lr, qt_error_loc
|
||||
ldr pc, [sp, #12]
|
||||
|
||||
qt_error_loc:
|
||||
.word qt_error
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
#
|
||||
# Compiling for the DEC AXP (alpha) with GNU CC or version 1.x of OSF.
|
||||
#
|
||||
CC = cc -std1 -D__AXP__ -D__OSF1__
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
#
|
||||
# Compiling for the DEC AXP (alpha) with GNU CC or version 2.x of OSF.
|
||||
#
|
||||
CC = cc -std1 -D__AXP__ -D__OSF2__
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
#
|
||||
# GNU CC
|
||||
#
|
||||
CC = gcc -D__AXP__
|
|
@ -1,10 +0,0 @@
|
|||
The handling of varargs is platform-dependent. Assar Westerlund
|
||||
stared at the problem for a while and deduces the following table:
|
||||
|
||||
vers / compiler cc gcc
|
||||
----------------------------------------------------------------------
|
||||
1.3 a0, offset __base, __offset
|
||||
2.0 _a0, _offset __base, __offset
|
||||
|
||||
The current code should handle both cc and gcc versions, provided
|
||||
you configure for the correct compiler.
|
133
qt/md/axp.c
133
qt/md/axp.c
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "qt.h"
|
||||
|
||||
|
||||
/* Varargs is harder on the AXP. Parameters are saved on the stack as
|
||||
something like (stack grows down to low memory; low at bottom of
|
||||
picture):
|
||||
|
||||
| :
|
||||
| arg6
|
||||
+---
|
||||
| iarg5
|
||||
| :
|
||||
| iarg3 <-- va_list._a0 + va_list._offset
|
||||
| :
|
||||
| iarg0 <-- va_list._a0
|
||||
+---
|
||||
| farg5
|
||||
| :
|
||||
| farg0
|
||||
+---
|
||||
|
||||
When some of the arguments have known type, there is no need to
|
||||
save all of them in the struct. So, for example, if the routine is
|
||||
called
|
||||
|
||||
zork (int a0, float a1, int a2, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, a2);
|
||||
qt_vargs (... &ap ...);
|
||||
}
|
||||
|
||||
then offset is set to 3 * 8 (8 === sizeof machine word) = 24.
|
||||
|
||||
What this means for us is that the user's routine needs to be
|
||||
called with an arg list where some of the words in the `any type'
|
||||
parameter list have to be split and moved up in to the int/fp
|
||||
region.
|
||||
|
||||
Ways in which this can fail:
|
||||
- The user might not know the size of the pushed arguments anyway.
|
||||
- Structures have funny promotion rules.
|
||||
- Probably lots of other things.
|
||||
|
||||
All in all, we never promised varargs would work reliably. */
|
||||
|
||||
|
||||
|
||||
#define QT_VADJ(sp) (((char *)sp) - QT_VSTKBASE)
|
||||
|
||||
#define QT_VARGS_MD0(sp, vabytes) \
|
||||
((qt_t *)(((char *)(sp)) - 6*2*8 - QT_STKROUNDUP(vabytes)))
|
||||
|
||||
extern void qt_vstart(void);
|
||||
#define QT_VARGS_MD1(sp) (QT_SPUT (sp, QT_R26, qt_vstart))
|
||||
|
||||
|
||||
/* Different machines use different implementations for varargs.
|
||||
Unfortunately, the code below ``looks in to'' the varargs
|
||||
structure, `va_list', and thus depends on the conventions.
|
||||
The following #defines try to deal with it but don't catch
|
||||
everything. */
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define _a0 __base
|
||||
#define _offset __offset
|
||||
#else
|
||||
#ifdef __OSF1__
|
||||
#define _a0 a0
|
||||
#define _offset offset
|
||||
#endif
|
||||
#endif /* def __GNUC__ */
|
||||
|
||||
|
||||
struct qt_t *
|
||||
qt_vargs (struct qt_t *qsp, int nbytes, struct va_list *vargs,
|
||||
void *pt, qt_function_t *startup,
|
||||
qt_function_t *vuserf, qt_function_t *cleanup)
|
||||
{
|
||||
va_list ap;
|
||||
int i;
|
||||
int max; /* Maximum *words* of args to copy. */
|
||||
int tmove; /* *Words* of args moved typed->typed. */
|
||||
qt_word_t *sp;
|
||||
|
||||
ap = *(va_list *)vargs;
|
||||
qsp = QT_VARGS_MD0 (qsp, nbytes);
|
||||
sp = (qt_word_t *)qsp;
|
||||
|
||||
tmove = 6 - ap._offset/sizeof(qt_word_t);
|
||||
|
||||
/* Copy from one typed area to the other. */
|
||||
for (i=0; i<tmove; ++i) {
|
||||
/* Integer args: */
|
||||
sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i];
|
||||
/* Fp args: */
|
||||
sp[i] = ((qt_word_t *)(ap._a0 + ap._offset))[i-6];
|
||||
}
|
||||
|
||||
max = nbytes/sizeof(qt_word_t);
|
||||
|
||||
/* Copy from the untyped area to the typed area. Split each arg.
|
||||
in to integer and floating-point save areas. */
|
||||
for (; i<6 && i<max; ++i) {
|
||||
sp[i] = sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i];
|
||||
}
|
||||
|
||||
/* Copy from the untyped area to the other untyped area. */
|
||||
for (; i<max; ++i) {
|
||||
sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i];
|
||||
}
|
||||
|
||||
QT_VARGS_MD1 (QT_VADJ(sp));
|
||||
QT_SPUT (QT_VADJ(sp), QT_VARGT_INDEX, pt);
|
||||
QT_SPUT (QT_VADJ(sp), QT_VSTARTUP_INDEX, startup);
|
||||
QT_SPUT (QT_VADJ(sp), QT_VUSERF_INDEX, vuserf);
|
||||
QT_SPUT (QT_VADJ(sp), QT_VCLEANUP_INDEX, cleanup);
|
||||
return ((qt_t *)QT_VADJ(sp));
|
||||
}
|
160
qt/md/axp.h
160
qt/md/axp.h
|
@ -1,160 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#ifndef QT_AXP_H
|
||||
#define QT_AXP_H
|
||||
|
||||
#define QT_GROW_DOWN
|
||||
|
||||
typedef unsigned long qt_word_t;
|
||||
|
||||
|
||||
/* Stack layout on the Alpha:
|
||||
|
||||
Integer:
|
||||
|
||||
Caller-save: r0..r8, r22..r25, r27..r29
|
||||
argument/caller-save: r16..r21
|
||||
callee-save: r9..r15
|
||||
return pc *callee-save*: r26
|
||||
stack pointer: r30
|
||||
zero: r31
|
||||
|
||||
Floating-point:
|
||||
|
||||
Caller-save: f0..f1, f10..f15
|
||||
argument/caller-save: f16..f21, f22..f30
|
||||
callee-save: f2..f9
|
||||
zero: f31
|
||||
|
||||
Non-varargs:
|
||||
|
||||
+---
|
||||
| padding
|
||||
| f9
|
||||
| f8
|
||||
| f7
|
||||
| f6
|
||||
| f5
|
||||
| f4
|
||||
| f3
|
||||
| f2
|
||||
| r26
|
||||
+---
|
||||
| padding
|
||||
| r29
|
||||
| r15
|
||||
| r14
|
||||
| r13
|
||||
| r12 on startup === `only'
|
||||
| r11 on startup === `userf'
|
||||
| r10 on startup === `qt'
|
||||
| r9 on startup === `qu'
|
||||
| r26 on startup === qt_start <--- qt.sp
|
||||
+---
|
||||
|
||||
Conventions for varargs startup:
|
||||
|
||||
| :
|
||||
| arg6
|
||||
| iarg5
|
||||
| :
|
||||
| iarg0
|
||||
| farg5
|
||||
| :
|
||||
| farg0
|
||||
+---
|
||||
| padding
|
||||
| r29
|
||||
| r15
|
||||
| r14
|
||||
| r13
|
||||
| r12 on startup === `startup'
|
||||
| r11 on startup === `vuserf'
|
||||
| r10 on startup === `cleanup'
|
||||
| r9 on startup === `qt'
|
||||
| r26 on startup === qt_vstart <--- qt.sp
|
||||
+---
|
||||
|
||||
Note: this is a pretty cheap/sleazy way to get things going,
|
||||
but ``there must be a better way.'' For instance, some varargs
|
||||
parameters could be loaded in to integer registers, or the return
|
||||
address could be stored on top of the stack. */
|
||||
|
||||
|
||||
/* Stack must be 16-byte aligned. */
|
||||
#define QT_STKALIGN (16)
|
||||
|
||||
/* How much space is allocated to hold all the crud for
|
||||
initialization: 7 registers times 8 bytes/register. */
|
||||
|
||||
#define QT_STKBASE (10 * 8)
|
||||
#define QT_VSTKBASE QT_STKBASE
|
||||
|
||||
|
||||
/* Offsets of various registers. */
|
||||
#define QT_R26 0
|
||||
#define QT_R9 1
|
||||
#define QT_R10 2
|
||||
#define QT_R11 3
|
||||
#define QT_R12 4
|
||||
|
||||
|
||||
/* When a never-before-run thread is restored, the return pc points
|
||||
to a fragment of code that starts the thread running. For
|
||||
non-vargs functions, it just calls the client's `only' function.
|
||||
For varargs functions, it calls the startup, user, and cleanup
|
||||
functions.
|
||||
|
||||
The varargs startup routine always reads 12 8-byte arguments from
|
||||
the stack. If fewer argumets were pushed, the startup routine
|
||||
would read off the top of the stack. To prevent errors we always
|
||||
allocate enough space. When there are fewer args, the preallocated
|
||||
words are simply wasted. */
|
||||
|
||||
extern void qt_start(void);
|
||||
#define QT_ARGS_MD(sp) (QT_SPUT (sp, QT_R26, qt_start))
|
||||
|
||||
|
||||
/* The AXP uses a struct for `va_list', so pass a pointer to the
|
||||
struct. This may break some uses of `QT_VARGS', but then we never
|
||||
claimed it was totally portable. */
|
||||
|
||||
typedef void (qt_function_t)(void);
|
||||
|
||||
struct qt_t;
|
||||
struct va_list;
|
||||
extern struct qt_t *qt_vargs (struct qt_t *sp, int nbytes,
|
||||
struct va_list *vargs, void *pt,
|
||||
qt_function_t *startup,
|
||||
qt_function_t *vuserf,
|
||||
qt_function_t *cleanup);
|
||||
|
||||
#define QT_VARGS(sp, nbytes, vargs, pt, startup, vuserf, cleanup) \
|
||||
(qt_vargs (sp, nbytes, (struct va_list *)(&(vargs)), pt, \
|
||||
(qt_function_t *) startup, (qt_function_t *)vuserf, \
|
||||
(qt_function_t *)cleanup));
|
||||
|
||||
|
||||
/* The *index* (positive offset) of where to put each value. */
|
||||
#define QT_ONLY_INDEX (QT_R12)
|
||||
#define QT_USER_INDEX (QT_R11)
|
||||
#define QT_ARGT_INDEX (QT_R10)
|
||||
#define QT_ARGU_INDEX (QT_R9)
|
||||
|
||||
#define QT_VCLEANUP_INDEX (QT_R10)
|
||||
#define QT_VUSERF_INDEX (QT_R11)
|
||||
#define QT_VSTARTUP_INDEX (QT_R12)
|
||||
#define QT_VARGT_INDEX (QT_R9)
|
||||
|
||||
#endif /* ndef QT_AXP_H */
|
160
qt/md/axp.s
160
qt/md/axp.s
|
@ -1,160 +0,0 @@
|
|||
#
|
||||
# QuickThreads -- Threads-building toolkit.
|
||||
# Copyright (c) 1993 by David Keppel
|
||||
#
|
||||
# Permission to use, copy, modify and distribute this software and
|
||||
# its documentation for any purpose and without fee is hereby
|
||||
# granted, provided that the above copyright notice and this notice
|
||||
# appear in all copies. This software is provided as a
|
||||
# proof-of-concept and for demonstration purposes# there is no
|
||||
# representation about the suitability of this software for any
|
||||
# purpose.
|
||||
#
|
||||
|
||||
# axp.s -- assembly support.
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.file "axp.s"
|
||||
|
||||
.globl qt_block
|
||||
.globl qt_blocki
|
||||
.globl qt_abort
|
||||
.globl qt_start
|
||||
.globl qt_vstart
|
||||
|
||||
#
|
||||
# $16: ptr to function to call once curr is suspended
|
||||
# and control is on r19's stack.
|
||||
# $17: 1'th arg to (*$16)(...).
|
||||
# $18: 2'th arg to (*$16)(...).
|
||||
# $19: sp of thread to resume.
|
||||
#
|
||||
# The helper routine returns a value that is passed on as the
|
||||
# return value from the blocking routine. Since we don't
|
||||
# touch r0 between the helper's return and the end of
|
||||
# function, we get this behavior for free.
|
||||
#
|
||||
|
||||
.ent qt_blocki
|
||||
qt_blocki:
|
||||
subq $30,80, $30 # Allocate save area.
|
||||
stq $26, 0($30) # Save registers.
|
||||
stq $9, 8($30)
|
||||
stq $10,16($30)
|
||||
stq $11,24($30)
|
||||
stq $12,32($30)
|
||||
stq $13,40($30)
|
||||
stq $14,48($30)
|
||||
stq $15,56($30)
|
||||
stq $29,64($30)
|
||||
.end qt_blocki
|
||||
.ent qt_abort
|
||||
qt_abort:
|
||||
addq $16,$31, $27 # Put argument function in PV.
|
||||
addq $30,$31, $16 # Save stack ptr in outgoing arg.
|
||||
addq $19,$31, $30 # Set new stack pointer.
|
||||
jsr $26,($27),0 # Call helper function.
|
||||
|
||||
ldq $26, 0($30) # Restore registers.
|
||||
ldq $9, 8($30)
|
||||
ldq $10,16($30)
|
||||
ldq $11,24($30)
|
||||
ldq $12,32($30)
|
||||
ldq $13,40($30)
|
||||
ldq $14,48($30)
|
||||
ldq $15,56($30)
|
||||
ldq $29,64($30)
|
||||
|
||||
addq $30,80, $30 # Deallocate save area.
|
||||
ret $31,($26),1 # Return, predict===RET.
|
||||
.end qt_abort
|
||||
|
||||
|
||||
#
|
||||
# Non-varargs thread startup.
|
||||
#
|
||||
.ent qt_start
|
||||
qt_start:
|
||||
addq $9,$31, $16 # Load up `qu'.
|
||||
addq $10,$31, $17 # ... user function's `pt'.
|
||||
addq $11,$31, $18 # ... user function's `userf'.
|
||||
addq $12,$31, $27 # ... set procedure value to `only'.
|
||||
jsr $26,($27),0 # Call `only'.
|
||||
|
||||
jsr $26,qt_error # `only' erroniously returned.
|
||||
.end qt_start
|
||||
|
||||
|
||||
.ent qt_vstart
|
||||
qt_vstart:
|
||||
# Call startup function.
|
||||
addq $9,$31, $16 # Arg0 to `startup'.
|
||||
addq $12,$31, $27 # Set procedure value.
|
||||
jsr $26,($27),0 # Call `startup'.
|
||||
|
||||
# Call user function.
|
||||
ldt $f16, 0($30) # Load fp arg regs.
|
||||
ldt $f17, 8($30)
|
||||
ldt $f18,16($30)
|
||||
ldt $f19,24($30)
|
||||
ldt $f20,32($30)
|
||||
ldt $f21,40($30)
|
||||
ldq $16,48($30) # And integer arg regs.
|
||||
ldq $17,56($30)
|
||||
ldq $18,64($30)
|
||||
ldq $19,72($30)
|
||||
ldq $20,80($30)
|
||||
ldq $21,88($30)
|
||||
addq $30,96, $30 # Pop 6*2*8 saved arg regs.
|
||||
addq $11,$31, $27 # Set procedure value.
|
||||
jsr $26,($27),0 # Call `vuserf'.
|
||||
|
||||
# Call cleanup.
|
||||
addq $9,$31, $16 # Arg0 to `cleanup'.
|
||||
addq $0,$31, $17 # Users's return value is arg1.
|
||||
addq $10,$31, $27 # Set procedure value.
|
||||
jsr $26,($27),0 # Call `cleanup'.
|
||||
|
||||
jsr $26,qt_error # Cleanup erroniously returned.
|
||||
.end qt_vstart
|
||||
|
||||
|
||||
#
|
||||
# Save calle-save floating-point regs $f2..$f9.
|
||||
# Also save return pc from whomever called us.
|
||||
#
|
||||
# Return value from `qt_block' is the same as the return from
|
||||
# `qt_blocki'. We get that for free since we don't touch $0
|
||||
# between the return from `qt_blocki' and the return from
|
||||
# `qt_block'.
|
||||
#
|
||||
.ent qt_block
|
||||
qt_block:
|
||||
subq $30,80, $30 # Allocate a save space.
|
||||
stq $26, 0($30) # Save registers.
|
||||
stt $f2, 8($30)
|
||||
stt $f3,16($30)
|
||||
stt $f4,24($30)
|
||||
stt $f5,32($30)
|
||||
stt $f6,40($30)
|
||||
stt $f7,48($30)
|
||||
stt $f8,56($30)
|
||||
stt $f9,64($30)
|
||||
|
||||
jsr $26,qt_blocki # Call helper.
|
||||
# .. who will also restore $gp.
|
||||
|
||||
ldq $26, 0($30) # restore registers.
|
||||
ldt $f2, 8($30)
|
||||
ldt $f3,16($30)
|
||||
ldt $f4,24($30)
|
||||
ldt $f5,32($30)
|
||||
ldt $f6,40($30)
|
||||
ldt $f7,48($30)
|
||||
ldt $f8,56($30)
|
||||
ldt $f9,64($30)
|
||||
|
||||
addq $30,80, $30 # Deallcate save space.
|
||||
ret $31,($26),1 # Return, predict===RET.
|
||||
.end qt_block
|
111
qt/md/axp_b.s
111
qt/md/axp_b.s
|
@ -1,111 +0,0 @@
|
|||
#
|
||||
# QuickThreads -- Threads-building toolkit.
|
||||
# Copyright (c) 1993 by David Keppel
|
||||
#
|
||||
# Permission to use, copy, modify and distribute this software and
|
||||
# its documentation for any purpose and without fee is hereby
|
||||
# granted, provided that the above copyright notice and this notice
|
||||
# appear in all copies. This software is provided as a
|
||||
# proof-of-concept and for demonstration purposes; there is no
|
||||
# representation about the suitability of this software for any
|
||||
# purpose.
|
||||
#
|
||||
|
||||
.text
|
||||
.globl b_call_reg
|
||||
.globl b_call_imm
|
||||
.globl b_add
|
||||
.globl b_load
|
||||
|
||||
.ent b_null
|
||||
b_null:
|
||||
ret $31,($18),1
|
||||
.end b_null
|
||||
|
||||
.ent b_call_reg
|
||||
b_call_reg:
|
||||
lda $27,b_null
|
||||
$L0:
|
||||
jsr $18,($27)
|
||||
jsr $18,($27)
|
||||
jsr $18,($27)
|
||||
jsr $18,($27)
|
||||
jsr $18,($27)
|
||||
|
||||
jsr $18,($27)
|
||||
jsr $18,($27)
|
||||
jsr $18,($27)
|
||||
jsr $18,($27)
|
||||
jsr $18,($27)
|
||||
|
||||
subq $16,1,$16
|
||||
bgt $16,$L0
|
||||
|
||||
ret $31,($26),1
|
||||
.end
|
||||
|
||||
|
||||
.ent b_call_imm
|
||||
b_call_imm:
|
||||
$L1:
|
||||
jsr $18,b_null
|
||||
jsr $18,b_null
|
||||
jsr $18,b_null
|
||||
jsr $18,b_null
|
||||
jsr $18,b_null
|
||||
|
||||
jsr $18,b_null
|
||||
jsr $18,b_null
|
||||
jsr $18,b_null
|
||||
jsr $18,b_null
|
||||
jsr $18,b_null
|
||||
|
||||
subq $16,1,$16
|
||||
bgt $16,$L1
|
||||
|
||||
ret $31,($26),1
|
||||
.end
|
||||
|
||||
|
||||
.ent b_add
|
||||
b_add:
|
||||
$L2:
|
||||
addq $31,$31,$31
|
||||
addq $31,$31,$31
|
||||
addq $31,$31,$31
|
||||
addq $31,$31,$31
|
||||
addq $31,$31,$31
|
||||
|
||||
addq $31,$31,$31
|
||||
addq $31,$31,$31
|
||||
addq $31,$31,$31
|
||||
addq $31,$31,$31
|
||||
addq $31,$31,$31
|
||||
|
||||
subq $16,1,$16
|
||||
bgt $16,$L2
|
||||
|
||||
ret $31,($26),1
|
||||
.end
|
||||
|
||||
|
||||
.ent b_load
|
||||
b_load:
|
||||
$L3:
|
||||
ldq $31,0($30)
|
||||
ldq $31,8($30)
|
||||
ldq $31,16($30)
|
||||
ldq $31,24($30)
|
||||
ldq $31,32($30)
|
||||
|
||||
ldq $31,0($30)
|
||||
ldq $31,8($30)
|
||||
ldq $31,16($30)
|
||||
ldq $31,24($30)
|
||||
ldq $31,32($30)
|
||||
|
||||
subq $16,1,$16
|
||||
bgt $16,$L3
|
||||
|
||||
ret $31,($26),1
|
||||
.end
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
#
|
||||
# `Normal' configuration.
|
||||
#
|
||||
CC = gcc -ansi -Wall -pedantic
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
# This file (cnx_spp.Makefile) is part of the port of QuickThreads for
|
||||
# PA-RISC 1.1 architecture on a Convex SPP. This file is a machine dependent
|
||||
# makefile for QuickThreads. It was written in 1994 by Uwe Reder
|
||||
# (`uereder@cip.informatik.uni-erlangen.de') for the Operating Systems
|
||||
# Department (IMMD4) at the University of Erlangen/Nuernberg Germany.
|
||||
|
||||
# `Normal' configuration.
|
||||
|
||||
CC = /usr/convex/bin/cc
|
|
@ -1,9 +0,0 @@
|
|||
# This file (pa-risc.Makefile) is part of the port of QuickThreads for
|
||||
# PA-RISC 1.1 architecture. This file is a machine dependent makefile
|
||||
# for QuickThreads. It was written in 1994 by Uwe Reder
|
||||
# (`uereder@cip.informatik.uni-erlangen.de') for the Operating Systems
|
||||
# Department (IMMD4) at the University of Erlangen/Nuernberg Germany.
|
||||
|
||||
# `Normal' configuration.
|
||||
|
||||
CC = cc -Aa
|
194
qt/md/hppa.h
194
qt/md/hppa.h
|
@ -1,194 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file (pa-risc.h) is part of the port of QuickThreads for the
|
||||
* PA-RISC 1.1 architecture. This file is a machine dependent header
|
||||
* file. It was written in 1994 by Uwe Reder
|
||||
* (`uereder@cip.informatik.uni-erlangen.de') for the Operating Systems
|
||||
* Department (IMMD4) at the University of Erlangen/Nuernberg Germany.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QT_PA_RISC_H
|
||||
#define QT_PA_RISC_H
|
||||
|
||||
#include <qt.h>
|
||||
|
||||
/* size of an integer-register (32 bit) */
|
||||
typedef unsigned long qt_word_t;
|
||||
|
||||
/* PA-RISC's stack grows up */
|
||||
#define QT_GROW_UP
|
||||
|
||||
/* Stack layout on PA-RISC according to PA-RISC Procedure Calling Conventions:
|
||||
|
||||
Callee-save registers are: gr3-gr18, fr12-fr21.
|
||||
Also save gr2, return pointer.
|
||||
|
||||
+---
|
||||
| fr12 Each floating register is a double word (8 bytes).
|
||||
| fr13 Floating registers are only saved if `qt_block' is
|
||||
| fr14 called, in which case it saves the floating-point
|
||||
| fr15 registers then calls `qt_blocki' to save the integer
|
||||
| fr16 registers.
|
||||
| fr17
|
||||
| fr18
|
||||
| fr19
|
||||
| fr20
|
||||
| fr21
|
||||
| <arg word 3> fixed arguments (must be allocated; may remain unused)
|
||||
| <arg word 2>
|
||||
| <arg word 1>
|
||||
| <arg word 0>
|
||||
| <LPT> frame marker
|
||||
| <LPT'>
|
||||
| <RP'>
|
||||
| <Current RP>
|
||||
| <Static Link>
|
||||
| <Clean Up>
|
||||
| <RP''>
|
||||
| <Previous SP>
|
||||
+---
|
||||
| gr3 word each (4 bytes)
|
||||
| gr4
|
||||
| gr5
|
||||
| gr6
|
||||
| gr7
|
||||
| gr8
|
||||
| gr9
|
||||
| gr10
|
||||
| gr11
|
||||
| gr12
|
||||
| gr13
|
||||
| gr14
|
||||
| gr15
|
||||
| gr16
|
||||
| gr17
|
||||
| gr18
|
||||
| <16 bytes filled in (sp has to be 64-bytes aligned)>
|
||||
| <arg word 3> fixed arguments (must be allocated; may remain unused)
|
||||
| <arg word 2>
|
||||
| <arg word 1>
|
||||
| <arg word 0>
|
||||
| <LPT> frame marker
|
||||
| <LPT'>
|
||||
| <RP'>
|
||||
| <Current RP>
|
||||
| <Static Link>
|
||||
| <Clean Up>
|
||||
| <RP''>
|
||||
| <Previous SP>
|
||||
+--- <--- sp
|
||||
*/
|
||||
|
||||
/* When a never-before-run thread is restored, the return pc points
|
||||
to a fragment of code that starts the thread running. For
|
||||
non-vargs functions, it just calls the client's `only' function.
|
||||
For varargs functions, it calls the startup, user, and cleanup
|
||||
functions. */
|
||||
|
||||
/* Note: Procedue Labels on PA-RISC
|
||||
|
||||
<--2--><-------28---------><1-><1->
|
||||
-----------------------------------
|
||||
| SID | Adress Part | L | X |
|
||||
-----------------------------------
|
||||
|
||||
On HP-UX the L field is used to flag wheather the procedure
|
||||
label (plabel) is a pointer to an LT entry or to the entry point
|
||||
of the procedure (PA-RISC Procedure Calling Conventions Reference
|
||||
Manual, 5.3.2 Procedure Labels and Dynamic Calls). */
|
||||
|
||||
#define QT_PA_RISC_READ_PLABEL(plabel) \
|
||||
( (((int)plabel) & 2) ? \
|
||||
( (*((int *)(((int)plabel) & 0xfffffffc)))) : ((int)plabel) )
|
||||
|
||||
/* Stack must be 64 bytes aligned. */
|
||||
#define QT_STKALIGN (64)
|
||||
|
||||
/* Internal helper for putting stuff on stack (negative index!). */
|
||||
#define QT_SPUT(top, at, val) \
|
||||
(((qt_word_t *)(top))[-(at)] = (qt_word_t)(val))
|
||||
|
||||
/* Offsets of various registers which are modified on the stack.
|
||||
rp (return-pointer) has to be stored in the frame-marker-area
|
||||
of the "older" stack-segment. */
|
||||
|
||||
#define QT_crp (12+4+16+5)
|
||||
#define QT_15 (12+4+4)
|
||||
#define QT_16 (12+4+3)
|
||||
#define QT_17 (12+4+2)
|
||||
#define QT_18 (12+4+1)
|
||||
|
||||
|
||||
/** This stuff is for NON-VARARGS. **/
|
||||
|
||||
/* Stack looks like this (2 stack frames):
|
||||
|
||||
<--- 64-bytes aligned --><------- 64-bytes aligned ------------>
|
||||
| || |
|
||||
<--16--><------48-------><----16*4-----><--16-><------48------->
|
||||
|| | || | | ||
|
||||
||filler|arg|frame-marker||register-save|filler|arg|frame-marker||
|
||||
------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define QT_STKBASE (16+48+(16*sizeof(qt_word_t))+16+48)
|
||||
|
||||
/* The index, relative to sp, of where to put each value. */
|
||||
#define QT_ONLY_INDEX (QT_15)
|
||||
#define QT_USER_INDEX (QT_16)
|
||||
#define QT_ARGT_INDEX (QT_17)
|
||||
#define QT_ARGU_INDEX (QT_18)
|
||||
|
||||
extern void qt_start(void);
|
||||
#define QT_ARGS_MD(sp) \
|
||||
(QT_SPUT (sp, QT_crp, QT_PA_RISC_READ_PLABEL(qt_start)))
|
||||
|
||||
|
||||
/** This is for VARARGS. **/
|
||||
|
||||
#define QT_VARGS_DEFAULT
|
||||
|
||||
/* Stack looks like this (2 stack frames):
|
||||
|
||||
<------ 64-bytes aligned -------><--------- 64-bytes aligned ---------->
|
||||
| || |
|
||||
<---?--><--?---><16><----32-----><----16*4-----><-16--><16><----32----->
|
||||
|| | | | || | | | ||
|
||||
||filler|varargs|arg|frame-marker||register-save|filler|arg|frame-marker||
|
||||
--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Sp is moved to the end of the first stack frame. */
|
||||
#define QT_VARGS_MD0(sp, vasize) \
|
||||
((qt_t *)(((char *)sp) + QT_STKROUNDUP(vasize + 4*4 + 32)))
|
||||
|
||||
/* To reach the arguments from the end of the first stack frame use 32
|
||||
as a negative adjustment. */
|
||||
#define QT_VARGS_ADJUST(sp) ((qt_t *)(((char *)sp) - 32))
|
||||
|
||||
/* Offset to reach the end of the second stack frame. */
|
||||
#define QT_VSTKBASE ((16*sizeof(qt_word_t)) + 16 + 4*4 + 32)
|
||||
|
||||
extern void qt_vstart(void);
|
||||
#define QT_VARGS_MD1(sp) \
|
||||
(QT_SPUT (sp, QT_crp, QT_PA_RISC_READ_PLABEL(qt_vstart)))
|
||||
|
||||
#define QT_VARGT_INDEX (QT_15)
|
||||
#define QT_VSTARTUP_INDEX (QT_16)
|
||||
#define QT_VUSERF_INDEX (QT_17)
|
||||
#define QT_VCLEANUP_INDEX (QT_18)
|
||||
|
||||
#endif /* ndef QT_PA_RISC_H */
|
237
qt/md/hppa.s
237
qt/md/hppa.s
|
@ -1,237 +0,0 @@
|
|||
; pa-risc.s -- assembly support.
|
||||
|
||||
; QuickThreads -- Threads-building toolkit.
|
||||
; Copyright (c) 1993 by David Keppel
|
||||
;
|
||||
; Permission to use, copy, modify and distribute this software and
|
||||
; its documentation for any purpose and without fee is hereby
|
||||
; granted, provided that the above copyright notice and this notice
|
||||
; appear in all copies. This software is provided as a
|
||||
; proof-of-concept and for demonstration purposes; there is no
|
||||
; representation about the suitability of this software for any
|
||||
; purpose.
|
||||
|
||||
; This file (pa-risc.s) is part of the port of QuickThreads for
|
||||
; PA-RISC 1.1 architecture. This file implements context switches
|
||||
; and thread startup. It was written in 1994 by Uwe Reder
|
||||
; (`uereder@cip.informatik.uni-erlangen.de') for the Operating
|
||||
; Systems Department (IMMD4) at the University of Erlangen/Nuernberg
|
||||
; Germany.
|
||||
|
||||
|
||||
; Callee saves general registers gr3..gr18,
|
||||
; floating-point registers fr12..fr21.
|
||||
|
||||
.CODE
|
||||
|
||||
.IMPORT $$dyncall, MILLICODE
|
||||
.IMPORT qt_error, CODE
|
||||
|
||||
.EXPORT qt_blocki, ENTRY
|
||||
.EXPORT qt_block, ENTRY
|
||||
.EXPORT qt_abort, ENTRY
|
||||
.EXPORT qt_start, ENTRY
|
||||
.EXPORT qt_vstart, ENTRY
|
||||
|
||||
|
||||
; arg0: ptr to function (helper) to call once curr is suspended
|
||||
; and control is on arg3's stack.
|
||||
; arg1: 1'th arg to *arg0.
|
||||
; arg2: 2'th arg to *arg0.
|
||||
; arg3: sp of new thread.
|
||||
|
||||
qt_blocki
|
||||
.PROC
|
||||
.CALLINFO CALLER, FRAME=0, SAVE_RP, ENTRY_GR=18
|
||||
.ENTRY
|
||||
|
||||
stw %rp,-20(%sp) ; save rp to old frame-marker
|
||||
|
||||
stwm %r3,128(%sp) ; save callee-saves general registers
|
||||
stw %r4,-124(%sp)
|
||||
stw %r5,-120(%sp)
|
||||
stw %r6,-116(%sp)
|
||||
stw %r7,-112(%sp)
|
||||
stw %r8,-108(%sp)
|
||||
stw %r9,-104(%sp)
|
||||
stw %r10,-100(%sp)
|
||||
stw %r11,-96(%sp)
|
||||
stw %r12,-92(%sp)
|
||||
stw %r13,-88(%sp)
|
||||
stw %r14,-84(%sp)
|
||||
stw %r15,-80(%sp)
|
||||
stw %r16,-76(%sp)
|
||||
stw %r17,-72(%sp)
|
||||
stw %r18,-68(%sp)
|
||||
|
||||
qt_abort
|
||||
copy %arg0,%r22 ; helper to be called by $$dyncall
|
||||
copy %sp,%arg0 ; pass current sp as arg0 to helper
|
||||
copy %arg3,%sp ; set new sp
|
||||
|
||||
.CALL
|
||||
bl $$dyncall,%mrp ; call helper
|
||||
copy %mrp,%rp
|
||||
|
||||
ldw -68(%sp),%r18 ; restore general registers
|
||||
ldw -72(%sp),%r17
|
||||
ldw -76(%sp),%r16
|
||||
ldw -80(%sp),%r15
|
||||
ldw -84(%sp),%r14
|
||||
ldw -88(%sp),%r13
|
||||
ldw -92(%sp),%r12
|
||||
ldw -96(%sp),%r11
|
||||
ldw -100(%sp),%r10
|
||||
ldw -104(%sp),%r9
|
||||
ldw -108(%sp),%r8
|
||||
ldw -112(%sp),%r7
|
||||
ldw -116(%sp),%r6
|
||||
ldw -120(%sp),%r5
|
||||
ldw -124(%sp),%r4
|
||||
|
||||
ldw -148(%sp),%rp ; restore return-pointer
|
||||
|
||||
bv %r0(%rp) ; return to caller
|
||||
ldwm -128(%sp),%r3
|
||||
|
||||
.EXIT
|
||||
.PROCEND
|
||||
|
||||
|
||||
qt_block
|
||||
.PROC
|
||||
.CALLINFO CALLER, FRAME=0, SAVE_RP, ENTRY_FR=21
|
||||
.ENTRY
|
||||
|
||||
stw %rp,-20(%sp) ; save rp to old frame-marker
|
||||
|
||||
fstds,ma %fr12,8(%sp) ; save callee-saves float registers
|
||||
fstds,ma %fr13,8(%sp)
|
||||
fstds,ma %fr14,8(%sp)
|
||||
fstds,ma %fr15,8(%sp)
|
||||
fstds,ma %fr16,8(%sp)
|
||||
fstds,ma %fr17,8(%sp)
|
||||
fstds,ma %fr18,8(%sp)
|
||||
fstds,ma %fr19,8(%sp)
|
||||
fstds,ma %fr20,8(%sp)
|
||||
fstds,ma %fr21,8(%sp)
|
||||
|
||||
.CALL
|
||||
bl qt_blocki,%rp
|
||||
ldo 48(%sp),%sp
|
||||
|
||||
ldo -48(%sp),%sp
|
||||
|
||||
fldds,mb -8(%sp),%fr21 ; restore callee-saves float registers
|
||||
fldds,mb -8(%sp),%fr20
|
||||
fldds,mb -8(%sp),%fr19
|
||||
fldds,mb -8(%sp),%fr18
|
||||
fldds,mb -8(%sp),%fr17
|
||||
fldds,mb -8(%sp),%fr16
|
||||
fldds,mb -8(%sp),%fr15
|
||||
fldds,mb -8(%sp),%fr14
|
||||
fldds,mb -8(%sp),%fr13
|
||||
|
||||
ldw -28(%sp),%rp ; restore return-pointer
|
||||
|
||||
bv %r0(%rp) ; return to caller.
|
||||
fldds,mb -8(%sp),%fr12
|
||||
|
||||
.EXIT
|
||||
.PROCEND
|
||||
|
||||
|
||||
qt_start
|
||||
.PROC
|
||||
.CALLINFO CALLER, FRAME=0
|
||||
.ENTRY
|
||||
|
||||
copy %r18,%arg0 ; set user arg `pu'.
|
||||
copy %r17,%arg1 ; ... user function pt.
|
||||
copy %r16,%arg2 ; ... user function userf.
|
||||
; %r22 is a caller-saves register
|
||||
copy %r15,%r22 ; function to be called by $$dyncall
|
||||
|
||||
.CALL ; in=%r22
|
||||
bl $$dyncall,%mrp ; call `only'.
|
||||
copy %mrp,%rp
|
||||
|
||||
bl,n qt_error,%r0 ; `only' erroniously returned.
|
||||
|
||||
.EXIT
|
||||
.PROCEND
|
||||
|
||||
|
||||
; Varargs
|
||||
;
|
||||
; First, call `startup' with the `pt' argument.
|
||||
;
|
||||
; Next, call the user's function with all arguments.
|
||||
; We don't know whether arguments are integers, 32-bit floating-points or
|
||||
; even 64-bit floating-points, so we reload all the registers, possibly
|
||||
; with garbage arguments. The thread creator provided non-garbage for
|
||||
; the arguments that the callee actually uses, so the callee never gets
|
||||
; garbage.
|
||||
;
|
||||
; -48 -44 -40 -36 -32
|
||||
; | arg3 | arg2 | arg1 | arg0 |
|
||||
; -----------------------------
|
||||
; integers: arg3 arg2 arg1 arg0
|
||||
; 32-bit fps: farg3 farg2 farg1 farg0
|
||||
; 64-bit fps: <---farg3--> <---farg1-->
|
||||
;
|
||||
; Finally, call `cleanup' with the `pt' argument and with the return value
|
||||
; from the user's function. It is an error for `cleanup' to return.
|
||||
|
||||
qt_vstart
|
||||
.PROC
|
||||
.CALLINFO CALLER, FRAME=0
|
||||
.ENTRY
|
||||
|
||||
; Because the startup function may damage the fixed arguments
|
||||
; on the stack (PA-RISC Procedure Calling Conventions Reference
|
||||
; Manual, 2.4 Fixed Arguments Area), we allocate a seperate
|
||||
; stack frame for it.
|
||||
ldo 64(%sp),%sp
|
||||
|
||||
; call: void startup(void *pt)
|
||||
|
||||
copy %r15,%arg0 ; `pt' is arg0 to `startup'.
|
||||
copy %r16,%r22
|
||||
.CALL
|
||||
bl $$dyncall,%mrp ; Call `startup'.
|
||||
copy %mrp,%rp
|
||||
|
||||
ldo -64(%sp),%sp
|
||||
|
||||
; call: void *qt_vuserf_t(...)
|
||||
|
||||
ldw -36(%sp),%arg0 ; Load args to integer registers.
|
||||
ldw -40(%sp),%arg1
|
||||
ldw -44(%sp),%arg2
|
||||
ldw -48(%sp),%arg3
|
||||
; Index of fld[w|d]s only ranges from -16 to 15, so we
|
||||
; take r22 to be our new base register.
|
||||
ldo -32(%sp),%r22
|
||||
fldws -4(%r22),%farg0 ; Load args to floating-point registers.
|
||||
fldds -8(%r22),%farg1
|
||||
fldws -12(%r22),%farg2
|
||||
fldds -16(%r22),%farg3
|
||||
copy %r17,%r22
|
||||
.CALL
|
||||
bl $$dyncall,%mrp ; Call `userf'.
|
||||
copy %mrp,%rp
|
||||
|
||||
; call: void cleanup(void *pt, void *vuserf_return)
|
||||
|
||||
copy %r15,%arg0 ; `pt' is arg0 to `cleanup'.
|
||||
copy %ret0,%arg1 ; Return-value is arg1 to `cleanup'.
|
||||
copy %r18,%r22
|
||||
.CALL
|
||||
bl $$dyncall,%mrp ; Call `cleanup'.
|
||||
copy %mrp,%rp
|
||||
|
||||
bl,n qt_error,%r0
|
||||
|
||||
.EXIT
|
||||
.PROCEND
|
203
qt/md/hppa_b.s
203
qt/md/hppa_b.s
|
@ -1,203 +0,0 @@
|
|||
; QuickThreads -- Threads-building toolkit.
|
||||
; Copyright (c) 1993 by David Keppel
|
||||
|
||||
; Permission to use, copy, modify and distribute this software and
|
||||
; its documentation for any purpose and without fee is hereby
|
||||
; granted, provided that the above copyright notice and this notice
|
||||
; appear in all copies. This software is provided as a
|
||||
; proof-of-concept and for demonstration purposes; there is no
|
||||
; representation about the suitability of this software for any
|
||||
; purpose.
|
||||
|
||||
; This file (pa-risc_b.s) is part of the port of QuickThreads for
|
||||
; PA-RISC 1.1 architecture. It contains assembly-level support for
|
||||
; raw processor performance measurement. It was written in 1994 by
|
||||
; Uwe Reder (`uereder@cip.informatik.uni-erlangen.de')
|
||||
; for the Operating Systems Department (IMMD4) at the
|
||||
; University of Erlangen/Nuernberg Germany.
|
||||
|
||||
|
||||
; Note that the number of instructions in the measurement-loops, differ
|
||||
; from implementation to implementation. I took eight instructions in a loop
|
||||
; for every test (execute eight instructions and loop to the start).
|
||||
|
||||
.CODE
|
||||
|
||||
.IMPORT $global$,DATA
|
||||
.IMPORT $$dyncall,MILLICODE
|
||||
.EXPORT b_call_reg
|
||||
.EXPORT b_call_imm
|
||||
.EXPORT b_add
|
||||
.EXPORT b_load
|
||||
|
||||
; Just do nothing, only return to caller. This procedure is called by
|
||||
; `b_call_reg' and `b_call_imm'.
|
||||
|
||||
b_null
|
||||
.PROC
|
||||
.CALLINFO NO_CALLS, FRAME=0
|
||||
.ENTRY
|
||||
|
||||
bv,n %r0(%rp) ; just return
|
||||
|
||||
.EXIT
|
||||
.PROCEND
|
||||
|
||||
; Call the procedure `b_null' with function pointer in a register.
|
||||
|
||||
b_call_reg
|
||||
.PROC
|
||||
.CALLINFO CALLER, FRAME=0
|
||||
.ENTRY
|
||||
|
||||
stwm %r3,64(%sp) ; store r3 (may be used by caller)
|
||||
stw %rp,-20(%sp) ; save return-pointer to frame-marker
|
||||
|
||||
addil LR'to_call-$global$,%r27
|
||||
ldw RR'to_call-$global$(%r1),%r3
|
||||
|
||||
_loop0
|
||||
copy %r3,%r22 ; copy the procedure label to r22, ...
|
||||
.CALL ; ...this is the input to $$dyncall
|
||||
bl $$dyncall,%mrp ; call $$dyncall (millicode function)
|
||||
copy %mrp,%rp ; remember the return-pointer
|
||||
|
||||
copy %r3,%r22
|
||||
.CALL
|
||||
bl $$dyncall,%mrp
|
||||
copy %mrp,%rp
|
||||
|
||||
copy %r3,%r22
|
||||
.CALL
|
||||
bl $$dyncall,%mrp
|
||||
copy %mrp,%rp
|
||||
|
||||
copy %r3,%r22
|
||||
.CALL
|
||||
bl $$dyncall,%mrp
|
||||
copy %mrp,%rp
|
||||
|
||||
copy %r3,%r22
|
||||
.CALL
|
||||
bl $$dyncall,%mrp
|
||||
copy %mrp,%rp
|
||||
|
||||
copy %r3,%r22
|
||||
.CALL
|
||||
bl $$dyncall,%mrp
|
||||
copy %mrp,%rp
|
||||
|
||||
copy %r3,%r22
|
||||
.CALL
|
||||
bl $$dyncall,%mrp
|
||||
copy %mrp,%rp
|
||||
|
||||
copy %r3,%r22
|
||||
.CALL
|
||||
bl $$dyncall,%mrp
|
||||
copy %mrp,%rp
|
||||
|
||||
addibf,<= -8,%arg0,_loop0 ; decrement counter by 8 and loop
|
||||
nop
|
||||
|
||||
ldw -20(%sp),%rp ; restore return-pointer
|
||||
bv %r0(%rp) ; return to caller
|
||||
ldwm -64(%sp),%r3 ; resore r3 and remove stack frame
|
||||
|
||||
.EXIT
|
||||
.PROCEND
|
||||
|
||||
; Call the procedure `b_null' immediate.
|
||||
|
||||
b_call_imm
|
||||
.PROC
|
||||
.CALLINFO CALLER, FRAME=0, SAVE_RP
|
||||
.ENTRY
|
||||
|
||||
ldo 64(%sp),%sp ; caller needs a stack-frame
|
||||
stw %rp,-20(%sp) ; save return-pointer to frame-marker
|
||||
|
||||
_loop1
|
||||
bl b_null,%rp ; call `b_null' immediate (8 times)
|
||||
nop
|
||||
bl b_null,%rp
|
||||
nop
|
||||
bl b_null,%rp
|
||||
nop
|
||||
bl b_null,%rp
|
||||
nop
|
||||
bl b_null,%rp
|
||||
nop
|
||||
bl b_null,%rp
|
||||
nop
|
||||
bl b_null,%rp
|
||||
nop
|
||||
bl b_null,%rp
|
||||
nop
|
||||
|
||||
addibf,<= -8,%arg0,_loop1 ; decrement counter by 8 and loop
|
||||
nop
|
||||
|
||||
ldw -20(%sp),%rp ; restore return-pointer
|
||||
bv %r0(%rp) ; return to caller
|
||||
ldo -64(%sp),%sp ; remove stack-frame
|
||||
|
||||
.EXIT
|
||||
.PROCEND
|
||||
|
||||
; Copy register-to-register.
|
||||
; On PA-RISC this is implemented with an `or'.
|
||||
; The `or' is hidden by a pseudo-operation called `copy'.
|
||||
|
||||
b_add
|
||||
.PROC
|
||||
.CALLINFO NO_CALLS, FRAME=0
|
||||
.ENTRY
|
||||
|
||||
_loop2
|
||||
copy %r19,%r20 ; copy register-to-register
|
||||
copy %r20,%r21 ; use caller-saves registers
|
||||
copy %r21,%r22
|
||||
copy %r22,%r21
|
||||
copy %r21,%r20
|
||||
copy %r20,%r19
|
||||
copy %r19,%r20
|
||||
copy %r20,%r21
|
||||
|
||||
addibf,<= -8,%arg0,_loop2 ; decrement counter by 8 and loop
|
||||
nop
|
||||
|
||||
bv,n %r0(%rp)
|
||||
|
||||
.EXIT
|
||||
.PROCEND
|
||||
|
||||
; Load memory to a register.
|
||||
|
||||
b_load
|
||||
.PROC
|
||||
.CALLINFO NO_CALLS, FRAME=0
|
||||
.ENTRY
|
||||
|
||||
_loop3
|
||||
ldw -4(%sp),%r22 ; load data from frame-marker
|
||||
ldw -8(%sp),%r22 ; use a caller-saves register
|
||||
ldw -12(%sp),%r22
|
||||
ldw -16(%sp),%r22
|
||||
ldw -20(%sp),%r22
|
||||
ldw -24(%sp),%r22
|
||||
ldw -28(%sp),%r22
|
||||
ldw -32(%sp),%r22
|
||||
|
||||
addibf,<= -8,%arg0,_loop3 ; decrement counter by 8 and loop
|
||||
nop
|
||||
|
||||
bv,n %r0(%rp)
|
||||
|
||||
.EXIT
|
||||
.PROCEND
|
||||
|
||||
|
||||
.ALIGN 8
|
||||
to_call
|
||||
.WORD b_null
|
|
@ -1,7 +0,0 @@
|
|||
Note that some machines want labels to have leading underscores,
|
||||
while others (e.g. System V) do not. Thus, several labels appear
|
||||
duplicated except for the leading underscore, e.g.
|
||||
|
||||
_qt_cswap:
|
||||
qt_cswap:
|
||||
|
112
qt/md/i386.asm
112
qt/md/i386.asm
|
@ -1,112 +0,0 @@
|
|||
;; i386.asm -- assembly support.
|
||||
|
||||
;;
|
||||
;; QuickThreads -- Threads-building toolkit.
|
||||
;; Copyright (c) 2001, 2006 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; Permission to use, copy, modify and distribute this software and
|
||||
;; its documentation for any purpose and without fee is hereby
|
||||
;; granted, provided that the above copyright notice and this notice
|
||||
;; appear in all copies. This software is provided as a
|
||||
;; proof-of-concept and for demonstration purposes; there is no
|
||||
;; representation about the suitability of this software for any
|
||||
;; purpose.
|
||||
|
||||
;; NOTE: double-labeled `_name' and `name' for System V compatability.
|
||||
;; NOTE: Comment lines start like this one, or with '//' ONLY. Sorry!
|
||||
|
||||
;; Callee-save: %esi, %edi, %ebx, %ebp
|
||||
;; Caller-save: %eax, %ecx
|
||||
;; Can't tell: %edx (seems to work w/o saving it.)
|
||||
;;
|
||||
;; Assignment:
|
||||
;;
|
||||
;; See ``i386.h'' for the somewhat unconventional stack layout.
|
||||
|
||||
|
||||
.386p
|
||||
.model flat
|
||||
.code
|
||||
|
||||
public _qt_abort
|
||||
public qt_abort
|
||||
public _qt_block
|
||||
public qt_block
|
||||
public _qt_blocki
|
||||
public qt_blocki
|
||||
|
||||
;; These all have the type signature
|
||||
;;
|
||||
;; void *blocking (helper, arg0, arg1, new)
|
||||
;;
|
||||
;; On procedure entry, the helper is at 4(sp), args at 8(sp) and
|
||||
;; 12(sp) and the new thread's sp at 16(sp). It *appears* that the
|
||||
;; calling convention for the 8X86 requires the caller to save all
|
||||
;; floating-point registers, this makes our life easy.
|
||||
|
||||
;; Halt the currently-running thread. Save it's callee-save regs on
|
||||
;; to the stack, 32 bytes. Switch to the new stack (next == 16+32(sp))
|
||||
;; and call the user function (f == 4+32(sp) with arguments: old sp
|
||||
;; arg1 (8+32(sp)) and arg2 (12+32(sp)). When the user function is
|
||||
;; done, restore the new thread's state and return.
|
||||
;;
|
||||
;; `qt_abort' is (currently) an alias for `qt_block' because most of
|
||||
;; the work is shared. We could save the insns up to `qt_common' by
|
||||
;; replicating, but w/o replicating we need an inital subtract (to
|
||||
;; offset the stack as if it had been a qt_block) and then a jump
|
||||
;; to qt_common. For the cost of a jump, we might as well just do
|
||||
;; all the work.
|
||||
;;
|
||||
;; The helper function (4(sp)) can return a void* that is returned
|
||||
;; by the call to `qt_blockk{,i}'. Since we don't touch %eax in
|
||||
;; between, we get that ``for free''.
|
||||
|
||||
_qt_abort:
|
||||
qt_abort:
|
||||
_qt_block:
|
||||
qt_block:
|
||||
_qt_blocki:
|
||||
qt_blocki:
|
||||
push ebp ; Save callee-save, sp-=4.
|
||||
push esi ; Save callee-save, sp-=4.
|
||||
push edi ; Save callee-save, sp-=4.
|
||||
push ebx ; Save callee-save, sp-=4.
|
||||
mov eax, esp ; Remember old stack pointer.
|
||||
|
||||
qt_common:
|
||||
mov esp, [esp+32] ; Move to new thread.
|
||||
push [eax+28] ; Push arg 2.
|
||||
push [eax+24] ; Push arg 1.
|
||||
push eax ; Push arg 0.
|
||||
mov ebx, [eax+20] ; Get function to call.
|
||||
call ebx ; Call f.
|
||||
add esp, 12 ; Pop args.
|
||||
|
||||
pop ebx ; Restore callee-save, sp+=4.
|
||||
pop edi ; Restore callee-save, sp+=4.
|
||||
pop esi ; Restore callee-save, sp+=4.
|
||||
pop ebp ; Restore callee-save, sp+=4.
|
||||
ret ; Resume the stopped function.
|
||||
hlt
|
||||
|
||||
|
||||
;; Start a varargs thread.
|
||||
|
||||
public _qt_vstart
|
||||
public qt_vstart
|
||||
|
||||
_qt_vstart:
|
||||
qt_vstart:
|
||||
push edi ; Push `pt' arg to `startup'.
|
||||
call ebp ; Call `startup'.
|
||||
pop eax ; Clean up the stack.
|
||||
|
||||
call ebx ; Call the user's function.
|
||||
|
||||
push eax ; Push return from user's.
|
||||
push edi ; Push `pt' arg to `cleanup'.
|
||||
call esi ; Call `cleanup'.
|
||||
|
||||
hlt ; `cleanup' never returns.
|
||||
|
||||
end
|
120
qt/md/i386.h
120
qt/md/i386.h
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#ifndef QT_386_H
|
||||
#define QT_386_H
|
||||
|
||||
typedef unsigned long qt_word_t;
|
||||
|
||||
/* Thread's initial stack layout on the i386:
|
||||
|
||||
non-varargs:
|
||||
|
||||
+---
|
||||
| arg[2] === `userf' on startup
|
||||
| arg[1] === `pt' on startup
|
||||
| arg[0] === `pu' on startup
|
||||
+---
|
||||
| ret pc === qt_error
|
||||
+---
|
||||
| ret pc === `only' on startup
|
||||
+---
|
||||
| %ebp
|
||||
| %esi
|
||||
| %edi
|
||||
| %ebx <--- qt_t.sp
|
||||
+---
|
||||
|
||||
When a non-varargs thread is started, it ``returns'' directly to
|
||||
the client's `only' function.
|
||||
|
||||
varargs:
|
||||
|
||||
+---
|
||||
| arg[n-1]
|
||||
| ..
|
||||
| arg[0]
|
||||
+---
|
||||
| ret pc === `qt_vstart'
|
||||
+---
|
||||
| %ebp === `startup'
|
||||
| %esi === `cleanup'
|
||||
| %edi === `pt'
|
||||
| %ebx === `vuserf' <--- qt_t.sp
|
||||
+---
|
||||
|
||||
When a varargs thread is started, it ``returns'' to the `qt_vstart'
|
||||
startup code. The startup code calls the appropriate functions. */
|
||||
|
||||
|
||||
/* What to do to start a varargs thread running. */
|
||||
QT_API void qt_vstart (void);
|
||||
|
||||
|
||||
/* Hold 4 saved regs plus two return pcs (qt_error, qt_start) plus
|
||||
three args. */
|
||||
#define QT_STKBASE (9 * 4)
|
||||
|
||||
/* Hold 4 saved regs plus one return pc (qt_vstart). */
|
||||
#define QT_VSTKBASE (5 * 4)
|
||||
|
||||
|
||||
/* Stack must be 4-byte aligned. */
|
||||
#define QT_STKALIGN (4)
|
||||
|
||||
|
||||
/* Where to place various arguments. */
|
||||
#define QT_ONLY_INDEX (QT_PC)
|
||||
#define QT_USER_INDEX (QT_ARG2)
|
||||
#define QT_ARGT_INDEX (QT_ARG1)
|
||||
#define QT_ARGU_INDEX (QT_ARG0)
|
||||
|
||||
#define QT_VSTARTUP_INDEX (QT_EBP)
|
||||
#define QT_VUSERF_INDEX (QT_EBX)
|
||||
#define QT_VCLEANUP_INDEX (QT_ESI)
|
||||
#define QT_VARGT_INDEX (QT_EDI)
|
||||
|
||||
|
||||
#define QT_EBX 0
|
||||
#define QT_EDI 1
|
||||
#define QT_ESI 2
|
||||
#define QT_EBP 3
|
||||
#define QT_PC 4
|
||||
/* The following are defined only for non-varargs. */
|
||||
#define QT_RPC 5
|
||||
#define QT_ARG0 6
|
||||
#define QT_ARG1 7
|
||||
#define QT_ARG2 8
|
||||
|
||||
|
||||
/* Stack grows down. The top of the stack is the first thing to
|
||||
pop off (preincrement, postdecrement). */
|
||||
#define QT_GROW_DOWN
|
||||
|
||||
QT_API void qt_error (void);
|
||||
|
||||
/* Push on the error return address. */
|
||||
#define QT_ARGS_MD(sto) \
|
||||
(QT_SPUT (sto, QT_RPC, qt_error))
|
||||
|
||||
|
||||
/* When varargs are pushed, allocate space for all the args. */
|
||||
#define QT_VARGS_MD0(sto, nbytes) \
|
||||
((qt_t *)(((char *)(sto)) - QT_STKROUNDUP(nbytes)))
|
||||
|
||||
#define QT_VARGS_MD1(sto) \
|
||||
(QT_SPUT (sto, QT_PC, qt_vstart))
|
||||
|
||||
#define QT_VARGS_DEFAULT
|
||||
|
||||
#endif /* QT_386_H */
|
108
qt/md/i386.s
108
qt/md/i386.s
|
@ -1,108 +0,0 @@
|
|||
/* i386.s -- assembly support. */
|
||||
|
||||
/*
|
||||
// QuickThreads -- Threads-building toolkit.
|
||||
// Copyright (c) 1993 by David Keppel
|
||||
//
|
||||
// Permission to use, copy, modify and distribute this software and
|
||||
// its documentation for any purpose and without fee is hereby
|
||||
// granted, provided that the above copyright notice and this notice
|
||||
// appear in all copies. This software is provided as a
|
||||
// proof-of-concept and for demonstration purposes; there is no
|
||||
// representation about the suitability of this software for any
|
||||
// purpose. */
|
||||
|
||||
/* NOTE: double-labeled `_name' and `name' for System V compatability. */
|
||||
/* NOTE: Comment lines start like this one, or with '//' ONLY. Sorry! */
|
||||
|
||||
/* Callee-save: %esi, %edi, %ebx, %ebp
|
||||
// Caller-save: %eax, %ecx
|
||||
// Can't tell: %edx (seems to work w/o saving it.)
|
||||
//
|
||||
// Assignment:
|
||||
//
|
||||
// See ``i386.h'' for the somewhat unconventional stack layout. */
|
||||
|
||||
|
||||
.text
|
||||
.align 2
|
||||
|
||||
.globl _qt_abort
|
||||
.globl qt_abort
|
||||
.globl _qt_block
|
||||
.globl qt_block
|
||||
.globl _qt_blocki
|
||||
.globl qt_blocki
|
||||
|
||||
/* These all have the type signature
|
||||
//
|
||||
// void *blocking (helper, arg0, arg1, new)
|
||||
//
|
||||
// On procedure entry, the helper is at 4(sp), args at 8(sp) and
|
||||
// 12(sp) and the new thread's sp at 16(sp). It *appears* that the
|
||||
// calling convention for the 8X86 requires the caller to save all
|
||||
// floating-point registers, this makes our life easy. */
|
||||
|
||||
/* Halt the currently-running thread. Save it's callee-save regs on
|
||||
// to the stack, 32 bytes. Switch to the new stack (next == 16+32(sp))
|
||||
// and call the user function (f == 4+32(sp) with arguments: old sp
|
||||
// arg1 (8+32(sp)) and arg2 (12+32(sp)). When the user function is
|
||||
// done, restore the new thread's state and return.
|
||||
//
|
||||
// `qt_abort' is (currently) an alias for `qt_block' because most of
|
||||
// the work is shared. We could save the insns up to `qt_common' by
|
||||
// replicating, but w/o replicating we need an inital subtract (to
|
||||
// offset the stack as if it had been a qt_block) and then a jump
|
||||
// to qt_common. For the cost of a jump, we might as well just do
|
||||
// all the work.
|
||||
//
|
||||
// The helper function (4(sp)) can return a void* that is returned
|
||||
// by the call to `qt_blockk{,i}'. Since we don't touch %eax in
|
||||
// between, we get that ``for free''. */
|
||||
|
||||
_qt_abort:
|
||||
qt_abort:
|
||||
_qt_block:
|
||||
qt_block:
|
||||
_qt_blocki:
|
||||
qt_blocki:
|
||||
pushl %ebp /* Save callee-save, sp-=4. */
|
||||
pushl %esi /* Save callee-save, sp-=4. */
|
||||
pushl %edi /* Save callee-save, sp-=4. */
|
||||
pushl %ebx /* Save callee-save, sp-=4. */
|
||||
movl %esp, %eax /* Remember old stack pointer. */
|
||||
|
||||
qt_common:
|
||||
movl 32(%esp), %esp /* Move to new thread. */
|
||||
pushl 28(%eax) /* Push arg 2. */
|
||||
pushl 24(%eax) /* Push arg 1. */
|
||||
pushl %eax /* Push arg 0. */
|
||||
movl 20(%eax), %ebx /* Get function to call. */
|
||||
call *%ebx /* Call f. */
|
||||
addl $12, %esp /* Pop args. */
|
||||
|
||||
popl %ebx /* Restore callee-save, sp+=4. */
|
||||
popl %edi /* Restore callee-save, sp+=4. */
|
||||
popl %esi /* Restore callee-save, sp+=4. */
|
||||
popl %ebp /* Restore callee-save, sp+=4. */
|
||||
ret /* Resume the stopped function. */
|
||||
hlt
|
||||
|
||||
|
||||
/* Start a varargs thread. */
|
||||
|
||||
.globl _qt_vstart
|
||||
.globl qt_vstart
|
||||
_qt_vstart:
|
||||
qt_vstart:
|
||||
pushl %edi /* Push `pt' arg to `startup'. */
|
||||
call *%ebp /* Call `startup'. */
|
||||
popl %eax /* Clean up the stack. */
|
||||
|
||||
call *%ebx /* Call the user's function. */
|
||||
|
||||
pushl %eax /* Push return from user's. */
|
||||
pushl %edi /* Push `pt' arg to `cleanup'. */
|
||||
call *%esi /* Call `cleanup'. */
|
||||
|
||||
hlt /* `cleanup' never returns. */
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
// QuickThreads -- Threads-building toolkit.
|
||||
// Copyright (c) 1993 by David Keppel
|
||||
//
|
||||
// Permission to use, copy, modify and distribute this software and
|
||||
// its documentation for any purpose and without fee is hereby
|
||||
// granted, provided that the above copyright notice and this notice
|
||||
// appear in all copies. This software is provided as a
|
||||
// proof-of-concept and for demonstration purposes; there is no
|
||||
// representation about the suitability of this software for any
|
||||
// purpose. */
|
||||
|
||||
.globl _b_call_reg
|
||||
.globl b_call_reg
|
||||
.globl _b_call_imm
|
||||
.globl b_call_imm
|
||||
.globl _b_add
|
||||
.globl b_add
|
||||
.globl _b_load
|
||||
.globl b_load
|
||||
|
||||
_b_call_reg:
|
||||
b_call_reg:
|
||||
_b_call_imm:
|
||||
b_call_imm:
|
||||
_b_add:
|
||||
b_add:
|
||||
_b_load:
|
||||
b_load:
|
||||
hlt
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
#
|
||||
# KSR1 configuration.
|
||||
#
|
||||
CC = cc -ansi
|
||||
|
164
qt/md/ksr1.h
164
qt/md/ksr1.h
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#ifndef QT_KSR1_H
|
||||
#define QT_KSR1_H
|
||||
|
||||
/*
|
||||
Stack layout:
|
||||
|
||||
Registers are saved in strictly low to high order, FPU regs first
|
||||
(only if qt_block is called), CEU regs second, IPU regs next, with no
|
||||
padding between the groups.
|
||||
|
||||
Callee-save: f16..f63; c15..c30; i12..i30.
|
||||
Args passed in i2..i5.
|
||||
|
||||
Note: c31 is a private data pointer. It is not changed on thread
|
||||
swaps with the assumption that it represents per-processor rather
|
||||
than per-thread state.
|
||||
|
||||
Note: i31 is an instruction count register that is updated by the
|
||||
context switch routines. Like c31, it is not changed on context
|
||||
switches.
|
||||
|
||||
This is what we want on startup:
|
||||
|
||||
|
||||
+------ <-- BOS: Bottom of stack (grows down)
|
||||
| 80 (128 - 48) bytes of padding to a 128-byte boundary
|
||||
+---
|
||||
| only
|
||||
| userf
|
||||
| t
|
||||
| u
|
||||
| qt_start$TXT
|
||||
| (empty) <-- qt.sp
|
||||
+------ <-- (BOS - 128)
|
||||
|
||||
This is why we want this on startup:
|
||||
|
||||
A thread begins running when the restore procedure switches thread stacks
|
||||
and pops a return address off of the top of the new stack (see below
|
||||
for the reason why we explicitly store qt_start$TXT). The
|
||||
block procedure pushes two jump addresses on a thread's stack before
|
||||
it switches stacks. The first is the return address for the block
|
||||
procedure, and the second is a restore address. The return address
|
||||
is used to jump back to the thread that has been switched to; the
|
||||
restore address is a jump within the block code to restore the registers.
|
||||
Normally, this is just a jump to the next address. However, on thread
|
||||
startup, this is a jump to qt_start$TXT. (The block procedure stores
|
||||
the restore address at an offset of 8 bytes from the top of the stack,
|
||||
which is also the offset at which qt_start$TXT is stored on the stacks
|
||||
of new threads. Hence, when the block procedure switches to a new
|
||||
thread stack, it will initially jump to qt_start$TXT; thereafter,
|
||||
it jumps to the restore code.)
|
||||
|
||||
qt_start$TXT, after it has read the initial data on the new thread's
|
||||
stack and placed it in registers, pops the initial stack frame
|
||||
and gives the thread the entire stack to use for execution.
|
||||
|
||||
The KSR runtime system has an unusual treatment of pointers to
|
||||
functions. From C, taking the `name' of a function yields a
|
||||
pointer to a _constant block_ and *not* the address of the
|
||||
function. The zero'th entry in the constant block is a pointer to
|
||||
the function.
|
||||
|
||||
We have to be careful: the restore procedure expects a return
|
||||
address on the top of the stack (pointed to by qt.sp). This is not
|
||||
a problem when restoring a thread that has run before, since the
|
||||
block routine would have stored the return address on top of the
|
||||
stack. However, when ``faking up'' a thread start (bootstrapping a
|
||||
thread stack frame), the top of the stack needs to contain a
|
||||
pointer to the code that will start the thread running.
|
||||
|
||||
The pointer to the startup code is *not* `qt_start'. It is the
|
||||
word *pointed to* by `qt_start'. Thus, we dereference `qt_start',
|
||||
see QT_ARGS_MD below.
|
||||
|
||||
On varargs startup (still unimplemented):
|
||||
|
||||
| padding to 128 byte boundary
|
||||
| varargs <-- padded to a 128-byte-boundary
|
||||
+---
|
||||
| caller's frame, 16 bytes
|
||||
| 80 bytes of padding (frame padded to a 128-byte boundary)
|
||||
+---
|
||||
| cleanup
|
||||
| vuserf
|
||||
| startup
|
||||
| t
|
||||
+---
|
||||
| qt_start <-- qt.sp
|
||||
+---
|
||||
|
||||
Of a suspended thread:
|
||||
|
||||
+---
|
||||
| caller's frame, 16 bytes
|
||||
| fpu registers 47 regs * 8 bytes/reg 376 bytes
|
||||
| ceu registers 16 regs * 8 bytes/reg 128 bytes
|
||||
| ipu registers 19 regs * 8 bytes/reg 152 bytes
|
||||
| :
|
||||
| 80 bytes of padding
|
||||
| :
|
||||
| qt_restore <-- qt.sp
|
||||
+---
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#define QT_STKALIGN 128
|
||||
#define QT_GROW_DOWN
|
||||
typedef unsigned long qt_word_t;
|
||||
|
||||
#define QT_STKBASE QT_STKALIGN
|
||||
#define QT_VSTKBASE QT_STKBASE
|
||||
|
||||
extern void qt_start(void);
|
||||
/*
|
||||
* See the discussion above for what indexing into a procedure ptr
|
||||
* does for us (it's lovely, though, isn't it?).
|
||||
*
|
||||
* This assumes that the address of a procedure's code is the
|
||||
* first word in a procedure's constant block. That's how the manual
|
||||
* says it will be arranged.
|
||||
*/
|
||||
#define QT_ARGS_MD(sp) (QT_SPUT (sp, 1, ((qt_word_t *)qt_start)[0]))
|
||||
|
||||
/*
|
||||
* The *index* (positive offset) of where to put each value.
|
||||
* See the picture of the stack above that explains the offsets.
|
||||
*/
|
||||
#define QT_ONLY_INDEX (5)
|
||||
#define QT_USER_INDEX (4)
|
||||
#define QT_ARGT_INDEX (3)
|
||||
#define QT_ARGU_INDEX (2)
|
||||
|
||||
#define QT_VARGS_DEFAULT
|
||||
#define QT_VARGS(sp, nb, vargs, pt, startup, vuserf, cleanup) \
|
||||
(qt_vargs (sp, nbytes, &vargs, pt, startup, vuserf, cleanup))
|
||||
|
||||
|
||||
#define QT_VARGS_MD0(sp, vabytes) \
|
||||
((qt_t *)(((char *)(sp)) - 4*8 - QT_STKROUNDUP(vabytes)))
|
||||
|
||||
extern void qt_vstart(void);
|
||||
#define QT_VARGS_MD1(sp) (QT_SPUT (sp, 0, ((qt_word_t *)qt_vstart)[0]))
|
||||
|
||||
#define QT_VCLEANUP_INDEX (4)
|
||||
#define QT_VUSERF_INDEX (3)
|
||||
#define QT_VSTARTUP_INDEX (2)
|
||||
#define QT_VARGT_INDEX (1)
|
||||
|
||||
#endif /* def QT_KSR1_H */
|
424
qt/md/ksr1.s
424
qt/md/ksr1.s
|
@ -1,424 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
.file "ksr1.s"
|
||||
.def .debug; .endef
|
||||
|
||||
.align 128
|
||||
.globl qt_blocki
|
||||
.globl qt_blocki$TXT
|
||||
.globl qt_block
|
||||
.globl qt_block$TXT
|
||||
.globl qt_start$TXT
|
||||
.globl qt_start
|
||||
.globl qt_abort$TXT
|
||||
.globl qt_abort
|
||||
.globl qt_vstart
|
||||
.globl qt_vstart$TXT
|
||||
|
||||
#
|
||||
# KSR convention: on procedure calls, load both the procedure address
|
||||
# and a pointer to a constant block. The address of function `f' is
|
||||
# `f$TXT', and the constant block address is `f'. The constant block
|
||||
# has several reserved values:
|
||||
#
|
||||
# 8 bytes fpu register save mask
|
||||
# 4 bytes ipu register save mask
|
||||
# 4 bytes ceu register save mask
|
||||
# f: f$TXT
|
||||
# ... whatever you want ... (not quite...read on)
|
||||
#
|
||||
# Note, by the way, that a pointer to a function is passed as a
|
||||
# pointer to the constant area, and the constant area has the text
|
||||
# address.
|
||||
#
|
||||
|
||||
#
|
||||
# Procedures that do not return structures prefix their code with
|
||||
#
|
||||
# proc$TXT:
|
||||
# finop; cxnop
|
||||
# finop; cxnop
|
||||
# <proc code>
|
||||
#
|
||||
# Calls to those procedures branch to a 16 byte offset (4 instrs) in
|
||||
# to the procedure to skip those instructions.
|
||||
#
|
||||
# Procedures that return structures use a different code prefix:
|
||||
#
|
||||
# proc$TXT:
|
||||
# finop; beq.qt %rc, %rc, 24 # return value entry
|
||||
# finop; cxnop
|
||||
# finop; movi8 0, %rc # no return value entry
|
||||
# <proc code>
|
||||
#
|
||||
# Calls that want the returned structure branch directly to the
|
||||
# procedure address. Callers that don't want (or aren't expecting) a
|
||||
# return value branche 16 bytes in to the procedure, which will zero
|
||||
# %rc, telling the called procedure not to return a structure.
|
||||
#
|
||||
|
||||
#
|
||||
# On entry:
|
||||
# %i2 -- control block of helper function to run
|
||||
# (dereference to get helper)
|
||||
# %i3 -- a1
|
||||
# %i4 -- a2
|
||||
# %i5 -- sp of new to run
|
||||
#
|
||||
|
||||
.data
|
||||
.half 0x0, 0x0, 0x7ffff000, 0x7fff8000
|
||||
qt_blocki:
|
||||
qt_abort:
|
||||
.word qt_blocki$TXT
|
||||
.word qt_restore$TXT
|
||||
|
||||
.text
|
||||
qt_abort$TXT:
|
||||
qt_blocki$TXT:
|
||||
finop ; cxnop # entry prefix
|
||||
finop ; cxnop # entry prefix
|
||||
add8.ntr 75,%i31,%i31 ; movi8 512,%c5 # ICR; stk adjust
|
||||
finop ; ssub8.ntr 0,%sp,%c5,%sp
|
||||
finop ; st8 %fp,504(%sp) # Save caller's fp
|
||||
finop ; st8 %cp,496(%sp) # Save caller's cp
|
||||
finop ; ld8 8(%c10),%c5 # ld qt_restore$TXT
|
||||
finop ; st8 %c14,0(%sp) # Save special ret addr
|
||||
finop ; mov8_8 %c10, %cp # Our cp
|
||||
finop ; sadd8.ntr 0,%sp,%c5,%fp # Our frame ptr
|
||||
finop ; st8 %c5,8(%sp) # st qt_restore$TXT
|
||||
#
|
||||
# CEU registers %c15-%c24, %c26-%c30 (%c14 we restore later)
|
||||
#
|
||||
finop ; st8 %c15,456(%sp)
|
||||
finop ; st8 %c16,448(%sp)
|
||||
finop ; st8 %c17,440(%sp)
|
||||
finop ; st8 %c18,432(%sp)
|
||||
finop ; st8 %c19,424(%sp)
|
||||
finop ; st8 %c20,416(%sp)
|
||||
finop ; st8 %c21,408(%sp)
|
||||
finop ; st8 %c22,400(%sp)
|
||||
finop ; st8 %c23,392(%sp)
|
||||
finop ; st8 %c24,384(%sp)
|
||||
#
|
||||
# %c25 is the Enclosing Frame Pointer (EFP) -- since C doesn't
|
||||
# use nested procedures, we ignore it (leaving a gap, though)
|
||||
#
|
||||
finop ; st8 %c26,368(%sp)
|
||||
finop ; st8 %c27,360(%sp)
|
||||
finop ; st8 %c28,352(%sp)
|
||||
finop ; st8 %c29,344(%sp)
|
||||
finop ; st8 %c30,336(%sp)
|
||||
#
|
||||
# IPU registers %i12-%i30
|
||||
#
|
||||
finop ; st8 %i12,328(%sp)
|
||||
finop ; st8 %i13,320(%sp)
|
||||
finop ; st8 %i14,312(%sp)
|
||||
finop ; st8 %i15,304(%sp)
|
||||
# (gap to get alignment for st64)
|
||||
# -- Doesn't work on version 1.1.3 of the OS
|
||||
# finop ; st64 %i16,256(%sp)
|
||||
|
||||
finop ; st8 %i16,256(%sp)
|
||||
finop ; st8 %i17,248(%sp)
|
||||
finop ; st8 %i18,240(%sp)
|
||||
finop ; st8 %i19,232(%sp)
|
||||
finop ; st8 %i20,224(%sp)
|
||||
finop ; st8 %i21,216(%sp)
|
||||
finop ; st8 %i22,208(%sp)
|
||||
finop ; st8 %i23,200(%sp)
|
||||
finop ; st8 %i24,192(%sp)
|
||||
finop ; st8 %i25,184(%sp)
|
||||
finop ; st8 %i26,176(%sp)
|
||||
finop ; st8 %i27,168(%sp)
|
||||
finop ; st8 %i28,160(%sp)
|
||||
finop ; st8 %i29,152(%sp)
|
||||
finop ; st8 %i30,144(%sp)
|
||||
#
|
||||
# FPU already saved, or saving not necessary
|
||||
#
|
||||
|
||||
#
|
||||
# Switch to the stack passed in as fourth argument to the block
|
||||
# routine (%i5) and call the helper routine passed in as the first
|
||||
# argument (%i2). Note that the address of the helper's constant
|
||||
# block is passed in, so we must derefence it to get the helper's text
|
||||
# address.
|
||||
#
|
||||
finop ; movb8_8 %i2,%c10 # helper's ConstBlock
|
||||
finop ; cxnop # Delay slot, fill w/
|
||||
finop ; cxnop # .. 2 st8 from above
|
||||
finop ; ld8 0(%c10),%c4 # load addr of helper
|
||||
finop ; movb8_8 %sp, %i2 # 1st arg to helper
|
||||
# is this stack; other
|
||||
# args remain in regs
|
||||
finop ; movb8_8 %i5,%sp # switch stacks
|
||||
finop ; jsr %c14,16(%c4) # call helper
|
||||
movi8 3, %i0 ; movi8 0,%c8 # nargs brain dmg
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
#
|
||||
# Here is where behavior differs for threads being restored and threads
|
||||
# being started. Blocked threads have a pointer to qt_restore$TXT on
|
||||
# the top of their stacks; manufactured stacks have a pointer to qt_start$TXT
|
||||
# on the top of their stacks. With this setup, starting threads
|
||||
# skip the (unecessary) restore operations.
|
||||
#
|
||||
# We jump to an offset of 16 to either (1) skip past the two noop pairs
|
||||
# at the start of qt_start$TXT, or (2) skip past the two noop pairs
|
||||
# after qt_restore$TXT.
|
||||
#
|
||||
finop ; ld8 8(%sp),%c4
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
finop ; jmp 16(%c4)
|
||||
qt_restore$TXT:
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
#
|
||||
# Point of Restore:
|
||||
#
|
||||
# The helper funtion will return here. Any result it has placed in
|
||||
# a return register (most likely %i0) will not get overwritten below
|
||||
# and will consequently be the return value of the blocking routine.
|
||||
#
|
||||
|
||||
#
|
||||
# CEU registers %c15-%c24, %c26-%c30 (%c14 we restore later)
|
||||
#
|
||||
finop ; ld8 456(%sp),%c15
|
||||
finop ; ld8 448(%sp),%c16
|
||||
finop ; ld8 440(%sp),%c17
|
||||
finop ; ld8 432(%sp),%c18
|
||||
finop ; ld8 424(%sp),%c19
|
||||
finop ; ld8 416(%sp),%c20
|
||||
finop ; ld8 408(%sp),%c21
|
||||
finop ; ld8 400(%sp),%c22
|
||||
finop ; ld8 392(%sp),%c23
|
||||
finop ; ld8 384(%sp),%c24
|
||||
#
|
||||
# %c25 is the Enclosing Frame Pointer (EFP) -- since C doesn't
|
||||
# use nested procedures, we ignore it (leaving a gap, though)
|
||||
#
|
||||
finop ; ld8 368(%sp),%c26
|
||||
finop ; ld8 360(%sp),%c27
|
||||
finop ; ld8 352(%sp),%c28
|
||||
finop ; ld8 344(%sp),%c29
|
||||
finop ; ld8 336(%sp),%c30
|
||||
#
|
||||
# IPU registers %i12-%i30
|
||||
#
|
||||
finop ; ld8 328(%sp),%i12
|
||||
finop ; ld8 320(%sp),%i13
|
||||
finop ; ld8 312(%sp),%i14
|
||||
finop ; ld8 304(%sp),%i15
|
||||
# (gap to get alignment for ld64)
|
||||
# -- Doesn't work on version 1.1.3 of the OS
|
||||
# finop ; ld64 256(%sp),%i16
|
||||
|
||||
finop ; ld8 256(%sp),%i16
|
||||
finop ; ld8 248(%sp),%i17
|
||||
finop ; ld8 240(%sp),%i18
|
||||
finop ; ld8 232(%sp),%i19
|
||||
finop ; ld8 224(%sp),%i20
|
||||
finop ; ld8 216(%sp),%i21
|
||||
finop ; ld8 208(%sp),%i22
|
||||
finop ; ld8 200(%sp),%i23
|
||||
finop ; ld8 192(%sp),%i24
|
||||
finop ; ld8 184(%sp),%i25
|
||||
finop ; ld8 176(%sp),%i26
|
||||
finop ; ld8 168(%sp),%i27
|
||||
finop ; ld8 160(%sp),%i28
|
||||
finop ; ld8 152(%sp),%i29
|
||||
finop ; ld8 144(%sp),%i30
|
||||
|
||||
#
|
||||
# FPU registers don't need to be loaded, or will be loaded by an
|
||||
# enclosing scope (e.g., if this is called by qt_block).
|
||||
#
|
||||
|
||||
#
|
||||
# Load the special registers. We don't load the stack ptr because
|
||||
# the new stack is passed in as an argument, we don't load the EFP
|
||||
# because we don't use it, and we load the return address specially
|
||||
# off the top of the stack.
|
||||
#
|
||||
finop ; ld8 0(%sp),%c14 # return addr
|
||||
finop ; ld8 496(%sp),%cp
|
||||
finop ; ld8 504(%sp),%fp
|
||||
|
||||
finop ; jmp 32(%c14) # jump back to thread
|
||||
finop ; movi8 512,%c5 # stack adjust
|
||||
finop ; sadd8.ntr 0,%sp,%c5,%sp
|
||||
|
||||
.data
|
||||
.half 0x0, 0x0, 0x7ffff000, 0x7fff8000
|
||||
qt_block:
|
||||
.word qt_block$TXT
|
||||
.word qt_error
|
||||
.word qt_error$TXT
|
||||
.word qt_blocki
|
||||
#
|
||||
# Handle saving and restoring the FPU regs, relying on qt_blocki
|
||||
# to save and restore the remaining registers.
|
||||
#
|
||||
.text
|
||||
qt_block$TXT:
|
||||
finop ; cxnop # entry prefix
|
||||
finop ; cxnop # entry prefix
|
||||
|
||||
add8.ntr 29,%i31,%i31 ; movi8 512,%c5 # ICR; stk adjust
|
||||
finop ; ssub8.ntr 0,%sp,%c5,%sp
|
||||
finop ; st8 %fp,504(%sp) # Save caller's fp
|
||||
finop ; st8 %cp,496(%sp) # Save caller's cp
|
||||
finop ; st8 %c14,488(%sp) # store ret addr
|
||||
finop ; sadd8.ntr 0,%sp,%c5,%fp # Our frame ptr
|
||||
finop ; mov8_8 %c10, %cp # Our cp
|
||||
|
||||
#
|
||||
# Store 8 registers at once...destination must be a multiple of 64
|
||||
#
|
||||
finop ; st64 %f16,384(%sp)
|
||||
finop ; st64 %f24,320(%sp)
|
||||
finop ; st64 %f32,256(%sp)
|
||||
finop ; st64 %f40,192(%sp)
|
||||
finop ; st64 %f48,128(%sp)
|
||||
finop ; st64 %f56,64(%sp)
|
||||
|
||||
#
|
||||
# Call the integer blocking routine, passing the arguments passed to us
|
||||
#
|
||||
finop ; ld8 24(%cp), %c10
|
||||
finop ; cxnop
|
||||
finop ; jsr %c14, qt_blocki$TXT
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
movi8 4,%i0 ; movi8 0,%c8 # nargs brain dmg
|
||||
|
||||
#
|
||||
# Load 8 registers at once...source must be a multiple of 64
|
||||
#
|
||||
finop ; ld64 64(%sp),%f56
|
||||
finop ; ld64 128(%sp),%f48
|
||||
finop ; ld64 192(%sp),%f40
|
||||
finop ; ld64 256(%sp),%f32
|
||||
finop ; ld64 320(%sp),%f24
|
||||
finop ; ld64 384(%sp),%f16
|
||||
|
||||
finop ; ld8 488(%sp),%c14
|
||||
finop ; ld8 496(%sp),%cp
|
||||
finop ; ld8 504(%sp),%fp
|
||||
finop ; jmp 32(%c14) # jump back to thread
|
||||
finop ; movi8 512,%c5 # stack adjust
|
||||
finop ; sadd8.ntr 0,%sp,%c5,%sp
|
||||
|
||||
|
||||
.data
|
||||
.half 0x0, 0x0, 0x7ffff000, 0x7fff8000
|
||||
qt_start:
|
||||
.word qt_start$TXT
|
||||
#
|
||||
# A new thread is set up to "appear" as if it were executing code at
|
||||
# the beginning of qt_start and then it called a blocking routine
|
||||
# (qt_blocki). So when a new thread starts to run, it gets unblocked
|
||||
# by the code above and "returns" to `qt_start$TXT' in the
|
||||
# restore step of the switch. Blocked threads jump to 16(qt_restore$TXT),
|
||||
# and starting threads jump to 16(qt_start$TXT).
|
||||
#
|
||||
.text
|
||||
qt_start$TXT:
|
||||
finop ; cxnop #
|
||||
finop ; cxnop #
|
||||
finop ; ld8 40(%sp),%c10 # `only' constant block
|
||||
finop ; ld8 32(%sp),%i4 # `userf' arg.
|
||||
finop ; ld8 24(%sp),%i3 # `t' arg.
|
||||
finop ; ld8 0(%c10),%c4 # `only' text location
|
||||
finop ; ld8 16(%sp),%i2 # `u' arg.
|
||||
finop ; cxnop
|
||||
finop ; jsr %c14,16(%c4) # call `only'
|
||||
#
|
||||
# Pop the frame used to store the thread's initial data
|
||||
#
|
||||
finop ; sadd8.ntr 0,%sp,128,%sp
|
||||
finop ; cxnop
|
||||
movi8 2,%i0 ; movi8 0,%c8 # nargs brain dmg
|
||||
#
|
||||
# If we ever return, it's an error.
|
||||
#
|
||||
finop ; jmp qt_error$TXT
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
movi8 0,%i0 ; movi8 0,%c8 # nargs brain dmg
|
||||
|
||||
|
||||
#
|
||||
# This stuff is broken
|
||||
#
|
||||
.data
|
||||
.half 0x0, 0x0, 0x7ffff000, 0x7fff8000
|
||||
qt_vstart:
|
||||
.word qt_vstart$TXT
|
||||
|
||||
.text
|
||||
qt_vstart$TXT:
|
||||
finop ; cxnop # entry prefix
|
||||
finop ; cxnop # entry prefix
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
add8.ntr 11,%i31,%i31 ; movi8 512,%c5
|
||||
finop ; ssub8.ntr 0,%sp,%c5,%sp # fix stack
|
||||
finop ; ld8 8(%sp),%i2 # load `t' as arg to
|
||||
finop ; cxnop # `startup'
|
||||
finop ; cxnop
|
||||
finop ; ld8 16(%sp),%c10 # `startup' const block
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
finop ; ld8 0(%c10),%c4 # `startup' text loc.
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
finop ; jsr %c14,16(%c4) # call `startup'
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
movi8 1, %i0 ; movi8 0,%c8 # nargs brain dmg
|
||||
#
|
||||
# finop ; sadd 0,%sp,128,%sp # alter stack
|
||||
#
|
||||
finop ; ld8 8(%sp),%i2 # load `t' as arg to
|
||||
finop ; ld8 8(%sp),%i2 # load `t' as arg to
|
||||
finop ; ld8 8(%sp),%i2 # load `t' as arg to
|
||||
finop ; ld8 8(%sp),%i2 # load `t' as arg to
|
||||
|
||||
finop ; ld8 32(%sp),%c10 # `only' constant block
|
||||
finop ; ld8 8(%sp),%i2 # `u' arg.
|
||||
finop ; ld8 16(%sp),%i3 # `t' arg.
|
||||
finop ; ld8 0(%c10),%c4 # `only' text location
|
||||
finop ; ld8 24(%sp),%i4 # `userf' arg.
|
||||
finop ; cxnop
|
||||
finop ; jsr %c4,16(%c4) # call `only'
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
#
|
||||
# If the callee ever calls `nargs', the following instruction (pair)
|
||||
# will be executed. However, we don't know when we compile this code
|
||||
# how many args are being passed. So we give our best guess: 0.
|
||||
#
|
||||
movi8 0,%i0 ; movi8 0,%c8 # nargs brain dmg
|
||||
#
|
||||
# If we ever return, it's an error.
|
||||
#
|
||||
finop ; jmp qt_error$TXT
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
movi8 0,%i0 ; movi8 0,%c8 # nargs brain dmg
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
.file "ksr1_b.s"
|
||||
.def .debug; .endef
|
||||
|
||||
.globl b_call_reg$TXT
|
||||
.globl b_call_reg
|
||||
.globl b_call_imm$TXT
|
||||
.globl b_call_imm
|
||||
.globl b_add$TXT
|
||||
.globl b_add
|
||||
.globl b_load$TXT
|
||||
.globl b_load
|
||||
|
||||
|
||||
b_call_reg:
|
||||
b_call_imm:
|
||||
b_add:
|
||||
b_load:
|
||||
.word b_call_reg$TXT
|
||||
.word qt_error
|
||||
.word qt_error$TXT
|
||||
|
||||
|
||||
b_call_reg$TXT:
|
||||
b_call_imm$TXT:
|
||||
b_add$TXT:
|
||||
b_load$TXT:
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
finop ; ld8 16(%cp),%c4
|
||||
finop ; ld8 8(%cp),%cp
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
finop ; jsr %c4,0(%c4)
|
||||
finop ; cxnop
|
||||
finop ; cxnop
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
#
|
||||
# Hosted compilers for 88k for Meerkat.
|
||||
#
|
||||
CC = gcc88 -Dm88k -ansi -pedantic -Wall -fno-builtin
|
||||
AS = as88
|
111
qt/md/m88k.c
111
qt/md/m88k.c
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "qt.h"
|
||||
|
||||
/* Varargs is harder on the m88k. Parameters are saved on the stack as
|
||||
something like (stack grows down to low memory; low at bottom of
|
||||
picture):
|
||||
|
||||
| :
|
||||
| arg8 <-- va_list.__va_stk
|
||||
+---
|
||||
| :
|
||||
+---
|
||||
| arg7
|
||||
| :
|
||||
| iarg0 <-- va_list.__va_reg
|
||||
+---
|
||||
| :
|
||||
| va_list { __va_arg, __va_stk, __va_reg }
|
||||
| :
|
||||
+---
|
||||
|
||||
Here, `va_list.__va_arg' is the number of word-size arguments
|
||||
that have already been skipped. Doubles must be double-arligned.
|
||||
|
||||
What this means for us is that the user's routine needs to be
|
||||
called with an arg list where some of the words in the `__va_stk'
|
||||
part of the parameter list have to be promoted to registers.
|
||||
|
||||
BUG: doubleword register arguments must be double-aligned. If
|
||||
something is passed as an even # arg and used as an odd # arg or
|
||||
vice-versa, the code in the called routine (in the new thread) that
|
||||
decides how to adjust the index will get it wrong, because it will
|
||||
be expect it to be, say, doubleword aligned and it will really be
|
||||
singleword aligned.
|
||||
|
||||
I'm not sure you can solve this without knowing the types of all
|
||||
the arguments. All in all, we never promised varargs would work
|
||||
reliably. */
|
||||
|
||||
|
||||
|
||||
#define QT_VADJ(sp) (((char *)sp) - QT_VSTKBASE)
|
||||
|
||||
/* Always allocate at least enough space for 8 args; waste some space
|
||||
at the base of the stack to ensure the startup routine doesn't read
|
||||
off the end of the stack. */
|
||||
|
||||
#define QT_VARGS_MD0(sp, vabytes) \
|
||||
((qt_t *)(((char *)(sp)) - 8*4 - QT_STKROUNDUP(vabytes)))
|
||||
|
||||
extern void qt_vstart(void);
|
||||
#define QT_VARGS_MD1(sp) (QT_SPUT (sp, QT_1, qt_vstart))
|
||||
|
||||
|
||||
struct qt_t *
|
||||
qt_vargs (struct qt_t *qsp, int nbytes, void *vargs,
|
||||
void *pt, qt_function_t *startup,
|
||||
qt_function_t *vuserf, qt_function_t *cleanup)
|
||||
{
|
||||
va_list ap;
|
||||
int i;
|
||||
int n; /* Number of words into original arg list. */
|
||||
qt_word_t *sp;
|
||||
int *reg; /* Where to read passed-in-reg args. */
|
||||
int *stk; /* Where to read passed-on-stk args. */
|
||||
|
||||
ap = *(va_list *)vargs;
|
||||
qsp = QT_VARGS_MD0 (qsp, nbytes);
|
||||
sp = (qt_word_t *)qsp;
|
||||
|
||||
reg = (ap.__va_arg < 8)
|
||||
? &ap.__va_reg[ap.__va_arg]
|
||||
: 0;
|
||||
stk = &ap.__va_stk[8];
|
||||
n = ap.__va_arg;
|
||||
for (i=0; i<nbytes/sizeof(qt_word_t) && n<8; ++i,++n) {
|
||||
sp[i] = *reg++;
|
||||
}
|
||||
for (; i<nbytes/sizeof(qt_word_t); ++i) {
|
||||
sp[i] = *stk++;
|
||||
}
|
||||
|
||||
#ifdef QT_NDEF
|
||||
for (i=0; i<nbytes/sizeof(qt_word_t); ++i) {
|
||||
sp[i] = (n < 8)
|
||||
? *reg++
|
||||
: *stk++;
|
||||
++n;
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_VARGS_MD1 (QT_VADJ(sp));
|
||||
QT_SPUT (QT_VADJ(sp), QT_VARGT_INDEX, pt);
|
||||
QT_SPUT (QT_VADJ(sp), QT_VSTARTUP_INDEX, startup);
|
||||
QT_SPUT (QT_VADJ(sp), QT_VUSERF_INDEX, vuserf);
|
||||
QT_SPUT (QT_VADJ(sp), QT_VCLEANUP_INDEX, cleanup);
|
||||
return ((qt_t *)QT_VADJ(sp));
|
||||
}
|
159
qt/md/m88k.h
159
qt/md/m88k.h
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#ifndef QT_M88K_H
|
||||
#define QT_M88K_H
|
||||
|
||||
typedef unsigned long qt_word_t;
|
||||
|
||||
#define QT_GROW_DOWN
|
||||
|
||||
/* Stack layout on the mips:
|
||||
|
||||
Callee-save registers are: $16-$23, $30; $f20-$f30.
|
||||
Also save $31, return pc.
|
||||
|
||||
Non-varargs:
|
||||
|
||||
+---
|
||||
| r30 (fp) on startup === 0
|
||||
| r25
|
||||
| r24
|
||||
| r23
|
||||
| r22
|
||||
| r21
|
||||
| r20
|
||||
| r19
|
||||
| r18
|
||||
| r17 on startup === `only'
|
||||
| r16 on startup === `userf'
|
||||
| r15 on startup === `pt'
|
||||
| r14 on startup === `pu'
|
||||
| r1 on startup === `qt_start'
|
||||
| 0
|
||||
| 0
|
||||
+---
|
||||
| 0
|
||||
| ... (8 regs worth === 32 bytes of homing area)
|
||||
| 0 <--- sp
|
||||
+---
|
||||
|
||||
Conventions for varargs:
|
||||
|
||||
| :
|
||||
| arg8
|
||||
+---
|
||||
| r30 (fp) arg7
|
||||
| r25 arg6
|
||||
| r24 arg5
|
||||
| r23 arg4
|
||||
| r22 arg3
|
||||
| r21 arg2
|
||||
| r20 arg1
|
||||
| r19 arg0
|
||||
| r18
|
||||
| r17 on startup === `startup'
|
||||
| r16 on startup === `vuserf'
|
||||
| r15 on startup === `pt'
|
||||
| r14 on startup === `cleanup'
|
||||
| r1 on startup === `qt_vstart'
|
||||
| 0
|
||||
| 0
|
||||
+---
|
||||
| 0
|
||||
| ... (8 regs worth === 32 bytes of homing area)
|
||||
| 0 <--- sp
|
||||
+---
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* Stack must be doubleword aligned. */
|
||||
#define QT_STKALIGN (16) /* Doubleword aligned. */
|
||||
|
||||
/* How much space is allocated to hold all the crud for
|
||||
initialization: saved registers plus padding to keep the stack
|
||||
aligned plus 8 words of padding to use as a `homing area' (for
|
||||
r2-r9) when calling helper functions on the stack of the (not yet
|
||||
started) thread. The varargs save area is small because it gets
|
||||
overlapped with the top of the parameter list. In case the
|
||||
parameter list is less than 8 args, QT_ARGS_MD0 adds some dead
|
||||
space at the top of the stack. */
|
||||
|
||||
#define QT_STKBASE (16*4 + 8*4)
|
||||
#define QT_VSTKBASE (8*4 + 8*4)
|
||||
|
||||
|
||||
/* Index of various registers. */
|
||||
#define QT_1 (8+2)
|
||||
#define QT_14 (8+3)
|
||||
#define QT_15 (8+4)
|
||||
#define QT_16 (8+5)
|
||||
#define QT_17 (8+6)
|
||||
#define QT_30 (8+15)
|
||||
|
||||
|
||||
/* When a never-before-run thread is restored, the return pc points
|
||||
to a fragment of code that starts the thread running. For
|
||||
non-vargs functions, it sets up arguments and calls the client's
|
||||
`only' function. For varargs functions, the startup code calls the
|
||||
startup, user, and cleanup functions.
|
||||
|
||||
For non-varargs functions, we set the frame pointer to 0 to
|
||||
null-terminate the call chain.
|
||||
|
||||
For varargs functions, the frame pointer register is used to hold
|
||||
one of the arguments, so that all arguments can be laid out in
|
||||
memory by the conventional `qt_vargs' varargs initialization
|
||||
routine.
|
||||
|
||||
The varargs startup routine always reads 8 words of arguments from
|
||||
the stack. If there are less than 8 words of arguments, then the
|
||||
arg list could call off the top of the stack. To prevent fall-off,
|
||||
always allocate 8 words. */
|
||||
|
||||
extern void qt_start(void);
|
||||
#define QT_ARGS_MD(sp) \
|
||||
(QT_SPUT (sp, QT_1, qt_start), \
|
||||
QT_SPUT (sp, QT_30, 0))
|
||||
|
||||
|
||||
/* The m88k uses a struct for `va_list', so pass a pointer to the
|
||||
struct. */
|
||||
|
||||
typedef void (qt_function_t)(void);
|
||||
|
||||
struct qt_t;
|
||||
extern struct qt_t *qt_vargs (struct qt_t *sp, int nbytes,
|
||||
void *vargs, void *pt,
|
||||
qt_function_t *startup,
|
||||
qt_function_t *vuserf,
|
||||
qt_function_t *cleanup);
|
||||
|
||||
#define QT_VARGS(sp, nbytes, vargs, pt, startup, vuserf, cleanup) \
|
||||
(qt_vargs (sp, nbytes, &(vargs), pt, (qt_function_t *)startup, \
|
||||
(qt_function_t *)vuserf, (qt_function_t *)cleanup))
|
||||
|
||||
|
||||
/* The *index* (positive offset) of where to put each value. */
|
||||
#define QT_ONLY_INDEX (QT_17)
|
||||
#define QT_USER_INDEX (QT_16)
|
||||
#define QT_ARGT_INDEX (QT_15)
|
||||
#define QT_ARGU_INDEX (QT_14)
|
||||
|
||||
#define QT_VCLEANUP_INDEX (QT_14)
|
||||
#define QT_VUSERF_INDEX (QT_16)
|
||||
#define QT_VSTARTUP_INDEX (QT_17)
|
||||
#define QT_VARGT_INDEX (QT_15)
|
||||
|
||||
#endif /* ndef QT_M88K_H */
|
132
qt/md/m88k.s
132
qt/md/m88k.s
|
@ -1,132 +0,0 @@
|
|||
/* m88k.s -- assembly support. */
|
||||
|
||||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
/* Callee-save r14..r25, r31(sp), r30(fp). r1 === return pc.
|
||||
* Argument registers r2..r9, return value r2..r3.
|
||||
*
|
||||
* On startup, restore regs so retpc === call to a function to start.
|
||||
*
|
||||
* We're going to call a function (r2) from within the context switch
|
||||
* routine. Call it on the new thread's stack on behalf of the old
|
||||
* thread.
|
||||
*/
|
||||
|
||||
.globl _qt_block
|
||||
.globl _qt_blocki
|
||||
.globl _qt_abort
|
||||
.globl _qt_start
|
||||
.globl _qt_vstart
|
||||
|
||||
/*
|
||||
** r2: ptr to function to call once curr is suspended
|
||||
** and control is on r5's stack.
|
||||
** r3: 1'th arg to *r2.
|
||||
** r4: 2'th arg to *r2.
|
||||
** r5: sp of thread to suspend.
|
||||
**
|
||||
** The helper routine returns a value that is passed on as the
|
||||
** return value from the blocking routine. Since we don't
|
||||
** touch r2 between the helper's return and the end of
|
||||
** function, we get this behavior for free.
|
||||
**
|
||||
** Same entry for integer-only and floating-point, since there
|
||||
** are no separate integer and floating-point registers.
|
||||
**
|
||||
** Each procedure call sets aside a ``home region'' of 8 regs
|
||||
** for r2-r9 for varargs. For context switches we don't use
|
||||
** the ``home region'' for varargs so use it to save regs.
|
||||
** Allocate 64 bytes of save space -- use 32 bytes of register
|
||||
** save area passed in to us plus 32 bytes we allcated, use
|
||||
** the other 32 bytes for save area for a save area to call
|
||||
** the helper function.
|
||||
*/
|
||||
_qt_block:
|
||||
_qt_blocki:
|
||||
sub r31, r31,64 /* Allocate reg save space. */
|
||||
st r1, r31,8+32 /* Save callee-save registers. */
|
||||
st r14, r31,12+32
|
||||
st.d r15, r31,16+32
|
||||
st.d r17, r31,24+32
|
||||
st.d r19, r31,32+32
|
||||
st.d r21, r31,40+32
|
||||
st.d r23, r31,48+32
|
||||
st r25, r31,56+32
|
||||
st r30, r31,60+32
|
||||
|
||||
_qt_abort:
|
||||
addu r14, r31,0 /* Remember old sp. */
|
||||
addu r31, r5,0 /* Set new sp. */
|
||||
jsr.n r2 /* Call helper. */
|
||||
addu r2, r14,0 /* Pass old sp as an arg0 to helper. */
|
||||
|
||||
ld r1, r31,8+32 /* Restore callee-save registers. */
|
||||
ld r14, r31,12+32
|
||||
ld.d r15, r31,16+32
|
||||
ld.d r17, r31,24+32
|
||||
ld.d r19, r31,32+32
|
||||
ld.d r21, r31,40+32
|
||||
ld.d r23, r31,48+32
|
||||
ld r25, r31,56+32
|
||||
ld r30, r31,60+32
|
||||
|
||||
jmp.n r1 /* Return to new thread's caller. */
|
||||
addu r31, r31,64 /* Free register save space. */
|
||||
|
||||
|
||||
/*
|
||||
** Non-varargs thread startup.
|
||||
** See `m88k.h' for register use conventions.
|
||||
*/
|
||||
_qt_start:
|
||||
addu r2, r14,0 /* Set user arg `pu'. */
|
||||
addu r3, r15,0 /* ... user function pt. */
|
||||
jsr.n r17 /* Call `only'. */
|
||||
addu r4, r16,0 /* ... user function userf. */
|
||||
|
||||
bsr _qt_error /* `only' erroniously returned. */
|
||||
|
||||
|
||||
/*
|
||||
** Varargs thread startup.
|
||||
** See `m88k.h' for register use conventions.
|
||||
**
|
||||
** Call the `startup' function with just argument `pt'.
|
||||
** Then call `vuserf' with 8 register args plus any
|
||||
** stack args.
|
||||
** Then call `cleanup' with `pt' and the return value
|
||||
** from `vuserf'.
|
||||
*/
|
||||
_qt_vstart:
|
||||
addu r18, r30,0 /* Remember arg7 to `vuserf'. */
|
||||
addu r30, r0,0 /* Null-terminate call chain. */
|
||||
|
||||
jsr.n r17 /* Call `startup'. */
|
||||
addu r2, r15,0 /* `pt' is arg0 to `startup'. */
|
||||
|
||||
addu r2, r19,0 /* Set arg0. */
|
||||
addu r3, r20,0 /* Set arg1. */
|
||||
addu r4, r21,0 /* Set arg2. */
|
||||
addu r5, r22,0 /* Set arg3. */
|
||||
addu r6, r23,0 /* Set arg4. */
|
||||
addu r7, r24,0 /* Set arg5. */
|
||||
addu r8, r25,0 /* Set arg6. */
|
||||
jsr.n r16 /* Call `vuserf'. */
|
||||
addu r9, r18,0 /* Set arg7. */
|
||||
|
||||
addu r3, r2,0 /* Ret. value is arg1 to `cleanup'. */
|
||||
jsr.n r14 /* Call `cleanup'. */
|
||||
addu r2, r15,0 /* `pt' is arg0 to `cleanup'. */
|
||||
|
||||
bsr _qt_error /* `cleanup' erroniously returned. */
|
117
qt/md/m88k_b.s
117
qt/md/m88k_b.s
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
.text
|
||||
.globl _b_call_reg
|
||||
.globl _b_call_imm
|
||||
.globl _b_add
|
||||
.globl _b_load
|
||||
|
||||
_b_null:
|
||||
jmp r1
|
||||
|
||||
_b_call_reg:
|
||||
subu r31, r31,8 /* Alloc ret pc save space. */
|
||||
st r1, r31,32 /* Save ret pc. */
|
||||
or.u r3, r0,hi16(_b_null) /* Put call addr in a reg. */
|
||||
or r3, r3,lo16(_b_null)
|
||||
jsr r3
|
||||
L0:
|
||||
jsr r3
|
||||
jsr r3
|
||||
jsr r3
|
||||
jsr.n r3
|
||||
subu r2, r2,5 /* Decrement #of iter to go. */
|
||||
bcnd.n gt0,r2,L0
|
||||
jsr r3
|
||||
|
||||
ld r1, r31,32
|
||||
jmp r1
|
||||
|
||||
|
||||
_b_call_imm:
|
||||
subu r31, r31,8 /* Alloc ret pc save space. */
|
||||
st r1, r31,32 /* Save ret pc. */
|
||||
bsr _b_null
|
||||
L1:
|
||||
bsr _b_null
|
||||
bsr _b_null
|
||||
bsr _b_null
|
||||
bsr.n _b_null
|
||||
subu r2, r2,5 /* Decrement #of iter to go. */
|
||||
bcnd.n gt0,r2,L1
|
||||
bsr _b_null
|
||||
|
||||
ld r1, r31,32
|
||||
jmp r1
|
||||
|
||||
_b_add:
|
||||
add r0, r3,r4
|
||||
L2:
|
||||
add r3, r4,r5
|
||||
add r4, r5,r6
|
||||
add r5, r6,r7
|
||||
add r8, r9,r0
|
||||
add r0, r3,r4
|
||||
add r3, r4,r5
|
||||
add r4, r5,r6
|
||||
add r5, r6,r7
|
||||
add r8, r9,r0
|
||||
|
||||
add r0, r3,r4
|
||||
add r3, r4,r5
|
||||
add r4, r5,r6
|
||||
add r5, r6,r7
|
||||
add r8, r9,r0
|
||||
add r0, r3,r4
|
||||
add r3, r4,r5
|
||||
add r4, r5,r6
|
||||
add r5, r6,r7
|
||||
add r8, r9,r0
|
||||
|
||||
subu r2, r2,20 /* Decrement #of iter to go. */
|
||||
bcnd.n gt0,r2,L2
|
||||
add r0, r3,r4
|
||||
|
||||
jmp r1
|
||||
|
||||
|
||||
_b_load:
|
||||
ld r0, r31,0
|
||||
L3:
|
||||
ld r3, r31,4
|
||||
ld r4, r31,8
|
||||
ld r5, r31,12
|
||||
ld r6, r31,16
|
||||
ld r0, r31,0
|
||||
ld r3, r31,4
|
||||
ld r4, r31,8
|
||||
ld r5, r31,12
|
||||
ld r6, r31,16
|
||||
|
||||
ld r0, r31,0
|
||||
ld r3, r31,4
|
||||
ld r4, r31,8
|
||||
ld r5, r31,12
|
||||
ld r6, r31,16
|
||||
ld r0, r31,0
|
||||
ld r3, r31,4
|
||||
ld r4, r31,8
|
||||
ld r5, r31,12
|
||||
ld r6, r31,16
|
||||
|
||||
subu r2, r2,20 /* Decrement #of iter to go. */
|
||||
bcnd.n gt0,r2,L3
|
||||
ld r0, r31,0
|
||||
|
||||
jmp r1
|
|
@ -1,182 +0,0 @@
|
|||
/* mips.s -- assembly support. */
|
||||
|
||||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
/* Callee-save $16-$23, $30-$31.
|
||||
*
|
||||
* $25 is used as a procedure value pointer, used to discover constants
|
||||
* in a callee. Thus, each caller here sets $25 before the call.
|
||||
*
|
||||
* On startup, restore regs so retpc === call to a function to start.
|
||||
* We're going to call a function ($4) from within this routine.
|
||||
* We're passing 3 args, therefore need to allocate 12 extra bytes on
|
||||
* the stack for a save area. The start routine needs a like 16-byte
|
||||
* save area. Must be doubleword aligned (_mips r3000 risc
|
||||
* architecture_, gerry kane, pg d-23).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Assar Westerlund <assar@sics.se> to support Irix 5.x
|
||||
* calling conventions for dynamically-linked code.
|
||||
*/
|
||||
|
||||
/* Make this position-independent code. */
|
||||
.option pic2
|
||||
|
||||
.globl qt_block
|
||||
.globl qt_blocki
|
||||
.globl qt_abort
|
||||
.globl qt_start
|
||||
.globl qt_vstart
|
||||
|
||||
/*
|
||||
** $4: ptr to function to call once curr is suspended
|
||||
** and control is on $7's stack.
|
||||
** $5: 1'th arg to $4.
|
||||
** $6: 2'th arg to $4
|
||||
** $7: sp of thread to suspend.
|
||||
**
|
||||
** Totally gross hack: The MIPS calling convention reserves
|
||||
** 4 words on the stack for a0..a3. This routine "ought" to
|
||||
** allocate space for callee-save registers plus 4 words for
|
||||
** the helper function, but instead we use the 4 words
|
||||
** provided by the function that called us (we don't need to
|
||||
** save our argument registers). So what *appears* to be
|
||||
** allocating only 40 bytes is actually allocating 56, by
|
||||
** using the caller's 16 bytes.
|
||||
**
|
||||
** The helper routine returns a value that is passed on as the
|
||||
** return value from the blocking routine. Since we don't
|
||||
** touch $2 between the helper's return and the end of
|
||||
** function, we get this behavior for free.
|
||||
*/
|
||||
qt_blocki:
|
||||
sub $sp,$sp,40 /* Allocate reg save space. */
|
||||
sw $16, 0+16($sp)
|
||||
sw $17, 4+16($sp)
|
||||
sw $18, 8+16($sp)
|
||||
sw $19,12+16($sp)
|
||||
sw $20,16+16($sp)
|
||||
sw $21,20+16($sp)
|
||||
sw $22,24+16($sp)
|
||||
sw $23,28+16($sp)
|
||||
sw $30,32+16($sp)
|
||||
sw $31,36+16($sp)
|
||||
add $2, $sp,$0 /* $2 <= old sp to pass to func@$4. */
|
||||
qt_abort:
|
||||
add $sp, $7,$0 /* $sp <= new sp. */
|
||||
.set noreorder
|
||||
add $25, $4,$0 /* Set helper function procedure value. */
|
||||
jal $31,$25 /* Call helper func@$4 . */
|
||||
add $4, $2,$0 /* $a0 <= pass old sp as a parameter. */
|
||||
.set reorder
|
||||
lw $31,36+16($sp) /* Restore callee-save regs... */
|
||||
lw $30,32+16($sp)
|
||||
lw $23,28+16($sp)
|
||||
lw $22,24+16($sp)
|
||||
lw $21,20+16($sp)
|
||||
lw $20,16+16($sp)
|
||||
lw $19,12+16($sp)
|
||||
lw $18, 8+16($sp)
|
||||
lw $17, 4+16($sp)
|
||||
lw $16, 0+16($sp) /* Restore callee-save */
|
||||
|
||||
add $sp,$sp,40 /* Deallocate reg save space. */
|
||||
j $31 /* Return to caller. */
|
||||
|
||||
/*
|
||||
** Non-varargs thread startup.
|
||||
** Note: originally, 56 bytes were allocated on the stack.
|
||||
** The thread restore routine (_blocki/_abort) removed 40
|
||||
** of them, which means there is still 16 bytes for the
|
||||
** argument area required by the MIPS calling convention.
|
||||
*/
|
||||
qt_start:
|
||||
add $4, $16,$0 /* Load up user function pu. */
|
||||
add $5, $17,$0 /* ... user function pt. */
|
||||
add $6, $18,$0 /* ... user function userf. */
|
||||
add $25, $19,$0 /* Set `only' procedure value. */
|
||||
jal $31,$25 /* Call `only'. */
|
||||
la $25,qt_error /* Set `qt_error' procedure value. */
|
||||
j $25
|
||||
|
||||
|
||||
/*
|
||||
** Save calle-save floating-point regs $f20-$f30
|
||||
** See comment in `qt_block' about calling conventinos and
|
||||
** reserved space. Use the same trick here, but here we
|
||||
** actually have to allocate all the bytes since we have to
|
||||
** leave 4 words leftover for `qt_blocki'.
|
||||
**
|
||||
** Return value from `qt_block' is the same as the return from
|
||||
** `qt_blocki'. We get that for free since we don't touch $2
|
||||
** between the return from `qt_blocki' and the return from
|
||||
** `qt_block'.
|
||||
*/
|
||||
qt_block:
|
||||
sub $sp, $sp,56 /* 6 8-byte regs, saved ret pc, aligned. */
|
||||
swc1 $f20, 0+16($sp)
|
||||
swc1 $f22, 8+16($sp)
|
||||
swc1 $f24, 16+16($sp)
|
||||
swc1 $f26, 24+16($sp)
|
||||
swc1 $f28, 32+16($sp)
|
||||
swc1 $f30, 40+16($sp)
|
||||
sw $31, 48+16($sp)
|
||||
jal qt_blocki
|
||||
lwc1 $f20, 0+16($sp)
|
||||
lwc1 $f22, 8+16($sp)
|
||||
lwc1 $f24, 16+16($sp)
|
||||
lwc1 $f26, 24+16($sp)
|
||||
lwc1 $f28, 32+16($sp)
|
||||
lwc1 $f30, 40+16($sp)
|
||||
lw $31, 48+16($sp)
|
||||
add $sp, $sp,56
|
||||
j $31
|
||||
|
||||
|
||||
/*
|
||||
** First, call `startup' with the `pt' argument.
|
||||
**
|
||||
** Next, call the user's function with all arguments.
|
||||
** Note that we don't know whether args were passed in
|
||||
** integer regs, fp regs, or on the stack (See Gerry Kane
|
||||
** "MIPS R2000 RISC Architecture" pg D-22), so we reload
|
||||
** all the registers, possibly with garbage arguments.
|
||||
**
|
||||
** Finally, call `cleanup' with the `pt' argument and with
|
||||
** the return value from the user's function. It is an error
|
||||
** for `cleanup' to return.
|
||||
*/
|
||||
qt_vstart:
|
||||
add $4, $17,$0 /* `pt' is arg0 to `startup'. */
|
||||
add $25, $18,$0 /* Set `startup' procedure value. */
|
||||
jal $31, $25 /* Call `startup'. */
|
||||
|
||||
add $sp, $sp,16 /* Free extra save space. */
|
||||
lw $4, 0($sp) /* Load up args. */
|
||||
lw $5, 4($sp)
|
||||
lw $6, 8($sp)
|
||||
lw $7, 12($sp)
|
||||
lwc1 $f12, 0($sp) /* Load up fp args. */
|
||||
lwc1 $f14, 8($sp)
|
||||
add $25, $19,$0 /* Set `userf' procedure value. */
|
||||
jal $31,$25 /* Call `userf'. */
|
||||
|
||||
add $4, $17,$0 /* `pt' is arg0 to `cleanup'. */
|
||||
add $5, $2,$0 /* Ret. val is arg1 to `cleanup'. */
|
||||
add $25, $16,$0 /* Set `cleanup' procedure value. */
|
||||
jal $31, $25 /* Call `cleanup'. */
|
||||
|
||||
la $25,qt_error /* Set `qt_error' procedure value. */
|
||||
j $25
|
134
qt/md/mips.h
134
qt/md/mips.h
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#ifndef QT_MIPS_H
|
||||
#define QT_MIPS_H
|
||||
|
||||
typedef unsigned long qt_word_t;
|
||||
|
||||
#define QT_GROW_DOWN
|
||||
|
||||
/* Stack layout on the mips:
|
||||
|
||||
Callee-save registers are: $16-$23, $30; $f20-$f30.
|
||||
Also save $31, return pc.
|
||||
|
||||
Non-varargs:
|
||||
|
||||
+---
|
||||
| $f30 The first clump is only saved if `qt_block'
|
||||
| $f28 is called, in which case it saves the fp regs
|
||||
| $f26 then calls `qt_blocki' to save the int regs.
|
||||
| $f24
|
||||
| $f22
|
||||
| $f20
|
||||
| $31 === return pc in `qt_block'
|
||||
+---
|
||||
| $31 === return pc; on startup == qt_start
|
||||
| $30
|
||||
| $23
|
||||
| $22
|
||||
| $21
|
||||
| $20
|
||||
| $19 on startup === only
|
||||
| $18 on startup === $a2 === userf
|
||||
| $17 on startup === $a1 === pt
|
||||
| $16 on startup === $a0 === pu
|
||||
| <a3> save area req'd by MIPS calling convention
|
||||
| <a2> save area req'd by MIPS calling convention
|
||||
| <a1> save area req'd by MIPS calling convention
|
||||
| <a0> save area req'd by MIPS calling convention <--- sp
|
||||
+---
|
||||
|
||||
Conventions for varargs:
|
||||
|
||||
| args ...
|
||||
+---
|
||||
| :
|
||||
| :
|
||||
| $21
|
||||
| $20
|
||||
| $19 on startup === `userf'
|
||||
| $18 on startup === `startup'
|
||||
| $17 on startup === `pt'
|
||||
| $16 on startup === `cleanup'
|
||||
| <a3>
|
||||
| <a2>
|
||||
| <a1>
|
||||
| <a0> <--- sp
|
||||
+---
|
||||
|
||||
Note: if we wanted to, we could muck about and try to get the 4
|
||||
argument registers loaded in to, e.g., $22, $23, $30, and $31,
|
||||
and the return pc in, say, $20. Then, the first 4 args would
|
||||
not need to be loaded from memory, they could just use
|
||||
register-to-register copies. */
|
||||
|
||||
|
||||
/* Stack must be doubleword aligned. */
|
||||
#define QT_STKALIGN (8) /* Doubleword aligned. */
|
||||
|
||||
/* How much space is allocated to hold all the crud for
|
||||
initialization: $16-$23, $30, $31. Just do an integer restore,
|
||||
no need to restore floating-point. Four words are needed for the
|
||||
argument save area for the helper function that will be called for
|
||||
the old thread, just before the new thread starts to run. */
|
||||
|
||||
#define QT_STKBASE (14 * 4)
|
||||
#define QT_VSTKBASE QT_STKBASE
|
||||
|
||||
|
||||
/* Offsets of various registers. */
|
||||
#define QT_31 (9+4)
|
||||
#define QT_19 (3+4)
|
||||
#define QT_18 (2+4)
|
||||
#define QT_17 (1+4)
|
||||
#define QT_16 (0+4)
|
||||
|
||||
|
||||
/* When a never-before-run thread is restored, the return pc points
|
||||
to a fragment of code that starts the thread running. For
|
||||
non-vargs functions, it just calls the client's `only' function.
|
||||
For varargs functions, it calls the startup, user, and cleanup
|
||||
functions.
|
||||
|
||||
The varargs startup routine always reads 4 words of arguments from
|
||||
the stack. If there are less than 4 words of arguments, then the
|
||||
startup routine can read off the top of the stack. To prevent
|
||||
errors we always allocate 4 words. If there are more than 3 words
|
||||
of arguments, the 4 preallocated words are simply wasted. */
|
||||
|
||||
extern void qt_start(void);
|
||||
#define QT_ARGS_MD(sp) (QT_SPUT (sp, QT_31, qt_start))
|
||||
|
||||
#define QT_VARGS_MD0(sp, vabytes) \
|
||||
((qt_t *)(((char *)(sp)) - 4*4 - QT_STKROUNDUP(vabytes)))
|
||||
|
||||
extern void qt_vstart(void);
|
||||
#define QT_VARGS_MD1(sp) (QT_SPUT (sp, QT_31, qt_vstart))
|
||||
|
||||
#define QT_VARGS_DEFAULT
|
||||
|
||||
|
||||
/* The *index* (positive offset) of where to put each value. */
|
||||
#define QT_ONLY_INDEX (QT_19)
|
||||
#define QT_USER_INDEX (QT_18)
|
||||
#define QT_ARGT_INDEX (QT_17)
|
||||
#define QT_ARGU_INDEX (QT_16)
|
||||
|
||||
#define QT_VCLEANUP_INDEX (QT_16)
|
||||
#define QT_VUSERF_INDEX (QT_19)
|
||||
#define QT_VSTARTUP_INDEX (QT_18)
|
||||
#define QT_VARGT_INDEX (QT_17)
|
||||
|
||||
#endif /* ndef QT_MIPS_H */
|
164
qt/md/mips.s
164
qt/md/mips.s
|
@ -1,164 +0,0 @@
|
|||
/* mips.s -- assembly support. */
|
||||
|
||||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
/* Callee-save $16-$23, $30-$31.
|
||||
*
|
||||
* On startup, restore regs so retpc === call to a function to start.
|
||||
* We're going to call a function ($4) from within this routine.
|
||||
* We're passing 3 args, therefore need to allocate 12 extra bytes on
|
||||
* the stack for a save area. The start routine needs a like 16-byte
|
||||
* save area. Must be doubleword aligned (_mips r3000 risc
|
||||
* architecture_, gerry kane, pg d-23).
|
||||
*/
|
||||
|
||||
.globl qt_block
|
||||
.globl qt_blocki
|
||||
.globl qt_abort
|
||||
.globl qt_start
|
||||
.globl qt_vstart
|
||||
|
||||
/*
|
||||
** $4: ptr to function to call once curr is suspended
|
||||
** and control is on $7's stack.
|
||||
** $5: 1'th arg to $4.
|
||||
** $6: 2'th arg to $4
|
||||
** $7: sp of thread to suspend.
|
||||
**
|
||||
** Totally gross hack: The MIPS calling convention reserves
|
||||
** 4 words on the stack for a0..a3. This routine "ought" to
|
||||
** allocate space for callee-save registers plus 4 words for
|
||||
** the helper function, but instead we use the 4 words
|
||||
** provided by the function that called us (we don't need to
|
||||
** save our argument registers). So what *appears* to be
|
||||
** allocating only 40 bytes is actually allocating 56, by
|
||||
** using the caller's 16 bytes.
|
||||
**
|
||||
** The helper routine returns a value that is passed on as the
|
||||
** return value from the blocking routine. Since we don't
|
||||
** touch $2 between the helper's return and the end of
|
||||
** function, we get this behavior for free.
|
||||
*/
|
||||
qt_blocki:
|
||||
sub $sp,$sp,40 /* Allocate reg save space. */
|
||||
sw $16, 0+16($sp)
|
||||
sw $17, 4+16($sp)
|
||||
sw $18, 8+16($sp)
|
||||
sw $19,12+16($sp)
|
||||
sw $20,16+16($sp)
|
||||
sw $21,20+16($sp)
|
||||
sw $22,24+16($sp)
|
||||
sw $23,28+16($sp)
|
||||
sw $30,32+16($sp)
|
||||
sw $31,36+16($sp)
|
||||
add $2, $sp,$0 /* $2 <= old sp to pass to func@$4. */
|
||||
qt_abort:
|
||||
add $sp, $7,$0 /* $sp <= new sp. */
|
||||
.set noreorder
|
||||
jal $31,$4 /* Call helper func@$4 . */
|
||||
add $4, $2,$0 /* $a0 <= pass old sp as a parameter. */
|
||||
.set reorder
|
||||
lw $31,36+16($sp) /* Restore callee-save regs... */
|
||||
lw $30,32+16($sp)
|
||||
lw $23,28+16($sp)
|
||||
lw $22,24+16($sp)
|
||||
lw $21,20+16($sp)
|
||||
lw $20,16+16($sp)
|
||||
lw $19,12+16($sp)
|
||||
lw $18, 8+16($sp)
|
||||
lw $17, 4+16($sp)
|
||||
lw $16, 0+16($sp) /* Restore callee-save */
|
||||
|
||||
add $sp,$sp,40 /* Deallocate reg save space. */
|
||||
j $31 /* Return to caller. */
|
||||
|
||||
/*
|
||||
** Non-varargs thread startup.
|
||||
** Note: originally, 56 bytes were allocated on the stack.
|
||||
** The thread restore routine (_blocki/_abort) removed 40
|
||||
** of them, which means there is still 16 bytes for the
|
||||
** argument area required by the MIPS calling convention.
|
||||
*/
|
||||
qt_start:
|
||||
add $4, $16,$0 /* Load up user function pu. */
|
||||
add $5, $17,$0 /* ... user function pt. */
|
||||
add $6, $18,$0 /* ... user function userf. */
|
||||
jal $31,$19 /* Call `only'. */
|
||||
j qt_error
|
||||
|
||||
|
||||
/*
|
||||
** Save calle-save floating-point regs $f20-$f30
|
||||
** See comment in `qt_block' about calling conventinos and
|
||||
** reserved space. Use the same trick here, but here we
|
||||
** actually have to allocate all the bytes since we have to
|
||||
** leave 4 words leftover for `qt_blocki'.
|
||||
**
|
||||
** Return value from `qt_block' is the same as the return from
|
||||
** `qt_blocki'. We get that for free since we don't touch $2
|
||||
** between the return from `qt_blocki' and the return from
|
||||
** `qt_block'.
|
||||
*/
|
||||
qt_block:
|
||||
sub $sp, $sp,56 /* 6 8-byte regs, saved ret pc, aligned. */
|
||||
swc1 $f20, 0+16($sp)
|
||||
swc1 $f22, 8+16($sp)
|
||||
swc1 $f24, 16+16($sp)
|
||||
swc1 $f26, 24+16($sp)
|
||||
swc1 $f28, 32+16($sp)
|
||||
swc1 $f30, 40+16($sp)
|
||||
sw $31, 48+16($sp)
|
||||
jal qt_blocki
|
||||
lwc1 $f20, 0+16($sp)
|
||||
lwc1 $f22, 8+16($sp)
|
||||
lwc1 $f24, 16+16($sp)
|
||||
lwc1 $f26, 24+16($sp)
|
||||
lwc1 $f28, 32+16($sp)
|
||||
lwc1 $f30, 40+16($sp)
|
||||
lw $31, 48+16($sp)
|
||||
add $sp, $sp,56
|
||||
j $31
|
||||
|
||||
|
||||
/*
|
||||
** First, call `startup' with the `pt' argument.
|
||||
**
|
||||
** Next, call the user's function with all arguments.
|
||||
** Note that we don't know whether args were passed in
|
||||
** integer regs, fp regs, or on the stack (See Gerry Kane
|
||||
** "MIPS R2000 RISC Architecture" pg D-22), so we reload
|
||||
** all the registers, possibly with garbage arguments.
|
||||
**
|
||||
** Finally, call `cleanup' with the `pt' argument and with
|
||||
** the return value from the user's function. It is an error
|
||||
** for `cleanup' to return.
|
||||
*/
|
||||
qt_vstart:
|
||||
add $4, $17,$0 /* `pt' is arg0 to `startup'. */
|
||||
jal $31, $18 /* Call `startup'. */
|
||||
|
||||
add $sp, $sp,16 /* Free extra save space. */
|
||||
lw $4, 0($sp) /* Load up args. */
|
||||
lw $5, 4($sp)
|
||||
lw $6, 8($sp)
|
||||
lw $7, 12($sp)
|
||||
lwc1 $f12, 0($sp) /* Load up fp args. */
|
||||
lwc1 $f14, 8($sp)
|
||||
jal $31,$19 /* Call `userf'. */
|
||||
|
||||
add $4, $17,$0 /* `pt' is arg0 to `cleanup'. */
|
||||
add $5, $2,$0 /* Ret. val is arg1 to `cleanup'. */
|
||||
jal $31, $16 /* Call `cleanup'. */
|
||||
|
||||
j qt_error
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
.globl b_call_reg
|
||||
.globl b_call_imm
|
||||
.globl b_add
|
||||
.globl b_load
|
||||
|
||||
.ent b_null
|
||||
b_null:
|
||||
j $31
|
||||
.end b_null
|
||||
|
||||
.ent b_call_reg
|
||||
b_call_reg:
|
||||
la $5,b_null
|
||||
add $6, $31,0
|
||||
$L0:
|
||||
jal $5
|
||||
jal $5
|
||||
jal $5
|
||||
jal $5
|
||||
jal $5
|
||||
|
||||
sub $4, $4,5
|
||||
bgtz $4,$L0
|
||||
j $6
|
||||
.end
|
||||
|
||||
|
||||
.ent b_call_imm
|
||||
b_call_imm:
|
||||
add $6, $31,0
|
||||
$L1:
|
||||
jal b_null
|
||||
jal b_null
|
||||
jal b_null
|
||||
jal b_null
|
||||
jal b_null
|
||||
|
||||
sub $4, $4,5
|
||||
bgtz $4,$L1
|
||||
j $6
|
||||
.end
|
||||
|
||||
|
||||
.ent b_add
|
||||
b_add:
|
||||
add $5, $0,$4
|
||||
add $6, $0,$4
|
||||
add $7, $0,$4
|
||||
add $8, $0,$4
|
||||
$L2:
|
||||
sub $4, $4,5
|
||||
sub $5, $5,5
|
||||
sub $6, $6,5
|
||||
sub $7, $7,5
|
||||
sub $8, $8,5
|
||||
|
||||
sub $4, $4,5
|
||||
sub $5, $5,5
|
||||
sub $6, $6,5
|
||||
sub $7, $7,5
|
||||
sub $8, $8,5
|
||||
|
||||
bgtz $4,$L2
|
||||
j $31
|
||||
.end
|
||||
|
||||
|
||||
.ent b_load
|
||||
b_load:
|
||||
$L3:
|
||||
ld $0, 0($sp)
|
||||
ld $0, 4($sp)
|
||||
ld $0, 8($sp)
|
||||
ld $0, 12($sp)
|
||||
ld $0, 16($sp)
|
||||
|
||||
ld $0, 20($sp)
|
||||
ld $0, 24($sp)
|
||||
ld $0, 28($sp)
|
||||
ld $0, 32($sp)
|
||||
ld $0, 36($sp)
|
||||
|
||||
sub $4, $4,10
|
||||
bgtz $4,$L3
|
||||
j $31
|
||||
.end
|
14
qt/md/null.c
14
qt/md/null.c
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
char const qtmd_rcsid[] = "$Header: /home/ludo/src/guile.cvs/gitification/guile-cvs/guile/guile-core/qt/md/null.c,v 1.1 1996-10-01 03:34:16 mdj Exp $";
|
|
@ -1,19 +0,0 @@
|
|||
Solaris 2.x is like System V (maybe it *is* System V?) and is different
|
||||
from older versions in that it uses no leading underscore for variable
|
||||
and function names. That is, the old convention was:
|
||||
|
||||
foo(){}
|
||||
|
||||
got compiled as
|
||||
|
||||
.globl _foo
|
||||
_foo:
|
||||
|
||||
and is now compiled as
|
||||
|
||||
.globl foo
|
||||
foo:
|
||||
|
||||
The `config' script should fix up the older (leading underscore) versions
|
||||
of the machine-dependent files to use the newer (no leading underscore)
|
||||
calling conventions.
|
140
qt/md/sparc.h
140
qt/md/sparc.h
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#ifndef QT_SPARC_H
|
||||
#define QT_SPARC_H
|
||||
|
||||
typedef unsigned long qt_word_t;
|
||||
|
||||
/* Stack layout on the sparc:
|
||||
|
||||
non-varargs:
|
||||
|
||||
+---
|
||||
| <blank space for alignment>
|
||||
| %o7 == return address -> qt_start
|
||||
| %i7
|
||||
| %i6 == frame pointer -> 0 (NULL-terminated stack frame chain)
|
||||
| %i5 -> only
|
||||
| %i4 -> userf
|
||||
| %i3
|
||||
| %i2 -> pt
|
||||
| %i1 -> pu
|
||||
| %i0
|
||||
| %l7
|
||||
| %l6
|
||||
| %l5
|
||||
| %l4
|
||||
| %l3
|
||||
| %l2
|
||||
| %l1
|
||||
| %l0 <--- qt_t.sp
|
||||
+---
|
||||
|
||||
varargs:
|
||||
|
||||
| :
|
||||
| :
|
||||
| argument list
|
||||
| one-word aggregate return pointer
|
||||
+---
|
||||
| <blank space for alignment>
|
||||
| %o7 == return address -> qt_vstart
|
||||
| %i7
|
||||
| %i6 == frame pointer -> 0 (NULL-terminated stack frame chain)
|
||||
| %i5 -> startup
|
||||
| %i4 -> userf
|
||||
| %i3 -> cleanup
|
||||
| %i2 -> pt
|
||||
| %i1
|
||||
| %i0
|
||||
| %l7
|
||||
| %l6
|
||||
| %l5
|
||||
| %l4
|
||||
| %l3
|
||||
| %l2
|
||||
| %l1
|
||||
| %l0 <--- qt_t.sp
|
||||
+---
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* What to do to start a thread running. */
|
||||
extern void qt_start (void);
|
||||
extern void qt_vstart (void);
|
||||
|
||||
|
||||
/* Hold 17 saved registers + 1 word for alignment. */
|
||||
#define QT_STKBASE (18 * 4)
|
||||
#define QT_VSTKBASE QT_STKBASE
|
||||
|
||||
|
||||
/* Stack must be doubleword aligned. */
|
||||
#define QT_STKALIGN (8) /* Doubleword aligned. */
|
||||
|
||||
#define QT_ONLY_INDEX (QT_I5)
|
||||
#define QT_USER_INDEX (QT_I4)
|
||||
#define QT_ARGT_INDEX (QT_I2)
|
||||
#define QT_ARGU_INDEX (QT_I1)
|
||||
|
||||
#define QT_VSTARTUP_INDEX (QT_I5)
|
||||
#define QT_VUSERF_INDEX (QT_I4)
|
||||
#define QT_VCLEANUP_INDEX (QT_I3)
|
||||
#define QT_VARGT_INDEX (QT_I2)
|
||||
|
||||
#define QT_O7 (16)
|
||||
#define QT_I6 (14)
|
||||
#define QT_I5 (13)
|
||||
#define QT_I4 (12)
|
||||
#define QT_I3 (11)
|
||||
#define QT_I2 (10)
|
||||
#define QT_I1 ( 9)
|
||||
|
||||
|
||||
/* The thread will ``return'' to the `qt_start' routine to get things
|
||||
going. The normal return sequence takes us to QT_O7+8, so we
|
||||
pre-subtract 8. The frame pointer chain is 0-terminated to prevent
|
||||
the trap handler from chasing off in to random memory when flushing
|
||||
stack windows. */
|
||||
|
||||
#define QT_ARGS_MD(top) \
|
||||
(QT_SPUT ((top), QT_O7, ((void *)(((int)qt_start)-8))), \
|
||||
QT_SPUT ((top), QT_I6, 0))
|
||||
|
||||
|
||||
/* The varargs startup routine always reads 6 words of arguments
|
||||
(6 argument registers) from the stack, offset by one word to
|
||||
allow for an aggregate return area pointer. If the varargs
|
||||
routine actually pushed fewer words than that, qt_vstart could read
|
||||
off the top of the stack. To prevent errors, we always allocate 8
|
||||
words. The space is often just wasted. */
|
||||
|
||||
#define QT_VARGS_MD0(sp, vabytes) \
|
||||
((qt_t *)(((char *)(sp)) - 8*4 - QT_STKROUNDUP(vabytes)))
|
||||
|
||||
#define QT_VARGS_MD1(sp) \
|
||||
(QT_SPUT (sp, QT_O7, ((void *)(((int)qt_vstart)-8))))
|
||||
|
||||
/* The SPARC has wierdo calling conventions which stores a hidden
|
||||
parameter for returning aggregate values, so the rest of the
|
||||
parameters are shoved up the stack by one place. */
|
||||
#define QT_VARGS_ADJUST(sp) (((char *)sp)+4)
|
||||
|
||||
#define QT_VARGS_DEFAULT
|
||||
|
||||
|
||||
#define QT_GROW_DOWN
|
||||
|
||||
#endif /* ndef QT_SPARC_H */
|
142
qt/md/sparc.s
142
qt/md/sparc.s
|
@ -1,142 +0,0 @@
|
|||
/* sparc.s -- assembly support for the `qt' thread building kit. */
|
||||
|
||||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
/* #include <machine/trap.h> */
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.global qt_blocki
|
||||
.global qt_block
|
||||
.global qt_abort
|
||||
.global qt_start
|
||||
.global qt_vstart
|
||||
|
||||
/* Register assignment:
|
||||
// %o0: incoming `helper' function to call after cswap
|
||||
// also used as outgoing sp of old thread (qt_t *)
|
||||
// %o1, %o2:
|
||||
// parameters to `helper' function called after cswap
|
||||
// %o3: sp of new thread
|
||||
// %o5: tmp used to save old thread sp, while using %o0
|
||||
// to call `helper' f() after cswap.
|
||||
//
|
||||
//
|
||||
// Aborting a thread is easy if there are no cached register window
|
||||
// frames: just switch to the new stack and away we go. If there are
|
||||
// cached register window frames they must all be written back to the
|
||||
// old stack before we move to the new stack. If we fail to do the
|
||||
// writeback then the old stack memory can be written with register
|
||||
// window contents e.g., after the stack memory has been freed and
|
||||
// reused.
|
||||
//
|
||||
// If you don't believe this, try setting the frame pointer to zero
|
||||
// once we're on the new stack. This will not affect correctnes
|
||||
// otherwise because the frame pointer will eventually get reloaded w/
|
||||
// the new thread's frame pointer. But it will be zero briefly before
|
||||
// the reload. You will eventually (100,000 cswaps later on a small
|
||||
// SPARC machine that I tried) get an illegal instruction trap from
|
||||
// the kernel trying to flush a cached window to location 0x0.
|
||||
//
|
||||
// Solution: flush windows before switching stacks, which invalidates
|
||||
// all the other register windows. We could do the trap
|
||||
// conditionally: if we're in the lowest frame of a thread, the fp is
|
||||
// zero already so we know there's nothing cached. But we expect most
|
||||
// aborts will be done from a first function that does a `save', so we
|
||||
// will rarely save anything and always pay the cost of testing to see
|
||||
// if we should flush.
|
||||
//
|
||||
// All floating-point registers are caller-save, so this routine
|
||||
// doesn't need to do anything to save and restore them.
|
||||
//
|
||||
// `qt_block' and `qt_blocki' return the same value as the value
|
||||
// returned by the helper function. We get this ``for free''
|
||||
// since we don't touch the return value register between the
|
||||
// return from the helper function and return from qt_block{,i}.
|
||||
*/
|
||||
|
||||
qt_block:
|
||||
qt_blocki:
|
||||
sub %sp, 8, %sp /* Allocate save area for return pc. */
|
||||
st %o7, [%sp+64] /* Save return pc. */
|
||||
qt_abort:
|
||||
ta 0x03 /* Save locals and ins. */
|
||||
mov %sp, %o5 /* Remember old sp w/o chng ins/locals. */
|
||||
sub %o3, 64, %sp /* Allocate kwsa, switch stacks. */
|
||||
call %o0, 0 /* Call `helper' routine. */
|
||||
mov %o5, %o0 /* Pass old thread to qt_after_t() */
|
||||
/* .. along w/ args in %o1 & %o2. */
|
||||
|
||||
/* Restore callee-save regs. The kwsa
|
||||
// is on this stack, so offset all
|
||||
// loads by sizeof(kwsa), 64 bytes.
|
||||
*/
|
||||
ldd [%sp+ 0+64], %l0
|
||||
ldd [%sp+ 8+64], %l2
|
||||
ldd [%sp+16+64], %l4
|
||||
ldd [%sp+24+64], %l6
|
||||
ldd [%sp+32+64], %i0
|
||||
ldd [%sp+40+64], %i2
|
||||
ldd [%sp+48+64], %i4
|
||||
ldd [%sp+56+64], %i6
|
||||
ld [%sp+64+64], %o7 /* Restore return pc. */
|
||||
|
||||
retl /* Return to address in %o7. */
|
||||
add %sp, 72, %sp /* Deallocate kwsa, ret pc area. */
|
||||
|
||||
|
||||
/* The function calling conventions say there has to be a 1-word area
|
||||
// in the caller's stack to hold a pointer to space for aggregate
|
||||
// return values. It also says there should be a 6-word area to hold
|
||||
// %o0..%o5 if the callee wants to save them (why? I don't know...)
|
||||
// Round up to 8 words to maintain alignment.
|
||||
//
|
||||
// Parameter values were stored in callee-save regs and are moved to
|
||||
// the parameter registers.
|
||||
*/
|
||||
qt_start:
|
||||
mov %i1, %o0 /* `pu': Set up args to `only'. */
|
||||
mov %i2, %o1 /* `pt'. */
|
||||
mov %i4, %o2 /* `userf'. */
|
||||
call %i5, 0 /* Call client function. */
|
||||
sub %sp, 32, %sp /* Allocate 6-word callee space. */
|
||||
|
||||
call qt_error, 0 /* `only' erroniously returned. */
|
||||
nop
|
||||
|
||||
|
||||
/* Same comments as `qt_start' about allocating rounded-up 7-word
|
||||
// save areas. */
|
||||
|
||||
qt_vstart:
|
||||
sub %sp, 32, %sp /* Allocate 7-word callee space. */
|
||||
call %i5, 0 /* call `startup'. */
|
||||
mov %i2, %o0 /* .. with argument `pt'. */
|
||||
|
||||
add %sp, 32, %sp /* Use 7-word space in varargs. */
|
||||
ld [%sp+ 4+64], %o0 /* Load arg0 ... */
|
||||
ld [%sp+ 8+64], %o1
|
||||
ld [%sp+12+64], %o2
|
||||
ld [%sp+16+64], %o3
|
||||
ld [%sp+20+64], %o4
|
||||
call %i4, 0 /* Call `userf'. */
|
||||
ld [%sp+24+64], %o5
|
||||
|
||||
/* Use 6-word space in varargs. */
|
||||
mov %o0, %o1 /* Pass return value from userf */
|
||||
call %i3, 0 /* .. when call `cleanup. */
|
||||
mov %i2, %o0 /* .. along with argument `pt'. */
|
||||
|
||||
call qt_error, 0 /* `cleanup' erroniously returned. */
|
||||
nop
|
106
qt/md/sparc_b.s
106
qt/md/sparc_b.s
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
.globl b_call_reg
|
||||
.globl b_call_imm
|
||||
.globl b_add
|
||||
.globl b_load
|
||||
|
||||
b_null:
|
||||
retl
|
||||
nop
|
||||
|
||||
b_call_reg:
|
||||
sethi %hi(b_null),%o4
|
||||
or %o4,%lo(b_null),%o4
|
||||
add %o7,%g0, %o3
|
||||
L0:
|
||||
call %o4
|
||||
nop
|
||||
call %o4
|
||||
nop
|
||||
call %o4
|
||||
nop
|
||||
call %o4
|
||||
nop
|
||||
call %o4
|
||||
nop
|
||||
|
||||
subcc %o0,1,%o0
|
||||
bg L0
|
||||
nop
|
||||
add %o3,%g0, %o7
|
||||
retl
|
||||
nop
|
||||
|
||||
b_call_imm:
|
||||
sethi %hi(b_null),%o4
|
||||
or %o4,%lo(b_null),%o4
|
||||
add %o7,%g0, %o3
|
||||
L1:
|
||||
call b_null
|
||||
call b_null
|
||||
call b_null
|
||||
call b_null
|
||||
call b_null
|
||||
|
||||
subcc %o0,1,%o0
|
||||
bg L0
|
||||
nop
|
||||
add %o3,%g0, %o7
|
||||
retl
|
||||
nop
|
||||
|
||||
|
||||
b_add:
|
||||
add %o0,%g0,%o1
|
||||
add %o0,%g0,%o2
|
||||
add %o0,%g0,%o3
|
||||
add %o0,%g0,%o4
|
||||
L2:
|
||||
sub %o0,5,%o0
|
||||
sub %o1,5,%o1
|
||||
sub %o2,5,%o2
|
||||
sub %o3,5,%o3
|
||||
sub %o4,5,%o4
|
||||
|
||||
subcc %o0,5,%o0
|
||||
sub %o1,5,%o1
|
||||
sub %o2,5,%o2
|
||||
sub %o3,5,%o3
|
||||
sub %o4,5,%o4
|
||||
|
||||
bg L2
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
|
||||
|
||||
b_load:
|
||||
ld [%sp+ 0], %g0
|
||||
L3:
|
||||
ld [%sp+ 4],%g0
|
||||
ld [%sp+ 8],%g0
|
||||
ld [%sp+12],%g0
|
||||
ld [%sp+16],%g0
|
||||
ld [%sp+20],%g0
|
||||
ld [%sp+24],%g0
|
||||
ld [%sp+28],%g0
|
||||
ld [%sp+32],%g0
|
||||
ld [%sp+36],%g0
|
||||
|
||||
subcc %o0,10,%o0
|
||||
bg L3
|
||||
ld [%sp+ 0],%g0
|
||||
retl
|
||||
nop
|
130
qt/md/vax.h
130
qt/md/vax.h
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#ifndef QT_VAX_H
|
||||
#define QT_VAX_H
|
||||
|
||||
typedef unsigned long qt_word_t;
|
||||
|
||||
/* Thread's initial stack layout on the VAX:
|
||||
|
||||
non-varargs:
|
||||
|
||||
+---
|
||||
| arg[2] === `userf' on startup
|
||||
| arg[1] === `pt' on startup
|
||||
| arg[0] === `pu' on startup
|
||||
| ... === `only' on startup.
|
||||
+---
|
||||
| ret pc === `qt_start' on startup
|
||||
| fp === 0 on startup
|
||||
| ap === 0 on startup
|
||||
| <mask>
|
||||
| 0 (handler) <--- qt_t.sp
|
||||
+---
|
||||
|
||||
When a non-varargs thread is started, it ``returns'' to the start
|
||||
routine, which calls the client's `only' function.
|
||||
|
||||
The varargs case is clearly bad code. The various values should be
|
||||
stored in a save area and snarfed in to callee-save registers on
|
||||
startup. However, it's too painful to figure out the register
|
||||
mask (right now), so do it the slow way.
|
||||
|
||||
+---
|
||||
| arg[n-1]
|
||||
| ..
|
||||
| arg[0]
|
||||
| nargs
|
||||
+---
|
||||
| === `cleanup'
|
||||
| === `vuserf'
|
||||
| === `startup'
|
||||
| === `pt'
|
||||
+---
|
||||
| ret pc === `qt_start' on startup
|
||||
| fp === 0 on startup
|
||||
| ap === 0 on startup
|
||||
| <mask>
|
||||
| 0 (handler) <--- qt_t.sp
|
||||
+---
|
||||
|
||||
When a varargs thread is started, it ``returns'' to the `qt_vstart'
|
||||
startup code. The startup code pops all the extra arguments, then
|
||||
calls the appropriate functions. */
|
||||
|
||||
|
||||
/* What to do to start a thread running. */
|
||||
extern void qt_start (void);
|
||||
extern void qt_vstart (void);
|
||||
|
||||
|
||||
/* Initial call frame for non-varargs and varargs cases. */
|
||||
#define QT_STKBASE (10 * 4)
|
||||
#define QT_VSTKBASE (9 * 4)
|
||||
|
||||
|
||||
/* Stack "must be" 4-byte aligned. (Actually, no, but it's
|
||||
easiest and probably fastest to do so.) */
|
||||
|
||||
#define QT_STKALIGN (4)
|
||||
|
||||
|
||||
/* Where to place various arguments. */
|
||||
#define QT_ONLY_INDEX (5)
|
||||
#define QT_USER_INDEX (8)
|
||||
#define QT_ARGT_INDEX (7)
|
||||
#define QT_ARGU_INDEX (6)
|
||||
|
||||
#define QT_VSTARTUP_INDEX (6)
|
||||
#define QT_VUSERF_INDEX (7)
|
||||
#define QT_VCLEANUP_INDEX (8)
|
||||
#define QT_VARGT_INDEX (5)
|
||||
|
||||
|
||||
/* Stack grows down. The top of the stack is the first thing to
|
||||
pop off (predecrement, postincrement). */
|
||||
#define QT_GROW_DOWN
|
||||
|
||||
|
||||
extern void qt_error (void);
|
||||
|
||||
#define QT_VAX_GMASK_NOREGS (0)
|
||||
|
||||
/* Push on the error return address, null termination to call chains,
|
||||
number of arguments to `only', register save mask (save no
|
||||
registers). */
|
||||
|
||||
#define QT_ARGS_MD(sto) \
|
||||
(QT_SPUT (sto, 0, 0), \
|
||||
QT_SPUT (sto, 1, QT_VAX_GMASK_NOREGS), \
|
||||
QT_SPUT (sto, 2, 0), \
|
||||
QT_SPUT (sto, 3, 0), \
|
||||
QT_SPUT (sto, 4, qt_start))
|
||||
|
||||
#define QT_VARGS_MD0(sto, nbytes) \
|
||||
(QT_SPUT (sto, (-(nbytes)/4)-1, (nbytes)/4), \
|
||||
((char *)(((sto)-4) - QT_STKROUNDUP(nbytes))))
|
||||
|
||||
#define QT_VARGS_ADJUST(sp) ((char *)sp + 4)
|
||||
|
||||
#define QT_VARGS_MD1(sto) \
|
||||
(QT_SPUT (sto, 0, 0), \
|
||||
QT_SPUT (sto, 1, QT_VAX_GMASK_NOREGS), \
|
||||
QT_SPUT (sto, 2, 0), \
|
||||
QT_SPUT (sto, 3, 0), \
|
||||
QT_SPUT (sto, 4, qt_vstart))
|
||||
|
||||
#define QT_VARGS_DEFAULT
|
||||
|
||||
#endif /* QT_VAX_H */
|
69
qt/md/vax.s
69
qt/md/vax.s
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
.text
|
||||
|
||||
.globl _qt_abort
|
||||
.globl _qt_block
|
||||
.globl _qt_blocki
|
||||
.globl _qt_start
|
||||
.globl _qt_vstart
|
||||
|
||||
|
||||
/*
|
||||
// Calls to these routines have the signature
|
||||
//
|
||||
// void *block (func, arg1, arg2, newsp)
|
||||
//
|
||||
// Since the prologue saves 5 registers, nargs, pc, fp, ap, mask, and
|
||||
// a condition handler (at sp+0), the first argument is 40=4*10 bytes
|
||||
// offset from the stack pointer.
|
||||
*/
|
||||
_qt_block:
|
||||
_qt_blocki:
|
||||
_qt_abort:
|
||||
.word 0x7c0 /* Callee-save mask: 5 registers. */
|
||||
movl 56(sp),r1 /* Get stack pointer of new thread. */
|
||||
movl 52(sp),-(r1) /* Push arg2 */
|
||||
movl 48(sp),-(r1) /* Push arg1 */
|
||||
movl sp,-(r1) /* Push arg0 */
|
||||
|
||||
movl 44(sp),r0 /* Get helper to call. */
|
||||
movl r1,sp /* Move to new thread's stack. */
|
||||
addl3 sp,$12,fp /* .. including the frame pointer. */
|
||||
calls $3,(r0) /* Call helper. */
|
||||
|
||||
ret
|
||||
|
||||
_qt_start:
|
||||
movl (sp)+,r0 /* Get `only'. */
|
||||
calls $3,(r0) /* Call `only'. */
|
||||
calls $0,_qt_error /* `only' erroniously returned. */
|
||||
|
||||
|
||||
_qt_vstart:
|
||||
movl (sp)+,r10 /* Get `pt'. */
|
||||
movl (sp)+,r9 /* Get `startup'. */
|
||||
movl (sp)+,r8 /* Get `vuserf'. */
|
||||
movl (sp)+,r7 /* Get `cleanup'. */
|
||||
|
||||
pushl r10 /* Push `qt'. */
|
||||
calls $1,(r9) /* Call `startup', pop `qt' on return. */
|
||||
|
||||
calls (sp)+,(r8) /* Call user's function. */
|
||||
|
||||
pushl r0 /* Push `vuserf_retval'. */
|
||||
pushl r10 /* Push `qt'. */
|
||||
calls $2,(r7) /* Call `cleanup', never return. */
|
||||
|
||||
calls $0,_qt_error /* `cleanup' erroniously returned. */
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
.text
|
||||
.globl _b_call_reg
|
||||
.globl _b_call_imm
|
||||
.globl _b_add
|
||||
.globl _b_load
|
||||
|
||||
_b_null:
|
||||
.word 0x0
|
||||
ret
|
||||
|
||||
_b_call_reg:
|
||||
.word 0x0
|
||||
movl 4(ap),r0
|
||||
moval _b_null,r1
|
||||
L0:
|
||||
calls $0,(r1)
|
||||
calls $0,(r1)
|
||||
calls $0,(r1)
|
||||
calls $0,(r1)
|
||||
calls $0,(r1)
|
||||
|
||||
subl2 $5,r0
|
||||
bgtr L0
|
||||
ret
|
||||
|
||||
|
||||
_b_call_imm:
|
||||
.word 0x0
|
||||
movl 4(ap),r0
|
||||
L1:
|
||||
calls $0,_b_null
|
||||
calls $0,_b_null
|
||||
calls $0,_b_null
|
||||
calls $0,_b_null
|
||||
calls $0,_b_null
|
||||
|
||||
subl2 $5,r0
|
||||
bgtr L1
|
||||
ret
|
||||
|
||||
|
||||
_b_add:
|
||||
.word 0x0
|
||||
movl 4(ap),r0
|
||||
L2:
|
||||
subl2 $1,r0
|
||||
subl2 $1,r0
|
||||
subl2 $1,r0
|
||||
subl2 $1,r0
|
||||
subl2 $1,r0
|
||||
|
||||
subl2 $1,r0
|
||||
subl2 $1,r0
|
||||
subl2 $1,r0
|
||||
subl2 $1,r0
|
||||
subl2 $1,r0
|
||||
|
||||
bgtr L2
|
||||
ret
|
||||
|
||||
|
||||
_b_load:
|
||||
.word 0x0
|
||||
movl 4(ap),r0
|
||||
L3:
|
||||
movl 0(sp),r1
|
||||
movl 4(sp),r1
|
||||
movl 8(sp),r1
|
||||
movl 12(sp),r1
|
||||
movl 16(sp),r1
|
||||
movl 20(sp),r1
|
||||
movl 24(sp),r1
|
||||
movl 28(sp),r1
|
||||
movl 32(sp),r1
|
||||
movl 36(sp),r1
|
||||
|
||||
subl2 $1,r0
|
||||
bgtr L3
|
||||
ret
|
48
qt/qt.c
48
qt/qt.c
|
@ -1,48 +0,0 @@
|
|||
#include "qt/copyright.h"
|
||||
#include "qt/qt.h"
|
||||
|
||||
#ifdef QT_VARGS_DEFAULT
|
||||
|
||||
/* If the stack grows down, `vargs' is a pointer to the lowest
|
||||
address in the block of arguments. If the stack grows up, it is a
|
||||
pointer to the highest address in the block. */
|
||||
|
||||
qt_t *
|
||||
qt_vargs (qt_t *sp, int nbytes, void *vargs,
|
||||
void *pt, qt_startup_t *startup,
|
||||
qt_vuserf_t *vuserf, qt_cleanup_t *cleanup)
|
||||
{
|
||||
int i;
|
||||
|
||||
sp = QT_VARGS_MD0 (sp, nbytes);
|
||||
#ifdef QT_GROW_UP
|
||||
for (i=nbytes/sizeof(qt_word_t); i>0; --i) {
|
||||
QT_SPUT (QT_VARGS_ADJUST(sp), i, ((qt_word_t *)vargs)[-i]);
|
||||
}
|
||||
#else
|
||||
for (i=nbytes/sizeof(qt_word_t); i>0; --i) {
|
||||
QT_SPUT (QT_VARGS_ADJUST(sp), i-1, ((qt_word_t *)vargs)[i-1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_VARGS_MD1 (QT_VADJ(sp));
|
||||
QT_SPUT (QT_VADJ(sp), QT_VARGT_INDEX, pt);
|
||||
QT_SPUT (QT_VADJ(sp), QT_VSTARTUP_INDEX, startup);
|
||||
QT_SPUT (QT_VADJ(sp), QT_VUSERF_INDEX, vuserf);
|
||||
QT_SPUT (QT_VADJ(sp), QT_VCLEANUP_INDEX, cleanup);
|
||||
return ((qt_t *)QT_VADJ(sp));
|
||||
}
|
||||
#endif /* def QT_VARGS_DEFAULT */
|
||||
|
||||
void
|
||||
qt_null (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
qt_error (void)
|
||||
{
|
||||
extern void abort(void);
|
||||
|
||||
abort();
|
||||
}
|
186
qt/qt.h.in
186
qt/qt.h.in
|
@ -1,186 +0,0 @@
|
|||
#ifndef QT_H
|
||||
#define QT_H
|
||||
|
||||
#if defined (QT_IMPORT)
|
||||
# define QT_API __declspec (dllimport) extern
|
||||
#elif defined (QT_EXPORT) || defined (DLL_EXPORT)
|
||||
# define QT_API __declspec (dllexport) extern
|
||||
#else
|
||||
# define QT_API extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <qt/@qtmd_h@>
|
||||
|
||||
|
||||
/* A QuickThreads thread is represented by it's current stack pointer.
|
||||
To restart a thread, you merely need pass the current sp (qt_t*) to
|
||||
a QuickThreads primitive. `qt_t*' is a location on the stack. To
|
||||
improve type checking, represent it by a particular struct. */
|
||||
|
||||
typedef struct qt_t {
|
||||
char dummy;
|
||||
} qt_t;
|
||||
|
||||
|
||||
/* Alignment is guaranteed to be a power of two. */
|
||||
#ifndef QT_STKALIGN
|
||||
#error "Need to know the machine-dependent stack alignment."
|
||||
#endif
|
||||
|
||||
#define QT_STKROUNDUP(bytes) \
|
||||
(((bytes)+QT_STKALIGN) & ~(QT_STKALIGN-1))
|
||||
|
||||
|
||||
/* Find ``top'' of the stack, space on the stack. */
|
||||
#ifndef QT_SP
|
||||
#ifdef QT_GROW_DOWN
|
||||
#define QT_SP(sto, size) ((qt_t *)(&((char *)(sto))[(size)]))
|
||||
#endif
|
||||
#ifdef QT_GROW_UP
|
||||
#define QT_SP(sto, size) ((void *)(sto))
|
||||
#endif
|
||||
#if !defined(QT_SP)
|
||||
#error "QT_H: Stack must grow up or down!"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* The type of the user function:
|
||||
For non-varargs, takes one void* function.
|
||||
For varargs, takes some number of arguments. */
|
||||
typedef void *(qt_userf_t)(void *pu);
|
||||
typedef void *(qt_vuserf_t)(int arg0, ...);
|
||||
|
||||
/* For non-varargs, just call a client-supplied function,
|
||||
it does all startup and cleanup, and also calls the user's
|
||||
function. */
|
||||
typedef void (qt_only_t)(void *pu, void *pt, qt_userf_t *userf);
|
||||
|
||||
/* For varargs, call `startup', then call the user's function,
|
||||
then call `cleanup'. */
|
||||
typedef void (qt_startup_t)(void *pt);
|
||||
typedef void (qt_cleanup_t)(void *pt, void *vuserf_return);
|
||||
|
||||
|
||||
/* Internal helper for putting stuff on stack. */
|
||||
#ifndef QT_SPUT
|
||||
#define QT_SPUT(top, at, val) \
|
||||
(((qt_word_t *)(top))[(at)] = (qt_word_t)(val))
|
||||
#endif
|
||||
|
||||
|
||||
/* Push arguments for the non-varargs case. */
|
||||
#ifndef QT_ARGS
|
||||
|
||||
#ifndef QT_ARGS_MD
|
||||
#define QT_ARGS_MD (0)
|
||||
#endif
|
||||
|
||||
#ifndef QT_STKBASE
|
||||
#error "Need to know the machine-dependent stack allocation."
|
||||
#endif
|
||||
|
||||
/* All things are put on the stack relative to the final value of
|
||||
the stack pointer. */
|
||||
#ifdef QT_GROW_DOWN
|
||||
#define QT_ADJ(sp) (((char *)sp) - QT_STKBASE)
|
||||
#else
|
||||
#define QT_ADJ(sp) (((char *)sp) + QT_STKBASE)
|
||||
#endif
|
||||
|
||||
#define QT_ARGS(sp, pu, pt, userf, only) \
|
||||
(QT_ARGS_MD (QT_ADJ(sp)), \
|
||||
QT_SPUT (QT_ADJ(sp), QT_ONLY_INDEX, only), \
|
||||
QT_SPUT (QT_ADJ(sp), QT_USER_INDEX, userf), \
|
||||
QT_SPUT (QT_ADJ(sp), QT_ARGT_INDEX, pt), \
|
||||
QT_SPUT (QT_ADJ(sp), QT_ARGU_INDEX, pu), \
|
||||
((qt_t *)QT_ADJ(sp)))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Push arguments for the varargs case.
|
||||
Has to be a function call because initialization is an expression
|
||||
and we need to loop to copy nbytes of stuff on to the stack.
|
||||
But that's probably OK, it's not terribly cheap, anyway. */
|
||||
|
||||
#ifdef QT_VARGS_DEFAULT
|
||||
#ifndef QT_VARGS_MD0
|
||||
#define QT_VARGS_MD0(sp, vasize) (sp)
|
||||
#endif
|
||||
#ifndef QT_VARGS_MD1
|
||||
#define QT_VARGS_MD1(sp) do { ; } while (0)
|
||||
#endif
|
||||
|
||||
#ifndef QT_VSTKBASE
|
||||
#error "Need base stack size for varargs functions."
|
||||
#endif
|
||||
|
||||
/* Sometimes the stack pointer needs to munged a bit when storing
|
||||
the list of arguments. */
|
||||
#ifndef QT_VARGS_ADJUST
|
||||
#define QT_VARGS_ADJUST(sp) (sp)
|
||||
#endif
|
||||
|
||||
/* All things are put on the stack relative to the final value of
|
||||
the stack pointer. */
|
||||
#ifdef QT_GROW_DOWN
|
||||
#define QT_VADJ(sp) (((char *)sp) - QT_VSTKBASE)
|
||||
#else
|
||||
#define QT_VADJ(sp) (((char *)sp) + QT_VSTKBASE)
|
||||
#endif
|
||||
|
||||
QT_API qt_t *qt_vargs (qt_t *sp, int nbytes, void *vargs,
|
||||
void *pt, qt_startup_t *startup,
|
||||
qt_vuserf_t *vuserf, qt_cleanup_t *cleanup);
|
||||
|
||||
#ifndef QT_VARGS
|
||||
#define QT_VARGS(sp, nbytes, vargs, pt, startup, vuserf, cleanup) \
|
||||
(qt_vargs (sp, nbytes, vargs, pt, startup, vuserf, cleanup))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
QT_API void qt_null (void);
|
||||
QT_API void qt_error (void);
|
||||
|
||||
/* Save the state of the thread and call the helper function
|
||||
using the stack of the new thread. */
|
||||
typedef void *(qt_helper_t)(qt_t *old, void *a0, void *a1);
|
||||
typedef void *(qt_block_t)(qt_helper_t *helper, void *a0, void *a1,
|
||||
qt_t *newthread);
|
||||
|
||||
/* Rearrange the parameters so that things passed to the helper
|
||||
function are already in the right argument registers. */
|
||||
#ifndef QT_ABORT
|
||||
QT_API void qt_abort (qt_helper_t *h, void *a0, void *a1, qt_t *newthread);
|
||||
/* The following does, technically, `return' a value, but the
|
||||
user had better not rely on it, since the function never
|
||||
returns. */
|
||||
#define QT_ABORT(h, a0, a1, newthread) \
|
||||
do { qt_abort (h, a0, a1, newthread); } while (0)
|
||||
#endif
|
||||
|
||||
#ifndef QT_BLOCK
|
||||
QT_API void *qt_block (qt_helper_t *h, void *a0, void *a1,
|
||||
qt_t *newthread);
|
||||
#define QT_BLOCK(h, a0, a1, newthread) \
|
||||
(qt_block (h, a0, a1, newthread))
|
||||
#endif
|
||||
|
||||
#ifndef QT_BLOCKI
|
||||
QT_API void *qt_blocki (qt_helper_t *h, void *a0, void *a1,
|
||||
qt_t *newthread);
|
||||
#define QT_BLOCKI(h, a0, a1, newthread) \
|
||||
(qt_blocki (h, a0, a1, newthread))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* Match `extern "C" {' at top. */
|
||||
#endif
|
||||
|
||||
#endif /* ndef QT_H */
|
199
qt/stp.c
199
qt/stp.c
|
@ -1,199 +0,0 @@
|
|||
#include "copyright.h"
|
||||
#include "qt.h"
|
||||
#include "stp.h"
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#define STP_STKSIZE (0x1000)
|
||||
|
||||
/* `alignment' must be a power of 2. */
|
||||
#define STP_STKALIGN(sp, alignment) \
|
||||
((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1)))
|
||||
|
||||
|
||||
/* The notion of a thread is merged with the notion of a queue.
|
||||
Thread stuff: thread status (sp) and stuff to use during
|
||||
(re)initialization. Queue stuff: next thread in the queue
|
||||
(next). */
|
||||
|
||||
struct stp_t {
|
||||
qt_t *sp; /* QuickThreads handle. */
|
||||
void *sto; /* `malloc'-allocated stack. */
|
||||
struct stp_t *next; /* Next thread in the queue. */
|
||||
};
|
||||
|
||||
|
||||
/* A queue is a circular list of threads. The queue head is a
|
||||
designated list element. If this is a uniprocessor-only
|
||||
implementation we can store the `main' thread in this, but in a
|
||||
multiprocessor there are several `heavy' threads but only one run
|
||||
queue. A fancier implementation might have private run queues,
|
||||
which would lead to a simpler (trivial) implementation */
|
||||
|
||||
typedef struct stp_q_t {
|
||||
stp_t t;
|
||||
stp_t *tail;
|
||||
} stp_q_t;
|
||||
|
||||
|
||||
/* Helper functions. */
|
||||
|
||||
extern void *malloc (unsigned size);
|
||||
extern void perror (char const *msg);
|
||||
extern void free (void *sto);
|
||||
|
||||
void *
|
||||
xmalloc (unsigned size)
|
||||
{
|
||||
void *sto;
|
||||
|
||||
sto = malloc (size);
|
||||
if (!sto) {
|
||||
perror ("malloc");
|
||||
exit (1);
|
||||
}
|
||||
return (sto);
|
||||
}
|
||||
|
||||
/* Queue access functions. */
|
||||
|
||||
static void
|
||||
stp_qinit (stp_q_t *q)
|
||||
{
|
||||
q->t.next = q->tail = &q->t;
|
||||
}
|
||||
|
||||
|
||||
static stp_t *
|
||||
stp_qget (stp_q_t *q)
|
||||
{
|
||||
stp_t *t;
|
||||
|
||||
t = q->t.next;
|
||||
q->t.next = t->next;
|
||||
if (t->next == &q->t) {
|
||||
if (t == &q->t) { /* If it was already empty .. */
|
||||
return (NULL); /* .. say so. */
|
||||
}
|
||||
q->tail = &q->t; /* Else now it is empty. */
|
||||
}
|
||||
return (t);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
stp_qput (stp_q_t *q, stp_t *t)
|
||||
{
|
||||
q->tail->next = t;
|
||||
t->next = &q->t;
|
||||
q->tail = t;
|
||||
}
|
||||
|
||||
|
||||
/* Thread routines. */
|
||||
|
||||
static stp_q_t stp_global_runq; /* A queue of runable threads. */
|
||||
static stp_t stp_global_main; /* Thread for the process. */
|
||||
static stp_t *stp_global_curr; /* Currently-executing thread. */
|
||||
|
||||
static void *stp_starthelp (qt_t *old, void *ignore0, void *ignore1);
|
||||
static void stp_only (void *pu, void *pt, qt_userf_t *f);
|
||||
static void *stp_aborthelp (qt_t *sp, void *old, void *null);
|
||||
static void *stp_yieldhelp (qt_t *sp, void *old, void *blockq);
|
||||
|
||||
|
||||
void
|
||||
stp_init()
|
||||
{
|
||||
stp_qinit (&stp_global_runq);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
stp_start()
|
||||
{
|
||||
stp_t *next;
|
||||
|
||||
while ((next = stp_qget (&stp_global_runq)) != NULL) {
|
||||
stp_global_curr = next;
|
||||
QT_BLOCK (stp_starthelp, 0, 0, next->sp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
stp_starthelp (qt_t *old, void *ignore0, void *ignore1)
|
||||
{
|
||||
stp_global_main.sp = old;
|
||||
stp_qput (&stp_global_runq, &stp_global_main);
|
||||
/* return (garbage); */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
stp_create (stp_userf_t *f, void *pu)
|
||||
{
|
||||
stp_t *t;
|
||||
void *sto;
|
||||
|
||||
t = xmalloc (sizeof(stp_t));
|
||||
t->sto = xmalloc (STP_STKSIZE);
|
||||
sto = STP_STKALIGN (t->sto, QT_STKALIGN);
|
||||
t->sp = QT_SP (sto, STP_STKSIZE - QT_STKALIGN);
|
||||
t->sp = QT_ARGS (t->sp, pu, t, (qt_userf_t *)f, stp_only);
|
||||
stp_qput (&stp_global_runq, t);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
stp_only (void *pu, void *pt, qt_userf_t *f)
|
||||
{
|
||||
stp_global_curr = (stp_t *)pt;
|
||||
(*(stp_userf_t *)f)(pu);
|
||||
stp_abort();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
stp_abort (void)
|
||||
{
|
||||
stp_t *old, *newthread;
|
||||
|
||||
newthread = stp_qget (&stp_global_runq);
|
||||
old = stp_global_curr;
|
||||
stp_global_curr = newthread;
|
||||
QT_ABORT (stp_aborthelp, old, (void *)NULL, newthread->sp);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
stp_aborthelp (qt_t *sp, void *old, void *null)
|
||||
{
|
||||
free (((stp_t *)old)->sto);
|
||||
free (old);
|
||||
/* return (garbage); */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
stp_yield()
|
||||
{
|
||||
stp_t *old, *newthread;
|
||||
|
||||
newthread = stp_qget (&stp_global_runq);
|
||||
old = stp_global_curr;
|
||||
stp_global_curr = newthread;
|
||||
QT_BLOCK (stp_yieldhelp, old, &stp_global_runq, newthread->sp);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
stp_yieldhelp (qt_t *sp, void *old, void *blockq)
|
||||
{
|
||||
((stp_t *)old)->sp = sp;
|
||||
stp_qput ((stp_q_t *)blockq, (stp_t *)old);
|
||||
/* return (garbage); */
|
||||
}
|
51
qt/stp.h
51
qt/stp.h
|
@ -1,51 +0,0 @@
|
|||
#ifndef STP_H
|
||||
#define STP_H
|
||||
|
||||
/*
|
||||
* QuickThreads -- Threads-building toolkit.
|
||||
* Copyright (c) 1993 by David Keppel
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice and this notice
|
||||
* appear in all copies. This software is provided as a
|
||||
* proof-of-concept and for demonstration purposes; there is no
|
||||
* representation about the suitability of this software for any
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
typedef struct stp_t stp_t;
|
||||
|
||||
/* Each thread starts by calling a user-supplied function of this
|
||||
type. */
|
||||
|
||||
typedef void (stp_userf_t)(void *p0);
|
||||
|
||||
/* Call this before any other primitives. */
|
||||
extern void stp_init();
|
||||
|
||||
/* When one or more threads are created by the main thread,
|
||||
the system goes multithread when this is called. It is done
|
||||
(no more runable threads) when this returns. */
|
||||
|
||||
extern void stp_start (void);
|
||||
|
||||
/* Create a thread and make it runable. When the thread starts
|
||||
running it will call `f' with the argument `p0'. */
|
||||
|
||||
extern void stp_create (stp_userf_t *f, void *p0);
|
||||
|
||||
/* The current thread stops running but stays runable.
|
||||
It is an error to call `stp_yield' before `stp_start'
|
||||
is called or after `stp_start' returns. */
|
||||
|
||||
extern void stp_yield (void);
|
||||
|
||||
/* Like `stp_yield' but the thread is discarded. Any intermediate
|
||||
state is lost. The thread can also terminate by simply
|
||||
returning. */
|
||||
|
||||
extern void stp_abort (void);
|
||||
|
||||
|
||||
#endif /* ndef STP_H */
|
|
@ -1,24 +0,0 @@
|
|||
## Process this file with automake to produce Makefile.in.
|
||||
##
|
||||
## Copyright (C) 1998, 2006 Free Software Foundation, Inc.
|
||||
##
|
||||
## This file is part of GUILE.
|
||||
##
|
||||
## GUILE is free software; you can redistribute it and/or modify it
|
||||
## under the terms of the GNU Lesser General Public License as
|
||||
## published by the Free Software Foundation; either version 3, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## GUILE is distributed in the hope that it will be useful, but
|
||||
## WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU Lesser General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU Lesser General Public
|
||||
## License along with GUILE; see the file COPYING.LESSER. If not,
|
||||
## write to the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
## Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
AUTOMAKE_OPTIONS = gnu
|
||||
|
||||
EXTRA_DIST = README.time assim cswap go init prim raw
|
|
@ -1,17 +0,0 @@
|
|||
The program `raw', when run in `..' runs the program `run' produced
|
||||
from `meas.c'. It produces a raw output file (see `../tmp/*.raw').
|
||||
`raw' will die with an error if run in the current directory. Note
|
||||
that some versions of `time' produce output in an unexpected format;
|
||||
edit them by hand.
|
||||
|
||||
`prim', `init', `cswap' and `go' produce formatted table entries used
|
||||
in the documentation (in `../doc'). For example, from `..',
|
||||
|
||||
foreach i (tmp/*.raw)
|
||||
time/prim $i
|
||||
end
|
||||
|
||||
See notes in the QuickThreads document about the applicability of
|
||||
these microbenchmark measurements -- in general, you can expect all
|
||||
QuickThreads operations to be a bit slower when used in a real
|
||||
application.
|
|
@ -1,42 +0,0 @@
|
|||
#! /bin/awk -f
|
||||
|
||||
BEGIN {
|
||||
nmach = 0;
|
||||
|
||||
init_test = "1";
|
||||
abort_test = "6";
|
||||
blocki_test = "7";
|
||||
block_test = "8";
|
||||
}
|
||||
|
||||
{
|
||||
mach = $1
|
||||
test = $2
|
||||
iter = $3
|
||||
time = $6 + $8
|
||||
|
||||
if (machi[mach] == 0) {
|
||||
machn[nmach] = mach;
|
||||
machi[mach] = 1;
|
||||
++nmach;
|
||||
}
|
||||
|
||||
us_per_op = time / iter * 1000000
|
||||
times[mach "_" test] = us_per_op;
|
||||
}
|
||||
|
||||
|
||||
END {
|
||||
for (i=0; i<nmach; ++i) {
|
||||
m = machn[i];
|
||||
init = times[m "_" init_test];
|
||||
printf ("init %s | %f\n", m, init);
|
||||
|
||||
init_abort_blocki = times[m "_" abort_test];
|
||||
abort_blocki = init_abort_blocki - init;
|
||||
blocki = times[m "_" blocki_test];
|
||||
abort = abort_blocki - blocki;
|
||||
blockf = times[m "_" block_test];
|
||||
printf ("swap %s | %f | %f | %f\n", m, abort, blocki, blockf);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#! /bin/awk -f
|
||||
|
||||
BEGIN {
|
||||
purpose = "report time used by int only and int+fp cswaps";
|
||||
|
||||
nmach = 0;
|
||||
|
||||
test_int = "7";
|
||||
test_fp = "8";
|
||||
}
|
||||
|
||||
{
|
||||
mach = $1
|
||||
test = $2
|
||||
iter = $3
|
||||
time = $6 + $8
|
||||
|
||||
if (machi[mach] == 0) {
|
||||
machn[nmach] = mach;
|
||||
machi[mach] = 1;
|
||||
++nmach;
|
||||
}
|
||||
|
||||
us_per_op = time / iter * 1000000
|
||||
times[mach "_" test] = us_per_op;
|
||||
}
|
||||
|
||||
|
||||
END {
|
||||
for (i=0; i<nmach; ++i) {
|
||||
m = machn[i];
|
||||
|
||||
integer = times[m "_" test_int];
|
||||
fp = times[m "_" test_fp];
|
||||
printf ("%s|%3.1f|%3.1f\n", m, integer, fp);
|
||||
}
|
||||
}
|
43
qt/time/go
43
qt/time/go
|
@ -1,43 +0,0 @@
|
|||
#! /bin/awk -f
|
||||
|
||||
BEGIN {
|
||||
purpose = "report times used for init/start/stop";
|
||||
|
||||
nmach = 0;
|
||||
|
||||
test_single = "6";
|
||||
test_v0 = "10";
|
||||
test_v2 = "11";
|
||||
test_v4 = "12";
|
||||
test_v8 = "13";
|
||||
}
|
||||
|
||||
{
|
||||
mach = $1
|
||||
test = $2
|
||||
iter = $3
|
||||
time = $6 + $8
|
||||
|
||||
if (machi[mach] == 0) {
|
||||
machn[nmach] = mach;
|
||||
machi[mach] = 1;
|
||||
++nmach;
|
||||
}
|
||||
|
||||
us_per_op = time / iter * 1000000
|
||||
times[mach "_" test] = us_per_op;
|
||||
}
|
||||
|
||||
|
||||
END {
|
||||
for (i=0; i<nmach; ++i) {
|
||||
m = machn[i];
|
||||
|
||||
single = times[m "_" test_single];
|
||||
v0 = times[m "_" test_v0];
|
||||
v2 = times[m "_" test_v2];
|
||||
v4 = times[m "_" test_v4];
|
||||
v8 = times[m "_" test_v8];
|
||||
printf ("%s|%3.1f|%3.1f|%3.1f|%3.1f|%3.1f\n", m, single, v0, v2, v4, v8);
|
||||
}
|
||||
}
|
42
qt/time/init
42
qt/time/init
|
@ -1,42 +0,0 @@
|
|||
#! /bin/awk -f
|
||||
|
||||
BEGIN {
|
||||
purpose = "Report time used to initialize a thread."
|
||||
nmach = 0;
|
||||
|
||||
test_single = "1";
|
||||
test_v0 = "14";
|
||||
test_v2 = "15";
|
||||
test_v4 = "16";
|
||||
test_v8 = "17";
|
||||
}
|
||||
|
||||
{
|
||||
mach = $1
|
||||
test = $2
|
||||
iter = $3
|
||||
time = $6 + $8
|
||||
|
||||
if (machi[mach] == 0) {
|
||||
machn[nmach] = mach;
|
||||
machi[mach] = 1;
|
||||
++nmach;
|
||||
}
|
||||
|
||||
us_per_op = time / iter * 1000000
|
||||
times[mach "_" test] = us_per_op;
|
||||
}
|
||||
|
||||
|
||||
END {
|
||||
for (i=0; i<nmach; ++i) {
|
||||
m = machn[i];
|
||||
|
||||
single = times[m "_" test_single];
|
||||
v0 = times[m "_" test_v0];
|
||||
v2 = times[m "_" test_v2];
|
||||
v4 = times[m "_" test_v4];
|
||||
v8 = times[m "_" test_v8];
|
||||
printf ("%s|%3.1f|%3.1f|%3.1f|%3.1f|%3.1f\n", m, single, v0, v2, v4, v8);
|
||||
}
|
||||
}
|
41
qt/time/prim
41
qt/time/prim
|
@ -1,41 +0,0 @@
|
|||
#! /bin/awk -f
|
||||
|
||||
BEGIN {
|
||||
purpose = "report times for microbenchmarks"
|
||||
|
||||
nmach = 0;
|
||||
|
||||
test_callind = "18";
|
||||
test_callimm = "18";
|
||||
test_addreg = "20";
|
||||
test_loadreg = "21";
|
||||
}
|
||||
|
||||
{
|
||||
mach = $1
|
||||
test = $2
|
||||
iter = $3
|
||||
time = $6 + $8
|
||||
|
||||
if (machi[mach] == 0) {
|
||||
machn[nmach] = mach;
|
||||
machi[mach] = 1;
|
||||
++nmach;
|
||||
}
|
||||
|
||||
ns_per_op = time / iter * 1000000
|
||||
times[mach "_" test] = ns_per_op;
|
||||
}
|
||||
|
||||
|
||||
END {
|
||||
for (i=0; i<nmach; ++i) {
|
||||
m = machn[i];
|
||||
|
||||
ind = times[m "_" test_callind];
|
||||
imm = times[m "_" test_callimm];
|
||||
add = times[m "_" test_addreg];
|
||||
load = times[m "_" test_loadreg];
|
||||
printf ("%s|%1.3f|%1.3f|%1.3f|%1.3f\n", m, ind, imm, add, load);
|
||||
}
|
||||
}
|
58
qt/time/raw
58
qt/time/raw
|
@ -1,58 +0,0 @@
|
|||
#! /bin/csh
|
||||
|
||||
rm -f timed
|
||||
|
||||
set init=1
|
||||
set runone=6
|
||||
set blockint=7
|
||||
set blockfloat=8
|
||||
set vainit0=14
|
||||
set vainit2=15
|
||||
set vainit4=16
|
||||
set vainit8=17
|
||||
set vastart0=10
|
||||
set vastart2=11
|
||||
set vastart4=12
|
||||
set vastart8=13
|
||||
set bench_regcall=18
|
||||
set bench_immcall=19
|
||||
set bench_add=20
|
||||
set bench_load=21
|
||||
|
||||
source configuration
|
||||
|
||||
echo -n $config_machine $init $config_init
|
||||
/bin/time run $init $config_init
|
||||
echo -n $config_machine $runone $config_runone
|
||||
/bin/time run $runone $config_runone
|
||||
echo -n $config_machine $blockint $config_blockint
|
||||
/bin/time run $blockint $config_blockint
|
||||
echo -n $config_machine $blockfloat $config_blockfloat
|
||||
/bin/time run $blockfloat $config_blockfloat
|
||||
|
||||
echo -n $config_machine $vainit0 $config_vainit0
|
||||
/bin/time run $vainit0 $config_vainit0
|
||||
echo -n $config_machine $vainit2 $config_vainit2
|
||||
/bin/time run $vainit2 $config_vainit2
|
||||
echo -n $config_machine $vainit4 $config_vainit4
|
||||
/bin/time run $vainit4 $config_vainit4
|
||||
echo -n $config_machine $vainit8 $config_vainit8
|
||||
/bin/time run $vainit8 $config_vainit8
|
||||
|
||||
echo -n $config_machine $vastart0 $config_vastart0
|
||||
/bin/time run $vastart0 $config_vastart0
|
||||
echo -n $config_machine $vastart2 $config_vastart2
|
||||
/bin/time run $vastart2 $config_vastart2
|
||||
echo -n $config_machine $vastart4 $config_vastart4
|
||||
/bin/time run $vastart4 $config_vastart4
|
||||
echo -n $config_machine $vastart8 $config_vastart8
|
||||
/bin/time run $vastart8 $config_vastart8
|
||||
|
||||
echo -n $config_machine $bench_regcall $config_bcall_reg
|
||||
/bin/time run $bench_regcall $config_bcall_reg
|
||||
echo -n $config_machine $bench_immcall $config_bcall_imm
|
||||
/bin/time run $bench_immcall $config_bcall_imm
|
||||
echo -n $config_machine $bench_add $config_b_add
|
||||
/bin/time run $bench_add $config_b_add
|
||||
echo -n $config_machine $bench_load $config_b_load
|
||||
/bin/time run $bench_load $config_b_load
|
Loading…
Add table
Add a link
Reference in a new issue