Compare commits
113 Commits
unlabeled-
...
distr2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d7ceb6d6c | ||
|
|
d10d14acac | ||
|
|
ca5599714b | ||
|
|
f337b8df6d | ||
|
|
7cd58cabab | ||
|
|
8b4f21bd95 | ||
|
|
ab820d3083 | ||
|
|
fb23d440f0 | ||
|
|
f70b857d1b | ||
|
|
bd07643039 | ||
|
|
686e5af1bb | ||
|
|
34ccddfc2d | ||
|
|
b6f73fdc29 | ||
|
|
c19324dfea | ||
|
|
772b64fabd | ||
|
|
ef92740400 | ||
|
|
ee9c5be180 | ||
|
|
ca9a6feeb0 | ||
|
|
022cb596be | ||
|
|
9eb53c3d47 | ||
|
|
dfcfa9883b | ||
|
|
fb6d291d38 | ||
|
|
e4e29ae837 | ||
|
|
94534b7c15 | ||
|
|
491040b2c7 | ||
|
|
b4adc21f19 | ||
|
|
bae4084355 | ||
|
|
d394fe5dda | ||
|
|
dcfe4e8a97 | ||
|
|
be9e253a2f | ||
|
|
620216fb26 | ||
|
|
70d71f4355 | ||
|
|
6b87f1082e | ||
|
|
fd44c34a61 | ||
|
|
6c247029bd | ||
|
|
6bbdb92784 | ||
|
|
22182c0d7f | ||
|
|
87f66789de | ||
|
|
1879c8e724 | ||
|
|
693830b09a | ||
|
|
e3fa99632e | ||
|
|
b3d11b1fa5 | ||
|
|
2b6187a009 | ||
|
|
a8fc6009f7 | ||
|
|
92141b52ce | ||
|
|
b63f304db1 | ||
|
|
ec3e755168 | ||
|
|
a41ff68078 | ||
|
|
244e172413 | ||
|
|
da936740a6 | ||
|
|
35fae90a9d | ||
|
|
c5a739c68f | ||
|
|
dc92fe358e | ||
|
|
59996174b6 | ||
|
|
84f9364d4c | ||
|
|
a635fb0203 | ||
|
|
e3e1c5ac20 | ||
|
|
e3e9add8b1 | ||
|
|
ffd0d165a7 | ||
|
|
c1d5a0c721 | ||
|
|
3e743d78f3 | ||
|
|
90c847ca59 | ||
|
|
1b162c577e | ||
|
|
a5f4b01d82 | ||
|
|
c5508c7c0b | ||
|
|
80e349860b | ||
|
|
157b243956 | ||
|
|
eabf214312 | ||
|
|
d52117c8dd | ||
|
|
d457c50945 | ||
|
|
b294ab5042 | ||
|
|
9d0812746b | ||
|
|
9f203c9a17 | ||
|
|
0c92039ba4 | ||
|
|
cf6d084155 | ||
|
|
7e6a6f6de2 | ||
|
|
954d3a0326 | ||
|
|
6f6356e0b4 | ||
|
|
9e26d0e0c0 | ||
|
|
bf3ba84e92 | ||
|
|
7a790e48fb | ||
|
|
32bc0f2982 | ||
|
|
fb4a3fd479 | ||
|
|
ccdb8693ee | ||
|
|
a8c5699241 | ||
|
|
e0c4e4b686 | ||
|
|
8a40c25069 | ||
|
|
0fd729951a | ||
|
|
7a30dc4868 | ||
|
|
4b1965afbc | ||
|
|
b2b281f525 | ||
|
|
d2a6847715 | ||
|
|
2690f07cbd | ||
|
|
aa82964563 | ||
|
|
c636aba734 | ||
|
|
ce92663b0a | ||
|
|
a89ba7074f | ||
|
|
a71e706aa4 | ||
|
|
736a2d1022 | ||
|
|
17e13e9e71 | ||
|
|
9d7b94ba34 | ||
|
|
218f7ed718 | ||
|
|
cb0b2e08cf | ||
|
|
c2a990768d | ||
|
|
36537eccc0 | ||
|
|
6cdcb391fb | ||
|
|
9d9c9ae97b | ||
|
|
c478b62711 | ||
|
|
e7f7f33f60 | ||
|
|
c1f3dbba33 | ||
|
|
d5098fe70f | ||
|
|
469d075e77 | ||
|
|
2a4b3fd616 |
14
Action
14
Action
@@ -67,7 +67,7 @@ dir mach/6809
|
||||
indir
|
||||
end
|
||||
name "Intel 8080 support"
|
||||
dir mach/8080
|
||||
dir mach/i80
|
||||
indir
|
||||
end
|
||||
name "2-2 Interpreter support"
|
||||
@@ -90,6 +90,10 @@ name "Motorola 68000 2-4 support"
|
||||
dir mach/m68k2
|
||||
indir
|
||||
end
|
||||
name "Motorola 68000 4-4 support"
|
||||
dir mach/m68k4
|
||||
indir
|
||||
end
|
||||
name "NS16032 support"
|
||||
dir mach/ns
|
||||
indir
|
||||
@@ -102,6 +106,10 @@ name "PMDS support"
|
||||
dir mach/pmds
|
||||
indir
|
||||
end
|
||||
name "PMDS 4/4 support"
|
||||
dir mach/pmds4
|
||||
indir
|
||||
end
|
||||
name "Signetics 2650 support"
|
||||
dir mach/s2650
|
||||
indir
|
||||
@@ -122,10 +130,6 @@ name "Zilog Z8000 support"
|
||||
dir mach/z8000
|
||||
indir
|
||||
end
|
||||
name "Nascom support"
|
||||
dir mach/z80a
|
||||
indir
|
||||
end
|
||||
name "Pascal frontend"
|
||||
dir lang/pc/pem
|
||||
end
|
||||
|
||||
35
Makefile
35
Makefile
@@ -1,35 +0,0 @@
|
||||
cmp: # compile everything and compare
|
||||
(cd etc ; make cmp )
|
||||
(cd util ; make cmp )
|
||||
(cd lang ; make cmp )
|
||||
(cd mach ; make cmp )
|
||||
|
||||
install: # compile everything to machine code
|
||||
(cd etc ; make install )
|
||||
(cd util ; make install )
|
||||
(cd lang/cem ; make install )
|
||||
(cd mach ; make install )
|
||||
(cd lang/pc ; make install )
|
||||
|
||||
clean: # remove all non-sources, except boot-files
|
||||
(cd doc ; make clean )
|
||||
(cd man ; make clean )
|
||||
(cd h ; make clean )
|
||||
(cd etc ; make clean )
|
||||
(cd util ; make clean )
|
||||
(cd lang ; make clean )
|
||||
(cd mach ; make clean )
|
||||
|
||||
opr: # print all sources
|
||||
make pr | opr
|
||||
|
||||
pr: # print all sources
|
||||
@( pr Makefile ; \
|
||||
(cd doc ; make pr ) ; \
|
||||
(cd man ; make pr ) ; \
|
||||
(cd h ; make pr ) ; \
|
||||
(cd etc ; make pr ) ; \
|
||||
(cd lang ; make pr ) ; \
|
||||
(cd util ; make pr ) ; \
|
||||
(cd mach ; make pr ) \
|
||||
)
|
||||
17
NEW
Normal file
17
NEW
Normal file
@@ -0,0 +1,17 @@
|
||||
What's new:
|
||||
A lot of things have changed since that previous distribution.
|
||||
It is not wise to mix files created by the previous version of the Kit
|
||||
with files belonging to this version, although that might sometimes work.
|
||||
The major additions are:
|
||||
- Basic frontend
|
||||
- New codegenerator
|
||||
- LL(1) parser generator
|
||||
- Vax backend with 4-byte wordsize
|
||||
- Motorola 68000 backend with 4-byte wordsize
|
||||
- Motorola 68000 interpreter for 2- and 4-byte wordsize
|
||||
- Z8000 assembler and backend.
|
||||
- 6805 assembler
|
||||
- NatSem 16032 assembler
|
||||
- Intel 8080 backend
|
||||
- Zilog Z80 backend
|
||||
- Signetics 2650 assembler
|
||||
1
bin/em.pascal
Executable file
1
bin/em.pascal
Executable file
@@ -0,0 +1 @@
|
||||
exec /usr/em/doc/em.doc/int/em /usr/em/doc/em.doc/int/tables ${1-e.out} core
|
||||
15
distr/Action
Normal file
15
distr/Action
Normal file
@@ -0,0 +1,15 @@
|
||||
name "Installation manual"
|
||||
dir doc
|
||||
end
|
||||
name "EM documentation"
|
||||
dir doc/em.doc
|
||||
end
|
||||
name "Pascal bootstrap files"
|
||||
dir lang/pc/pem
|
||||
end
|
||||
name "LLgen bootstrap files"
|
||||
dir util/LLgen
|
||||
end
|
||||
name "MSC6500 vend_library"
|
||||
dir mach/6500/libem
|
||||
end
|
||||
6
distr/Action1
Normal file
6
distr/Action1
Normal file
@@ -0,0 +1,6 @@
|
||||
name "vax2/cg bootstrap files"
|
||||
dir mach/vax2/cg
|
||||
end
|
||||
name "vax4/cg bootstrap files"
|
||||
dir mach/vax4/cg
|
||||
end
|
||||
42
distr/Exceptions
Normal file
42
distr/Exceptions
Normal file
@@ -0,0 +1,42 @@
|
||||
-- ./bin/em.pascal no RCS file
|
||||
-- ./doc/em.doc/doc.pr no RCS file
|
||||
-- ./doc/install.pr no RCS file
|
||||
-- ./h/em_mnem.h no RCS file
|
||||
-- ./h/em_pseu.h no RCS file
|
||||
-- ./h/em_spec.h no RCS file
|
||||
-- ./lang/basic/src/y.tab.c no RCS file
|
||||
-- ./lang/basic/src/y.tab.h no RCS file
|
||||
-- ./lang/pc/pem/pem22.m no RCS file
|
||||
-- ./lang/pc/pem/pem24.m no RCS file
|
||||
-- ./lib/LLgen/incl no RCS file
|
||||
-- ./lib/LLgen/rec no RCS file
|
||||
-- ./lib/ix/head_em no RCS file
|
||||
-- ./lib/ix/head_i no RCS file
|
||||
-- ./lib/ix/tail_em no RCS file
|
||||
-- ./lib/ix/tail_em.vend no RCS file
|
||||
-- ./lib/ix/tail_mon no RCS file
|
||||
-- ./mach/6500/libem/tail_em.ve.s.a no RCS file
|
||||
-- ./mach/vax2/cg/tables1.c no RCS file
|
||||
-- ./mach/vax2/cg/tables1.h no RCS file
|
||||
-- ./mach/vax4/cg/tables1.c no RCS file
|
||||
-- ./mach/vax4/cg/tables1.h no RCS file
|
||||
-- ./mach/z80/int/libpc/pc_tail.c.a no RCS file
|
||||
-- ./mkun/pubmac no distr2 yet
|
||||
-- ./mkun/tmac.q no distr2 yet
|
||||
-- ./mkun/tmac.q1 no distr2 yet
|
||||
-- ./mkun/tmac.q2 no distr2 yet
|
||||
-- ./mkun/tmac.q3 no distr2 yet
|
||||
-- ./mkun/tmac.q4 no distr2 yet
|
||||
-- ./mkun/tmac.q5 no distr2 yet
|
||||
-- ./mkun/tmac.q6 no distr2 yet
|
||||
-- ./mkun/tmac.q7 no distr2 yet
|
||||
-- ./mkun/tmac.q8 no distr2 yet
|
||||
-- ./util/LLgen/src/parser no RCS file
|
||||
-- ./util/LLgen/src/LLgen.c no RCS file
|
||||
-- ./util/LLgen/src/Lpars.c no RCS file
|
||||
-- ./util/LLgen/src/Lpars.h no RCS file
|
||||
-- ./util/LLgen/src/tokens.c no RCS file
|
||||
-- ./util/data/em_flag.c no RCS file
|
||||
-- ./util/data/em_mnem.c no RCS file
|
||||
-- ./util/data/em_pseu.c no RCS file
|
||||
-- ./util/data/em_ptyp.c no RCS file
|
||||
74
distr/How_To
Normal file
74
distr/How_To
Normal file
@@ -0,0 +1,74 @@
|
||||
How to make a fresh distribution:
|
||||
For a distribution you need ".distr" files and RCS files.
|
||||
The EM home directory contains a file called ".distr". It contains
|
||||
the names of all the files and directories you want to have in the distribution.
|
||||
The directories should contain .distr files, the other files should
|
||||
be placed under RCS.
|
||||
The current RCS revision name is "distr2".
|
||||
The are files that derive from other files and yet should be placed
|
||||
in the distribution.
|
||||
These files should not be placed under RCS.
|
||||
The file "Exceptions" in this directory contains the current list of
|
||||
these files.
|
||||
|
||||
When all this is correct, use the shell script mktree the extract
|
||||
the distribution from the EM tree.
|
||||
cd /usr/em ; sh distr/mktree destination_tree >distr/f.attf 2>&1
|
||||
Make sure that the destination tree exists and is empty!
|
||||
Failing to do that will almost certainly result in a welter of
|
||||
error messages.
|
||||
The file f.attf contains mktree error messages and should be compared
|
||||
to Exceptions.
|
||||
The actions of mktree are quite complicated. It starts in the current
|
||||
directory reading the ".distr" file, after copying that file to the
|
||||
destination tree.
|
||||
For each file mentioned there it performes certain actions:
|
||||
1- Directory Change to that directory and call yourself recursively.
|
||||
2- File
|
||||
a- Try to do "co -rdistr2 destination_tree/path/destination_file"
|
||||
on succes "chmod +w destination_file"
|
||||
else
|
||||
b- Try to do "co destination_tree/destination_file"
|
||||
on succes "chmod +w destination_file" and
|
||||
give message that says "Missing distr2 entry" (or some such).
|
||||
else
|
||||
c- I Does a file LIST exist in this directory AND
|
||||
is the first line of LIST equal to the name of the
|
||||
destination file? If so, try to extract all the files
|
||||
named in the rest of the LIST file and call the program
|
||||
arch to create a library "arch cr `cat LIST`".
|
||||
In this manner libraries can be distributed whose members
|
||||
have their own RCS file!
|
||||
else
|
||||
II try to do "cp file destination_tree/path/destination_file"
|
||||
on succes give message that says "Missing RCS entry"
|
||||
(or some such).
|
||||
else
|
||||
d-
|
||||
give message that says "Missing entry" (or some such).
|
||||
|
||||
Now you have the tree but not everything is kosher yet.
|
||||
Some files derive from other files in the tree, those derivations should
|
||||
be done with the use of an already installed distribution.
|
||||
The files Action and Action1 in this directory contain the actions
|
||||
we now take. (Confession: most of the time we use /usr/em)
|
||||
One warning, to re-nroff the IR-81 report it takes more then just nroff
|
||||
because most nroff's can't stand that report and stop half-way.
|
||||
The ntroff program does the trick, but only on the 11's.
|
||||
tbl sources | ntroff -Tlp | ntlp
|
||||
|
||||
After running these re-derivation programs the distrubtion tree starts
|
||||
to look like the tree you need.
|
||||
There are too many files there though, especially the files created by
|
||||
the derivation process.
|
||||
That is why we now give the command:
|
||||
dtar cdf distr2 .
|
||||
The file distr2 is the one you should put on tape!
|
||||
But,.... before doing that: Try it out!
|
||||
Repeat the process described in the installation manual.
|
||||
Only if that succeeds you are sure that you included the files needed,
|
||||
and gave all other files the correct "distr2" RCS id.
|
||||
After you sent the tape away, forbid ANYBODY to touch the distr2 id
|
||||
in your RCS files.
|
||||
Good Luck,
|
||||
Ed Keizer, 85/4/15.
|
||||
25
distr/dwalk
Executable file
25
distr/dwalk
Executable file
@@ -0,0 +1,25 @@
|
||||
: ${CDIR=.}
|
||||
if test ! -r .distr
|
||||
then
|
||||
echo ++ no .distr in $CDIR
|
||||
exit 0
|
||||
fi
|
||||
${DS-:} $CDIR
|
||||
for i in `cat .distr`
|
||||
do
|
||||
if test -d $i
|
||||
then
|
||||
( if cd $i
|
||||
then
|
||||
${DD-:} $CDIR $i
|
||||
CDIR=$CDIR/$i
|
||||
export CDIR
|
||||
exec /usr/em/distr/dwalk
|
||||
else
|
||||
echo ++ Could not access $CDIR/$i
|
||||
fi
|
||||
)
|
||||
else
|
||||
${DF-:} $CDIR $i
|
||||
fi
|
||||
done
|
||||
1
distr/echod
Executable file
1
distr/echod
Executable file
@@ -0,0 +1 @@
|
||||
echo $1/$2
|
||||
42
distr/f.attf
Normal file
42
distr/f.attf
Normal file
@@ -0,0 +1,42 @@
|
||||
-- ./bin/em.pascal no RCS file
|
||||
-- ./doc/em.doc/doc.pr no RCS file
|
||||
-- ./doc/install.pr no RCS file
|
||||
-- ./h/em_mnem.h no RCS file
|
||||
-- ./h/em_pseu.h no RCS file
|
||||
-- ./h/em_spec.h no RCS file
|
||||
-- ./lang/basic/src/y.tab.c no RCS file
|
||||
-- ./lang/basic/src/y.tab.h no RCS file
|
||||
-- ./lang/pc/pem/pem22.m no RCS file
|
||||
-- ./lang/pc/pem/pem24.m no RCS file
|
||||
-- ./lib/LLgen/incl no RCS file
|
||||
-- ./lib/LLgen/rec no RCS file
|
||||
-- ./lib/ix/head_em no RCS file
|
||||
-- ./lib/ix/head_i no RCS file
|
||||
-- ./lib/ix/tail_em no RCS file
|
||||
-- ./lib/ix/tail_em.vend no RCS file
|
||||
-- ./lib/ix/tail_mon no RCS file
|
||||
-- ./mach/6500/libem/tail_em.ve.s.a no RCS file
|
||||
-- ./mach/vax2/cg/tables1.c no RCS file
|
||||
-- ./mach/vax2/cg/tables1.h no RCS file
|
||||
-- ./mach/vax4/cg/tables1.c no RCS file
|
||||
-- ./mach/vax4/cg/tables1.h no RCS file
|
||||
-- ./mach/z80/int/libpc/pc_tail.c.a no RCS file
|
||||
-- ./mkun/pubmac no distr2 yet
|
||||
-- ./mkun/tmac.q no distr2 yet
|
||||
-- ./mkun/tmac.q1 no distr2 yet
|
||||
-- ./mkun/tmac.q2 no distr2 yet
|
||||
-- ./mkun/tmac.q3 no distr2 yet
|
||||
-- ./mkun/tmac.q4 no distr2 yet
|
||||
-- ./mkun/tmac.q5 no distr2 yet
|
||||
-- ./mkun/tmac.q6 no distr2 yet
|
||||
-- ./mkun/tmac.q7 no distr2 yet
|
||||
-- ./mkun/tmac.q8 no distr2 yet
|
||||
-- ./util/LLgen/src/parser no RCS file
|
||||
-- ./util/LLgen/src/LLgen.c no RCS file
|
||||
-- ./util/LLgen/src/Lpars.c no RCS file
|
||||
-- ./util/LLgen/src/Lpars.h no RCS file
|
||||
-- ./util/LLgen/src/tokens.c no RCS file
|
||||
-- ./util/data/em_flag.c no RCS file
|
||||
-- ./util/data/em_mnem.c no RCS file
|
||||
-- ./util/data/em_pseu.c no RCS file
|
||||
-- ./util/data/em_ptyp.c no RCS file
|
||||
10
distr/listall
Executable file
10
distr/listall
Executable file
@@ -0,0 +1,10 @@
|
||||
case $# in
|
||||
0) DIR=. ;;
|
||||
1) DIR=$1 ;;
|
||||
*) echo $0 [directory] ; exit 1 ;;
|
||||
esac
|
||||
DD=`pwd`/listall.d
|
||||
DW=`pwd`/dwalk
|
||||
export DD
|
||||
cd $DIR
|
||||
$DW
|
||||
2
distr/listall.d
Executable file
2
distr/listall.d
Executable file
@@ -0,0 +1,2 @@
|
||||
echo "<$1/$2>"
|
||||
ls -bCdx `cat .distr`
|
||||
10
distr/listdirs
Executable file
10
distr/listdirs
Executable file
@@ -0,0 +1,10 @@
|
||||
case $# in
|
||||
0) DIR=. ;;
|
||||
1) DIR=$1 ;;
|
||||
*) echo $0 [directory] ; exit 1 ;;
|
||||
esac
|
||||
DD=`pwd`/echod
|
||||
DW=`pwd`/dwalk
|
||||
export DD
|
||||
cd $DIR
|
||||
$DW
|
||||
9
distr/mka
Executable file
9
distr/mka
Executable file
@@ -0,0 +1,9 @@
|
||||
set -e
|
||||
for i in `tail +2 $DESTDIR/$1/LIST`
|
||||
do
|
||||
${DF-false} $1 $i
|
||||
done
|
||||
cd $DESTDIR/$1
|
||||
arch cr `cat LIST`
|
||||
: I do not remove the files constituating the library, because
|
||||
: they might be present in .distr
|
||||
23
distr/mkf
Executable file
23
distr/mkf
Executable file
@@ -0,0 +1,23 @@
|
||||
if co -q -rdistr2 $DESTDIR/$1/$2 >/dev/null 2>&1
|
||||
then
|
||||
chmod +w $DESTDIR/$1/$2
|
||||
elif co -q $DESTDIR/$1/$2 >/dev/null 2>&1
|
||||
then
|
||||
chmod +w $DESTDIR/$1/$2
|
||||
echo -- $1/$2 no distr2 yet
|
||||
elif grep LIST .distr >/dev/null 2>&1 &&
|
||||
(test "$2" = "`head -1 $DESTDIR/$1/LIST`") >/dev/null 2>&1 &&
|
||||
${DA-false} "$1" "$2"
|
||||
then
|
||||
: Fetched library contents one by one and put them together
|
||||
elif cp $2 $DESTDIR/$1/$2 >/dev/null 2>&1
|
||||
then
|
||||
echo -- $1/$2 no RCS file
|
||||
else
|
||||
echo ++ $1/$2 not present
|
||||
fi
|
||||
case $2 in
|
||||
LIST) if (test -r $DESTDIR/$1/`head -1 $DESTDIR/$1/LIST`) >/dev/null 2>&1
|
||||
then echo ++ LIST files must be in .distr before their libraries!!!
|
||||
fi ;;
|
||||
esac
|
||||
15
distr/mktree
Normal file
15
distr/mktree
Normal file
@@ -0,0 +1,15 @@
|
||||
case $# in
|
||||
1) ;;
|
||||
*) echo $0 directory ; exit 1 ;;
|
||||
esac
|
||||
DDIR=/usr/em/distr
|
||||
case $1 in
|
||||
/*) DESTDIR=$1 ;;
|
||||
*) DESTDIR=`pwd`/$1 ;;
|
||||
esac
|
||||
DS=$DDIR/mks
|
||||
DD=$DDIR/mkd
|
||||
DF=$DDIR/mkf
|
||||
DA=$DDIR/mka
|
||||
export DESTDIR DS DD DF DA
|
||||
$DDIR/dwalk
|
||||
@@ -51,11 +51,8 @@ ordered alphabetically.
|
||||
Appendix A discusses the differences with
|
||||
Microsoft BASIC. Appendix B describes all reserved symbols.
|
||||
Appendix C lists the error messages in use.
|
||||
.sp
|
||||
Additional information about EM and the Amsterdam Compiler Kit
|
||||
can be obtained from .... and found in ......
|
||||
.SH
|
||||
SyNTAX NOTATION
|
||||
SYNTAX NOTATION
|
||||
.LP
|
||||
The conventions for syntax presentation are as follows:
|
||||
.IP CAPS 10
|
||||
@@ -80,8 +77,6 @@ GENERAL INFORMATION
|
||||
The BASIC-EM compiler is designed for a UNIX based environment.
|
||||
It accepts a text file with your BASIC program (suffix .b) and generates
|
||||
an executable file, called a.out.
|
||||
.LP
|
||||
Should we call the preprocessor first?
|
||||
.NH 2
|
||||
LINE FORMAT
|
||||
.LP
|
||||
@@ -145,7 +140,7 @@ Defines a double precision variable
|
||||
Defines a string variable.
|
||||
.LP
|
||||
NOTE: Two variables with the same name but different type is
|
||||
considered illegal (DONE?).
|
||||
considered illegal.
|
||||
.LP
|
||||
Beside single valued variables, values may be grouped
|
||||
into tables or arrays.
|
||||
@@ -542,7 +537,7 @@ MID$
|
||||
MID$(<string expr1>,n[,m])=<string expr2>
|
||||
.PU
|
||||
To replace a portion of a string with another string value.
|
||||
The characters of <string expr> replaces characters in <string expr1>
|
||||
The characters of <string expr2> replaces characters in <string expr1>
|
||||
starting at position n. If m is present, at most m characters are copied,
|
||||
otherwise all characters are copied.
|
||||
However, the string obtained never exceeds the length of string expr1.
|
||||
|
||||
830
doc/i80.doc
Normal file
830
doc/i80.doc
Normal file
@@ -0,0 +1,830 @@
|
||||
." $Header$
|
||||
.RP
|
||||
.TL
|
||||
Back end table for the Intel 8080 micro-processor
|
||||
.AU
|
||||
Gerard Buskermolen
|
||||
.AB
|
||||
A back end is a part of the Amsterdam Compiler Kit (ACK).
|
||||
It translates EM, a family of intermediate languages, into the
|
||||
assembly language of some target machine, here the Intel 8080 and Intel 8085 microprocessors.
|
||||
.AE
|
||||
.NH1
|
||||
INTRODUCTION
|
||||
.PP
|
||||
To simplify the task of producing portable (cross) compilers and
|
||||
interpreters, the Vrije Universiteit designed an integrated collection
|
||||
of programs, the Amsterdam Compiler Kit (ACK).
|
||||
It is based on the old UNCOL-idea ([4]) which attempts to solve the problem
|
||||
of making a compiler for each of
|
||||
.B N
|
||||
languages on
|
||||
.B M
|
||||
different machines without having to write
|
||||
.B N\ *\ M
|
||||
programs.
|
||||
.sp 1
|
||||
The UNCOL approach is to write
|
||||
.B N
|
||||
"front ends", each of which translates one source language into
|
||||
a common intermediate language, UNCOL (UNiversal Computer Oriented
|
||||
Language), and
|
||||
.B M
|
||||
"back ends", each of which translates programs in UNCOL into a
|
||||
specific machine language.
|
||||
Under these conditions, only
|
||||
.B N\ +\ M
|
||||
programs should be written to provide all
|
||||
.B N
|
||||
languages on all
|
||||
.B M
|
||||
machines, instead of
|
||||
.B N\ *\ M
|
||||
programs.
|
||||
.sp 1
|
||||
The intermediate language for the Amsterdam Compiler Kit is the machine
|
||||
language for a simple stack machine called EM (Encoding Machine).
|
||||
So a back end for the Intel 8080 micro translates EM code into
|
||||
8080 assembly language.
|
||||
.sp 1
|
||||
The back end is a single program that is driven by a machine dependent
|
||||
driving table.
|
||||
This driving table, or back end table,
|
||||
defines the mapping from EM code to the machine's assembly language.
|
||||
.NH 1
|
||||
THE 8080 MICRO PROCESSOR
|
||||
.PP
|
||||
This back end table can be used without modification for the Intel 8085
|
||||
processor.
|
||||
Except for two additional instructions, the 8085 instruction set
|
||||
is identical and fully compatible with the 8080 instruction set.
|
||||
So everywhere in this document '8080' can be read as '8080 and 8085'.
|
||||
.NH 2
|
||||
Registers
|
||||
.PP
|
||||
The 8080 processor has an 8 bit accumulator,
|
||||
six general purpose 8-bit registers,
|
||||
a 16 bit programcounter and a 16 bit stackpointer.
|
||||
Assembler programs can refer the accumulator by A and
|
||||
the general purpose registers by B, C, D, E, H and L. (*)
|
||||
.FS
|
||||
* In this document 8080 registers and mnemonics are referenced by capitals, for the sake of clarity.
|
||||
Nevertheless the assembler expects small letters.
|
||||
.FE
|
||||
Several instructions address registers in groups of two, thus creating
|
||||
16 bit registers:
|
||||
.DS
|
||||
Registers referenced: Symbolic reference:
|
||||
B and C B
|
||||
D and E D
|
||||
H and L H
|
||||
.DE
|
||||
The first named register, contains the high order byte
|
||||
(H and L stand for High and Low).
|
||||
.br
|
||||
The instruction determines how the processor interprets the reference.
|
||||
For example, ADD B is an 8 bit operation, adding the contents of
|
||||
register B to accumulator A. By contrast PUSH B is a 16 bit operation
|
||||
pushing B and C onto the stack.
|
||||
.sp 1
|
||||
There are no index registers.
|
||||
.sp 1
|
||||
.NH 2
|
||||
Flip-flops
|
||||
.PP
|
||||
The 8080 microprocessor provides five flip-flops used as condition flags
|
||||
(S, Z, P, C, AC) and one interrupt enable flip-flop IE.
|
||||
.br
|
||||
The sign bit S is set (cleared) by certain instructions when the most significant
|
||||
bit of the result of an operation equals one (zero).
|
||||
.br
|
||||
The zero bit Z is set (cleared) by certain operations when the
|
||||
8-bit result of an operation equals (does not equal) zero.
|
||||
.br
|
||||
The parity bit P is set (cleared) if the 8-bit result of an
|
||||
operation includes an even (odd) number of ones.
|
||||
.br
|
||||
C is the normal carry bit.
|
||||
.br
|
||||
AC is an auxiliary carry that indicates whether there has been a carry
|
||||
out of bit 3 of the accumulator.
|
||||
This auxiliary carry is used only by the DAA instruction, which
|
||||
adjusts the 8-bit value in the accumulator to form two 4-bit
|
||||
binary coded decimal digits.
|
||||
Needless to say this instruction is not used in the back-end.
|
||||
.sp 1
|
||||
The interrupt enable flip-flop IE is set and cleared under
|
||||
program control using the instructions EI (Enable Interrupt) and
|
||||
DI (Disable Interrupt).
|
||||
It is automatically cleared when the CPU is reset and when
|
||||
an interrupt occurs, disabling further interrupts until IE = 1 again.
|
||||
.NH 2
|
||||
Addressing modes
|
||||
.NH 3
|
||||
Implied addressing
|
||||
.PP
|
||||
The addressing mode of some instructions is implied by the instruction itself.
|
||||
For example, the RAL (rotate accumulator left) instruction deals only with
|
||||
the accumulator, and PCHL loads the programcounter with the contents
|
||||
of register-pair HL.
|
||||
.NH 3
|
||||
Register addressing
|
||||
.PP
|
||||
|
||||
With each intruction using register addressing,
|
||||
only one register is specified (except for the MOV instruction),
|
||||
although in many of them the accumulator is implied as
|
||||
second operand.
|
||||
Examples are CMP E, which compares register E with the accumulator,
|
||||
and DCR B, which decrements register B.
|
||||
.br
|
||||
A few instructions deal with 16 bit register-pairs:
|
||||
examples are DCX B, which decrements register-pair BC and the
|
||||
PUSH and POP instructions.
|
||||
.NH 3
|
||||
Register indirect addressing
|
||||
.PP
|
||||
Each instruction that may refer to an 8 bit register, may
|
||||
refer also to a memory location. In this case the letter M
|
||||
(for Memory) has to be used instead of a register.
|
||||
It indicates the memory location pointed to by H and L,
|
||||
so ADD M adds the contents of the memory location specified
|
||||
by H and L to the contents of the accumulator.
|
||||
.br
|
||||
The register-pairs BC and DE can also be used for indirect addressing,
|
||||
but only to load or store the accumulator.
|
||||
For example, STAX B stores the contents of the accumulator
|
||||
into the memory location addressed by register-pair BC.
|
||||
.NH 3
|
||||
Immediate addressing
|
||||
.PP
|
||||
The immediate value can be an 8 bit value, as in ADI 10 which
|
||||
adds 10 to the accumulator, or a 16 bit value, as in
|
||||
LXI H,1000, which loads 1000 in the register-pair HL.
|
||||
.NH 3
|
||||
Direct addressing
|
||||
.PP
|
||||
Jump instructions include a 16 bit address as part of the instruction.
|
||||
.br
|
||||
The instruction SHLD 1234 stores the contents of register
|
||||
pair HL on memory locations 1234 and 1235.
|
||||
The high order byte is stored at the highest address.
|
||||
.NH 1
|
||||
THE 8080 BACK END TABLE
|
||||
.PP
|
||||
The back end table is designed as described in [5].
|
||||
So for an overall design of a back end table I refer to this document.
|
||||
.br
|
||||
This section deals with problems encountered in writing the
|
||||
8080 back-end table.
|
||||
Some remarks are made about particular parts
|
||||
of the table that might not seem clear at first sight.
|
||||
.NH 2
|
||||
Constant definitions
|
||||
.PP
|
||||
Word size (EM_WSIZE) and pointer size (EM_PSIZE) are both
|
||||
defined as two bytes.
|
||||
The hole between AB and LB (EM_BSIZE) is four bytes: only the
|
||||
return address and the localbase are saved.
|
||||
.NH 2
|
||||
Registers and their properties
|
||||
.PP
|
||||
All properties have the default size of two bytes, because one-byte
|
||||
registers also cover two bytes when put on the real stack.
|
||||
.sp 1
|
||||
The next considerations led to the choise of register-pair BC
|
||||
as localbase.
|
||||
Though saving the localbase in memory would leave one more register-pair
|
||||
available as scratch register, it would slow down instructions
|
||||
as 'lol' and 'stl' too much.
|
||||
So a register-pair should be sacrificed as localbase.
|
||||
Because a back-end without a free register-pair HL is completely
|
||||
broken-winged, the only reasonable choises are BC and DE.
|
||||
Though the choise between them might seem arbitrary at first sight,
|
||||
there is a difference between register-pairs BC and DE:
|
||||
the instruction XCHG exchanges the contents of register-pairs DE and
|
||||
HL.
|
||||
When DE and HL are both heavily used on the fake-stack, this instruction
|
||||
is very usefull.
|
||||
Since it won't be usefull too often to exchange HL with the localbase
|
||||
and since an instruction exchanging BC and HL does not exist, BC is
|
||||
chosen as localbase.
|
||||
.sp 1
|
||||
Many of the register properties are never mentioned in the
|
||||
PATTERNS part of the table.
|
||||
They are only needed to define the INSTRUCTIONS correctly.
|
||||
.sp 1
|
||||
The properties really used in the PATTERNS part are:
|
||||
.IP areg: 24
|
||||
the accumulator only
|
||||
.IP reg:
|
||||
any of the registers A, D, E, H or L. Of course the registers B and C which are
|
||||
used as localbase don't possess this property.
|
||||
When there is a single register on the fake-stack, its value
|
||||
is always considered non-negative.
|
||||
.IP dereg:
|
||||
register-pair DE only
|
||||
.IP hlreg:
|
||||
register-pair HL only
|
||||
.IP hl_or_de:
|
||||
register-pairs HL and DE both have this property
|
||||
.IP localbase:
|
||||
used only once (i.e. in the EM-instruction 'str 0')
|
||||
.PP
|
||||
.sp 1
|
||||
The stackpointer SP and the processor status word PSW have to be
|
||||
defined explicitely because they are needed in some instructions
|
||||
(i.e. SP in LXI, DCX and INX and PSW in PUSH and POP).
|
||||
.br
|
||||
It doesn't matter that the processor status word is not just register A
|
||||
but includes the condition flags.
|
||||
.NH 2
|
||||
Tokens
|
||||
.PP
|
||||
The tokens 'm' and 'const1' are used in the INSTRUCTIONS- and MOVES parts only.
|
||||
They will never be on the fake-stack.
|
||||
.sp 1
|
||||
The token 'label' reflects addresses known at assembly time.
|
||||
It is used to take full profit of the instructions LHLD
|
||||
(Load HL Direct) and SHLD (Store HL Direct).
|
||||
.sp 1
|
||||
Compared with many other back-end tables, there are only a small number of
|
||||
different tokens (four).
|
||||
Reasons are the limited addressing modes of the 8080 microprocessor,
|
||||
no index registers etc.
|
||||
.br
|
||||
For example to translate the EM-instruction
|
||||
.DS
|
||||
lol 10
|
||||
.DE
|
||||
the next 8080 instructions are generated:
|
||||
.DS L
|
||||
LXI H,10 /* load registers pair HL with value 10 */
|
||||
DAD B /* add localbase (BC) to HL */
|
||||
MOV E,M /* load E with byte pointed to by HL */
|
||||
INX H /* increment HL */
|
||||
MOV D,M /* load D with next byte */
|
||||
.DE
|
||||
Of course, instead of emitting code immmediately, it could be postponed
|
||||
by placing something like a {LOCAL,10} on the fake-stack, but some day the above
|
||||
mentioned code will have to be generated, so a LOCAL-token is
|
||||
hardly usefull.
|
||||
.br
|
||||
See also the comment on the load instructions.
|
||||
.NH 2
|
||||
Sets
|
||||
.PP
|
||||
Only 'src1or2' is used in the PATTERNS.
|
||||
.NH 2
|
||||
Instructions
|
||||
.PP
|
||||
Each instruction indicates whether or not the condition flags
|
||||
are affected, but this information will never have any influence
|
||||
because there are no tests in the PATTERNS part of the table.
|
||||
.sp 1
|
||||
For each instruction a cost vector indicates the number of bytes
|
||||
the instruction occupies and the number of time periods it takes
|
||||
to execute the instruction.
|
||||
The length of a time period depends on the clock frequency
|
||||
and may range from 480 nanoseconds to 2 microseconds on a
|
||||
8080 system and from 320 nanoseconds to 2 microseconds
|
||||
on a 8085 system.
|
||||
.sp 1
|
||||
In the TOKENS-part the cost of token 'm' is defined as (0,3).
|
||||
In fact it usually takes 3 extra time periods when this register indirect mode
|
||||
is used instead of register mode, but since the costs are not completely
|
||||
orthogonal this results in small deficiencies for the DCR, INR and MOV
|
||||
instructions.
|
||||
Although it is not particularly usefull these deficiencies are
|
||||
corrected in the INSTRUCTIONS part, by treating the register indirect
|
||||
mode seperately.
|
||||
.sp 1
|
||||
The costs of the conditional call and return instructions really
|
||||
depend on whether or not the call resp. return is actually made.
|
||||
Unimportant.
|
||||
.sp 1
|
||||
Instructions not used in this table have been commented out.
|
||||
Of course many of them are used in the library routines.
|
||||
.NH 2
|
||||
Moves
|
||||
.PP
|
||||
This section is supposed to be straight-forward.
|
||||
.NH 2
|
||||
Tests
|
||||
.PP
|
||||
The TESTS section is only included to refrain
|
||||
.B cgg
|
||||
from complaining.
|
||||
.NH 2
|
||||
Stackingrules
|
||||
.PP
|
||||
When, for example, the token {const2,10} has to be stacked while
|
||||
no free register-pair is available, the next code is generated:
|
||||
.DS
|
||||
PUSH H
|
||||
LXI H,10
|
||||
XTHL
|
||||
.DE
|
||||
The last instruction exchanges the contents of HL with the value
|
||||
on top of the stack, giving HL its original value again.
|
||||
.NH 2
|
||||
Coercions
|
||||
.PP
|
||||
The coercion to unstack register A, is somewhat tricky,
|
||||
but unfortunately just popping PSW leaves the high-order byte in
|
||||
the accumulator.
|
||||
.sp 1
|
||||
The cheapest way to coerce HL to DE (or DE to HL) is by using
|
||||
the XCHG instruction, but it is not possible to explain
|
||||
.B cgg
|
||||
this instruction in fact exchanges the contents of these
|
||||
register-pairs.
|
||||
Before the coercion is carried out other appearances of DE and HL
|
||||
on the fake-stack will be moved to the real stack, because in
|
||||
the INSTRUCTION-part is told that XCHG destroyes the contents
|
||||
of both DE and HL.
|
||||
.br
|
||||
The coercion transposing one register-pair to another one by
|
||||
emitting two MOV-instructions, will be used only if
|
||||
one of the register-pairs is the localbase.
|
||||
.NH 2
|
||||
Patterns
|
||||
.PP
|
||||
As a general habit I have allocated (uses ...) all registers
|
||||
that should be free to generate the code, although it is not
|
||||
always necessary.
|
||||
For example in the code rule
|
||||
.DS
|
||||
pat loe
|
||||
uses hlreg
|
||||
gen lhld {label,$1} yields hl
|
||||
.DE
|
||||
the 'uses'-clause could have been omitted because
|
||||
.B cgg
|
||||
knows that LHLD destroyes register-pair HL.
|
||||
.sp 1
|
||||
Since there is only one register with property 'hlreg',
|
||||
there is no difference between 'uses hlreg' (allocate a
|
||||
register with property 'hlreg') and 'kills hlreg' (remove
|
||||
all registers with property 'hlreg' from the fake-stack).
|
||||
The same applies for the property 'dereg'.
|
||||
.br
|
||||
As a consequence 'kills' is rarely used in this back-end table.
|
||||
.NH 3
|
||||
Group 1: Load instructions
|
||||
.PP
|
||||
When a local variable must be squared, there will probably be EM-code like:
|
||||
.DS
|
||||
lol 10
|
||||
lol 10
|
||||
mli 2
|
||||
.DE
|
||||
When the code for the first 'lol 10' has been executed, DE contains the
|
||||
wanted value.
|
||||
To refrain
|
||||
.B cgg
|
||||
from emitting the code for 'lol 10' again, an extra
|
||||
pattern is included in the table for cases like this.
|
||||
.br
|
||||
The same applies for two consecutive 'loe'-s or 'lil'-s.
|
||||
.sp 1
|
||||
A bit tricky is 'lof'.
|
||||
It expects either DE or HL on the fake-stack, moves {const2,$1}
|
||||
into the other one, and eventually adds them.
|
||||
The 'kills' part is necessary here because if DE was on the fake-stack,
|
||||
.B cgg
|
||||
doesn't see that the contents of DE is destroyed by the code
|
||||
(in fact 'kills dereg' would have been sufficient: because of the
|
||||
DAD instruction
|
||||
.B cgg
|
||||
knows that HL is destroyed).
|
||||
.sp 1
|
||||
By lookahead,
|
||||
.B cgg
|
||||
can make a clever choise between the first and
|
||||
second code rule of 'loi 4'.
|
||||
The same applies for several other instructions.
|
||||
.NH 3
|
||||
Group 2: Store instructions
|
||||
.PP
|
||||
A similar idea as with the two consecutive identical load instructions
|
||||
in Group 1, applies for a store instruction followed by a corresponding load instruction.
|
||||
.NH 3
|
||||
Groups 3 and 4: Signed and unsigned integer arithmetic
|
||||
.PP
|
||||
Since the 8080 instruction set doesn't provide multiply and
|
||||
divide instructions, special routines are made to accomplish these tasks.
|
||||
.sp 1
|
||||
Instead of providing four slighty differing routines for 16 bit signed or
|
||||
unsigned division, yielding the quotient or the remainder,
|
||||
the routines are merged.
|
||||
This saves space and assembly time
|
||||
when several variants are used in a particular program,
|
||||
at the cost of a little speed.
|
||||
.br
|
||||
When the routine is called, bit 7 of register A indicates whether
|
||||
the operands should be considered as signed or as unsigned integers,
|
||||
and bit 0 of register A indicates whether the quotient or the
|
||||
remainder has to be delivered.
|
||||
.br
|
||||
The same applies for 32 bit division.
|
||||
.sp 1
|
||||
The routine doing the 16 bit unsigned multiplication could
|
||||
have been used for 16 bit signed multiplication too.
|
||||
Nevertheless a special 16 bit signed multiplication routine is
|
||||
provided, because this one will usually be much faster.
|
||||
.NH 3
|
||||
Group 5: Floating point arithmetic
|
||||
.PP
|
||||
Floating points are not implemented.
|
||||
.br
|
||||
Whenever an EM-instruction involving floating points is offered
|
||||
to the code-generator, it generates the code 'call eunimpl',
|
||||
which traps with trap number 63.
|
||||
Some of the Pascal and C library routines output floating point
|
||||
EM-instructions, so code has to be generated for them.
|
||||
Of course this doesn't imply the code will ever be executed.
|
||||
.NH 3
|
||||
Group 12: Compare instructions
|
||||
.PP
|
||||
The code for 'cmu 2', with its 4 labels, is terrible.
|
||||
But it is the best I could find.
|
||||
.NH 3
|
||||
Group 9: Logical instructions
|
||||
.PP
|
||||
I have tried to merge both variants of the instructions 'and 2', 'ior 2' and 'xor 2',
|
||||
as in
|
||||
.DS
|
||||
pat and $1==2
|
||||
with hl_or_de hl_or_de
|
||||
uses reusing %1, reusing %2, hl_or_de, areg
|
||||
gen mov a,%1.2
|
||||
ana %2.2
|
||||
mov %a.2,a
|
||||
mov a,%1.1
|
||||
ana %2.1
|
||||
mov %a.1,a yields %a
|
||||
.DE
|
||||
but the current version of
|
||||
.B cgg
|
||||
doesn't approve this.
|
||||
.br
|
||||
In any case
|
||||
.B cgg
|
||||
chooses either DE or HL to store the result, using lookahead.
|
||||
.NH 3
|
||||
Group 14: Procedure call instructions
|
||||
.PP
|
||||
There is an 8 bytes function return area, called '.fra'.
|
||||
If only 2 bytes have to be returned, register-pair DE is used.
|
||||
.NH 1
|
||||
LIBRARY ROUTINES
|
||||
.PP
|
||||
Most of the library routines start with saving the return address
|
||||
and the localbase, so that the parameters are on the top of the stack
|
||||
and the registers B and C are available as scratch registers.
|
||||
Since register-pair HL is needed to accomplish these tasks,
|
||||
and also to restore everything just before the routine returns,
|
||||
it is not possible to transfer data between the routines and the
|
||||
surrounding world through register H or L.
|
||||
Only registers A, D and E can be used for this.
|
||||
.sp
|
||||
When a routine returns 2 bytes, they are usually returned in
|
||||
registers-pair DE.
|
||||
When it returns more than 2 bytes they are pushed onto the stack.
|
||||
.br
|
||||
|
||||
It would have been possible to let the 32 bit arithmetic routines
|
||||
return 2 bytes in DE and the remaining 2 bytes on the stack
|
||||
(this often would have saved some space and execution time),
|
||||
but I don't consider that as well-structured programming.
|
||||
.NH 1
|
||||
TRAPS
|
||||
.PP
|
||||
Whenever a trap, for example trying to divide by zero,
|
||||
occurs in a program that originally was written in C or Pascal,
|
||||
a special trap handler is called.
|
||||
.br
|
||||
This trap handler wants to write an appropriate error message on the
|
||||
monitor.
|
||||
It tries to read the message from a file (e.g. etc/pc_rt_errors in the
|
||||
EM home directory for Pascal programs), but since the 8080 back-end
|
||||
doesn't know about files, we are in trouble.
|
||||
This problem is solved, as far as possible, by including the 'open'-monitor call in the mon-routine.
|
||||
It returns with file descriptor -1.
|
||||
The trap handler reacts by generating another trap, with the original
|
||||
trap number.
|
||||
But this time, instead of calling the C- or Pascal trap handler again,
|
||||
the next message is printed on the monitor:
|
||||
.DS L
|
||||
trap number <TN>
|
||||
line <LN> of file <FN>
|
||||
|
||||
where <TN> is the trap number (decimal)
|
||||
<LN> is the line number (decimal)
|
||||
<FN> is the filename of the original program
|
||||
.DE
|
||||
.sp 1
|
||||
Trap numbers are subdivided as follows:
|
||||
.IP 1-27: 20
|
||||
EM-machine error, as described in [3]
|
||||
.IP 63:
|
||||
an unimplemented EM-instruction is used
|
||||
.IP 64-127:
|
||||
generated by compilers, runtime systems, etc.
|
||||
.IP 128-252:
|
||||
generated by user programs
|
||||
.NH 1
|
||||
IMPLEMENTATION
|
||||
.PP
|
||||
It will not be possible to run the entire Amsterdam Compiler Kit on a
|
||||
8080-based computer system.
|
||||
One has to write a program on another
|
||||
system, a system where the compiler kit runs on.
|
||||
This program may be a mixture of high-level languages, such as
|
||||
C or Pascal, EM and 8080 assembly code.
|
||||
The program should be compiled using the compiler kit, producing 8080 machine code.
|
||||
This code should come available to the 8080 machine
|
||||
for example by downloading or
|
||||
by storing it in ROM (Read Only Memory).
|
||||
.sp 1
|
||||
Depending on the characteristics of the particular 8080 based system, some
|
||||
adaptions have to be made:
|
||||
.IP 1) 10
|
||||
In 'head_em': the base address, which is the address where the first
|
||||
8080 instruction will be stored, and the initial value of the
|
||||
stackpointer are set to 0x1000 and 0x8000 respectivally.
|
||||
.br
|
||||
Other systems require other values.
|
||||
.IP 2)
|
||||
In 'head_em': before calling "_m_a_i_n", the environment
|
||||
pointer, argument vector and argument count will have to be pushed
|
||||
onto the stack.
|
||||
Since this back-end is tested on a system without any knowledge
|
||||
of these things, dummies are pushed now.
|
||||
.IP 3)
|
||||
In 'tail_em': proper routines "putchar" and "getchar" should
|
||||
be provided.
|
||||
They should write resp. read a character on/from the monitor.
|
||||
Maybe some conversions will have to be made.
|
||||
.IP 4)
|
||||
In 'head_em': an application program returns control to the monitor by
|
||||
jumping to address 0xFB52.
|
||||
If this is not the right way on your system, change it.
|
||||
.IP 5)
|
||||
In 'tail_em': the current version of the 8080 back-end has very limited I/O
|
||||
capabilities, because it was tested on a system that
|
||||
had no knowlegde of files.
|
||||
So the implementation of the EM-instruction 'mon' is very simple;
|
||||
it can only do the following things:
|
||||
.RS
|
||||
.IP Monitor\ call\ 1: 40
|
||||
Exit
|
||||
.IP Monitor\ call\ 3:
|
||||
read, always reads from the monitor.
|
||||
.br
|
||||
echos the read character.
|
||||
.br
|
||||
ignores file descriptor.
|
||||
.IP Monitor\ call\ 4:
|
||||
write, always writes on the monitor.
|
||||
.br
|
||||
ignores file descriptor.
|
||||
.IP Monitor\ call\ 5:
|
||||
open file, returns file descriptor -1.
|
||||
.br
|
||||
(compare chapter about TRAPS)
|
||||
.IP Monitor\ call\ 6:
|
||||
close file, returns error code = 0.
|
||||
.IP Monitor\ call\ 54:
|
||||
io-control, returns error code = 0.
|
||||
.RE
|
||||
.sp
|
||||
If the system should do file-handling the routine ".mon"
|
||||
should be extended thoroughly.
|
||||
.NH 1
|
||||
INTEL 8080 VERSUS ZILOG Z80 AND INTEL 8086
|
||||
.NH 2
|
||||
Introduction
|
||||
.PP
|
||||
At about the same time I develloped the back end
|
||||
for the Intel 8080 and Intel 8085,
|
||||
Frans van Haarlem did the same job for the Zilog z80 microprocessor.
|
||||
Since the z80 processor is an extension of the 8080,
|
||||
any machine code offered to a 8080 processor can be offered
|
||||
to a z80 too.
|
||||
The assembly languages are quite different however.
|
||||
.br
|
||||
During the devellopments of the back ends we have used
|
||||
two micro-computers, both equiped with a z80 microprocessor.
|
||||
Of course the output of the 8080 back end is assembled by an
|
||||
8080 assembler. This should assure I have never used any of
|
||||
the features that are potentially available in the z80 processor,
|
||||
but are not part of a true 8080 processor.
|
||||
.sp 1
|
||||
As a final job, I have
|
||||
investigated the differences between the 8080 and z80 processors
|
||||
and their influence on the back ends.
|
||||
I have tried to measure this influence by examining the length of
|
||||
the generated code.
|
||||
I have also involved the 8086 micro-processor in this measurements.
|
||||
.NH 2
|
||||
Differences between the 8080 and z80 processors
|
||||
.PP
|
||||
Except for some features that are less important concerning back ends,
|
||||
there are two points where the z80 improves the 8080:
|
||||
.IP First, 18
|
||||
the z80 has two additional index registers, IX and IY.
|
||||
They are used as in
|
||||
.DS
|
||||
LD B,(IX+10)
|
||||
.DE
|
||||
The offset, here 10, should fit in one byte.
|
||||
.IP Second,
|
||||
the z80 has several additional instructions.
|
||||
The most important ones are:
|
||||
.RS
|
||||
.IP 1) 8
|
||||
The 8080 can only load or store register-pair HL direct
|
||||
(using LHLD or SHLD).
|
||||
The z80 can handle BC, DE and SP too.
|
||||
.IP 2)
|
||||
Instructions are included to ease block movements.
|
||||
.IP 3)
|
||||
There is a 16 bit subtract instruction.
|
||||
.IP 4)
|
||||
While the 8080 can only rotate the accumulator, the z80
|
||||
can rotate and shift each 8 bit register.
|
||||
.IP 5)
|
||||
Special routines are included to jump to near locations, saving 1 byte.
|
||||
.RE
|
||||
.NH 2
|
||||
Consequences for the 8080 and z80 back end
|
||||
.PP
|
||||
The most striking difference between the 8080 and z80 back ends
|
||||
is the choise of the localbase.
|
||||
The writer of the z80 back end chose index register IY as localbase,
|
||||
because this results in the cheapest coding of EM-instructions
|
||||
like 'lol' and 'stl'.
|
||||
.br
|
||||
The z80 instructions that load local 10, for example
|
||||
.DS
|
||||
LD E,(IY+10)
|
||||
LD D,(IY+11)
|
||||
.DE
|
||||
occupy 6 bytes and take 38 time periods to execute.
|
||||
The five corresponding 8080 instructions loading a local
|
||||
occupy 7 bytes and take 41 time periods.
|
||||
Although the profit of the z80 might be not world-shocking,
|
||||
it should be noted that as a side effect it may save some
|
||||
pushing and popping since register pair HL is not used.
|
||||
.sp 1
|
||||
The choise of IY as localbase has its drawbacks too.
|
||||
The root of the problem is that it is not possible to add
|
||||
IY to HL.
|
||||
For the EM-instruction
|
||||
.DS
|
||||
lal 20
|
||||
.DE
|
||||
the z80 back end generates code like
|
||||
.DS
|
||||
LD BC,20
|
||||
PUSH IY
|
||||
POP HL
|
||||
ADD HL,BC
|
||||
.DE
|
||||
leaving the wanted address in HL.
|
||||
.br
|
||||
This annoying push and pop instructions are also needed in some
|
||||
other instructions, for instance in 'lol' when the offset
|
||||
doesn't fit in one byte.
|
||||
.sp 1
|
||||
Beside the choise of the localbase, I think there is no
|
||||
fundamental difference between the 8080 and z80 back ends,
|
||||
except of course that the z80 back end has register pair BC
|
||||
and, less important, index register IX available as scratch registers.
|
||||
.sp 1
|
||||
Most of the PATTERNS in the 8080 and z80 tables are more or less
|
||||
a direct translation of each other.
|
||||
.NH 2
|
||||
What did I do?
|
||||
.PP
|
||||
To get an idea of the quality of the code generated by
|
||||
the 8080, z80 and 8086 back ends I have gathered
|
||||
some C programs and some Pascal programs.
|
||||
Then I produced 8080, z80 and 8086 code for them.
|
||||
Investigating the assembler listing I found the
|
||||
lengths of the different parts of the generated code.
|
||||
.br
|
||||
I have checked two areas:
|
||||
.IP 1) 8
|
||||
the entire text part
|
||||
.IP 2)
|
||||
the text part without any library routine, so only the plain user program
|
||||
.LP
|
||||
I have to admit that neither one of them is really honest.
|
||||
When the entire text part is checked, the result is disturbed
|
||||
because not always the same library routines are loaded.
|
||||
And when only the user program itself is considered, the result is
|
||||
disturbed too.
|
||||
For example the 8086 has a multiply instruction,
|
||||
so the EM-instruction 'mli 2' is translated in the main program,
|
||||
but the 8080 and z80 call a library routine that is not counted.
|
||||
Also the 8080 uses library routines at some places where the
|
||||
z80 does not.
|
||||
.sp 1
|
||||
But nevertheless I think the measurements will give an idea
|
||||
about the code produced by the three back ends.
|
||||
.NH 2
|
||||
The results
|
||||
.PP
|
||||
The table below should be read as follows.
|
||||
For all programs I have computed the ratio of the code-lengths
|
||||
of the 8080, z80 and 8086.
|
||||
The averages of all Pascal/C programs are listed in the table,
|
||||
standarized to '100' for the 8080.
|
||||
So the listed '107' indicates that the lengths
|
||||
of the text parts of the z80 programs that originally were Pascal programs,
|
||||
averaged 7 percent larger than in the corresponding 8080 programs.
|
||||
.DS C
|
||||
--------------------------------------------------
|
||||
| | 8080 | z80 | 8086 |
|
||||
--------------------------------------------------
|
||||
| C, text part | 100 | 103 | 65 |
|
||||
| Pascal, text part | 100 | 107 | 55 |
|
||||
| C, user program | 100 | 110 | 71 |
|
||||
| Pascal, user program | 100 | 118 | 67 |
|
||||
--------------------------------------------------
|
||||
.DE
|
||||
.TE
|
||||
The most striking thing in this table is that the z80 back end appears
|
||||
to produce larger code than the 8080 back end.
|
||||
The reason is that the current z80 back end table is
|
||||
not very elaborate yet.
|
||||
For instance it doesn't look for any EM-pattern longer than one.
|
||||
So the table shows that the preparations in the 8080 back end table
|
||||
to produce faster code (like recognizing special EM-patterns
|
||||
and permitting one byte registers on the fake-stack)
|
||||
was not just for fun, but really improved the generated code
|
||||
significantly.
|
||||
.sp 1
|
||||
The table shows that the 8080 table is relativelly better
|
||||
when only the plain user program is considered instead of the entire text part.
|
||||
This is not very surprising since the 8080 back end sometimes
|
||||
uses library routines where the z80 and especially the 8086 don't.
|
||||
.sp 1
|
||||
The difference between the 8080 and z80 on the one hand and the 8086
|
||||
on the other is very big.
|
||||
But of course it was not equal game:
|
||||
the 8086 is a 16 bit processor that is much more advanced than the
|
||||
8080 or z80 and the 8086 back end is known to produce
|
||||
very good code.
|
||||
.bp
|
||||
.B REFERENCES
|
||||
.sp 2
|
||||
.IP [1] 10
|
||||
8080/8085 Assembly Language Programming Manual,
|
||||
.br
|
||||
Intel Corporation (1977,1978)
|
||||
.IP [2]
|
||||
Andrew S. Tanenbaum, Hans van Staveren, E.G. Keizer and Johan W. Stevenson,
|
||||
.br
|
||||
A practical tool kit for making portable compilers,
|
||||
.br
|
||||
Informatica report 74, Vrije Universiteit, Amsterdam, 1983.
|
||||
.sp
|
||||
An overview on the Amsterdam Compiler Kit.
|
||||
.IP [3]
|
||||
Tanenbaum, A.S., Stevenson, J.W., Keizer, E.G., and van Staveren, H.
|
||||
.br
|
||||
Desciption of an experimental machine architecture for use with block
|
||||
structured languages,
|
||||
.br
|
||||
Informatica report 81, Vrije Universiteit, Amsterdam, 1983.
|
||||
.sp
|
||||
The defining document for EM.
|
||||
.IP [4]
|
||||
Steel, T.B., Jr.
|
||||
.br
|
||||
UNCOL: The myth and the Fact. in Ann. Rev. Auto. Prog.
|
||||
.br
|
||||
Goodman, R. (ed.), vol. 2, (1960), p325-344.
|
||||
.sp
|
||||
An introduction to the UNCOL idea by its originator.
|
||||
.IP [5]
|
||||
van Staveren, Hans
|
||||
.br
|
||||
The table driven code generator from the Amsterdam Compiler Kit
|
||||
(Second Revised Edition),
|
||||
.br
|
||||
Vrije Universiteit, Amsterdam.
|
||||
.sp
|
||||
The defining document for writing a back end table.
|
||||
.IP [6]
|
||||
Voors, Jan
|
||||
.br
|
||||
A back end for the Zilog z8000 micro,
|
||||
.br
|
||||
Vrije Universiteit, Amsterdam.
|
||||
.sp
|
||||
A document like this one, but for the z8000.
|
||||
1077
doc/install.doc
1077
doc/install.doc
File diff suppressed because it is too large
Load Diff
366
doc/ncg.doc
366
doc/ncg.doc
@@ -57,7 +57,7 @@ and the assembly code of the machine at hand.
|
||||
.NH 1
|
||||
What has changed since version 1 ?
|
||||
.PP
|
||||
This chapter can be skipped by anyone not familiar with the first version.
|
||||
This section can be skipped by anyone not familiar with the first version.
|
||||
It is not needed to understand the current version.
|
||||
.PP
|
||||
This paper describes the second version of the code generator system.
|
||||
@@ -116,39 +116,40 @@ Alternatively one can think of the real stack as an infinite extension
|
||||
at the bottom of the fake stack.
|
||||
Both ways, the concatenation of the real stack and the fake stack
|
||||
will be the stack as it would have been on a real EM machine (see figure).
|
||||
.KF
|
||||
.DS L
|
||||
.ta 8 16 24 32 40 48 56 64 72
|
||||
EM machine target machine
|
||||
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | real stack |
|
||||
| | | | |
|
||||
| | | | | growing
|
||||
| EM stack | | | |
|
||||
| | |_______________| \e|/
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | fake stack |
|
||||
| | | |
|
||||
|_______________| |_______________|
|
||||
.TS
|
||||
center;
|
||||
cw(3.5c) cw(3c) cw(3.5c)
|
||||
cw(3.5c) cw(3c) cw(3.5c)
|
||||
|cw(3.5c)| cw(3c) |cw(3.5c)| .
|
||||
EM machine target machine
|
||||
|
||||
|
||||
.I
|
||||
Relation between EM stack, real stack and fake stack.
|
||||
.R
|
||||
.DE
|
||||
.KE
|
||||
|
||||
|
||||
|
||||
real stack
|
||||
stack
|
||||
grows
|
||||
EM stack \s+2\(br\s0
|
||||
\s+2\(br\s0
|
||||
\s+2\(br\s0 _
|
||||
\s+2\(br\s0
|
||||
\s+2\(da\s0
|
||||
fake stack
|
||||
|
||||
|
||||
|
||||
_ _
|
||||
.T&
|
||||
ci s s.
|
||||
Relation between EM stack, real stack and fake stack.
|
||||
.TE
|
||||
During code generation tokens will be kept on the fake stack as long
|
||||
as possible but when they are moved to the real stack,
|
||||
by generating code for the push,
|
||||
all tokens above\u*\d
|
||||
all tokens above\v'-.25m'\(dg\v'.25m'
|
||||
.FS
|
||||
* in this document the stack is assumed to grow downwards,
|
||||
\(dg in this document the stack is assumed to grow downwards,
|
||||
although the top of the stack will mean the first element that will
|
||||
be popped.
|
||||
.FE
|
||||
@@ -233,7 +234,7 @@ to register variables in the rest of this document.
|
||||
.PP
|
||||
The front ends generate messages to the back ends telling them which
|
||||
local variables could go into registers.
|
||||
The information given is the offset of the local, it's size and type
|
||||
The information given is the offset of the local, its size and type
|
||||
and a scoring number, roughly the number of times it occurs.
|
||||
.PP
|
||||
The decision which variable to put in which register is taken by the
|
||||
@@ -297,8 +298,9 @@ at will to improve legibility.
|
||||
Identifiers used in the table have the same syntax as C identifiers,
|
||||
upper and lower case considered different, all characters significant.
|
||||
Here is a list of reserved words; all of these are unavailable as identifiers.
|
||||
.DS L
|
||||
.ta 14 28 42 56
|
||||
.TS
|
||||
box;
|
||||
l l l l l.
|
||||
ADDR STACK from reg_any test
|
||||
COERCIONS STACKINGRULES gen reg_float to
|
||||
INSTRUCTIONS TESTS highw reg_loop ufit
|
||||
@@ -309,7 +311,7 @@ PROPERTIES cost loww reusing
|
||||
REGISTERS defined move rom
|
||||
SETS exact pat samesign
|
||||
SIZEFACTOR example proc sfit
|
||||
.DE
|
||||
.TE
|
||||
C style comments are accepted.
|
||||
.DS
|
||||
/* this is a comment */
|
||||
@@ -330,7 +332,7 @@ NAME=value
|
||||
.DE
|
||||
value being an integer or string.
|
||||
Three constants must be defined here:
|
||||
.IP EM_WSIZE 10
|
||||
.IP EM_WSIZE 14
|
||||
Number of bytes in a machine word.
|
||||
This is the number of bytes
|
||||
a \fBloc\fP instruction will put on the stack.
|
||||
@@ -360,21 +362,21 @@ This is given as
|
||||
FORMAT = string
|
||||
.DE
|
||||
The string must be a valid printf(III) format,
|
||||
and defaults to "%d" or "%ld" depending on the wordsize of
|
||||
the machine. For example on the PDP-11 one can use
|
||||
and defaults to "%ld".
|
||||
For example on the PDP-11 one can use
|
||||
.DS
|
||||
FORMAT= "0%o"
|
||||
FORMAT= "0%lo"
|
||||
.DE
|
||||
to satisfy the old UNIX assembler that reads octal unless followed by
|
||||
a period, and the ACK assembler that follows C conventions.
|
||||
.PP
|
||||
Tables under control of programs like
|
||||
Tables under control of source code control systems like
|
||||
.I sccs
|
||||
or
|
||||
.I rcs
|
||||
can put their id-string here, for example
|
||||
.DS
|
||||
rcsid="$Header$"
|
||||
rcsid="$\&Header$"
|
||||
.DE
|
||||
These strings, like all strings in the table, will eventually
|
||||
end up in the binary code generator produced.
|
||||
@@ -385,6 +387,7 @@ same order of magnitude.
|
||||
This can be done as
|
||||
.DS
|
||||
SIZEFACTOR = C\d3\u/C\d4\u
|
||||
.sp
|
||||
TIMEFACTOR = C\d1\u/C\d2\u
|
||||
.DE
|
||||
Above numbers must be read as rational numbers.
|
||||
@@ -403,24 +406,24 @@ It consists of a list of user-defined
|
||||
identifiers optionally followed by the size
|
||||
of the property in parentheses, default EM_WSIZE.
|
||||
Example for the PDP-11:
|
||||
.DS
|
||||
.ta 8 16 24 32 40
|
||||
PROPERTIES /* The header word for this section */
|
||||
.TS
|
||||
l l.
|
||||
PROPERTIES /* The header word for this section */
|
||||
|
||||
GENREG /* All PDP registers */
|
||||
REG /* Normal registers (allocatable) */
|
||||
ODDREG /* All odd registers (allocatable) */
|
||||
REGPAIR(4) /* Register pairs for division */
|
||||
FLTREG(4) /* Floating point registers */
|
||||
DBLREG(8) /* Same, double precision */
|
||||
GENFREG(4) /* generic floating point */
|
||||
GENDREG(8) /* Same, double precision */
|
||||
FLTREGPAIR(8) /* register pair for modf */
|
||||
DBLREGPAIR(16) /* Same, double precision */
|
||||
LOCALBASE /* Guess what */
|
||||
GENREG /* All PDP registers */
|
||||
REG /* Normal registers (allocatable) */
|
||||
ODDREG /* All odd registers (allocatable) */
|
||||
REGPAIR(4) /* Register pairs for division */
|
||||
FLTREG(4) /* Floating point registers */
|
||||
DBLREG(8) /* Same, double precision */
|
||||
GENFREG(4) /* generic floating point */
|
||||
GENDREG(8) /* Same, double precision */
|
||||
FLTREGPAIR(8) /* register pair for modf */
|
||||
DBLREGPAIR(16) /* Same, double precision */
|
||||
LOCALBASE /* Guess what */
|
||||
STACKPOINTER
|
||||
PROGRAMCOUNTER
|
||||
.DE
|
||||
.TE
|
||||
Registers are allocated by asking for a property,
|
||||
so if for some reason in later parts of the table
|
||||
one particular register must be allocated it
|
||||
@@ -438,22 +441,22 @@ Syntax:
|
||||
<register> : ident [ '(' string ')' ] [ '=' ident [ '+' ident ] ]
|
||||
.DE
|
||||
Example for the PDP-11:
|
||||
.DS L
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.TS
|
||||
l l.
|
||||
REGISTERS
|
||||
|
||||
r0,r2,r4 : GENREG,REG.
|
||||
r1,r3 : GENREG,REG,ODDREG.
|
||||
r01("r0")=r0+r1 : REGPAIR.
|
||||
fr0("r0"),fr1("r1"),fr2("r2"),fr3("r3") : GENFREG,FLTREG.
|
||||
r0,r2,r4 : GENREG,REG.
|
||||
r1,r3 : GENREG,REG,ODDREG.
|
||||
r01("r0")=r0+r1 : REGPAIR.
|
||||
fr0("r0"),fr1("r1"),fr2("r2"),fr3("r3") : GENFREG,FLTREG.
|
||||
dr0("r0")=fr0,dr1("r1")=fr1,
|
||||
dr2("r2")=fr2,dr3("r3")=fr3 : GENDREG,DBLREG.
|
||||
dr2("r2")=fr2,dr3("r3")=fr3 : GENDREG,DBLREG.
|
||||
fr01("r0")=fr0+fr1,fr23("r2")=fr2+fr3 : FLTREGPAIR.
|
||||
dr01("r0")=dr0+dr1,dr23("r2")=dr2+dr3 : DBLREGPAIR.
|
||||
lb("r5") : GENREG,LOCALBASE.
|
||||
sp : GENREG,STACKPOINTER.
|
||||
pc : GENREG,PROGRAMCOUNTER.
|
||||
.DE
|
||||
lb("r5") : GENREG,LOCALBASE.
|
||||
sp : GENREG,STACKPOINTER.
|
||||
pc : GENREG,PROGRAMCOUNTER.
|
||||
.TE
|
||||
.PP
|
||||
The names in the left hand lists are names of registers as used
|
||||
in the table.
|
||||
@@ -525,20 +528,21 @@ Tokens should usually be declared for every addressing mode
|
||||
of the machine at hand and for every size directly usable in
|
||||
a machine instruction.
|
||||
Example for the PDP-11 (incomplete):
|
||||
.DS L
|
||||
.TS
|
||||
l l.
|
||||
TOKENS
|
||||
|
||||
const2 = { INT num; } 2 cost(2,300) "$" num .
|
||||
addr_local = { INT ind; } 2 .
|
||||
addr_external = { ADDR off; } 2 "$" off.
|
||||
const2 = { INT num; } 2 cost(2,300) "$" num .
|
||||
addr_local = { INT ind; } 2 .
|
||||
addr_external = { ADDR off; } 2 "$" off.
|
||||
|
||||
regdef2 = { GENREG reg; } 2 "*" reg.
|
||||
regind2 = { GENREG reg; ADDR off; } 2 off "(" reg ")" .
|
||||
reginddef2 = { GENREG reg; ADDR off; } 2 "*" off "(" reg ")" .
|
||||
regdef2 = { GENREG reg; } 2 "*" reg.
|
||||
regind2 = { GENREG reg; ADDR off; } 2 off "(" reg ")" .
|
||||
reginddef2 = { GENREG reg; ADDR off; } 2 "*" off "(" reg ")" .
|
||||
regconst2 = { GENREG reg; ADDR off; } 2 .
|
||||
relative2 = { ADDR off; } 2 off .
|
||||
reldef2 = { ADDR off; } 2 "*" off.
|
||||
.DE
|
||||
reldef2 = { ADDR off; } 2 "*" off.
|
||||
.TE
|
||||
.PP
|
||||
Types allowed in the struct are ADDR, INT and all register properties.
|
||||
The type ADDR means a string and an integer,
|
||||
@@ -574,7 +578,7 @@ that can adjust the time/space tradeoff to all positions
|
||||
from 100% time to 100% space.
|
||||
.LP
|
||||
By supplying different code rules in certain situations
|
||||
it is possible to get a code generator that can adjust it's
|
||||
it is possible to get a code generator that can adjust its
|
||||
code to the need of the moment.
|
||||
This is probably most useful with small machines,
|
||||
experience has shown that on the larger micro's and mini's
|
||||
@@ -620,21 +624,21 @@ in the remainder of the table,
|
||||
but for clarity it is usually better not to.
|
||||
.LP
|
||||
Example for the PDP-11 (incomplete):
|
||||
.DS L
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.TS
|
||||
l l.
|
||||
SETS
|
||||
|
||||
src2 = GENREG + regdef2 + regind2 + reginddef2 + relative2 +
|
||||
reldef2 + addr_external + const2 + LOCAL + ILOCAL +
|
||||
autodec + autoinc .
|
||||
dst2 = src2 - ( const2 + addr_external ) .
|
||||
xsrc2 = src2 + ftoint .
|
||||
src1 = regdef1 + regind1 + reginddef1 + relative1 + reldef1 .
|
||||
dst1 = src1 .
|
||||
src1or2 = src1 + src2 .
|
||||
src4 = relative4 + regdef4 + DLOCAL + regind4 .
|
||||
dst4 = src4 .
|
||||
.DE
|
||||
src2 = GENREG + regdef2 + regind2 + reginddef2 + relative2 +
|
||||
\h'\w'= 'u'reldef2 + addr_external + const2 + LOCAL + ILOCAL +
|
||||
\h'\w'= 'u'autodec + autoinc .
|
||||
dst2 = src2 - ( const2 + addr_external ) .
|
||||
xsrc2 = src2 + ftoint .
|
||||
src1 = regdef1 + regind1 + reginddef1 + relative1 + reldef1 .
|
||||
dst1 = src1 .
|
||||
src1or2 = src1 + src2 .
|
||||
src4 = relative4 + regdef4 + DLOCAL + regind4 .
|
||||
dst4 = src4 .
|
||||
.TE
|
||||
Permissible in the set construction are all the usual set operators, i.e.
|
||||
.IP +
|
||||
set union
|
||||
@@ -1154,9 +1158,10 @@ This can of course be done with
|
||||
.DS
|
||||
kills ALL
|
||||
.DE
|
||||
or by ending the stack pattern with the word STACK, which is equivalent,
|
||||
or by ending the stack pattern with the word STACK,
|
||||
if the stack pattern does not start with
|
||||
.I exact .
|
||||
The latter does not erase the contents of registers.
|
||||
.PP
|
||||
It is unfortunate that this part is still present in the table
|
||||
but it is too much for now to let the
|
||||
@@ -1248,7 +1253,7 @@ The author of
|
||||
.I cgg
|
||||
could not get
|
||||
.I yacc
|
||||
to be silent without it.
|
||||
to accept his syntax without it.
|
||||
Sorry about this.
|
||||
.IP 2)
|
||||
a
|
||||
@@ -1366,20 +1371,19 @@ A list of examples for the PDP-11 is given here.
|
||||
Far from being complete it gives examples of most kinds
|
||||
of instructions.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
pat loc yields {const2, $1}
|
||||
.ta 7.5c
|
||||
pat loc yields {const2, $1}
|
||||
|
||||
pat ldc yields {const2, loww($1)}
|
||||
{const2, highw($1)}
|
||||
pat ldc yields {const2, loww($1)} {const2, highw($1)}
|
||||
.DE
|
||||
These simple patterns just push one or more tokens onto the fake stack.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat lof
|
||||
with REG yields {regind2,%1,$1}
|
||||
with exact regconst2 yields {regind2,%1.reg,$1+%1.off}
|
||||
with exact addr_external yields {relative2,$1+%1.off}
|
||||
with exact addr_local yields {LOCAL, %1.ind + $1,2}
|
||||
with REG yields {regind2,%1,$1}
|
||||
with exact regconst2 yields {regind2,%1.reg,$1+%1.off}
|
||||
with exact addr_external yields {relative2,$1+%1.off}
|
||||
with exact addr_local yields {LOCAL, %1.ind + $1,2}
|
||||
.DE
|
||||
This pattern shows the possibility to do different things
|
||||
depending on the fake stack contents,
|
||||
@@ -1389,13 +1393,12 @@ not preceded by
|
||||
that can always be taken after a coercion,
|
||||
if necessary.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat lxl $1>3
|
||||
uses REG={LOCAL, SL, 2},
|
||||
REG={const2,$1-1}
|
||||
uses REG={LOCAL, SL, 2}, REG={const2,$1-1}
|
||||
gen 1:
|
||||
move {regind2,%a, SL},%a
|
||||
sob %b,{label,1b} yields %a
|
||||
sob %b,{label,1b} yields %a
|
||||
.DE
|
||||
This rule shows register allocation with initialisation,
|
||||
and the use of a temporary label.
|
||||
@@ -1404,7 +1407,7 @@ of the static link,
|
||||
that is pushed by the Pascal compiler as the last argument of
|
||||
a function.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat stf
|
||||
with regconst2 xsrc2
|
||||
kills allexeptcon
|
||||
@@ -1419,7 +1422,7 @@ part in a store instruction.
|
||||
The set allexeptcon contains all tokens that can be the destination
|
||||
of an indirect store.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat sde
|
||||
with exact FLTREG
|
||||
kills posextern
|
||||
@@ -1445,51 +1448,52 @@ The third rule is taken by default,
|
||||
resulting in two separate stores,
|
||||
nothing better exists on the PDP-11.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat sbi $1==2
|
||||
with src2 REG
|
||||
gen sub %1,%2 yields %2
|
||||
gen sub %1,%2 yields %2
|
||||
with exact REG src2-REG
|
||||
gen sub %2,%1
|
||||
neg %1 yields %1
|
||||
neg %1 yields %1
|
||||
.DE
|
||||
This rule for
|
||||
.I sbi
|
||||
has a normal first part,
|
||||
and a hand optimized special case as it's second part.
|
||||
and a hand optimized special case as its second part.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat mli $1==2
|
||||
with ODDREG src2
|
||||
gen mul %2,%1 yields %1
|
||||
gen mul %2,%1 yields %1
|
||||
with src2 ODDREG
|
||||
gen mul %1,%2 yields %2
|
||||
gen mul %1,%2 yields %2
|
||||
.DE
|
||||
This shows the general property for rules with commutative
|
||||
operators,
|
||||
heuristics or look ahead will have to decide which rule is the best.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat loc sli $1==1 && $2==2
|
||||
with REG
|
||||
gen asl %1 yields %1
|
||||
gen asl %1 yields %1
|
||||
.DE
|
||||
A simple rule involving a longer EM-pattern,
|
||||
to make use of a specialized instruction available.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat loc loc cii $1==1 && $2==2
|
||||
with src1or2
|
||||
uses reusing %1,REG
|
||||
gen movb %1,%a yields %a
|
||||
gen movb %1,%a yields %a
|
||||
.DE
|
||||
A somewhat more complicated example of the same.
|
||||
Note the
|
||||
.I reusing
|
||||
clause.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
pat loc loc loc cii $1>=0 && $2==2 && $3==4 leaving loc $1 loc 0
|
||||
.ta 7.5c
|
||||
pat loc loc loc cii $1>=0 && $2==2 && $3==4
|
||||
leaving loc $1 loc 0
|
||||
.DE
|
||||
Shows a trivial example of EM-replacement.
|
||||
This is a rule that could be done by the
|
||||
@@ -1498,40 +1502,40 @@ if word order in longs was defined in EM.
|
||||
On a `big-endian' machine the two replacement
|
||||
instructions would be the other way around.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat and $1==2
|
||||
with const2 REG
|
||||
gen bic {const2,~%1.num},%2 yields %2
|
||||
gen bic {const2,~%1.num},%2 yields %2
|
||||
with REG const2
|
||||
gen bic {const2,~%2.num},%1 yields %1
|
||||
gen bic {const2,~%2.num},%1 yields %1
|
||||
with REG REG
|
||||
gen com %1
|
||||
bic %1,%2 yields %2
|
||||
bic %1,%2 yields %2
|
||||
.DE
|
||||
Shows the way you have to twist the table,
|
||||
if an
|
||||
.I and -instruction
|
||||
is not available on your machine.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat set $1==2
|
||||
with REG
|
||||
uses REG={const2,1}
|
||||
gen ash %1,%a yields %a
|
||||
gen ash %1,%a yields %a
|
||||
.DE
|
||||
Shows the building of a word-size set.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat lae aar $2==2 && rom($1,3)==1 && rom($1,1)==0
|
||||
leaving adi 2
|
||||
leaving adi 2
|
||||
|
||||
pat lae aar $2==2 && rom($1,3)==1 && rom($1,1)!=0
|
||||
leaving adi 2 adp 0-rom($1,1)
|
||||
leaving adi 2 adp 0-rom($1,1)
|
||||
.DE
|
||||
Two rules showing the use of the rom pseudo function,
|
||||
and some array optimalisation.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat bra
|
||||
with STACK
|
||||
gen jbr {label, $1}
|
||||
@@ -1540,7 +1544,7 @@ A simple jump.
|
||||
The stack pattern guarantees that everything will be stacked
|
||||
before the jump is taken.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat cal
|
||||
with STACK
|
||||
gen jsr pc,{label, $1}
|
||||
@@ -1548,9 +1552,9 @@ gen jsr pc,{label, $1}
|
||||
A simple call.
|
||||
Same comments as previous rule.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
pat lfr $1==2 yields r0
|
||||
pat lfr $1==4 yields r1 r0
|
||||
.ta 7.5c
|
||||
pat lfr $1==2 yields r0
|
||||
pat lfr $1==4 yields r1 r0
|
||||
.DE
|
||||
Shows the return area conventions of the PDP-11 table.
|
||||
At this point a reminder:
|
||||
@@ -1560,7 +1564,7 @@ instruction, and some other instructions must leave
|
||||
the function return area intact.
|
||||
See the defining document for EM for exact information.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat ret $1==0
|
||||
with STACK
|
||||
gen mov lb,sp
|
||||
@@ -1574,7 +1578,7 @@ In a table with register variables the
|
||||
part would just contain
|
||||
.I return .
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat blm
|
||||
with REG REG
|
||||
uses REG={const2,$1/2}
|
||||
@@ -1592,16 +1596,16 @@ It uses the marriage thesis from Hall,
|
||||
a thesis from combinatorial mathematics,
|
||||
to accomplish this.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
pat exg $1==2
|
||||
with src2 src2 yields %1 %2
|
||||
with src2 src2 yields %1 %2
|
||||
.DE
|
||||
This rule shows the exchanging of two elements on the fake stack.
|
||||
.NH 2
|
||||
Code rules using procedures
|
||||
.PP
|
||||
To start this chapter it must be admitted at once that the
|
||||
word procedure is chosen here mainly for it's advertising
|
||||
To start this section it must be admitted at once that the
|
||||
word procedure is chosen here mainly for its advertising
|
||||
value.
|
||||
It more resembles a glorified goto but this of course can
|
||||
not be admitted in the glossy brochures.
|
||||
@@ -1660,12 +1664,12 @@ The string `*' can be used as an equivalent for `[1]'.
|
||||
Just in case this is not clear, here is an example for
|
||||
a procedure to increment/decrement a register.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
incop REG:rw:cc . /* in the INSTRUCTIONS part of course */
|
||||
|
||||
proc incdec
|
||||
with REG
|
||||
gen incop* %1 yields %1
|
||||
gen incop* %1 yields %1
|
||||
.DE
|
||||
The procedure is called with parameter "inc" or "dec".
|
||||
.PP
|
||||
@@ -1676,18 +1680,18 @@ call <identifier> '(' string [ ',' string ] ')'
|
||||
.DE
|
||||
which leads to the following large example:
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
proc bxx example beq
|
||||
with src2 src2 STACK
|
||||
gen cmp %2,%1
|
||||
jxx* {label, $1}
|
||||
|
||||
pat blt call bxx("jlt")
|
||||
pat ble call bxx("jle")
|
||||
pat beq call bxx("jeq")
|
||||
pat bne call bxx("jne")
|
||||
pat bgt call bxx("jgt")
|
||||
pat bge call bxx("jge")
|
||||
pat blt call bxx("jlt")
|
||||
pat ble call bxx("jle")
|
||||
pat beq call bxx("jeq")
|
||||
pat bne call bxx("jne")
|
||||
pat bgt call bxx("jgt")
|
||||
pat bge call bxx("jge")
|
||||
.DE
|
||||
.NH 2
|
||||
Move definitions
|
||||
@@ -1852,38 +1856,38 @@ The next part of the table defines the coercions that are possible
|
||||
on the defined tokens.
|
||||
Example for the PDP-11:
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
COERCIONS
|
||||
|
||||
from STACK
|
||||
uses REG
|
||||
gen mov {autoinc,sp},%a yields %a
|
||||
gen mov {autoinc,sp},%a yields %a
|
||||
|
||||
from STACK
|
||||
uses DBLREG
|
||||
gen movf {autoinc,sp},%a yields %a
|
||||
gen movf {autoinc,sp},%a yields %a
|
||||
|
||||
from STACK
|
||||
uses REGPAIR
|
||||
gen mov {autoinc,sp},%a.1
|
||||
mov {autoinc,sp},%a.2 yields %a
|
||||
mov {autoinc,sp},%a.2 yields %a
|
||||
.DE
|
||||
These three coercions just deliver a certain type
|
||||
of register by popping it from the real stack.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
from LOCAL yields {regind2,lb,%1.ind}
|
||||
.ta 7.5c
|
||||
from LOCAL yields {regind2,lb,%1.ind}
|
||||
|
||||
from DLOCAL yields {regind4,lb,%1.ind}
|
||||
from DLOCAL yields {regind4,lb,%1.ind}
|
||||
|
||||
from REG yields {regconst2, %1, 0}
|
||||
from REG yields {regconst2, %1, 0}
|
||||
.DE
|
||||
These three are zero-cost rewriting rules.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
from regconst2 %1.off==1
|
||||
uses reusing %1,REG=%1.reg
|
||||
gen inc %a yields %a
|
||||
gen inc %a yields %a
|
||||
|
||||
from regconst2
|
||||
uses reusing %1,REG=%1.reg
|
||||
@@ -1892,7 +1896,7 @@ gen add {addr_external, %1.off},%a yields %a
|
||||
from addr_local
|
||||
uses REG
|
||||
gen mov lb,%a
|
||||
add {const2, %1.ind},%a yields %a
|
||||
add {const2, %1.ind},%a yields %a
|
||||
.DE
|
||||
The last three are three different cases of the coercion
|
||||
register+constant to register.
|
||||
@@ -1900,19 +1904,19 @@ Only in the last case is it always necessary to allocate
|
||||
an extra register,
|
||||
since arithmetic on the localbase is unthinkable.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 7.5c
|
||||
from xsrc2
|
||||
uses reusing %1, REG=%1 yields %a
|
||||
uses reusing %1, REG=%1 yields %a
|
||||
|
||||
from longf4
|
||||
uses FLTREG=%1 yields %a
|
||||
uses FLTREG=%1 yields %a
|
||||
|
||||
from double8
|
||||
uses DBLREG=%1 yields %a
|
||||
uses DBLREG=%1 yields %a
|
||||
|
||||
from src1
|
||||
uses REG={const2,0}
|
||||
gen bisb %1,%a yields %a
|
||||
gen bisb %1,%a yields %a
|
||||
.DE
|
||||
These examples show the coercion of different
|
||||
tokens to a register of the needed type.
|
||||
@@ -1921,14 +1925,14 @@ ensure bytes are not sign-extended.
|
||||
In EM it is defined that the result of a \fBloi\fP\ 1
|
||||
instruction is an integer in the range 0..255.
|
||||
.DS
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
from REGPAIR yields %1.2 %1.1
|
||||
.ta 7.5c
|
||||
from REGPAIR yields %1.2 %1.1
|
||||
|
||||
from regind4 yields {regind2,%1.reg,2+%1.off}
|
||||
{regind2,%1.reg,%1.off}
|
||||
from regind4 yields {regind2,%1.reg,2+%1.off}
|
||||
{regind2,%1.reg,%1.off}
|
||||
|
||||
from relative4 yields {relative2,2+%1.off}
|
||||
{relative2,%1.off}
|
||||
from relative4 yields {relative2,2+%1.off}
|
||||
{relative2,%1.off}
|
||||
.DE
|
||||
The last examples are splitting rules.
|
||||
.PP
|
||||
@@ -1953,7 +1957,7 @@ and TEM_PSIZE.
|
||||
The type 'int' is used for things like counters that won't require
|
||||
more than 16 bits precision.
|
||||
The type 'word' is used among others to assemble datawords and
|
||||
is of type 'long' if TEM_WSIZE>2.
|
||||
is of type 'long'.
|
||||
The type 'full' is used for addresses and is of type 'long' if
|
||||
TEM_WSIZE>2 or TEM_PSIZE>2.
|
||||
.PP
|
||||
@@ -2082,25 +2086,25 @@ If omitted no initialization is assumed.
|
||||
.NH 3
|
||||
Example mach.h for the PDP-11
|
||||
.DS L
|
||||
.ta 8 16 24 32 40 48 56
|
||||
.ta 4c
|
||||
#define ex_ap(y) fprintf(codefile,"\et.globl %s\en",y)
|
||||
#define in_ap(y) /* nothing */
|
||||
|
||||
#define newplb(x) fprintf(codefile,"%s:\en",x)
|
||||
#define newilb(x) fprintf(codefile,"%s:\en",x)
|
||||
#define newdlb(x) fprintf(codefile,"%s:\en",x)
|
||||
#define dlbdlb(x,y) fprintf(codefile,"%s=%s\en",x,y)
|
||||
#define dlbdlb(x,y) fprintf(codefile,"%s=%s\en",x,y)
|
||||
#define newlbss(l,x) fprintf(codefile,"%s:.=.+%d.\en",l,x);
|
||||
|
||||
#define cst_fmt "$%d."
|
||||
#define off_fmt "%d."
|
||||
#define ilb_fmt "I%02x%x"
|
||||
#define dlb_fmt "_%d"
|
||||
#define hol_fmt "hol%d"
|
||||
#define cst_fmt "$%d."
|
||||
#define off_fmt "%d."
|
||||
#define ilb_fmt "I%x_%x"
|
||||
#define dlb_fmt "_%d"
|
||||
#define hol_fmt "hol%d"
|
||||
|
||||
#define hol_off "%d.+hol%d"
|
||||
#define hol_off "%ld.+hol%d"
|
||||
|
||||
#define con_cst(x) fprintf(codefile,"%d.\en",x)
|
||||
#define con_cst(x) fprintf(codefile,"%ld.\en",x)
|
||||
#define con_ilb(x) fprintf(codefile,"%s\en",x)
|
||||
#define con_dlb(x) fprintf(codefile,"%s\en",x)
|
||||
|
||||
@@ -2153,7 +2157,7 @@ mes(w_mesno)
|
||||
This function is called when a
|
||||
.B mes
|
||||
pseudo is seen that is not handled by the machine independent part.
|
||||
Example below shows all you probably have to know about that.
|
||||
The example below shows all you probably have to know about that.
|
||||
.IP -
|
||||
segname[]
|
||||
.br
|
||||
@@ -2212,7 +2216,7 @@ Example mach.c for the PDP-11
|
||||
As an example of the sort of code expected,
|
||||
the mach.c for the PDP-11 is presented here.
|
||||
.DS L
|
||||
.ta 8 16 24 32 40 48 56 64
|
||||
.ta 0.5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i
|
||||
/*
|
||||
* machine dependent back end routines for the PDP-11
|
||||
*/
|
||||
@@ -2678,7 +2682,7 @@ otherwise the register is marked empty.
|
||||
.NH 4
|
||||
DO_INSTR
|
||||
.PP
|
||||
This prints an instruction and it's operands.
|
||||
This prints an instruction and its operands.
|
||||
Only done on toplevel.
|
||||
.NH 4
|
||||
DO_MOVE
|
||||
|
||||
68
doc/z80.doc
Normal file
68
doc/z80.doc
Normal file
@@ -0,0 +1,68 @@
|
||||
THE Z80 BACK END TABLE
|
||||
|
||||
INTRODUCTION
|
||||
|
||||
This table was written to make it run, not to make it clever!
|
||||
The effect is, that the table written for the intel 8080,
|
||||
which was made very clever runs faster and requiers less space!!
|
||||
So, for anyone to run programs on a z80 machine:
|
||||
You could try to make the table as clever as the one for the i80,
|
||||
or you could run the i80 table, for that can run on every z80 too.
|
||||
|
||||
IMPLEMENTATION
|
||||
|
||||
It will not be possible to run the entire Amsterdam Compiler Kit on a
|
||||
Z80-based computer system.
|
||||
One has to write a program on another
|
||||
system, a system where the compiler kit runs on.
|
||||
This program may be a mixture of high-level languages, such as
|
||||
C or Pascal, EM and z80 assembly code.
|
||||
The program should be compiled using the compiler kit,
|
||||
producing z80 machine code.
|
||||
This code should come available to the z80 machine
|
||||
for example by downloading or
|
||||
by storing it in ROM (Read Only Memory).
|
||||
Depending on the characteristics of the particular z80 based system, some
|
||||
adaptions have to be made:
|
||||
1) In 'head_em': the base address, which is the address where the first
|
||||
z80 instruction will be stored, and the initial value of the
|
||||
stackpointer are set to 0x1000 and 0x7ffe respectivally.
|
||||
The latter because it could run on a 32K machine as well.
|
||||
Other systems require other values.
|
||||
2) In 'head_em': before calling "_m_a_i_n", the environment
|
||||
pointer, argument vector and argument count will have to be pushed
|
||||
onto the stack.
|
||||
Since this back-end is tested on a system without any knowledge
|
||||
of these things, dummies are pushed now.
|
||||
3) In 'tail_em': proper routines "putchar" and "getchar" should
|
||||
be provided.
|
||||
They should write resp. read a character on/from the monitor.
|
||||
Maybe some conversions will have to be made.
|
||||
The ones for the Nascom and Hermac z80 micro's are to be found
|
||||
in the EM-library.
|
||||
4) In 'head_em': an application program returns control to the monitor by
|
||||
jumping to address 0x20.
|
||||
If this is not the right way on your system, change it.
|
||||
For an CPM-machine for example this should be 0x5, to provide a warm boot.
|
||||
5) In 'tail_em': the current version of the z80 back-end has very limited I/O
|
||||
capabilities, because it was tested on a system that
|
||||
had no knowlegde of files.
|
||||
So the implementation of the EM-instruction 'mon' is very simple;
|
||||
it can only do the following things:
|
||||
Monitor call 1:
|
||||
Exit
|
||||
Monitor call 3:
|
||||
read, always reads from the monitor.
|
||||
echos the read character.
|
||||
ignores file descriptor.
|
||||
Monitor call 4:
|
||||
write, always writes on the monitor.
|
||||
ignores file descriptor.
|
||||
Monitor call 5:
|
||||
open file, returns file descriptor -1.
|
||||
Monitor call 6:
|
||||
close file, returns error code = 0.
|
||||
Monitor call 54:
|
||||
io-control, returns error code = 0.
|
||||
If the system should do file-handling the routine ".mon"
|
||||
should be extended thoroughly.
|
||||
22
first/first
22
first/first
@@ -4,6 +4,21 @@ then :
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
: check write-ability of /tmp and /usr/tmp
|
||||
if ( >/usr/tmp/aaax.$$ )
|
||||
then
|
||||
rm /usr/tmp/aaax.$$
|
||||
else
|
||||
echo /usr/tmp must exist and be writable.
|
||||
exit 2
|
||||
fi
|
||||
if ( >/tmp/aaax.$$ )
|
||||
then
|
||||
rm /tmp/aaax.$$
|
||||
else
|
||||
echo /tmp must exist and be writable.
|
||||
exit 2
|
||||
fi
|
||||
: set ACK HOME Directory in ../h/em_path.h
|
||||
rm -f em_path.h
|
||||
sed -e "/^#define[ ]*EM_DIR/s@\".*\"@\"`cd .. ; pwd`\"@" <../h/em_path.h >em_path.h
|
||||
@@ -31,7 +46,6 @@ vax_bsd4_1c VAX11 with BSD4.1c
|
||||
vax_bsd4_2 VAX11 with BSD4.2
|
||||
pc_ix IBM PC with PC/IX
|
||||
m68_unisoft Motorola 68000 with Unisoft UNIX
|
||||
m68_pmds Philips PMDS
|
||||
ANY Neither of the above
|
||||
|
||||
system type: "
|
||||
@@ -40,9 +54,8 @@ system type: "
|
||||
echo echo "$SYSNAME" >../bin/ack_sys
|
||||
chmod +x ../bin/ack_sys
|
||||
case `ack_sys` in
|
||||
pdp_v7|vax_bsd4_1[ac]|vax_bsd4_2|pc_ix|m68_unisoft|m68_pmds) ;;
|
||||
*) echo None of the software especially intended for
|
||||
the named systems will work ;;
|
||||
pdp_v7|vax_bsd4_1[ac]|vax_bsd4_2|pc_ix|m68_unisoft) ;;
|
||||
*) echo None of the software especially intended for the named systems will work ;;
|
||||
esac
|
||||
else
|
||||
echo Sorry, got EOF when reading system name.
|
||||
@@ -95,7 +108,6 @@ vax_bsd4_1[ac]) ACM=vax2 ;;
|
||||
vax_bsd4_2) ACM=vax2 ;;
|
||||
pc_ix) ACM=ix ;;
|
||||
m68_unisoft) ACM=m68k2 ;;
|
||||
m68_pmds) ACM=pmds ;;
|
||||
*) ACM=m68k2 ;;
|
||||
esac
|
||||
rm -f local.h
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
# define VERSION 3 /* 16 bits number */
|
||||
|
||||
/* The default machine used by ack, acc, apc */
|
||||
# define ACKM "vax2"
|
||||
# define ACKM "pdp"
|
||||
|
||||
120
h/out.h
120
h/out.h
@@ -1,120 +0,0 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* output format for ACK assemblers
|
||||
*/
|
||||
#ifndef ushort
|
||||
#define ushort unsigned short
|
||||
#endif ushort
|
||||
|
||||
struct outhead {
|
||||
ushort oh_magic; /* magic number */
|
||||
ushort oh_stamp; /* version stamp */
|
||||
ushort oh_flags; /* several format flags */
|
||||
ushort oh_nsect; /* number of outsect structures */
|
||||
ushort oh_nrelo; /* number of outrelo structures */
|
||||
ushort oh_nname; /* number of outname structures */
|
||||
long oh_nemit; /* sum of all os_flen */
|
||||
long oh_nchar; /* size of string area */
|
||||
};
|
||||
|
||||
#define O_MAGIC 0x0201 /* magic number of output file */
|
||||
#define O_STAMP 0 /* version stamp */
|
||||
|
||||
#ifdef JOHAN
|
||||
#define HF_BREV 0x0001 /* high order byte lowest address */
|
||||
#define HF_WREV 0x0002 /* high order word lowest address */
|
||||
#endif JOHAN
|
||||
#define HF_LINK 0x0004 /* unresolved references left */
|
||||
#define HF_8086 0x0008 /* os_base specially encoded */
|
||||
|
||||
struct outsect {
|
||||
long os_base; /* startaddress in machine */
|
||||
long os_size; /* section size in machine */
|
||||
long os_foff; /* startaddress in file */
|
||||
long os_flen; /* section size in file */
|
||||
long os_lign; /* section alignment */
|
||||
};
|
||||
|
||||
struct outrelo {
|
||||
char or_type; /* type of reference */
|
||||
char or_sect; /* referencing section */
|
||||
ushort or_nami; /* referenced symbol index */
|
||||
long or_addr; /* referencing address */
|
||||
};
|
||||
|
||||
struct outname {
|
||||
union {
|
||||
char *on_ptr; /* symbol name (in core) */
|
||||
long on_off; /* symbol name (in file) */
|
||||
} on_u;
|
||||
#define on_mptr on_u.on_ptr
|
||||
#define on_foff on_u.on_off
|
||||
ushort on_type; /* symbol type */
|
||||
ushort on_desc; /* debug info */
|
||||
long on_valu; /* symbol value */
|
||||
};
|
||||
|
||||
/*
|
||||
* relocation type bits
|
||||
*/
|
||||
#define RELSZ 0x07 /* relocation length */
|
||||
#define RELO1 1 /* 1 byte */
|
||||
#define RELO2 2 /* 2 bytes */
|
||||
#define RELO4 4 /* 4 bytes */
|
||||
#define RELPC 0x08 /* pc relative */
|
||||
#ifndef JOHAN
|
||||
#define RELBR 0x10 /* High order byte lowest address. */
|
||||
#define RELWR 0x20 /* High order word lowest address. */
|
||||
#endif JOHAN
|
||||
|
||||
/*
|
||||
* section type bits and fields
|
||||
*/
|
||||
#define S_TYP 0x007F /* undefined, absolute or relative */
|
||||
#define S_EXT 0x0080 /* external flag */
|
||||
#define S_ETC 0x7F00 /* for symbolic debug, bypassing 'as' */
|
||||
|
||||
/*
|
||||
* S_TYP field values
|
||||
*/
|
||||
#define S_UND 0x0000 /* undefined item */
|
||||
#define S_ABS 0x0001 /* absolute item */
|
||||
#define S_MIN 0x0002 /* first user section */
|
||||
#define S_MAX S_TYP /* last user section */
|
||||
|
||||
/*
|
||||
* S_ETC field values
|
||||
*/
|
||||
#define S_SCT 0x0100 /* section names */
|
||||
#define S_LIN 0x0200 /* hll source line item */
|
||||
#define S_FIL 0x0300 /* hll source file item */
|
||||
#define S_MOD 0x0400 /* ass source file item */
|
||||
#ifndef JOHAN
|
||||
#define S_COM 0x1000 /* Common name. */
|
||||
#endif JOHAN
|
||||
|
||||
/*
|
||||
* structure format strings
|
||||
*/
|
||||
#define SF_HEAD "22222244"
|
||||
#define SF_SECT "44444"
|
||||
#define SF_RELO "1124"
|
||||
#define SF_NAME "4224"
|
||||
|
||||
/*
|
||||
* structure sizes (bytes in file; add digits in SF_*)
|
||||
*/
|
||||
#define SZ_HEAD 20
|
||||
#define SZ_SECT 20
|
||||
#define SZ_RELO 8
|
||||
#define SZ_NAME 12
|
||||
|
||||
/*
|
||||
* file access macros
|
||||
*/
|
||||
#define BADMAGIC(x) ((x).oh_magic!=O_MAGIC)
|
||||
#define OFF_SECT(x) SZ_HEAD
|
||||
#define OFF_EMIT(x) (OFF_SECT(x) + ((long)(x).oh_nsect * SZ_SECT))
|
||||
#define OFF_RELO(x) (OFF_EMIT(x) + (x).oh_nemit)
|
||||
#define OFF_NAME(x) (OFF_RELO(x) + ((long)(x).oh_nrelo * SZ_RELO))
|
||||
#define OFF_CHAR(x) (OFF_NAME(x) + ((long)(x).oh_nname * SZ_NAME))
|
||||
25
h/ranlib.h
25
h/ranlib.h
@@ -1,25 +0,0 @@
|
||||
/* $Header$ */
|
||||
|
||||
#ifndef SYMDEF
|
||||
# define SYMDEF "__.SYMDEF"
|
||||
#endif SYMDEF
|
||||
|
||||
/*
|
||||
* Structure of the SYMDEF table of contents for an archive.
|
||||
* SYMDEF begins with a long giving the number of ranlib
|
||||
* structures that immediately follow, and then continues with a string
|
||||
* table consisting of a long giving the number of bytes of
|
||||
* strings that follow and then the strings themselves.
|
||||
*/
|
||||
struct ranlib {
|
||||
union {
|
||||
char *ran__ptr; /* symbol name (in core) */
|
||||
long ran__off; /* symbol name (in file) */
|
||||
} ran_u;
|
||||
#define ran_ptr ran_u.ran__ptr
|
||||
#define ran_off ran_u.ran__off
|
||||
long ran_pos; /* library member is at this position */
|
||||
};
|
||||
|
||||
#define SZ_RAN 8
|
||||
#define SF_RAN "44"
|
||||
@@ -19,7 +19,7 @@ double d;
|
||||
String *s;
|
||||
|
||||
s= _newstr(buffer);
|
||||
* ( (double *)s->strval ) = i ;
|
||||
* ( (double *)s->strval ) = d ;
|
||||
return(s);
|
||||
}
|
||||
long _cvi(s)
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# $Revision$
|
||||
var w=2
|
||||
var i=2
|
||||
var p=2
|
||||
var s=2
|
||||
var l=4
|
||||
var f=4
|
||||
var d=8
|
||||
var NAME=m6805
|
||||
var M=6805
|
||||
var LIB=lib/{M}/tail_
|
||||
var RT=lib/{M}/head_
|
||||
var INCLUDES=-I{EM}/include -I/usr/include
|
||||
name asld
|
||||
from .s.a
|
||||
to .out
|
||||
outfile a.out
|
||||
program {EM}/lib/{M}/as
|
||||
mapflag -l* LNAME={EM}/{LIB}*
|
||||
mapflag -d* ASFL={ASFL?} -d*
|
||||
args {ASFL?} (.e:{HEAD}={EM}/{RT}em) \
|
||||
({RTS}:.b.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
|
||||
(.p:{TAIL}={EM}/{LIB}pc) \
|
||||
(.b:{TAIL}={EM}/{LIB}bc) \
|
||||
(.b.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
|
||||
(.b.c.p:{TAIL}={EM}/{LIB}mon) \
|
||||
(.e:{TAIL}={EM}/{LIB}em)
|
||||
linker
|
||||
end
|
||||
@@ -1,40 +0,0 @@
|
||||
# $Revision$
|
||||
var w=2
|
||||
var p=2
|
||||
var s=2
|
||||
var l=4
|
||||
var f=4
|
||||
var d=8
|
||||
var NAME=i8086
|
||||
var M=i86
|
||||
var LIB=lib/i86/tail_
|
||||
var LIBIBM=lib/ibm/tail_
|
||||
var RT=lib/i86/head_
|
||||
var RTIBM=lib/ibm/head_
|
||||
var CPP_F=-Dunix
|
||||
var INCLUDES=-I{EM}/include -I{EM}/lib/ibm/include
|
||||
name be
|
||||
from .m.g
|
||||
to .s
|
||||
program {EM}/lib/{M}/cg
|
||||
args <
|
||||
stdout
|
||||
need .e
|
||||
end
|
||||
name asld
|
||||
from .s.a
|
||||
to .out
|
||||
outfile a.out
|
||||
program {EM}/lib/{M}/as
|
||||
mapflag -l* LNAME={EM}/{LIB}*
|
||||
mapflag -i IFILE={EM}/{RT}i
|
||||
args {IFILE?} (.e:{HEAD}={EM}/{RTIBM}em) \
|
||||
({RTS}:.b.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
|
||||
(.p:{TAIL}={EM}/{LIB}pc) \
|
||||
(.b:{TAIL}={EM}/{LIB}bc) \
|
||||
(.b.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
|
||||
(.e:{TAIL}={EM}/{LIBIBM}em) \
|
||||
(.b.c.p:{TAIL}={EM}/{LIBIBM}mon) \
|
||||
(.e:{TAIL}={EM}/{LIBIBM}em.vend)
|
||||
linker
|
||||
end
|
||||
@@ -1,39 +0,0 @@
|
||||
# $Revision$
|
||||
var w=2
|
||||
var p=4
|
||||
var s=2
|
||||
var l=4
|
||||
var f=4
|
||||
var d=8
|
||||
var NAME=m68k2
|
||||
var M=m68k2
|
||||
var LIBDIR=/lib/{M}
|
||||
var LIB=lib/{M}/tail_
|
||||
var RT=lib/{M}/head_
|
||||
var INCLUDES=-I{EM}/include -I/usr/include
|
||||
name be
|
||||
from .m.g
|
||||
to .s
|
||||
program {EM}/lib/{M}/cg
|
||||
args <
|
||||
stdout
|
||||
need .e
|
||||
end
|
||||
name asld
|
||||
from .s.a
|
||||
to .out
|
||||
outfile a.out
|
||||
program {EM}/lib/{M}/as
|
||||
mapflag -l* LNAME={EM}/{LIB}*
|
||||
args (.e:{HEAD}={EM}/{RT}em) \
|
||||
({RTS}:.b.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
|
||||
(.p.c.b:{TAIL}={EM}/{LIBDIR}/sys1.s) (.p:{TAIL}={EM}/{LIBDIR}/sys2.s) \
|
||||
(.c:{TAIL}={EM}/{LIBDIR}/write.s) \
|
||||
(.p:{TAIL}={EM}/{LIB}pc) \
|
||||
(.b:{TAIL}={EM}/{LIB}bc) \
|
||||
(.b.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
|
||||
(.b.c:{TAIL}={EM}/{LIB}mon {EM}/{LIB}fake) \
|
||||
(.e:{TAIL}={EM}/{LIB}em.rt {EM}/{LIB}em.vend)
|
||||
prep cond
|
||||
linker
|
||||
end
|
||||
@@ -1,30 +0,0 @@
|
||||
# $Revision$
|
||||
var w=1
|
||||
var p=2
|
||||
var s=1
|
||||
var l=2
|
||||
var f=4
|
||||
var d=8
|
||||
var NAME=nascom
|
||||
var M=z80a
|
||||
var LIB=lib/{M}/tail_
|
||||
var RT=lib/{M}/head_
|
||||
var INCLUDES=-I{EM}/include -I/usr/include
|
||||
name be
|
||||
from .m.g
|
||||
to .s
|
||||
program {EM}/lib/{M}/be
|
||||
args <
|
||||
stdout
|
||||
need .e
|
||||
end
|
||||
name asld
|
||||
from .s.a
|
||||
to .out
|
||||
outfile a.out
|
||||
program {EM}/lib/z80/as
|
||||
mapflag -l* LNAME={EM}/{LIB}*
|
||||
args (.e:{HEAD}={EM}/{RT}em) ({RTS}:.b.c={EM}/{RT}cc) -o > \
|
||||
(.e:{TAIL}={EM}/{LIB}em.1 {EM}/{LIB}em.2)
|
||||
linker
|
||||
end
|
||||
@@ -1,32 +0,0 @@
|
||||
var w=2
|
||||
var p=2
|
||||
var s=2
|
||||
var l=4
|
||||
var f=4
|
||||
var d=8
|
||||
var NAME=i8086
|
||||
var M=i86
|
||||
var LIB=mach/i86/lib/tail_
|
||||
var RT=mach/i86/lib/head_
|
||||
var INCLUDES=-I{EM}/include -I/usr/include
|
||||
name be
|
||||
from .m
|
||||
to .s
|
||||
program {EM}/lib/{M}_cg
|
||||
args <
|
||||
prop >
|
||||
need .e
|
||||
end
|
||||
name asld
|
||||
from .s.a
|
||||
to a.out
|
||||
program {EM}/lib/{M}_as
|
||||
mapflag -l* LNAME={EM}/{LIB}*
|
||||
mapflag -i IFILE={EM}/{RT}i
|
||||
args {IFILE?} (.e:{HEAD}={EM}/{RT}em) \
|
||||
({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
|
||||
(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
|
||||
(.c.p.e:{TAIL}={EM}/{LIB}netio) (.c.p.e:{TAIL}={EM}/{LIB}alo) \
|
||||
(.c.p:{TAIL}={EM}/{LIB}mon) (.e:{TAIL}={EM}/{LIB}em)
|
||||
prop C
|
||||
end
|
||||
@@ -1,34 +0,0 @@
|
||||
var w=2
|
||||
var p=2
|
||||
var s=2
|
||||
var l=4
|
||||
var f=4
|
||||
var d=8
|
||||
var NAME=i8086
|
||||
var M=i86
|
||||
var LIB=mach/i86/lib/tail_
|
||||
var ALIB=mach/i86/lib/sat_tail_
|
||||
var RT=mach/i86/lib/head_
|
||||
var ART=mach/i86/lib/sat_head_
|
||||
var CCP_F=-Dunix
|
||||
var INCLUDES=-I{EM}/include -I/usr/include
|
||||
name be
|
||||
from .m
|
||||
to .s
|
||||
program {EM}/lib/{M}_cg
|
||||
args <
|
||||
prop >
|
||||
need .e
|
||||
end
|
||||
name asld
|
||||
from .s.a
|
||||
to a.out
|
||||
program {EM}/lib/{M}_as
|
||||
mapflag -l* LNAME={EM}/{LIB}*
|
||||
args (.e:{HEAD}={EM}/{ART}em) \
|
||||
({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
|
||||
(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
|
||||
(.c.p:{TAIL}={EM}/{ALIB}mon) (.c.p.e:{TAIL}={EM}/{LIB}alo) \
|
||||
(.e:{TAIL}={EM}/{LIB}em)
|
||||
prop C
|
||||
end
|
||||
@@ -6,7 +6,7 @@ var l=4
|
||||
var f=4
|
||||
var d=8
|
||||
var NAME=i8080
|
||||
var M=8080
|
||||
var M=i80
|
||||
var LIB=lib/{M}/tail_
|
||||
var RT=lib/{M}/head_
|
||||
var INCLUDES=-I{EM}/include -I/usr/include
|
||||
@@ -31,6 +31,6 @@ name asld
|
||||
(.b:{TAIL}={EM}/{LIB}bc) \
|
||||
(.b.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
|
||||
(.b.c.p:{TAIL}={EM}/{LIB}mon) \
|
||||
(.e:{TAIL}={EM}/{LIB}em)
|
||||
(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}sys)
|
||||
linker
|
||||
end
|
||||
|
||||
@@ -22,7 +22,6 @@ end
|
||||
name asld
|
||||
from .s.a
|
||||
to .out
|
||||
outfile a.out
|
||||
program {EM}/lib/{M}/as
|
||||
mapflag -l* LNAME={EM}/{LIB}*
|
||||
args (.e:{HEAD}={EM}/{RT}em) \
|
||||
@@ -34,3 +33,10 @@ name asld
|
||||
prep cond
|
||||
linker
|
||||
end
|
||||
name cv
|
||||
from .out
|
||||
to .cv
|
||||
program {EM}/lib/{M}/cv
|
||||
args < >
|
||||
outfile a.out
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# $Revision$
|
||||
# $Revision 2.2$
|
||||
var w=4
|
||||
var p=4
|
||||
var s=2
|
||||
@@ -7,32 +7,37 @@ var f=4
|
||||
var d=8
|
||||
var NAME=m68k4
|
||||
var M=m68k4
|
||||
var LIBDIR=/lib/{M}
|
||||
var LIB=lib/{M}/tail_
|
||||
var RT=lib/{M}/head_
|
||||
var CPP_F=-Dunix
|
||||
var LIB=lib/m68k4/tail_
|
||||
var RT=lib/m68k4/head_
|
||||
var INCLUDES=-I{EM}/include -I/usr/include
|
||||
name be
|
||||
from .m.g
|
||||
to .s
|
||||
from .m
|
||||
to .o
|
||||
program {EM}/lib/{M}/cg
|
||||
args <
|
||||
stdout
|
||||
need .e
|
||||
end
|
||||
name asld
|
||||
from .s.a
|
||||
from .s.a.o
|
||||
to .out
|
||||
outfile a.out
|
||||
program {EM}/lib/m68k2/as
|
||||
mapflag -l* LNAME={EM}/{LIB}*
|
||||
args (.e:{HEAD}={EM}/{RT}em) \
|
||||
({RTS}:.b.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
|
||||
(.p.c.b:{TAIL}={EM}/{LIBDIR}/sys1.s) (.p:{TAIL}={EM}/{LIBDIR}/sys2.s) \
|
||||
(.c.b:{TAIL}={EM}/{LIBDIR}/write.s) \
|
||||
(.p:{TAIL}={EM}/{LIB}pc) (.b.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
|
||||
(.c.b:{TAIL}={EM}/{LIB}mon {EM}/{LIB}fake) \
|
||||
(.e:{TAIL}={EM}/{LIB}em.rt {EM}/{LIB}em.vend)
|
||||
mapflag -d* LFLAG={LFLAG?} -d*
|
||||
mapflag -s* LFLAG={LFLAG?} -s*
|
||||
mapflag -n*
|
||||
mapflag -i*
|
||||
args {LFLAG?} (.e:{HEAD}={EM}/{RT}em) \
|
||||
({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
|
||||
(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
|
||||
(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}mon {EM}/lib/{M}/end_em)
|
||||
prep cond
|
||||
linker
|
||||
end
|
||||
name cv
|
||||
from .out
|
||||
to .cv
|
||||
program {EM}/lib/m68k2/cv
|
||||
args < >
|
||||
outfile a.out
|
||||
end
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# $Revision$
|
||||
# Script for use of ACK as cross C-compiler on VAX for PMDS machine
|
||||
# The output has its int's in the pmds order.
|
||||
# Conversion from VU-a.out to PMDS-a.out should still be done on the pmds.
|
||||
var w=2
|
||||
var p=4
|
||||
var s=2
|
||||
@@ -46,7 +44,7 @@ end
|
||||
name cv
|
||||
from .out
|
||||
to .cv
|
||||
program {EM}/lib/{PMDS}/pmcv
|
||||
program {EM}/lib/{PMDS}/cv
|
||||
args < >
|
||||
outfile a.out
|
||||
end
|
||||
|
||||
43
lib/pmds4/descr
Normal file
43
lib/pmds4/descr
Normal file
@@ -0,0 +1,43 @@
|
||||
# $Header$
|
||||
var w=4
|
||||
var p=4
|
||||
var s=2
|
||||
var l=4
|
||||
var f=4
|
||||
var d=8
|
||||
var NAME=m68k4
|
||||
var M=m68k4
|
||||
var LIB=mach/m68k4/lib/tail_
|
||||
var RT=mach/m68k4/lib/head_
|
||||
var INCLUDES=-I{EM}/include
|
||||
name be
|
||||
from .m
|
||||
to .o
|
||||
program {EM}/lib/{M}/cg
|
||||
args <
|
||||
stdout
|
||||
need .e
|
||||
end
|
||||
name asld
|
||||
from .s.a.o
|
||||
to .out
|
||||
program {EM}/lib/m68k2/as
|
||||
mapflag -l* LNAME={EM}/{LIB}*
|
||||
mapflag -d* LFLAG={LFLAG?} -d*
|
||||
mapflag -s* LFLAG={LFLAG?} -s*
|
||||
mapflag -n*
|
||||
mapflag -i*
|
||||
args {LFLAG?} (.e:{HEAD}={EM}/lib/pmds4/head_em) \
|
||||
({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
|
||||
(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
|
||||
(.e:{TAIL}={EM}/{LIB}em {EM}/lib/pmds4/mon {EM}/end_em)
|
||||
prep cond
|
||||
linker
|
||||
end
|
||||
name cv
|
||||
from .out
|
||||
to .cv
|
||||
program {EM}/lib/{PMDS}/cv
|
||||
args < >
|
||||
outfile a.out
|
||||
end
|
||||
@@ -24,13 +24,13 @@ name asld
|
||||
outfile a.out
|
||||
program {EM}/lib/{M}/as
|
||||
mapflag -l* LNAME={EM}/{LIB}*
|
||||
mapflag -i IFILE={EM}/{RT}i
|
||||
args {IFILE?} (.e:{HEAD}={EM}/{RT}em) \
|
||||
mapflag -i
|
||||
args (.e:{HEAD}={EM}/{RT}em) \
|
||||
({RTS}:.b.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
|
||||
(.p:{TAIL}={EM}/{LIB}pc) \
|
||||
(.b:{TAIL}={EM}/{LIB}bc) \
|
||||
(.b.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
|
||||
(.b.c.p:{TAIL}={EM}/{LIB}mon) \
|
||||
(.e:{TAIL}={EM}/{LIB}em)
|
||||
(.e:{TAIL}={EM}/{LIB}em {EM}/{LIB}sys {EM}/lib/{M}/end_em)
|
||||
linker
|
||||
end
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.define endtext, enddata, endbss, end
|
||||
|
||||
.text
|
||||
.align 2
|
||||
endtext:
|
||||
.align 2
|
||||
.data
|
||||
.align 2
|
||||
enddata:
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
name "4-4 Interpreter C libraries"
|
||||
dir libcc
|
||||
end
|
||||
name "4-4 Interpreter Pascal library"
|
||||
dir libpc
|
||||
end
|
||||
name "4-4 Interpreter Basic library"
|
||||
dir libbc
|
||||
end
|
||||
|
||||
@@ -3,7 +3,6 @@ MACHDEF="MACH=int44" "SUF=m"
|
||||
BCDEF="PREF=bc" "SUB=" "SRC=lang/basic/lib"
|
||||
|
||||
install:
|
||||
RANLIB=ranlib ; export RANLIB ;\
|
||||
make -f $(MAKEFILE) $(BCDEF) $(MACHDEF) tailcp
|
||||
|
||||
cmp:
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
name "Intel 8080 assembler"
|
||||
dir as
|
||||
end
|
||||
name "Intel 8080 code generator"
|
||||
dir cg
|
||||
end
|
||||
name "Intel 8080 download programs"
|
||||
dir dl
|
||||
end
|
||||
name "Intel 8080 Basic library"
|
||||
dir libbc
|
||||
end
|
||||
name "Intel 8080 C libraries"
|
||||
dir libcc
|
||||
end
|
||||
name "Intel 8080 EM library"
|
||||
dir libem
|
||||
end
|
||||
name "Intel 8080 Pascal library"
|
||||
dir libpc
|
||||
end
|
||||
name "Intel 8080 System library"
|
||||
dir libsys
|
||||
end
|
||||
|
||||
19
mach/i80/dl/Makefile
Normal file
19
mach/i80/dl/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
head: mccpm nascom
|
||||
|
||||
mccpm: mccpm.c
|
||||
cc -o mccpm mccpm.c
|
||||
|
||||
nascom: nascom.c
|
||||
cc -o nascom nascom.c
|
||||
|
||||
install:
|
||||
@echo Nothing is installed
|
||||
|
||||
clean:
|
||||
rm nascom mccpm
|
||||
|
||||
pr:
|
||||
@pr `pwd`/Makefile `pwd`/mccpm.c `pwd`/nascom.c
|
||||
|
||||
opr:
|
||||
make pr | opr
|
||||
5
mach/i80/dl/README
Normal file
5
mach/i80/dl/README
Normal file
@@ -0,0 +1,5 @@
|
||||
This directory contains files mccpm.c and nascom.c.
|
||||
The first one downloads the mc/cpm
|
||||
computer, using the standard Intel hex-dump format.
|
||||
The output appears on standard output.
|
||||
The latter does the same for the Nascom.
|
||||
@@ -1,18 +1,32 @@
|
||||
static char rcsid[] = "$Header$";
|
||||
/*
|
||||
* dit programma leest een a.out file
|
||||
* voor een kleine uP (adres space = 64K)
|
||||
* en levert aan de standaard output een
|
||||
* download formaat voor de MCCPM computer.
|
||||
*
|
||||
*/
|
||||
|
||||
#define MAXBYTE 24
|
||||
#include <stdio.h>
|
||||
char hex[] = "0123456789ABCDEF";
|
||||
FILE *fp, *fopen();
|
||||
char **s;
|
||||
int bytes, bytcnt, checksum;
|
||||
long pc;
|
||||
unsigned pc;
|
||||
unsigned offset;
|
||||
unsigned htou();
|
||||
|
||||
|
||||
main (argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
if (argc != 2) fatal ("usage: %s filename\n",argv[0]);
|
||||
if (argc > 3)
|
||||
fatal ("usage: %s filename [start-adres]\n",argv[0]);
|
||||
offset = 0;
|
||||
if (argc == 3)
|
||||
if (!(offset = htou(argv[2])))
|
||||
fatal ("adres error %s\n", argv[2]);
|
||||
if ((fp = fopen (*++argv,"r")) == NULL)
|
||||
fatal ("can't open %s\n",*argv);
|
||||
else {
|
||||
@@ -28,50 +42,44 @@ convert ()
|
||||
do
|
||||
{
|
||||
pc = getword ();
|
||||
pc = (pc << 16) | getword ();
|
||||
pc -= offset;
|
||||
bytes = getword ();
|
||||
bytes = getword ();
|
||||
while (bytes != 0)
|
||||
{
|
||||
bytcnt = (bytes < MAXBYTE) ? bytes : MAXBYTE;
|
||||
bytes -= bytcnt;
|
||||
checksum = 0;
|
||||
if (pc > 0xffffL) S2record (); else S1record ();
|
||||
Irecord ();
|
||||
}
|
||||
c = getc (fp);
|
||||
ungetc (c, fp);
|
||||
}
|
||||
while (c != EOF);
|
||||
printf ("S9030000FC\n");
|
||||
printf (":00000001FF\n");
|
||||
}
|
||||
|
||||
|
||||
S2record ()
|
||||
Irecord ()
|
||||
{
|
||||
printf ("S2");
|
||||
printf (":");
|
||||
outbyte (bytcnt);
|
||||
bytcnt += 4;
|
||||
outbyte (bytcnt);
|
||||
outbyte (pc >> 8);
|
||||
outbyte (pc);
|
||||
outbyte (0);
|
||||
record ();
|
||||
}
|
||||
|
||||
S1record ()
|
||||
{
|
||||
printf ("S1");
|
||||
bytcnt += 3;
|
||||
outbyte (bytcnt);
|
||||
record ();
|
||||
}
|
||||
|
||||
record ()
|
||||
{
|
||||
outbyte (pc << 8);
|
||||
outbyte (pc << 16);
|
||||
while (bytcnt != 0)
|
||||
{
|
||||
outbyte (getbyte ());
|
||||
pc ++;
|
||||
}
|
||||
outbyte (~checksum);
|
||||
outbyte (-checksum);
|
||||
putchar ('\n');
|
||||
putchar (0);
|
||||
putchar (0);
|
||||
@@ -80,9 +88,9 @@ record ()
|
||||
outbyte (b)
|
||||
int b;
|
||||
{
|
||||
checksum = (checksum + b) & 0377;
|
||||
putchar (hex[(b>>4) & 017]);
|
||||
putchar (hex[b & 017]);
|
||||
checksum = (checksum + b) & 0xFF;
|
||||
putchar (hex[(b>>4) & 0xF]);
|
||||
putchar (hex[b & 0xF]);
|
||||
-- bytcnt;
|
||||
}
|
||||
|
||||
@@ -104,3 +112,24 @@ fatal (s,a)
|
||||
printf (s,a);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
/* convert a string of hex digits to an unsigned 16 bit number */
|
||||
|
||||
unsigned htou(t)
|
||||
char *t;
|
||||
{
|
||||
unsigned n = 0;
|
||||
char c;
|
||||
while(c = *t++){
|
||||
if(c >= '0' && c <= '9')
|
||||
c -= '0';
|
||||
else if(c >= 'a' && c <= 'f')
|
||||
c -= 'a' - 10;
|
||||
else if(c >= 'A' && c <= 'F')
|
||||
c -= 'A' - 10;
|
||||
else
|
||||
return(0);
|
||||
n = n * 16 + c;
|
||||
}
|
||||
return(n);
|
||||
}
|
||||
139
mach/i80/dl/nascom.c
Normal file
139
mach/i80/dl/nascom.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Download Z80 load module into the NASCOM
|
||||
*
|
||||
* Johan Stevenson, Vrije Universiteit, Amsterdam
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <sgtty.h>
|
||||
#include <signal.h>
|
||||
|
||||
int check;
|
||||
int nascom = 1;
|
||||
int nl = '\037';
|
||||
int zero = 0;
|
||||
int disp = 0;
|
||||
|
||||
char hex[] = "0123456789ABCDEF";
|
||||
|
||||
struct sgttyb ttynormal;
|
||||
struct sgttyb ttyraw;
|
||||
int rawmode = 0;
|
||||
|
||||
stop(code) {
|
||||
if (rawmode)
|
||||
stty(1, &ttynormal);
|
||||
exit(code);
|
||||
}
|
||||
|
||||
main(argc,argv) char **argv; {
|
||||
register unsigned nd,pc;
|
||||
register char *s;
|
||||
|
||||
while (argc > 1 && argv[1][0] == '-') {
|
||||
switch (argv[1][1]) {
|
||||
case 'u':
|
||||
/* unix output */
|
||||
nascom = 0;
|
||||
nl = '\n';
|
||||
break;
|
||||
case 'e':
|
||||
/* fill EPROM. make minimal change */
|
||||
zero = 0xFF;
|
||||
break;
|
||||
case 'd':
|
||||
/* displacement at load time */
|
||||
disp = atoi(&argv[1][2]);
|
||||
break;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
s = "a.out";
|
||||
if (argc == 2)
|
||||
s = argv[1];
|
||||
else if (argc != 1) {
|
||||
fprintf(stderr,"usage: %s [flags] [object file]\n",argv[0]);
|
||||
stop(-1);
|
||||
}
|
||||
if (freopen(s,"r",stdin) == NULL) {
|
||||
fprintf(stderr,"%s: can't open %s\n",argv[0],s);
|
||||
stop(-1);
|
||||
}
|
||||
if (nascom) {
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGQUIT, stop);
|
||||
signal(SIGTERM, stop);
|
||||
if (gtty(1, &ttynormal) < 0) {
|
||||
fprintf(stderr, "no tty\n");
|
||||
stop(-1);
|
||||
}
|
||||
rawmode++;
|
||||
ttyraw = ttynormal;
|
||||
ttyraw.sg_flags |= RAW;
|
||||
ttyraw.sg_ispeed = B1200;
|
||||
ttyraw.sg_ospeed = B1200;
|
||||
stty(1, &ttyraw);
|
||||
sleep(5);
|
||||
}
|
||||
for (;;) {
|
||||
pc = get2c(stdin);
|
||||
if (feof(stdin))
|
||||
break;
|
||||
nd = get2c(stdin);
|
||||
nd = get2c(stdin);
|
||||
if (nd > 256) {
|
||||
fprintf(stderr,"bad format on %s\n",s);
|
||||
stop(1);
|
||||
}
|
||||
while (nd > 8) {
|
||||
data(8,pc);
|
||||
nd -= 8;
|
||||
pc += 8;
|
||||
}
|
||||
if (nd > 0)
|
||||
data(nd,pc);
|
||||
assert(feof(stdin) == 0);
|
||||
}
|
||||
putchar('.');
|
||||
putchar(nl);
|
||||
if (nascom)
|
||||
sleep(5);
|
||||
stop(0);
|
||||
}
|
||||
|
||||
data(nd,pc) {
|
||||
register i;
|
||||
|
||||
check = 0;
|
||||
pc += disp;
|
||||
byte(pc>>8);
|
||||
byte(pc);
|
||||
for (i = 0; i < nd; i++) {
|
||||
putchar(' ');
|
||||
byte(getc(stdin));
|
||||
}
|
||||
while (i < 8) {
|
||||
putchar(' ');
|
||||
byte(zero);
|
||||
i++;
|
||||
}
|
||||
putchar(' ');
|
||||
byte(check);
|
||||
putchar(nl);
|
||||
}
|
||||
|
||||
byte(b) {
|
||||
|
||||
check += b;
|
||||
putchar(hex[(b>>4) & 017]);
|
||||
putchar(hex[b & 017]);
|
||||
}
|
||||
|
||||
get2c(f) FILE *f; {
|
||||
register c;
|
||||
|
||||
c = getc(f);
|
||||
return((getc(f) << 8) | c);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
MAKEFILE=../../proto/libg/Makefile
|
||||
MACHDEF="MACH=8080" "SUF=s"
|
||||
MACHDEF="MACH=i80" "SUF=s"
|
||||
BCDEF="PREF=bc" "SUB=" "SRC=lang/basic/lib"
|
||||
|
||||
install:
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
${MACH?ack} -I../../../h ${MACHFL?} $1 1>&2
|
||||
echo `basename $1 $2`.s
|
||||
if ${MACH?ack} -DCPM -I../../../h ${MACHFL?} $1 1>&2
|
||||
then echo `basename $1 $2`.s
|
||||
else rm -f `basename $1 $2`.s
|
||||
fi
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
MAKEFILE=../../proto/libg/Makefile
|
||||
MACHDEF="MACH=8080" "SUF=s"
|
||||
MACHDEF="MACH=i80" "SUF=s"
|
||||
STDIO="PREF=cc" "SUB=.1s" "SRC=lang/cem/libcc/stdio"
|
||||
GEN="PREF=cc" "SUB=.2g" "SRC=lang/cem/libcc/gen"
|
||||
MON="PREF=mon" "SRC=lang/cem/libcc/mon"
|
||||
|
||||
4
mach/i80/libcc/compmodule
Executable file
4
mach/i80/libcc/compmodule
Executable file
@@ -0,0 +1,4 @@
|
||||
if ${MACH?ack} -DCPM -I../../../h ${MACHFL?} $1 1>&2
|
||||
then echo `basename $1 $2`.s
|
||||
else rm -f `basename $1 $2`.s
|
||||
fi
|
||||
37
mach/i80/libem/LIST
Normal file
37
mach/i80/libem/LIST
Normal file
@@ -0,0 +1,37 @@
|
||||
tail
|
||||
aar2.s
|
||||
adi4.s
|
||||
and.s
|
||||
blm.s
|
||||
cii.s
|
||||
cmi4.s
|
||||
cms.s
|
||||
com.s
|
||||
csa.s
|
||||
csb.s
|
||||
dup.s
|
||||
dvi2.s
|
||||
exg.s
|
||||
inn.s
|
||||
ior.s
|
||||
lar2.s
|
||||
mli2.s
|
||||
mli4.s
|
||||
mlu2.s
|
||||
ngi4.s
|
||||
nop.s
|
||||
rol4.s
|
||||
ror4.s
|
||||
sar2.s
|
||||
sbi4.s
|
||||
set.s
|
||||
set2.s
|
||||
sli2.s
|
||||
sli4.s
|
||||
sri2.s
|
||||
sri4.s
|
||||
xor.s
|
||||
loi.s
|
||||
sti.s
|
||||
dvi4.s
|
||||
rck.s
|
||||
14
mach/i80/libem/Makefile
Normal file
14
mach/i80/libem/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
install: tail
|
||||
../../install tail tail_em
|
||||
|
||||
cmp: tail
|
||||
-../../compare tail tail_em
|
||||
|
||||
tail:
|
||||
arch cr `cat LIST`
|
||||
|
||||
opr:
|
||||
make pr | opr
|
||||
pr:
|
||||
@pr `pwd`/Makefile
|
||||
@pr -l33 `tail +1 LIST|sort`
|
||||
42
mach/i80/libem/aar2.s
Normal file
42
mach/i80/libem/aar2.s
Normal file
@@ -0,0 +1,42 @@
|
||||
.define .aar2
|
||||
|
||||
! Load address of array element, decriptor contains 2-bytes integers
|
||||
! Expects on stack: pointer to array descriptor
|
||||
! index
|
||||
! base address
|
||||
! Yields on stack: address of array element
|
||||
|
||||
.aar2:
|
||||
pop h
|
||||
shld .retadr1
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
pop h ! hl = pointer to descriptor
|
||||
pop d ! de = index
|
||||
mov a,e ! bc = index - lower bound
|
||||
sub m
|
||||
inx h
|
||||
mov c,a
|
||||
mov a,d
|
||||
sbb m
|
||||
inx h
|
||||
mov b,a
|
||||
push b ! first operand to multiply
|
||||
inx h
|
||||
inx h
|
||||
mov c,m ! bc = size
|
||||
inx h
|
||||
mov b,m
|
||||
push b ! second operand to multiply
|
||||
call .mli2 ! de = size * (index - lower bound)
|
||||
pop h ! hl = base address
|
||||
dad d ! hl = address of array[index]
|
||||
push h
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr1
|
||||
pchl
|
||||
23
mach/i80/libem/adi4.s
Normal file
23
mach/i80/libem/adi4.s
Normal file
@@ -0,0 +1,23 @@
|
||||
.define .adi4
|
||||
|
||||
! Add two 32 bits signed or unsigned integers
|
||||
! Expects on stack: operands
|
||||
! Yields on stack: result
|
||||
|
||||
.adi4: pop h
|
||||
shld .retadr ! get return address out of the way
|
||||
pop d
|
||||
pop h
|
||||
xthl
|
||||
dad d
|
||||
shld .tmp1
|
||||
pop d
|
||||
pop h
|
||||
jnc 1f
|
||||
inx h
|
||||
1: dad d
|
||||
push h
|
||||
lhld .tmp1
|
||||
push h
|
||||
lhld .retadr
|
||||
pchl
|
||||
37
mach/i80/libem/and.s
Normal file
37
mach/i80/libem/and.s
Normal file
@@ -0,0 +1,37 @@
|
||||
.define .and
|
||||
|
||||
! Any size logical-'and'.
|
||||
! Expects: size in de-registers
|
||||
! operands on stack
|
||||
! Yields: result on stack
|
||||
|
||||
.and: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
lxi h,0
|
||||
dad sp
|
||||
mov c,l
|
||||
mov b,h !now bc points to top of first operand
|
||||
dad d !and hl points to top of second perand
|
||||
push h !this will be the new stackpointer
|
||||
1: ldax b
|
||||
ana m
|
||||
mov m,a
|
||||
inx h
|
||||
inx b
|
||||
dcx d
|
||||
mov a,e
|
||||
ora d
|
||||
jnz 1b
|
||||
|
||||
pop h
|
||||
sphl
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
31
mach/i80/libem/blm.s
Normal file
31
mach/i80/libem/blm.s
Normal file
@@ -0,0 +1,31 @@
|
||||
.define .blm
|
||||
|
||||
! Block move
|
||||
! Expects in de-reg: size of block
|
||||
! Expects on stack: destination address
|
||||
! source address
|
||||
|
||||
.blm: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
pop h ! hl = destination address
|
||||
pop b ! bc = source address
|
||||
|
||||
1: ldax b
|
||||
mov m,a
|
||||
inx b
|
||||
inx h
|
||||
dcx d
|
||||
mov a,d
|
||||
ora e
|
||||
jnz 1b
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
|
||||
84
mach/i80/libem/cii.s
Normal file
84
mach/i80/libem/cii.s
Normal file
@@ -0,0 +1,84 @@
|
||||
.define .cii
|
||||
|
||||
! Convert integer to integer
|
||||
! Expects in a-reg: 1 for signed integer to signed integer (cii)
|
||||
! 0 for unsigned integer to unsigned integer (cuu)
|
||||
! Expects on stack: destination size
|
||||
! source size
|
||||
! source
|
||||
! Yields on stack: result
|
||||
|
||||
.cii: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
sta .areg ! save a-register
|
||||
pop b
|
||||
mov e,c
|
||||
pop b ! c = source size
|
||||
mov b,e ! b = destination size
|
||||
mov a,b
|
||||
cmp c
|
||||
jz 3f ! destination size = source size
|
||||
jc shrink ! destination size < source size
|
||||
|
||||
! if destination size > source size only:
|
||||
lxi h,0
|
||||
dad sp
|
||||
mov e,l
|
||||
mov d,h ! de = stackpointer
|
||||
mov a,b
|
||||
sub c ! c = (still) source size
|
||||
mov b,a ! b = destination size - source size
|
||||
cma
|
||||
mov l,a
|
||||
mvi h,255
|
||||
inx h
|
||||
dad d ! hl = stackpointer - (dest. size - source size)
|
||||
sphl ! new stackpointer
|
||||
|
||||
1: ldax d ! move source downwards
|
||||
mov m,a
|
||||
inx d
|
||||
inx h
|
||||
dcr c
|
||||
jnz 1b
|
||||
|
||||
ral ! a-reg still contains most significant byte of source
|
||||
jnc 1f ! jump if is a positive integer
|
||||
lda .areg
|
||||
ora a
|
||||
jz 1f ! jump if it is a cuu
|
||||
mvi c,255 ! c-reg contains filler byte
|
||||
|
||||
1: mov m,c ! fill
|
||||
inx h
|
||||
dcr b
|
||||
jnz 1b
|
||||
jmp 3f ! done
|
||||
|
||||
!if destination size < source size only:
|
||||
shrink: mov l,c ! load source size in hl
|
||||
mvi h,0
|
||||
dad sp
|
||||
mov d,h
|
||||
mov e,l ! de points just above source
|
||||
mov l,b ! load destination size in hl
|
||||
mvi h,0
|
||||
dad sp ! hl points just above "destination"
|
||||
|
||||
1: dcx d ! move upwards
|
||||
dcx h
|
||||
mov a,m
|
||||
stax d
|
||||
dcr b
|
||||
jnz 1b
|
||||
sphl
|
||||
|
||||
3: lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
66
mach/i80/libem/cmi4.s
Normal file
66
mach/i80/libem/cmi4.s
Normal file
@@ -0,0 +1,66 @@
|
||||
.define .cmi4
|
||||
|
||||
! Compare 32 bits integers
|
||||
! Expects: operands on stack
|
||||
! a-register = 1 for signed integers
|
||||
! a-register = 0 for unsigned integers
|
||||
! Yields in de-registers: -1 if second operand < first operand
|
||||
! 0 if second operand = first operand
|
||||
! 1 if second operand > first operand
|
||||
|
||||
.cmi4: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
lxi b,4
|
||||
lxi h,0
|
||||
dad sp
|
||||
dad b
|
||||
dcx h
|
||||
mov d,h
|
||||
mov e,l !now de points to the first operand
|
||||
dad b !and hl to the second
|
||||
ora a !is it a cmi or cmu?
|
||||
jz 1f
|
||||
|
||||
!for cmi only:
|
||||
mov a,m
|
||||
ral
|
||||
jnc 2f
|
||||
ldax d !second operand is negative
|
||||
ral
|
||||
jc 1f !jump if both operands are negative
|
||||
lxi d,-1 !second operand is smaller
|
||||
jmp 4f
|
||||
2: ldax d !second operand is positive
|
||||
ral
|
||||
jnc 1f !jump if both operand are positive
|
||||
lxi d,1 !second operand is larger
|
||||
jmp 4f
|
||||
|
||||
!cmi and cmu rejoin here
|
||||
1: ldax d
|
||||
cmp m
|
||||
jz 3f
|
||||
jnc 2f
|
||||
lxi d,1 !second operand is larger
|
||||
jmp 4f
|
||||
2: lxi d,-1 !second operand is smaller
|
||||
jmp 4f
|
||||
3: dcx d
|
||||
dcx h
|
||||
dcr c
|
||||
jnz 1b
|
||||
lxi d,0 !operands are equal
|
||||
|
||||
4: lxi h,8
|
||||
dad sp
|
||||
sphl
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
35
mach/i80/libem/cms.s
Normal file
35
mach/i80/libem/cms.s
Normal file
@@ -0,0 +1,35 @@
|
||||
.define .cms
|
||||
|
||||
! Any size compare
|
||||
! Expects: size in de-registers
|
||||
! operands on stack
|
||||
! Yields in de-registers: 0 if operands are equal
|
||||
! 1 if operands are not equal
|
||||
|
||||
.cms:
|
||||
pop h
|
||||
shld .retadr
|
||||
|
||||
mov l,e
|
||||
mov h,d
|
||||
mov a,l
|
||||
rar
|
||||
cc eoddz !trap is size is odd
|
||||
dad sp !now hl points to second operand
|
||||
!and sp points to the first.
|
||||
1: dcx sp
|
||||
pop psw !get next byte in accumulator
|
||||
cmp m
|
||||
inx h
|
||||
dcx d
|
||||
jnz 2f !jump if bytes are not equal
|
||||
mov a,d
|
||||
ora e
|
||||
jnz 1b
|
||||
jmp 3f
|
||||
2: dad d
|
||||
lxi d,1
|
||||
3: sphl
|
||||
|
||||
lhld .retadr
|
||||
pchl
|
||||
20
mach/i80/libem/com.s
Normal file
20
mach/i80/libem/com.s
Normal file
@@ -0,0 +1,20 @@
|
||||
.define .com
|
||||
|
||||
! Complement bytes on top of stack.
|
||||
! Expects in de-registers: number of bytes
|
||||
|
||||
.com: pop h
|
||||
shld .retadr
|
||||
lxi h,0
|
||||
dad sp
|
||||
1: mov a,m
|
||||
cma
|
||||
mov m,a
|
||||
inx h
|
||||
dcx d
|
||||
mov a,e
|
||||
ora d
|
||||
jnz 1b
|
||||
lhld .retadr
|
||||
pchl
|
||||
|
||||
52
mach/i80/libem/csa.s
Normal file
52
mach/i80/libem/csa.s
Normal file
@@ -0,0 +1,52 @@
|
||||
.define .csa
|
||||
|
||||
! Case jump
|
||||
! Expects on stack: address of case descriptor
|
||||
! case index
|
||||
! This is not a subroutine, but just a piece of code that computes
|
||||
! the jump address and jumps to it.
|
||||
! Traps if resulting address is zero.
|
||||
|
||||
.csa: pop h !hl = address of case descriptor
|
||||
pop d !de = index
|
||||
push b !save localbase
|
||||
mov c,m
|
||||
inx h
|
||||
mov b,m
|
||||
inx h
|
||||
push b !save default pointer on stack
|
||||
mov a,e
|
||||
sub m
|
||||
inx h
|
||||
mov c,a
|
||||
mov a,d
|
||||
sbb m
|
||||
inx h
|
||||
mov b,a !bc = index - lower bound
|
||||
jc 1f !get default pointer
|
||||
mov a,m
|
||||
inx h
|
||||
sub c
|
||||
mov a,m
|
||||
inx h
|
||||
sbb b
|
||||
jc 1f !upper-lower should be >= index-lower
|
||||
dad b
|
||||
dad b !hl now points to the wanted pointer
|
||||
mov a,m
|
||||
inx h
|
||||
mov h,m
|
||||
mov l,a !hl = pointer for index
|
||||
ora h
|
||||
jz 1f !get default pointer if pointer = 0
|
||||
pop b !remove default pointer
|
||||
pop b !localbase
|
||||
pchl !jump!!!!
|
||||
|
||||
1: pop h !get default pointer
|
||||
mov a,l
|
||||
ora h
|
||||
cz ecase !trap
|
||||
pop b !restore localbase
|
||||
pchl !jump!!!!
|
||||
|
||||
53
mach/i80/libem/csb.s
Normal file
53
mach/i80/libem/csb.s
Normal file
@@ -0,0 +1,53 @@
|
||||
.define .csb
|
||||
|
||||
! Table lookup jump
|
||||
! Expects on stack: address of case descriptor
|
||||
! case index
|
||||
! This is not a subroutine, but just a piece of code that computes
|
||||
! the jump address and jumps to it.
|
||||
! Traps if resulting address is zero.
|
||||
|
||||
.csb: pop h !hl = pointer to descriptor
|
||||
pop d !de = case index
|
||||
push b !save localbase
|
||||
mov c,m !bc = default pointer
|
||||
inx h
|
||||
mov b,m
|
||||
inx h
|
||||
push b !save default on stack
|
||||
mov c,m !bc = number of entries
|
||||
inx h
|
||||
mov b,m
|
||||
inx h
|
||||
!loop: try to find the case index in the descriptor
|
||||
1: mov a,b
|
||||
ora c
|
||||
jz 4f !done, index not found
|
||||
mov a,m !do we have the right index?
|
||||
inx h
|
||||
cmp e
|
||||
jnz 2f !no
|
||||
mov a,m
|
||||
inx h
|
||||
cmp d
|
||||
jnz 3f !no
|
||||
mov a,m
|
||||
inx h
|
||||
mov h,m
|
||||
mov l,a
|
||||
pop psw !remove default pointer
|
||||
jmp 5f
|
||||
|
||||
2: inx h !skip high byte of index
|
||||
3: inx h !skip jump address
|
||||
inx h
|
||||
dcx b
|
||||
jmp 1b
|
||||
|
||||
4: pop h !take default exit
|
||||
5: pop b !restore localbase
|
||||
mov a,l !jump address is zero?
|
||||
ora h
|
||||
cz ecase !trap
|
||||
pchl !jump!!!!
|
||||
|
||||
34
mach/i80/libem/dup.s
Normal file
34
mach/i80/libem/dup.s
Normal file
@@ -0,0 +1,34 @@
|
||||
.define .dup
|
||||
|
||||
! Duplicate top bytes of stack
|
||||
! Expects in de-registers: number of bytes to duplicate
|
||||
|
||||
.dup: mov a,e !trap if number is odd
|
||||
rar
|
||||
cc eoddz
|
||||
|
||||
pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
mov h,d
|
||||
mov l,e
|
||||
dad sp
|
||||
1: dcx h
|
||||
mov b,m
|
||||
dcx h
|
||||
mov c,m
|
||||
push b
|
||||
dcx d
|
||||
dcx d !number of bytes must be a word-multiple i.e. even
|
||||
mov a,d
|
||||
ora e
|
||||
jnz 1b
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
114
mach/i80/libem/dvi2.s
Normal file
114
mach/i80/libem/dvi2.s
Normal file
@@ -0,0 +1,114 @@
|
||||
|
||||
.define .dvi2
|
||||
|
||||
! 16 bits signed and unsigned integer divide and remainder routine
|
||||
! Bit 0 of a-reg is set iff quotient has to be delivered
|
||||
! Bit 7 of a-reg is set iff the operands are signed, so:
|
||||
! Expects in a-reg: 0 if called by rmu 2
|
||||
! 1 if called by dvu 2
|
||||
! 128 if called by rmi 2
|
||||
! 129 if called by dvi 2
|
||||
! Expects on stack: divisor
|
||||
! dividend
|
||||
! Yields in de-reg: quotient or remainder
|
||||
|
||||
.dvi2: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
sta .areg
|
||||
pop b ! bc = divisor
|
||||
mov a,b ! trap if divisor = 0
|
||||
ora c
|
||||
cz eidivz
|
||||
pop d ! de = dividend
|
||||
|
||||
mvi h,0
|
||||
lda .areg
|
||||
ral
|
||||
jnc 0f ! jump if unsigned
|
||||
|
||||
mov a,d
|
||||
ral
|
||||
jnc 1f ! jump if dividend >= 0
|
||||
mvi h,129 ! indicate dividend is negative
|
||||
xra a ! negate dividend
|
||||
sub e
|
||||
mov e,a
|
||||
mvi a,0
|
||||
sbb d
|
||||
mov d,a
|
||||
! de is positive now
|
||||
|
||||
1: mov a,b
|
||||
ral
|
||||
jc 2f ! jump if divisor < 0
|
||||
0: inr h ! indicate negation
|
||||
xra a ! negate divisor
|
||||
sub c
|
||||
mov c,a
|
||||
mvi a,0
|
||||
sbb b
|
||||
mov b,a
|
||||
! bc is negative now
|
||||
|
||||
2: push h ! save h-reg
|
||||
lxi h,0 ! initial value of remainder
|
||||
mvi a,16 ! initialize loop counter
|
||||
|
||||
3: push psw ! save loop counter
|
||||
dad h ! shift left: hl <- de <- 0
|
||||
xchg
|
||||
dad h
|
||||
xchg
|
||||
jnc 4f
|
||||
inx h
|
||||
|
||||
4: push h ! save remainder
|
||||
dad b ! subtract divisor (add negative)
|
||||
jnc 5f
|
||||
xthl
|
||||
inx d
|
||||
|
||||
5: pop h
|
||||
pop psw ! restore loop counter
|
||||
dcr a
|
||||
jnz 3b
|
||||
|
||||
pop b ! b-reg becomes what once was h-reg
|
||||
lda .areg
|
||||
rar ! what has to be delivered: quotient or remainder?
|
||||
jnc 6f
|
||||
|
||||
! for dvi 2 and dvu 2 only:
|
||||
mov a,b
|
||||
rar
|
||||
jc 8f ! jump if divisor and dividend had same sign
|
||||
xra a ! negate quotient
|
||||
sub e
|
||||
mov e,a
|
||||
mvi a,0
|
||||
sbb d
|
||||
mov d,a
|
||||
jmp 8f
|
||||
|
||||
! for rmi 2 and rmu 2 only:
|
||||
6: mov a,b
|
||||
ral
|
||||
jnc 7f ! negate remainder if dividend was negative
|
||||
xra a
|
||||
sub l
|
||||
mov l,a
|
||||
mvi a,0
|
||||
sbb h
|
||||
mov h,a
|
||||
7: mov d,h ! return remainder
|
||||
mov e,l
|
||||
|
||||
8: lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
145
mach/i80/libem/dvi4.s
Normal file
145
mach/i80/libem/dvi4.s
Normal file
@@ -0,0 +1,145 @@
|
||||
.define .dvi4
|
||||
|
||||
! 32 bits integer divide and remainder routine
|
||||
! Bit 0 of a-reg is set iff quotient has to be delivered
|
||||
! Bit 7 of a-reg is set iff the operands are signed, so:
|
||||
! Expects in a-reg: 0 if called by rmu 4
|
||||
! 1 if called by dvu 4
|
||||
! 128 if called by rmi 4
|
||||
! 129 if called by dvi 4
|
||||
! Expects on stack: divisor
|
||||
! dividend
|
||||
! Yields on stack: quotient or remainder
|
||||
|
||||
.dvi4: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
sta .areg
|
||||
pop h ! store divisor
|
||||
shld block3
|
||||
xchg
|
||||
pop h
|
||||
shld block3+2
|
||||
dad d
|
||||
jc 1f
|
||||
mov a,l
|
||||
ora h
|
||||
cz eidivz ! trap if divisor = 0
|
||||
|
||||
1: pop h ! store dividend
|
||||
shld block1
|
||||
pop h
|
||||
shld block1+2
|
||||
lxi h,0 ! store initial value of remainder
|
||||
shld block2
|
||||
shld block2+2
|
||||
|
||||
mvi b,0
|
||||
lda .areg
|
||||
ral
|
||||
jnc 2f ! jump if unsigned
|
||||
|
||||
lda block1+3
|
||||
ral
|
||||
jnc 1f
|
||||
mvi b,129
|
||||
lxi h,block1
|
||||
call compl ! dividend is positive now
|
||||
|
||||
1: lda block3+3
|
||||
ral
|
||||
jnc 2f
|
||||
inr b
|
||||
lxi h,block3
|
||||
call compl ! divisor is positive now
|
||||
|
||||
2: push b ! save b-reg
|
||||
mvi b,32
|
||||
|
||||
dv0: lxi h,block1 ! left shift: block2 <- block1 <- 0
|
||||
mvi c,8
|
||||
xra a
|
||||
1: mov a,m
|
||||
ral
|
||||
mov m,a
|
||||
inx h
|
||||
dcr c
|
||||
jnz 1b
|
||||
lxi h,block2+3 ! which is larger: divisor or remainder?
|
||||
lxi d,block3+3
|
||||
mvi c,4
|
||||
1: ldax d
|
||||
cmp m
|
||||
jz 0f
|
||||
jnc 3f
|
||||
jmp 4f
|
||||
0: dcx d
|
||||
dcx h
|
||||
dcr c
|
||||
jnz 1b
|
||||
|
||||
4: lxi d,block2 ! remainder is larger or equal: subtract divisor
|
||||
lxi h,block3
|
||||
mvi c,4
|
||||
xra a
|
||||
1: ldax d
|
||||
sbb m
|
||||
stax d
|
||||
inx d
|
||||
inx h
|
||||
dcr c
|
||||
jnz 1b
|
||||
lxi h,block1
|
||||
inr m
|
||||
|
||||
3: dcr b
|
||||
jnz dv0 ! keep looping
|
||||
|
||||
pop b
|
||||
lda .areg ! quotient or remainder?
|
||||
rar
|
||||
jnc 4f
|
||||
|
||||
! for dvi 4 and dvu 4 only:
|
||||
mov a,b
|
||||
rar
|
||||
lxi h,block1 ! complement quotient if divisor
|
||||
cc compl ! and dividend have different signs
|
||||
lhld block1+2 ! push quotient
|
||||
push h
|
||||
lhld block1
|
||||
push h
|
||||
jmp 5f
|
||||
|
||||
! for rmi 4 and rmu 4 only:
|
||||
4: mov a,b
|
||||
ral
|
||||
lxi h,block2
|
||||
cc compl ! negate remainder if dividend was negative
|
||||
lhld block2+2
|
||||
push h
|
||||
lhld block2
|
||||
push h
|
||||
|
||||
5: lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
|
||||
! make 2's complement of 4 bytes pointed to by hl.
|
||||
compl: push b
|
||||
mvi c,4
|
||||
xra a
|
||||
1: mvi a,0
|
||||
sbb m
|
||||
mov m,a
|
||||
inx h
|
||||
dcr c
|
||||
jnz 1b
|
||||
pop b
|
||||
ret
|
||||
|
||||
40
mach/i80/libem/exg.s
Normal file
40
mach/i80/libem/exg.s
Normal file
@@ -0,0 +1,40 @@
|
||||
.define .exg
|
||||
|
||||
! Exchange top bytes of stack
|
||||
! Expects in de-registers the number of bytes to be exchanged.
|
||||
|
||||
.exg: mov a,e
|
||||
rar
|
||||
cc eoddz !trap if numer of bytes is odd
|
||||
pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
lxi h,0
|
||||
dad sp
|
||||
mov b,h
|
||||
mov c,l !now bc points to first operand
|
||||
dad d !and hl to the second
|
||||
push d !place number of bytes on top of stack
|
||||
1: mov d,m
|
||||
ldax b
|
||||
mov m,a
|
||||
mov a,d
|
||||
stax b
|
||||
xthl !caused by a lack of registers
|
||||
dcx h !decrement top of stack
|
||||
mov a,h
|
||||
ora l
|
||||
xthl
|
||||
inx h
|
||||
inx b
|
||||
jnz 1b
|
||||
|
||||
pop d
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
61
mach/i80/libem/inn.s
Normal file
61
mach/i80/libem/inn.s
Normal file
@@ -0,0 +1,61 @@
|
||||
.define .inn
|
||||
|
||||
! Any size bit test on set.
|
||||
! Expects in de-reg: size of set (in bytes)
|
||||
! Expects on stack: bit number
|
||||
! set to be tested
|
||||
! Yields in de-reg.: 0 if bit is reset or bit number out of range
|
||||
! 1 if bit is set
|
||||
|
||||
.inn: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
pop h
|
||||
xchg !hl = size, de = bit number
|
||||
mov a,d !test if bit number is negative
|
||||
ral
|
||||
jc 3f
|
||||
mov a,e
|
||||
ani 7
|
||||
mov b,a !save bits 0-2 of bit number in b-reg
|
||||
mvi c,3
|
||||
1: xra a
|
||||
mov a,d !shift bit number right 3 times
|
||||
rar
|
||||
mov d,a
|
||||
mov a,e
|
||||
rar
|
||||
mov e,a
|
||||
dcr c
|
||||
jnz 1b
|
||||
|
||||
mov a,l !test if bit number is small enough
|
||||
sub e
|
||||
mov a,h
|
||||
sbb d
|
||||
jc 3f
|
||||
xchg
|
||||
dad sp
|
||||
xchg
|
||||
ldax d !a-register = wanted byte
|
||||
2: dcr b !dcr doesn't affect carry bit
|
||||
jm 4f
|
||||
rar
|
||||
jmp 2b
|
||||
|
||||
3: xra a !return 0 if bit number out of range
|
||||
4: ani 1
|
||||
mov e,a
|
||||
mvi d,0
|
||||
dad sp
|
||||
sphl
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
|
||||
38
mach/i80/libem/ior.s
Normal file
38
mach/i80/libem/ior.s
Normal file
@@ -0,0 +1,38 @@
|
||||
.define .ior
|
||||
|
||||
|
||||
! Any size inclusive-or.
|
||||
! Expects: size in de-registers
|
||||
! operands on stack
|
||||
! Yields: result on stack
|
||||
|
||||
.ior: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
lxi h,0
|
||||
dad sp
|
||||
mov c,l
|
||||
mov b,h !now bc points to top of first operand
|
||||
dad d !and hl points to top of second operand
|
||||
push h !this will be the new stackpointer
|
||||
1: ldax b
|
||||
ora m
|
||||
mov m,a
|
||||
inx h
|
||||
inx b
|
||||
dcx d
|
||||
mov a,e
|
||||
ora d
|
||||
jnz 1b
|
||||
|
||||
pop h
|
||||
sphl
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
71
mach/i80/libem/lar2.s
Normal file
71
mach/i80/libem/lar2.s
Normal file
@@ -0,0 +1,71 @@
|
||||
.define .lar2
|
||||
|
||||
! Load array element, descriptor contains 2-bytes integers
|
||||
! Expects on stack: pointer to array descriptor
|
||||
! index
|
||||
! base address
|
||||
! Yields on stack: array element
|
||||
! Adapted from .aar2 and .loi
|
||||
|
||||
.lar2:
|
||||
pop h
|
||||
shld .retadr1
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
pop h ! hl = pointer to descriptor
|
||||
pop d ! de = index
|
||||
mov a,e ! bc = index - lower bound
|
||||
sub m
|
||||
inx h
|
||||
mov c,a
|
||||
mov a,d
|
||||
sbb m
|
||||
inx h
|
||||
mov b,a
|
||||
push b ! first operand to multiply
|
||||
inx h
|
||||
inx h
|
||||
mov c,m ! bc = size
|
||||
inx h
|
||||
mov b,m
|
||||
push b ! second operand to multiply
|
||||
call .mli2 ! de = size * (index - lower bound)
|
||||
pop h ! hl = base address
|
||||
dad d ! hl = address of array[index]
|
||||
dad b ! hl= load pointer
|
||||
xra a ! clear carry bit
|
||||
mov a,b ! divide bc by 2
|
||||
rar
|
||||
mov b,a
|
||||
mov a,c
|
||||
rar
|
||||
mov c,a
|
||||
jnc 1f
|
||||
|
||||
! for 1 byte array element only:
|
||||
mov a,c ! trap if bc odd and <>1
|
||||
ora b
|
||||
cnz eoddz
|
||||
dcx h
|
||||
mov e,m
|
||||
mvi d,0
|
||||
push d
|
||||
jmp 2f
|
||||
|
||||
1: dcx h
|
||||
mov d,m
|
||||
dcx h
|
||||
mov e,m
|
||||
push d
|
||||
dcx b
|
||||
mov a,b
|
||||
ora c
|
||||
jnz 1b
|
||||
|
||||
2: lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr1
|
||||
pchl
|
||||
50
mach/i80/libem/loi.s
Normal file
50
mach/i80/libem/loi.s
Normal file
@@ -0,0 +1,50 @@
|
||||
.define .loi
|
||||
|
||||
! Load indirect
|
||||
! Expects in de-registers: number of bytes to be loaded
|
||||
! (this number should be 1 or even )
|
||||
! Expects on stack: base address
|
||||
! Yields on stack: result
|
||||
|
||||
.loi: pop h
|
||||
shld .retadr
|
||||
mov l,c ! free bc for scratch
|
||||
mov h,b
|
||||
shld .bcreg
|
||||
|
||||
pop h ! hl = base address
|
||||
dad d ! hl = load pointer
|
||||
xra a ! clear carry bit
|
||||
mov a,d ! divide d by 2
|
||||
rar
|
||||
mov d,a
|
||||
mov a,e
|
||||
rar
|
||||
mov e,a
|
||||
jnc 1f
|
||||
|
||||
! if 1 byte has to be loaded only:
|
||||
mov a,d
|
||||
ora e
|
||||
cnz eoddz ! trap if number is odd and <> 1
|
||||
dcx h
|
||||
mov c,m
|
||||
mvi b,0
|
||||
push b
|
||||
jmp 2f
|
||||
|
||||
1: dcx h
|
||||
mov b,m
|
||||
dcx h
|
||||
mov c,m
|
||||
push b
|
||||
dcx d ! is count exhausted?
|
||||
mov a,d
|
||||
ora e
|
||||
jnz 1b
|
||||
|
||||
2: lhld .bcreg
|
||||
mov c,l
|
||||
mov b,h
|
||||
lhld .retadr
|
||||
pchl
|
||||
80
mach/i80/libem/mli2.s
Normal file
80
mach/i80/libem/mli2.s
Normal file
@@ -0,0 +1,80 @@
|
||||
.define .mli2
|
||||
|
||||
! 16 bits signed integer multiply
|
||||
! the algorithm multiples A * B, where A = A0*2^8 + A1 and B = B0*2^8 + B1
|
||||
! product is thus A0*B0*2^16 + 2^8 * (A0 * B1 + B0 * A1) + A0 * B0
|
||||
! hence either A0 = 0 or B0 = 0 or overflow.
|
||||
! initial part of code determines which high byte is 0 (also for negative #s)
|
||||
! then the multiply is reduced to 8 x 16 bits, with the 8 bit number in the
|
||||
! a register, the 16 bit number in the hl register, and the product in de
|
||||
! Expects operands on stack
|
||||
! Yields result in de-registers
|
||||
|
||||
.mli2: pop h
|
||||
shld .retadr ! get the return address out of the way
|
||||
lxi h,255
|
||||
pop d
|
||||
mov a,d ! check hi byte for 0
|
||||
cmp h ! h = 0
|
||||
jz 1f ! jump if de is a positive 8 bit number
|
||||
cmp l
|
||||
jz 5f ! jump if de is a negative 8 bit number
|
||||
xchg
|
||||
shld .tmp1 ! we ran out of scratch registers
|
||||
pop h
|
||||
mov a,h
|
||||
cmp e
|
||||
jz 7f ! jump if second operand is 8 bit negative
|
||||
jmp 6f ! assume second operand is 8 bit positive
|
||||
|
||||
1: mov a,e ! 8 bit positive number in a
|
||||
pop h ! 16 bit number in hl
|
||||
|
||||
! here is the main loop of the multiplication. the a register is shifted
|
||||
! right 1 bit to load the carry bit for testing.
|
||||
! as soon as the a register goes to zero, the loop terminates.
|
||||
! in most cases this requires fewer than 8 iterations.
|
||||
2: lxi d,0
|
||||
ora a
|
||||
3: rar ! load carry bit from a
|
||||
jnc 4f ! add hl to de if low bit was a 1
|
||||
xchg
|
||||
dad d
|
||||
xchg
|
||||
4: dad h
|
||||
ora a ! sets zero correct and resets carry bit
|
||||
jnz 3b ! if a has more bits, continue the loop
|
||||
lhld .retadr ! go get return address
|
||||
pchl
|
||||
|
||||
! the 8 bit operand is negative. negate both operands
|
||||
5: pop h
|
||||
mov a,l
|
||||
cma
|
||||
mov l,a
|
||||
mov a,h
|
||||
cma
|
||||
mov h,a
|
||||
inx h ! 16 bit negate is 1s complement + 1
|
||||
xra a
|
||||
sub e ! negate 8 bit operand
|
||||
jmp 2b
|
||||
|
||||
! second operand is small and positive
|
||||
6: mov a,l
|
||||
lhld .tmp1
|
||||
jmp 2b
|
||||
|
||||
! second operand is small and negative
|
||||
7: mov e,l
|
||||
lhld .tmp1
|
||||
mov a,l
|
||||
cma
|
||||
mov l,a
|
||||
mov a,h
|
||||
cma
|
||||
mov h,a
|
||||
inx h
|
||||
xra a
|
||||
sub e
|
||||
jmp 2b
|
||||
72
mach/i80/libem/mli4.s
Normal file
72
mach/i80/libem/mli4.s
Normal file
@@ -0,0 +1,72 @@
|
||||
.define .mli4
|
||||
|
||||
! 32 bits signed and unsigned integer multiply routine
|
||||
! Expects operands on stack
|
||||
! Yields product on stack
|
||||
|
||||
.mli4: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
pop h ! store multiplier
|
||||
shld block1
|
||||
pop h
|
||||
shld block1+2
|
||||
pop h ! store multiplicand
|
||||
shld block2
|
||||
pop h
|
||||
shld block2+2
|
||||
lxi h,0
|
||||
shld block3 ! product = 0
|
||||
shld block3+2
|
||||
lxi b,0
|
||||
lp1: lxi h,block1
|
||||
dad b
|
||||
mov a,m ! get next byte of multiplier
|
||||
mvi b,8
|
||||
lp2: rar
|
||||
jnc 2f
|
||||
lhld block2 ! add multiplicand to product
|
||||
xchg
|
||||
lhld block3
|
||||
dad d
|
||||
shld block3
|
||||
lhld block2+2
|
||||
jnc 1f
|
||||
inx h
|
||||
1: xchg
|
||||
lhld block3+2
|
||||
dad d
|
||||
shld block3+2
|
||||
|
||||
2: lhld block2 ! shift multiplicand left
|
||||
dad h
|
||||
shld block2
|
||||
lhld block2+2
|
||||
jnc 3f
|
||||
dad h
|
||||
inx h
|
||||
jmp 4f
|
||||
3: dad h
|
||||
4: shld block2+2
|
||||
|
||||
dcr b
|
||||
jnz lp2
|
||||
|
||||
inr c
|
||||
mov a,c
|
||||
cpi 4
|
||||
jnz lp1
|
||||
|
||||
lhld block3+2
|
||||
push h
|
||||
lhld block3
|
||||
push h
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
46
mach/i80/libem/mlu2.s
Normal file
46
mach/i80/libem/mlu2.s
Normal file
@@ -0,0 +1,46 @@
|
||||
.define .mlu2
|
||||
|
||||
! 16 bits unsigned multiply routine
|
||||
! Expects operands on stack
|
||||
! Yields result in de-registers
|
||||
! This routine could also be used for signed integers, but it won't
|
||||
! because there is a more clever one just for signed integers.
|
||||
|
||||
.mlu2:
|
||||
pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
pop b ! bc = multiplier
|
||||
pop d ! de = multiplicand
|
||||
lxi h,0 ! hl = product
|
||||
|
||||
1: mov a,b ! if multiplier = 0 then finished
|
||||
ora c
|
||||
jz 3f
|
||||
|
||||
xra a ! reset carry
|
||||
mov a,b ! shift multiplier right
|
||||
rar
|
||||
mov b,a
|
||||
mov a,c
|
||||
rar
|
||||
mov c,a
|
||||
|
||||
jnc 2f !if carry set: add multiplicand to product
|
||||
dad d
|
||||
|
||||
2: xchg ! shift multiplicand left
|
||||
dad h
|
||||
xchg
|
||||
jmp 1b ! keep looping
|
||||
|
||||
3: xchg ! de becomes product
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
26
mach/i80/libem/ngi4.s
Normal file
26
mach/i80/libem/ngi4.s
Normal file
@@ -0,0 +1,26 @@
|
||||
.define .ngi4
|
||||
|
||||
! Exchange 32 bits integer by its two's complement
|
||||
! Expects operand on stack
|
||||
! Yields result on stack
|
||||
|
||||
.ngi4: pop d
|
||||
lxi h,0
|
||||
dad sp
|
||||
xra a
|
||||
sub m
|
||||
mov m,a
|
||||
inx h
|
||||
mvi a,0
|
||||
sbb m
|
||||
mov m,a
|
||||
inx h
|
||||
mvi a,0
|
||||
sbb m
|
||||
mov m,a
|
||||
inx h
|
||||
mvi a,0
|
||||
sbb m
|
||||
mov m,a
|
||||
push d
|
||||
ret
|
||||
25
mach/i80/libem/nop.s
Normal file
25
mach/i80/libem/nop.s
Normal file
@@ -0,0 +1,25 @@
|
||||
.define .nop
|
||||
|
||||
.nop: push b
|
||||
lhld hol0+4
|
||||
mov d,h
|
||||
mov e,l
|
||||
call prstring
|
||||
lxi d,lin
|
||||
call prstring
|
||||
lhld hol0
|
||||
call prdec
|
||||
lxi d,stpr
|
||||
call prstring
|
||||
lxi h,0
|
||||
dad sp
|
||||
call prdec
|
||||
lxi d,newline
|
||||
call prstring
|
||||
pop b
|
||||
ret
|
||||
|
||||
|
||||
lin: .asciz " lin:"
|
||||
stpr: .asciz " sp:"
|
||||
newline:.asciz "\n"
|
||||
52
mach/i80/libem/rck.s
Normal file
52
mach/i80/libem/rck.s
Normal file
@@ -0,0 +1,52 @@
|
||||
.define .rck
|
||||
|
||||
! Range check
|
||||
! Expects on stack: address of range check descriptor
|
||||
! index
|
||||
! Yields index on stack unchanged
|
||||
! Causes a trap if index is out of bounds
|
||||
|
||||
.rck: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
pop h ! hl = return address
|
||||
pop d ! de = index
|
||||
mov c,m ! bc = lower bound
|
||||
inx h
|
||||
mov b,m
|
||||
inx h
|
||||
mov a,d
|
||||
xor b
|
||||
jm 1f ! jump if index and l.b. have different signs
|
||||
mov a,e
|
||||
sub c
|
||||
mov a,d
|
||||
sbb b
|
||||
jmp 2f
|
||||
|
||||
1: xor b ! now a = d again
|
||||
2: cm erange ! trap if index too small
|
||||
|
||||
mov c,m
|
||||
inx h
|
||||
mov b,m
|
||||
mov a,d
|
||||
xor b
|
||||
jm 1f ! jump if index and u.b. have different signs
|
||||
mov a,c
|
||||
sub e
|
||||
mov a,b
|
||||
sbb d
|
||||
jmp 2f
|
||||
|
||||
1: xor d ! now a = b
|
||||
2: cm erange ! trap if index is too large
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
47
mach/i80/libem/rol4.s
Normal file
47
mach/i80/libem/rol4.s
Normal file
@@ -0,0 +1,47 @@
|
||||
.define .rol4
|
||||
|
||||
! Rotate 4 bytes left
|
||||
! Expects in de-reg: number of rotates
|
||||
! Expects on stack: operand
|
||||
! Yields on stack: result
|
||||
|
||||
.rol4 pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
.rol4: pop h ! low-order bytes of operand
|
||||
pop b ! high order bytes of operand
|
||||
|
||||
mov a,e
|
||||
ani 31
|
||||
jz 2f
|
||||
mov e,a
|
||||
|
||||
mov a,b
|
||||
ral
|
||||
1: mov a,l
|
||||
ral
|
||||
mov l,a
|
||||
mov a,h
|
||||
ral
|
||||
mov h,a
|
||||
mov a,c
|
||||
ral
|
||||
mov c,a
|
||||
mov a,b
|
||||
ral
|
||||
mov b,a
|
||||
|
||||
dcr e
|
||||
jnz 1b ! keep looping
|
||||
|
||||
2: push b
|
||||
push h
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
47
mach/i80/libem/ror4.s
Normal file
47
mach/i80/libem/ror4.s
Normal file
@@ -0,0 +1,47 @@
|
||||
.define .ror4
|
||||
|
||||
! Rotate 4 bytes right
|
||||
! Expects in de-reg: number of rotates
|
||||
! Expects on stack: operand
|
||||
! Yields on stack: result
|
||||
|
||||
.ror4 pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
.ror4: pop h ! low-order bytes of operand
|
||||
pop b ! high order bytes of operand
|
||||
|
||||
mov a,e
|
||||
ani 31
|
||||
jz 2f
|
||||
mov e,a
|
||||
|
||||
mov a,l
|
||||
rar
|
||||
1: mov a,b
|
||||
rar
|
||||
mov b,a
|
||||
mov a,c
|
||||
rar
|
||||
mov c,a
|
||||
mov a,h
|
||||
rar
|
||||
mov h,a
|
||||
mov a,l
|
||||
rar
|
||||
mov l,a
|
||||
|
||||
dcr e
|
||||
jnz 1b ! keep looping
|
||||
|
||||
2: push b
|
||||
push h
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
68
mach/i80/libem/sar2.s
Normal file
68
mach/i80/libem/sar2.s
Normal file
@@ -0,0 +1,68 @@
|
||||
.define .sar2
|
||||
|
||||
! Store array element, descriptor contains 2-bytes integers
|
||||
! Expects on stack: pointer to array descriptor
|
||||
! index
|
||||
! base address
|
||||
! array element
|
||||
! Adapted from .aar2 and .sti
|
||||
|
||||
.sar2:
|
||||
pop h
|
||||
shld .retadr1
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
pop h ! hl = pointer to descriptor
|
||||
pop d ! de = index
|
||||
mov a,e ! bc = index - lower bound
|
||||
sub m
|
||||
inx h
|
||||
mov c,a
|
||||
mov a,d
|
||||
sbb m
|
||||
inx h
|
||||
mov b,a
|
||||
push b ! first operand to multiply
|
||||
inx h
|
||||
inx h
|
||||
mov c,m ! bc = size
|
||||
inx h
|
||||
mov b,m
|
||||
push b ! second operand to multiply
|
||||
call .mli2 ! de = size * (index - lower bound)
|
||||
pop h ! hl = base address
|
||||
dad d ! hl = address of array[index]
|
||||
xra a
|
||||
mov a,b
|
||||
rar
|
||||
mov b,a
|
||||
mov a,c
|
||||
rar
|
||||
mov c,a ! bc = word count
|
||||
jnc 1f
|
||||
|
||||
! if 1 byte array element only:
|
||||
mov a,c ! trap if bc odd and <>1
|
||||
ora b
|
||||
cnz eoddz
|
||||
pop d
|
||||
mov m,e
|
||||
jmp 2f
|
||||
|
||||
1: pop d
|
||||
mov m,e
|
||||
inx h
|
||||
mov m,d
|
||||
inx h
|
||||
dcx b
|
||||
mov a,b
|
||||
ora c
|
||||
jnz 1b
|
||||
|
||||
2: lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr1
|
||||
pchl
|
||||
37
mach/i80/libem/sbi4.s
Normal file
37
mach/i80/libem/sbi4.s
Normal file
@@ -0,0 +1,37 @@
|
||||
.define .sbi4
|
||||
|
||||
! Subtract two 32 bits signed or unsigned integers.
|
||||
! Expects operands on stack
|
||||
! Yields result on stack
|
||||
|
||||
.sbi4:
|
||||
pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
lxi h,0
|
||||
dad sp !now hl points to the first operand
|
||||
mov d,h
|
||||
mov e,l
|
||||
inx d
|
||||
inx d
|
||||
inx d
|
||||
inx d !and de points to the second.
|
||||
mvi b,4
|
||||
xra a
|
||||
1: ldax d
|
||||
sbb m
|
||||
stax d
|
||||
inx d
|
||||
inx h
|
||||
dcr b
|
||||
jnz 1b
|
||||
sphl
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
65
mach/i80/libem/set.s
Normal file
65
mach/i80/libem/set.s
Normal file
@@ -0,0 +1,65 @@
|
||||
.define .set
|
||||
|
||||
! Create set with one bit on
|
||||
! Expects in de-reg: size of set to be created
|
||||
! Expects on stack: bit number
|
||||
! Yields on stack: resulting set
|
||||
|
||||
.set: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
mov a,e
|
||||
rar
|
||||
cc eoddz ! trap if size is odd
|
||||
xchg ! hl = size of set
|
||||
pop d ! de = bit number
|
||||
mov a,e ! c = bit number in byte
|
||||
ani 7
|
||||
sta .areg ! save bit number in byte
|
||||
|
||||
mvi b,3 ! de = byte number
|
||||
1: xra a
|
||||
mov a,d
|
||||
rar
|
||||
mov d,a
|
||||
mov a,e
|
||||
rar
|
||||
mov e,a
|
||||
dcr b
|
||||
jnz 1b
|
||||
|
||||
mov a,l ! trap if bit number is too large
|
||||
sub e
|
||||
mov a,h
|
||||
sbb d
|
||||
cc eset
|
||||
|
||||
lxi b,0 ! make empty set on stack
|
||||
1: push b
|
||||
dcx h
|
||||
dcx h
|
||||
mov a,l
|
||||
ora h
|
||||
jnz 1b
|
||||
|
||||
lxi h,0
|
||||
dad sp
|
||||
dad d ! hl points to byte that will contain a one
|
||||
lda .areg
|
||||
mov c,a ! c = bit number in byte
|
||||
mvi a,1
|
||||
1: dcr c
|
||||
jm 2f
|
||||
rlc
|
||||
jmp 1b
|
||||
|
||||
2: mov m,a
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
36
mach/i80/libem/set2.s
Normal file
36
mach/i80/libem/set2.s
Normal file
@@ -0,0 +1,36 @@
|
||||
.define .set2
|
||||
|
||||
! Create 16 bits set with one bit on
|
||||
! Expects in de-reg: bit number
|
||||
! Yields in de-reg: resulting set
|
||||
|
||||
.set2: mov a,d !trap if bit number >= 16
|
||||
ora a
|
||||
cnz eset
|
||||
mov a,e
|
||||
cpi 16
|
||||
cnc eset
|
||||
|
||||
pop h
|
||||
shld .retadr
|
||||
mov a,e
|
||||
ani 7
|
||||
mov d,a
|
||||
mvi a,1
|
||||
1: dcr d
|
||||
jm 2f
|
||||
rlc
|
||||
jmp 1b
|
||||
2: mov d,a
|
||||
mov a,e
|
||||
ani 8
|
||||
jnz 3f ! jump if bit 3 is set
|
||||
|
||||
mov e,d
|
||||
mvi d,0
|
||||
jmp 4f
|
||||
|
||||
3: mvi e,0
|
||||
|
||||
4: lhld .retadr
|
||||
pchl
|
||||
28
mach/i80/libem/sli2.s
Normal file
28
mach/i80/libem/sli2.s
Normal file
@@ -0,0 +1,28 @@
|
||||
.define .sli2
|
||||
|
||||
! Shift 16 bits integer left
|
||||
! Expects on stack: number of shifts
|
||||
! number to be shifted
|
||||
! Yields in de-reg: result
|
||||
|
||||
.sli2: pop h
|
||||
shld .retadr
|
||||
|
||||
pop d !de = number of shifts
|
||||
pop h !hl= number to be shifted
|
||||
mov a,d !if de>15 return zero
|
||||
ora a
|
||||
jnz 2f
|
||||
mov a,e
|
||||
cpi 16
|
||||
jnc 2f
|
||||
1: dcr e
|
||||
jm 3f
|
||||
dad h
|
||||
jmp 1b
|
||||
|
||||
2: lxi h,0
|
||||
3: xchg !result in de-registers
|
||||
|
||||
lhld .retadr
|
||||
pchl
|
||||
45
mach/i80/libem/sli4.s
Normal file
45
mach/i80/libem/sli4.s
Normal file
@@ -0,0 +1,45 @@
|
||||
.define .sli4
|
||||
|
||||
! Shift 32 bits integer left
|
||||
! Expects on stack: number of shifts
|
||||
! number to be shifted
|
||||
! Yields on stack: result
|
||||
|
||||
.sli4:
|
||||
pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
pop b !number of shifts
|
||||
pop d !low-order bytes of number to be shifted
|
||||
pop h !high-order bytes
|
||||
mov a,b !if bc>=32 return 0
|
||||
ora a
|
||||
jnz 2f
|
||||
mov a,c
|
||||
cpi 32
|
||||
jnc 2f
|
||||
1: dcr c
|
||||
jm 3f
|
||||
dad h
|
||||
xchg
|
||||
dad h
|
||||
xchg
|
||||
jnc 1b
|
||||
inx h
|
||||
jmp 1b
|
||||
|
||||
2: lxi h,0
|
||||
lxi d,0
|
||||
|
||||
3: push h
|
||||
push d
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
|
||||
43
mach/i80/libem/sri2.s
Normal file
43
mach/i80/libem/sri2.s
Normal file
@@ -0,0 +1,43 @@
|
||||
.define .sri2
|
||||
|
||||
! Shift 16 bits signed or unsigned integer right
|
||||
! Expects in a-reg.: 1 if signed integer
|
||||
! 0 if unsigned integer
|
||||
! Expects on stack: number of shifts
|
||||
! number to be shifted
|
||||
! Yields in de-reg.: result
|
||||
|
||||
.sri2: pop h
|
||||
shld .retadr
|
||||
|
||||
pop h !hl = number of shifts
|
||||
pop d !de = number to be shifted
|
||||
mvi h,0
|
||||
ora a
|
||||
jz 1f !jump if unsigned integer
|
||||
mov a,d
|
||||
ral
|
||||
jnc 1f !jump if positive signed integer
|
||||
mvi h,255 !now h=1 if negative signed number, h=0 otherwise.
|
||||
|
||||
1: mov a,l !return 0 or -1 if hl>=16
|
||||
cpi 16
|
||||
jnc 3f
|
||||
|
||||
2: dcr l
|
||||
jm 4f
|
||||
mov a,h
|
||||
rar !set carry bit correct
|
||||
mov a,d
|
||||
rar
|
||||
mov d,a
|
||||
mov a,e
|
||||
rar
|
||||
mov e,a
|
||||
jmp 2b
|
||||
|
||||
3: mov d,h
|
||||
mov e,h
|
||||
|
||||
4: lhld .retadr
|
||||
pchl
|
||||
61
mach/i80/libem/sri4.s
Normal file
61
mach/i80/libem/sri4.s
Normal file
@@ -0,0 +1,61 @@
|
||||
.define .sri4
|
||||
|
||||
! Shift 32 bits signed or unsigned integer right
|
||||
! Expects in a-reg.: 1 if signed integer
|
||||
! 0 if unsigned integer
|
||||
! Expects on stack: number of shifts
|
||||
! number to be shifted
|
||||
! Yields on stack: result
|
||||
|
||||
.sri4: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
pop b !number of shifts
|
||||
pop d !low-order bytes of number to be shifted
|
||||
pop h !high-order bytes
|
||||
mvi b,0
|
||||
ora a
|
||||
jz 1f !jump if unsigned integer
|
||||
mov a,h
|
||||
ral
|
||||
jnc 1f !jump if positive signed integer
|
||||
mvi b,255
|
||||
|
||||
1: mov a,c
|
||||
cpi 32
|
||||
jnc 3f
|
||||
|
||||
2: dcr c
|
||||
jm 4f
|
||||
mov a,b
|
||||
rar
|
||||
mov a,h
|
||||
rar
|
||||
mov h,a
|
||||
mov a,l
|
||||
rar
|
||||
mov l,a
|
||||
mov a,d
|
||||
rar
|
||||
mov d,a
|
||||
mov a,e
|
||||
rar
|
||||
mov e,a
|
||||
jmp 2b
|
||||
|
||||
3: mov d,b
|
||||
mov e,b
|
||||
mov h,b
|
||||
mov l,b
|
||||
|
||||
4: push h
|
||||
push d
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
46
mach/i80/libem/sti.s
Normal file
46
mach/i80/libem/sti.s
Normal file
@@ -0,0 +1,46 @@
|
||||
.define .sti
|
||||
|
||||
! Store indirect
|
||||
! Expects on stack: number of bytes to be stored
|
||||
! bytes to be stored
|
||||
|
||||
.sti: pop h
|
||||
shld .retadr
|
||||
mov l,c
|
||||
mov h,b
|
||||
shld .bcreg ! save bc
|
||||
|
||||
pop h
|
||||
xra a
|
||||
mov a,d
|
||||
rar
|
||||
mov d,a
|
||||
mov a,e
|
||||
rar
|
||||
mov e,a ! de = word count
|
||||
jnc 1f
|
||||
|
||||
! if 1 byte array element only:
|
||||
mov a,d ! trap if de odd and <>1
|
||||
ora e
|
||||
cnz eoddz
|
||||
pop b
|
||||
mov m,c
|
||||
jmp 2f
|
||||
|
||||
1: pop b
|
||||
mov m,c
|
||||
inx h
|
||||
mov m,b
|
||||
inx h
|
||||
dcx d
|
||||
mov a,d
|
||||
ora e
|
||||
jnz 1b
|
||||
|
||||
2: lhld .bcreg
|
||||
mov c,l
|
||||
mov b,h
|
||||
lhld .retadr
|
||||
pchl
|
||||
|
||||
38
mach/i80/libem/xor.s
Normal file
38
mach/i80/libem/xor.s
Normal file
@@ -0,0 +1,38 @@
|
||||
.define .xor
|
||||
|
||||
|
||||
! Any size exclusive-or.
|
||||
! Expects: size in de-registers
|
||||
! operands on stack
|
||||
! Yields: result on stack
|
||||
|
||||
.xor: pop h
|
||||
shld .retadr
|
||||
mov h,b
|
||||
mov l,c
|
||||
shld .bcreg
|
||||
|
||||
lxi h,0
|
||||
dad sp
|
||||
mov c,l
|
||||
mov b,h !now bc points to top of first operand
|
||||
dad d !and hl points to top of second operand
|
||||
push h !this will be the new stackpointer
|
||||
1: ldax b
|
||||
xra m
|
||||
mov m,a
|
||||
inx h
|
||||
inx b
|
||||
dcx d
|
||||
mov a,e
|
||||
ora d
|
||||
jnz 1b
|
||||
|
||||
pop h
|
||||
sphl
|
||||
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
mov c,l
|
||||
lhld .retadr
|
||||
pchl
|
||||
8
mach/i80/libmon/LIST
Normal file
8
mach/i80/libmon/LIST
Normal file
@@ -0,0 +1,8 @@
|
||||
tail
|
||||
mon.s
|
||||
trp.s
|
||||
inn2.s
|
||||
prstring.s
|
||||
prdec.s
|
||||
char.her.s
|
||||
tail.s
|
||||
16
mach/i80/libmon/Makefile
Normal file
16
mach/i80/libmon/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
install: tail
|
||||
../../install head.s head_em
|
||||
../../install tail tail_sys
|
||||
|
||||
cmp: tail
|
||||
-../../compare head.s head_em
|
||||
-../../compare tail tail_sys
|
||||
|
||||
tail:
|
||||
arch cr `cat LIST`
|
||||
|
||||
opr:
|
||||
make pr | opr
|
||||
pr:
|
||||
@pr `pwd`/Makefile `pwd`/head.s
|
||||
@pr -l33 `tail +1 LIST|sort`
|
||||
6
mach/i80/libmon/README
Normal file
6
mach/i80/libmon/README
Normal file
@@ -0,0 +1,6 @@
|
||||
This library should contain one of the files char.her.s, that has routines
|
||||
getchar and putchar for the MC-CPM, and char.nas.s, that
|
||||
has the same routines for the Nascom.
|
||||
The default is char.her.s.
|
||||
The file char.nas.s is presented in this directory and not included
|
||||
in the libarary.
|
||||
31
mach/i80/libmon/char.her.s
Normal file
31
mach/i80/libmon/char.her.s
Normal file
@@ -0,0 +1,31 @@
|
||||
.define getchar, putchar
|
||||
|
||||
! These getchar and putchar routines can be used for HERMAC computer
|
||||
|
||||
! Read a character from HERMAC-monitor
|
||||
! Character is returned in a-reg
|
||||
|
||||
getchar:
|
||||
in 0xF1
|
||||
ani 1
|
||||
jz getchar
|
||||
in 0xF0
|
||||
cpi 0x0D
|
||||
jnz 1f
|
||||
mvi a,0x0A
|
||||
1: ret
|
||||
|
||||
! Write character on HERMAC monitor
|
||||
! Assumes character in a-reg
|
||||
|
||||
putchar:
|
||||
cpi 0x0A
|
||||
jnz 1f
|
||||
mvi a,0x1F
|
||||
1: push psw
|
||||
2: in 0xF1
|
||||
ani 4
|
||||
jz 2b
|
||||
pop psw
|
||||
out 0xF0
|
||||
ret
|
||||
50
mach/i80/libmon/char.nas.s
Normal file
50
mach/i80/libmon/char.nas.s
Normal file
@@ -0,0 +1,50 @@
|
||||
.define getchar, putchar
|
||||
|
||||
! These getchar and putchar routines can be used for NASCOM computer.
|
||||
|
||||
! Read character from NASCOM-monitor
|
||||
! Character is returned in a-reg
|
||||
|
||||
getchar:
|
||||
call 0x69
|
||||
jnc getchar
|
||||
cpi 0x1F
|
||||
jz CR
|
||||
cpi 0x1D
|
||||
jz BS
|
||||
ret
|
||||
|
||||
CR: mvi a,0x0A
|
||||
ret
|
||||
|
||||
BS: mvi a,0x08
|
||||
ret
|
||||
|
||||
! Write charcacter on NASCOM-monitor
|
||||
! Assumes character in a-reg
|
||||
|
||||
putchar:
|
||||
push h
|
||||
push b
|
||||
lxi h,tab
|
||||
mvi b,5
|
||||
1: cmp m
|
||||
jz fetch
|
||||
inx h
|
||||
inx h
|
||||
dcr b
|
||||
jnz 1b
|
||||
2: call 0x013B
|
||||
pop b
|
||||
pop h
|
||||
ret
|
||||
fetch: inx h
|
||||
mov a,m
|
||||
jmp 2b
|
||||
! conversion table for NASCOM characters
|
||||
tab: .byte 0x0D,0x00
|
||||
.byte 0x1B,0x1E
|
||||
.byte 0x08,0x1D
|
||||
.byte 0x0A,0x1F
|
||||
.byte 0x7F,0x00
|
||||
|
||||
49
mach/i80/libmon/head.s
Normal file
49
mach/i80/libmon/head.s
Normal file
@@ -0,0 +1,49 @@
|
||||
.define hol0, argv, envp, begbss
|
||||
.define .ignmask,.reghp,.trapproc,.fra
|
||||
.define .retadr,.retadr1,.areg,.bcreg,.tmp1
|
||||
.define block1, block2, block3
|
||||
.define .stop
|
||||
|
||||
.base 0x1000
|
||||
.text
|
||||
lxi h,0x1000 ! stack will grow from 0x1000 downwards
|
||||
sphl
|
||||
lxi h,begbss ! clear bss
|
||||
lxi d,endbss-begbss
|
||||
mvi c,0
|
||||
|
||||
2: mov m,c
|
||||
inx h
|
||||
dcx d
|
||||
mov a,e
|
||||
ora d
|
||||
jnz 2b
|
||||
|
||||
lxi h,envp ! call main
|
||||
push h
|
||||
lxi h,argv
|
||||
push h
|
||||
lxi h,0
|
||||
push h
|
||||
call _m_a_i_n
|
||||
.stop: jmp 0xfb52
|
||||
|
||||
.bss
|
||||
begbss:
|
||||
.trapproc: .space 2
|
||||
.ignmask: .space 2
|
||||
.data
|
||||
hol0: .space 8
|
||||
.reghp: .word endbss
|
||||
argv: .word 0
|
||||
envp: .word 0
|
||||
.retadr: .space 2 ! used to save return address
|
||||
.retadr1: .space 2 ! reserve
|
||||
.bcreg: .space 2 ! used to save localbase
|
||||
.areg: .space 1
|
||||
.tmp1: .space 2
|
||||
.fra: .space 8 ! 8 bytes function return area
|
||||
block1: .space 4 ! used by 32 bits divide and
|
||||
block2: .space 4 ! multiply routines
|
||||
block3: .space 4
|
||||
|
||||
38
mach/i80/libmon/inn2.s
Normal file
38
mach/i80/libmon/inn2.s
Normal file
@@ -0,0 +1,38 @@
|
||||
.define .inn2
|
||||
|
||||
! Bit test on 16 bits set
|
||||
! Expects on stack: bit number
|
||||
! set to be tested
|
||||
! Yields in de-registers: 0 if bit is reset or bit number out of range
|
||||
! 1 if bit is set
|
||||
|
||||
.inn2: pop h
|
||||
shld .retadr
|
||||
|
||||
pop d !bit number
|
||||
pop h !set to be tested
|
||||
mov a,e
|
||||
cpi 16
|
||||
jnc 3f
|
||||
cpi 8
|
||||
jnc 1f
|
||||
mov e,a
|
||||
mov a,l !l-reg contains the wanted bit
|
||||
jmp 2f
|
||||
|
||||
1: sbi 8
|
||||
mov e,a
|
||||
mov a,h !h-reg contains the wanted bit
|
||||
|
||||
2: dcr e
|
||||
jm 4f
|
||||
rar
|
||||
jmp 2b
|
||||
|
||||
3: xra a !return 0 if bit number out of range
|
||||
4: ani 1
|
||||
mov e,a
|
||||
mvi d,0
|
||||
|
||||
lhld .retadr
|
||||
pchl
|
||||
@@ -7,6 +7,9 @@
|
||||
! number 1: exit
|
||||
! number 3: read
|
||||
! number 4: write
|
||||
! number 5: open
|
||||
! number 6: close
|
||||
! number 54: ioctl
|
||||
! If called with a number of a call that is not implemented,
|
||||
! a trap is generated.
|
||||
|
||||
@@ -24,10 +27,16 @@
|
||||
jz monread ! is it a read?
|
||||
cpi 4
|
||||
jz monwrite ! is it a write?
|
||||
cpi 5
|
||||
jz monopen ! is it an open?
|
||||
cpi 6
|
||||
jz monclose ! is it a close?
|
||||
cpi 54
|
||||
jz monioctl
|
||||
jmp ebadmon ! trap
|
||||
|
||||
monexit:
|
||||
rst 4
|
||||
jmp .stop
|
||||
|
||||
monread:
|
||||
pop h ! file-descriptor, not used
|
||||
@@ -69,6 +78,28 @@ monwrite:
|
||||
2: push d ! no error
|
||||
jmp monret
|
||||
|
||||
|
||||
monopen:
|
||||
pop h ! pointer to string
|
||||
pop h ! flag
|
||||
lxi h,-1
|
||||
push h ! push file descriptor
|
||||
push h ! push error code twice
|
||||
push h
|
||||
jmp monret
|
||||
|
||||
monclose:
|
||||
lxi h,0
|
||||
xthl ! remove file descriptor and push error code
|
||||
jmp monret
|
||||
|
||||
monioctl:
|
||||
pop h ! file descriptor
|
||||
pop h ! request
|
||||
lxi h,0
|
||||
xthl ! remove argp and push error code
|
||||
jmp monret
|
||||
|
||||
monret:
|
||||
lhld .bcreg
|
||||
mov b,h
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user