113 Commits

Author SHA1 Message Date
cvs2hg
8d7ceb6d6c fixup commit for tag 'distr2' 1987-08-26 13:58:31 +00:00
em
d10d14acac Initial revision 1985-04-15 00:05:45 +00:00
em
ca5599714b Initial revision 1985-04-14 23:26:24 +00:00
keie
f337b8df6d Removed RANLIB . 1985-04-14 14:27:04 +00:00
keie
7cd58cabab Added m68k4, pmds4
Removed one superfluous line.
1985-04-14 13:59:14 +00:00
em
8b4f21bd95 Added libraries needed after installation of cg. 1985-04-14 13:57:31 +00:00
em
ab820d3083 8080->i80. 1985-04-14 13:54:33 +00:00
em
fb23d440f0 Removed a superfluous line. 1985-04-14 13:46:54 +00:00
em
f70b857d1b Added pmds4. 1985-04-14 13:22:26 +00:00
em
bd07643039 To prevent a (incorrrect) error message from distr/mktree. 1985-04-12 20:32:06 +00:00
keie
686e5af1bb *** empty log message *** 1985-04-12 20:07:13 +00:00
keie
34ccddfc2d The library name was incorrect. 1985-04-12 17:21:52 +00:00
keie
b6f73fdc29 Initial revision 1985-04-12 17:08:56 +00:00
keie
c19324dfea *** empty log message *** 1985-04-12 17:06:38 +00:00
keie
772b64fabd *** empty log message *** 1985-04-12 16:56:43 +00:00
keie
ef92740400 Deletion of a few coercions caused a translation failure
for setjmp.e.
The coercions have been grabbed from an old version by FvH.
1985-04-12 16:43:40 +00:00
keie
ee9c5be180 Initial revision 1985-04-12 16:40:22 +00:00
bal
ca9a6feeb0 floating point stuff added 1985-04-12 15:47:30 +00:00
keie
022cb596be *** empty log message *** 1985-04-12 15:06:05 +00:00
keie
9eb53c3d47 *** empty log message *** 1985-04-12 14:59:45 +00:00
keie
dfcfa9883b Initial revision 1985-04-12 14:55:00 +00:00
em
fb6d291d38 *** empty log message *** 1985-04-12 14:33:09 +00:00
em
e4e29ae837 Added flp.s, contains subroutines for all EM fp instructions.
They trap.
1985-04-12 14:29:07 +00:00
em
94534b7c15 1- Floating point routines now call routines instead of calling trp. 1985-04-12 14:25:59 +00:00
em
491040b2c7 *** empty log message *** 1985-04-12 14:01:20 +00:00
keie
b4adc21f19 Putting some dots on some i's. 1985-04-12 11:32:41 +00:00
keie
bae4084355 *** empty log message *** 1985-04-12 11:25:21 +00:00
keie
d394fe5dda Just newer. 1985-04-12 11:20:15 +00:00
keie
dcfe4e8a97 *** empty log message *** 1985-04-09 13:48:55 +00:00
keie
be9e253a2f Added 1)libsys 2)end_em.
Changed handling of -i flag.
1985-04-02 11:21:33 +00:00
keie
620216fb26 Error code 0 was returned when the installation failed! 1985-04-02 10:55:02 +00:00
keie
70d71f4355 Copy of ../libbc/compmodule. 1985-04-02 10:50:53 +00:00
keie
6b87f1082e Removed -DCPM. 1985-04-02 10:46:43 +00:00
em
fd44c34a61 *** empty log message *** 1985-04-01 17:02:55 +00:00
keie
6c247029bd *** empty log message *** 1985-04-01 14:44:26 +00:00
keie
6bbdb92784 Adapted after installation of backend. 1985-04-01 14:02:58 +00:00
keie
22182c0d7f *** empty log message *** 1985-04-01 14:00:00 +00:00
keie
87f66789de Some minor cleaning up. 1985-04-01 13:20:42 +00:00
em
1879c8e724 *** empty log message *** 1985-03-29 21:44:50 +00:00
em
693830b09a *** empty log message *** 1985-03-29 21:10:43 +00:00
keie
e3fa99632e Corrected parameter name usage from i to d. 1985-03-26 17:03:30 +00:00
keie
b3d11b1fa5 Removed pascal library. 1985-03-26 16:27:23 +00:00
keie
2b6187a009 *** empty log message *** 1985-03-26 16:23:21 +00:00
keie
a8fc6009f7 The dl programs is replaced by a more general cv. 1985-03-26 16:20:11 +00:00
keie
92141b52ce Installed backend and libraries. 1985-03-26 16:18:24 +00:00
keie
b63f304db1 Or's are not allowed on a-registers, add's are. 1985-03-26 16:09:07 +00:00
keie
ec3e755168 Adapted to Unisoft signal handling. 1985-03-26 16:08:09 +00:00
keie
a41ff68078 *** empty log message *** 1985-03-26 15:04:46 +00:00
keie
244e172413 Added head_em. 1985-03-26 15:04:02 +00:00
keie
da936740a6 Added head_em to libsys. 1985-03-26 15:00:09 +00:00
keie
35fae90a9d Fetch head_em from pmds4.
Short size is 2 not 4!
1985-03-26 14:58:54 +00:00
keie
c5a739c68f Moved head_em to libsys. 1985-03-26 14:53:00 +00:00
keie
dc92fe358e *** empty log message *** 1985-03-26 14:48:32 +00:00
keie
59996174b6 Added some more system calls.
Moved errno to a separate file.
1985-03-21 14:13:55 +00:00
keie
84f9364d4c errno is moved to a sfile of its own. 1985-03-21 14:05:03 +00:00
keie
a635fb0203 *** empty log message *** 1985-03-21 14:04:45 +00:00
em
e3e1c5ac20 *** empty log message *** 1985-03-18 17:27:42 +00:00
em
e3e9add8b1 Initial revision 1985-03-18 17:24:31 +00:00
em
ffd0d165a7 *** empty log message *** 1985-03-18 15:52:00 +00:00
em
c1d5a0c721 Changed 8080 into i80. 1985-03-18 14:44:15 +00:00
em
3e743d78f3 *** empty log message *** 1985-03-18 14:39:26 +00:00
em
90c847ca59 *** empty log message *** 1985-03-18 14:32:46 +00:00
em
1b162c577e *** empty log message *** 1985-03-18 13:46:31 +00:00
em
a5f4b01d82 Initial revision 1985-03-18 13:15:00 +00:00
em
c5508c7c0b *** empty log message *** 1985-03-18 13:12:07 +00:00
garde
80e349860b Added RCS id. 1985-03-18 12:55:07 +00:00
em
157b243956 *** empty log message *** 1985-03-18 12:46:51 +00:00
em
eabf214312 *** empty log message *** 1985-03-18 11:11:44 +00:00
garde
d52117c8dd Some less important changes 1985-03-18 10:00:30 +00:00
keie
d457c50945 The universal assembler has a bug that precludes use of .align
in text segments, except as the very last command.
1985-03-15 11:03:41 +00:00
keie
b294ab5042 The universal assembler has a bug that precludes use of .align
in text segments, except as the very last command.
1985-03-15 10:50:35 +00:00
em
9d0812746b The assembler proved to contain yet another bug.
.align in text segments will not work for values that are
not a divisor of the gcd of the instruction sizes.
1985-03-14 17:33:28 +00:00
em
9f203c9a17 Expressions are now always calculated in long.
Some backends needed that.
1985-03-12 10:41:29 +00:00
em
0c92039ba4 Expression are always evaluated in longs.
Some 2-4 backends needed long expressions.
1985-03-12 10:39:24 +00:00
em
cf6d084155 Use of the Pascal library will not occur.
/.
1985-03-12 10:24:51 +00:00
keie
7e6a6f6de2 Now also testing for availability of /tmp and /usr/tmp. 1985-03-11 13:10:52 +00:00
bal
954d3a0326 Argument is 4 bytes (pointer), not 2 bytes. 1985-03-05 12:33:29 +00:00
keie
6f6356e0b4 Initial revision 1985-03-05 00:17:40 +00:00
keie
9e26d0e0c0 *** empty log message *** 1985-03-05 00:15:40 +00:00
keie
bf3ba84e92 Adapted to 4-4. 1985-03-04 17:26:31 +00:00
keie
7a790e48fb Bleasdale only. 1985-03-04 16:47:56 +00:00
keie
32bc0f2982 Initial revision 1985-03-04 16:44:32 +00:00
keie
fb4a3fd479 *** empty log message *** 1985-03-04 16:35:40 +00:00
keie
ccdb8693ee Now using 4-byte integers and clearing D1 for double size
instruction pointers.
1985-03-04 16:12:10 +00:00
keie
a8c5699241 Now returns correct values. 1985-03-04 16:11:56 +00:00
keie
e0c4e4b686 Added execv and execle. 1985-03-04 16:11:41 +00:00
keie
8a40c25069 Now using .reghp. 1985-03-04 16:11:26 +00:00
keie
0fd729951a Removed superfluous instruction. 1985-03-04 16:10:47 +00:00
keie
7a30dc4868 *** empty log message *** 1985-03-04 16:08:41 +00:00
keie
4b1965afbc *** empty log message *** 1985-03-04 15:55:28 +00:00
keie
b2b281f525 To force the first part of a circular ring of modules in from
tail_em.
/.
1985-03-04 15:37:38 +00:00
keie
d2a6847715 The previous version still assumed two-byte integers. 1985-03-04 15:33:28 +00:00
keie
2690f07cbd Incorrect alignment caused odd _end, which caused
failures of malloc().
1985-03-04 15:30:44 +00:00
keie
aa82964563 Now also prints stack height. 1985-03-04 15:29:36 +00:00
keie
c636aba734 Alignment now also works when the alignment ended on odd boundaries. 1985-03-04 15:28:02 +00:00
keie
ce92663b0a Initial revision 1985-03-04 15:27:09 +00:00
keie
a89ba7074f Always returned non-zero value. 1985-03-04 15:25:33 +00:00
keie
a71e706aa4 *** empty log message *** 1985-03-04 15:14:01 +00:00
garde
736a2d1022 Many things improved and extended 1985-03-04 13:42:38 +00:00
keie
17e13e9e71 Adapted to single cv for all machines. 1985-03-01 22:11:46 +00:00
keie
9d7b94ba34 Adapted to a single cv for all machines. 1985-03-01 22:10:44 +00:00
keie
218f7ed718 Corrected a horrible typing mistake. 1985-03-01 20:08:45 +00:00
keie
cb0b2e08cf 1 - At RREMOVE also check the stack set aside for coercions.
2 - When coercions unexpectedly need stack of part of the
stakpattern, discontinue this option.
1985-03-01 16:25:21 +00:00
keie
c2a990768d The top of the stack, which is set aside for certain
coercions is now saved with special routines.
This allows RREMOVE to check for registers.
1985-03-01 16:20:13 +00:00
keie
36537eccc0 Also clear D1 (for static link). 1985-03-01 16:00:23 +00:00
keie
6cdcb391fb Added RCS ID. 1985-03-01 10:34:00 +00:00
keie
9d9c9ae97b *** empty log message *** 1985-03-01 10:30:23 +00:00
bal
c478b62711 bug fixed in kill_much():
for ( .. ; i != (Lindex) i; ..  ) should be
for ( .. ; i != (Lindex) 0; ..  ).
1985-02-28 10:35:57 +00:00
keie
e7f7f33f60 cg tried to stack register parameters of moves, when
these registers were killed.
1985-02-26 16:31:38 +00:00
keie
c1f3dbba33 1 - Removed PMDS from selection list.
2 - Joined two line, that should have been one.
1985-02-26 11:56:57 +00:00
bal
d5098fe70f Bug fixed: co_lfirst received wrong value for multiply-optimization. 1985-02-25 14:03:09 +00:00
bal
469d075e77 Calls of which the actual and formal parameters do not match
are no longer substituted inline.
1985-02-20 15:01:02 +00:00
keie
2a4b3fd616 Removed nascom/z80a from the distribution. 1985-02-19 13:59:17 +00:00
472 changed files with 12307 additions and 30859 deletions

14
Action
View File

@@ -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

View File

@@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
echo $1/$2

42
distr/f.attf Normal file
View 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
View 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
View File

@@ -0,0 +1,2 @@
echo "<$1/$2>"
ls -bCdx `cat .distr`

10
distr/listdirs Executable file
View 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
View 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

1
distr/mkd Executable file
View File

@@ -0,0 +1 @@
mkdir $DESTDIR/$1/$2

23
distr/mkf Executable file
View 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

1
distr/mks Executable file
View File

@@ -0,0 +1 @@
cp .distr $DESTDIR/$1

15
distr/mktree Normal file
View 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

2
distr/ts Executable file
View File

@@ -0,0 +1,2 @@
DD=`pwd`/ts
echo OK

View File

@@ -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
View 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.

File diff suppressed because it is too large Load Diff

View File

@@ -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
View 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.

View File

@@ -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

View File

@@ -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
View File

@@ -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))

View File

@@ -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"

View File

@@ -19,7 +19,7 @@ double d;
String *s;
s= _newstr(buffer);
* ( (double *)s->strval ) = i ;
* ( (double *)s->strval ) = d ;
return(s);
}
long _cvi(s)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -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

View File

@@ -1,8 +1,8 @@
.define endtext, enddata, endbss, end
.text
.align 2
endtext:
.align 2
.data
.align 2
enddata:

View File

@@ -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

View File

@@ -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:

View File

@@ -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
View 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
View 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.

View File

@@ -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
View 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);
}

View File

@@ -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:

View File

@@ -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

View File

@@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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.

View 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

View 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
View 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
View 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

View File

@@ -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